【问题标题】:How to update shadows in modified MeshPhysicalMaterial shader如何在修改后的 MeshPhysicalMaterial 着色器中更新阴影
【发布时间】:2021-04-09 14:59:58
【问题描述】:

我无法让我的模型使用自定义着色器投射正确的阴影。

我为 THREE.MeshPhysicalMaterial 做了一个稍微修改的顶点着色器块,它允许我调整变形目标的行为。具体来说,我在顶点着色器中移动位置变量 transformed 以根据输入 uniform 变形模型的不同部分,而不是像正常的那样一次全部变形。这与渲染几何体的预期相同,但是它投射到地面等对象上的阴影本身并不能反映变化。我附上了一张说明问题的图片。应用变形后,模型会分成小块,但地面上的阴影仍显示为实心环形。

我认为这与需要 customDepthMaterial 有关,但我找不到太多关于它的信息来了解我应该如何整合我的调整。如果您能提供任何见解,我们将不胜感激。

这是我替换标准变形目标块的顶点片段块:morphtarget_vertex

float t = fillAmount;
float u = uv.x;
t = fit(t, 0.0, 1.0, -fillWidth, 1.0 + fillWidth);
t = fit(u, t, t + fillWidth, 1.0, 0.0);

transformed *= morphTargetBaseInfluence;
transformed += morphTarget0 * t;
#ifndef USE_MORPHNORMALS
    transformed += morphTarget4 * t;
#endif

这是我创建修改后的 MeshPhysicalMaterial 的代码,它使用我的自定义顶点着色器块

function getModifiedMaterial()
{
    return new Promise((resolve, reject) =>
    {
        Promise.all([
            fetch("donut.prefix.vertex").then(res => res.text()),
            fetch("donut.vertex").then(res => res.text())
        ])
        .then(results =>
        {
            var prefix = results[0];
            var body = results[1];

            var material = new THREE.MeshPhysicalMaterial(
            {
                morphTargets: true,
                vertexColors: true
            }).clone();

            material.userData.fillAmount = { value: 0.9 };
            material.userData.fillWidth = { value: 0.0 };

            material.customProgramCacheKey = () => "donut";
            material.onBeforeCompile = shader =>
            {
                shader.uniforms.fillAmount = material.userData.fillAmount;
                shader.uniforms.fillWidth = material.userData.fillWidth;[![enter image description here][1]][1]

                shader.vertexShader = prefix + "\n" + shader.vertexShader.replace("#include <morphtarget_vertex>", body);
            };

            resolve(material);
        });
    });
}

【问题讨论】:

  • 提示:mesh.customDepthMaterial = new THREE.MeshDepthMaterial( { depthPacking: THREE.RGBADepthPacking } ); MeshDepthMaterial 使用 depth_vert.glsl.js。对您在上面所做的自定义深度材质进行相同的更改。
  • 漂亮!这正是我所需要的。如果你想让你的评论成为答案,我会接受它
  • 没关系。您可以更详细地回答您自己的问题。 :-)

标签: three.js glsl shader vertex-shader


【解决方案1】:

答案确实来自 WestLangley 的评论,但这里有一些额外的细节:

您创建一个 THREE.MeshDepthMaterial 的实例,其顶点颜色和变形目标的设置相同,然后对 vertexShader 进行相同的修改作为主要材质。然后将此新材质分配给 mesh.customDepthMaterial 插槽。您可能会遇到的一件事是,虽然主着色器可以访问法线和顶点颜色,但深度着色器却不能。您可以通过在着色器的定义中添加一个条目来解决此问题,如下所示:shaders.defines.ISDEPTH = "" 然后您可以使用 #ifdef ISDEPTH 在着色器中检查它

我的物质功能变成了这个

function getModifiedMaterial()
{
    return new Promise((resolve, reject) =>
    {
        Promise.all([
            fetch("donut.prefix.vertex").then(res => res.text()),
            fetch("donut.vertex").then(res => res.text())
        ])
        .then(results =>
        {
            var prefix = results[0];
            var body = results[1];

            var material = new THREE.MeshPhysicalMaterial(
            {
                morphTargets: true,
                vertexColors: true
            });

            material.userData.fillAmount = { value: 0.9 };
            material.userData.fillWidth = { value: 0.0 };

            material.customProgramCacheKey = () => "donut";
            material.onBeforeCompile = shader =>
            {
                shader.defines.FULL = "";
                shader.uniforms.fillAmount = material.userData.fillAmount;
                shader.uniforms.fillWidth = material.userData.fillWidth;

                shader.vertexShader = prefix + "\n" + shader.vertexShader.replace("#include <morphtarget_vertex>", body);
            };

            var depthMaterial = new THREE.MeshDepthMaterial(
            { 
                depthPacking: THREE.RGBADepthPacking,
                morphTargets: true,
                vertexColors: true
            });
            depthMaterial.customProgramCacheKey = () => "donutdepth";
            depthMaterial.onBeforeCompile = shader =>
            {
                shader.uniforms.fillAmount = material.userData.fillAmount;
                shader.uniforms.fillWidth = material.userData.fillWidth;

                shader.vertexShader = prefix + "\n" + shader.vertexShader.replace("#include <morphtarget_vertex>", body);
            };

            resolve({ main: material, depth: depthMaterial });
        });
    });
}

你可以像这样分配结果

            getModifiedMaterial().then(materials =>
            {
                mesh.material = materials.main;
                mesh.customDepthMaterial = materials.depth;
                scene.add(mesh);

                resolve();
            });

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-26
    • 1970-01-01
    • 2019-06-30
    • 2019-11-02
    • 2013-08-23
    • 1970-01-01
    相关资源
    最近更新 更多