You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Three.js自定义顶点着色器后阴影静态问题求助

解决Three.js自定义顶点着色器阴影静态问题

问题根源

Three.js中物体的阴影是通过渲染深度材质生成的深度缓冲计算而来的。你当前只给主材质应用了自定义顶点着色器,但customDepthMaterial仍使用默认的顶点逻辑,没有同步顶点变换,导致深度缓冲里的物体位置还是原始状态,阴影自然不会跟随物体变形。

解决方案

需要给customDepthMaterial也应用相同的顶点变换逻辑,并同步所有动态uniforms(比如time),具体修改如下:

1. 复用顶点变换逻辑,给深度材质添加onBeforeCompile

修改你的材质工厂函数,将顶点变换逻辑提取为可复用的函数,同时给customDepthMaterial设置相同的着色器处理:

make = (shaderUniforms, shader_type) =>
{
    let material
    switch(shader_type)
    {
        case SHADER_TYPES.GRASS:
            material = this.raw_material; break;
        default:
            material = this.phong_material
    }
    material = material.clone()
    material.needsUpdate = true;
    let {uuid} = material

    // 提取顶点变换逻辑,主材质和深度材质共用
    const setupShader = (shader) => {
        // 合并uniforms,包括动态变量
        shader.uniforms = {
            ...shader.uniforms,
            ...shaderUniforms,
            time: {value: 0},
        }
        // 应用自定义顶点着色器
        shader.vertexShader = this.shader_maker.make(shader_type).vertex;
    }

    // 处理主材质
    material.onBeforeCompile = (shader) => {
        setupShader(shader);
        // 主材质需要自定义片元着色器
        shader.fragmentShader = this.shader_maker.make(shader_type).fragment;
        this.context.shaders[uuid] = shader
    }

    // 创建并配置自定义深度材质
    material.customDepthMaterial = new THREE.MeshDepthMaterial({
        depthPacking: THREE.RGBADepthPacking,
        alphaTest: 0.5
    });
    // 深度材质应用相同的顶点变换
    material.customDepthMaterial.onBeforeCompile = setupShader;

    return material
}

2. 同步动态Uniforms的更新

在你的动画循环中,需要同时更新主材质和深度材质的动态uniforms(比如time),确保两者的顶点变换同步:

// 示例动画循环
function animate() {
    requestAnimationFrame(animate);
    const currentTime = performance.now() * 0.001;

    // 更新主材质的uniforms
    Object.values(this.context.shaders).forEach(shader => {
        shader.uniforms.time.value = currentTime;
    });

    // 更新深度材质的uniforms
    scene.traverse(obj => {
        if (obj.material?.customDepthMaterial?.uniforms) {
            obj.material.customDepthMaterial.uniforms.time.value = currentTime;
            // 其他需要同步的uniforms也在这里更新
        }
    });

    renderer.render(scene, camera);
}

关键注意点

  • 自定义顶点着色器必须正确输出gl_Position:确保顶点变换后,通过projectionMatrix * modelViewMatrix * vec4(transformed, 1.0)计算最终位置,深度材质依赖这个值生成正确的深度缓冲。
  • 如果你的自定义顶点着色器依赖其他属性(如UV、法线),深度材质的顶点着色器也要确保这些属性被正确传递(MeshDepthMaterial默认已处理基础属性,一般无需额外修改)。

内容的提问来源于stack exchange,提问作者Roman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 23:07:45