Three.js中如何让自定义Shader接收阴影?
解决Three.js自定义Shader无法接收阴影的问题
我完全懂你现在的困扰——Three.js官方在自定义Shader处理阴影这块的文档和示例确实少得可怜,好在你已经搞定了渲染和投射阴影,就差接收阴影这最后一步了。咱们来拆解下代码里漏掉的关键环节:
问题核心:接收阴影的必要逻辑缺失
要让自定义Shader能接收阴影,片元着色器里必须完成阴影采样计算,并把阴影衰减值应用到最终颜色上。从你提供的代码看,有两个关键步骤没做到位:
- 虽然引入了
shadowmap_pars_fragment这个着色器块,但没在主函数里调用shadowmap_fragment来实际计算阴影因子; - 没有把计算出的阴影衰减值和你的光照结果结合,导致阴影无法体现在画面上。
修改后的完整代码建议
下面是调整后的代码,重点看片元着色器的修改部分:
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
相关产品推荐
相关产品推荐

