如何在修改后的 MeshPhysicalMaterial 着色器中更新阴影
How to update shadows in modified MeshPhysicalMaterial shader
我无法使用自定义着色器让我的模型投射正确的阴影。
我为 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);
});
});
}
答案确实来自 WestLangley 的评论,但这里有一些额外的细节:
您创建了一个 THREE.MeshDepthMaterial 的实例,其顶点颜色和变形目标设置相同,然后对顶点着色器进行与主 material 相同的修改。然后将这个新的 material 分配给 mesh.customDepthMaterial 槽。您可能 运行 了解的一件事是,虽然主着色器可以访问法线和顶点颜色,但深度着色器不能。您可以通过向着色器的定义添加一个条目来解决此问题,如下所示: shaders.defines.ISDEPTH = "" 然后您可以使用 #ifdef ISDEPTH
在着色器中检查它
我的material函数变成了这个
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();
});
我无法使用自定义着色器让我的模型投射正确的阴影。
我为 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);
});
});
}
答案确实来自 WestLangley 的评论,但这里有一些额外的细节:
您创建了一个 THREE.MeshDepthMaterial 的实例,其顶点颜色和变形目标设置相同,然后对顶点着色器进行与主 material 相同的修改。然后将这个新的 material 分配给 mesh.customDepthMaterial 槽。您可能 运行 了解的一件事是,虽然主着色器可以访问法线和顶点颜色,但深度着色器不能。您可以通过向着色器的定义添加一个条目来解决此问题,如下所示: shaders.defines.ISDEPTH = "" 然后您可以使用 #ifdef ISDEPTH
在着色器中检查它我的material函数变成了这个
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();
});