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

Three.js中如何让自定义Shader接收阴影?

解决Three.js自定义Shader无法接收阴影的问题

我完全懂你现在的困扰——Three.js官方在自定义Shader处理阴影这块的文档和示例确实少得可怜,好在你已经搞定了渲染和投射阴影,就差接收阴影这最后一步了。咱们来拆解下代码里漏掉的关键环节:

问题核心:接收阴影的必要逻辑缺失

要让自定义Shader能接收阴影,片元着色器里必须完成阴影采样计算,并把阴影衰减值应用到最终颜色上。从你提供的代码看,有两个关键步骤没做到位:

  1. 虽然引入了shadowmap_pars_fragment这个着色器块,但没在主函数里调用shadowmap_fragment来实际计算阴影因子;
  2. 没有把计算出的阴影衰减值和你的光照结果结合,导致阴影无法体现在画面上。

修改后的完整代码建议

下面是调整后的代码,重点看片元着色器的修改部分:

var mat = new THREE.ShaderMaterial({ 
    uniforms: THREE.UniformsUtils.merge([ 
        THREE.UniformsLib.fog, 
        THREE.UniformsLib.lights, 
        THREE.UniformsLib.shadowmap, 
        { 
            mapMain: {value: null}, 
            mapGlow: {value: null} 
        } 
    ]), 
    vertexShader: [ 
        "uniform vec4 offsetRepeat;", 
        "varying vec3 vNormal;", 
        "varying vec2 vUv;", 
        "varying vec3 vViewPosition;", 
        "varying vec3 fPosition;", 
        "varying vec2 vUvM;", 
        THREE.ShaderChunk.common, 
        THREE.ShaderChunk.lights_pars_begin, 
        THREE.ShaderChunk.shadowmap_pars_vertex, 
        THREE.ShaderChunk.fog_pars_vertex, 
        "void main(){", 
        "vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);", 
        "vec4 worldPosition = modelMatrix * vec4(position, 1.0);", 
        "vViewPosition = - mvPosition.xyz;", 
        "vNormal = normalize( normalMatrix *normal );", 
        "vUv = uv ;", 
        "vUvM = uv;", 
        "gl_Position = projectionMatrix * mvPosition;", 
        THREE.ShaderChunk.shadowmap_vertex, 
        THREE.ShaderChunk.fog_vertex, 
        "}" 
    ].join("\n"), 
    fragmentShader: [ 
        "uniform sampler2D mapMain;", 
        "uniform sampler2D mapGlow;", 
        THREE.ShaderChunk.common, 
        THREE.ShaderChunk.bsdfs, 
        THREE.ShaderChunk.packing, 
        THREE.ShaderChunk.shadowmap_pars_fragment, 
        THREE.ShaderChunk.fog_pars_fragment, 
        THREE.ShaderChunk.lights_pars_begin, 
        THREE.ShaderChunk.lights_pars_maps, 
        "varying vec3 vNormal;", 
        "varying vec2 vUv;", 
        "varying vec2 vUvM;", 
        "varying vec3 vViewPosition;", 
        "void main(){", 
        "vec4 mainColor = texture2D(mapMain, vUv);", 
        "vec3 glowColor = texture2D(mapGlow, vUvM).rgb;", 
        "vec3 glow = (1.0 - mainColor.a) * glowColor;", 
        "vec3 normal = normalize( vNormal );", 
        "vec3 viewPosition = normalize( vViewPosition );", 
        "vec3 totalDiffuseLight = vec3( 0.0 );", 
        // 初始化阴影因子:默认无阴影,全亮
        "float shadow = 1.0;", 
        // 执行阴影计算,自动更新shadow变量的值
        THREE.ShaderChunk.shadowmap_fragment, 
        "#if NUM_DIR_LIGHTS > 0", 
        "vec3 dirDiffuse = vec3( 0.0 );", 
        "for( int i = 0; i < NUM_DIR_LIGHTS; i++ ) {", 
        "vec3 dirVector = directionalLights[ i ].direction;", 
        "float dirDiffuseWeight = max( dot( normal, dirVector ), 0.0 );", 
        "totalDiffuseLight += directionalLights[ i ].color * dirDiffuseWeight;", 
        "}", 
        "#endif", 
        // 将阴影因子应用到最终颜色,阴影区域会变暗
        "gl_FragColor = vec4((mainColor.rgb + glow) * totalDiffuseLight * shadow, 1.0);", 
        THREE.ShaderChunk.fog_fragment, 
        "}" 
    ].join("\n")
});

额外注意事项

别忘了在网格对象上开启接收阴影:

mesh.receiveShadow = true;

同时要确保你的光源已经正确配置了阴影(比如light.castShadow = true,并设置合适的阴影相机参数),这一步如果没做好,阴影也不会正常显示。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 07:17:48