Three.js自定义着色器中灯光颜色值异常问题求助
问题分析与解决
核心原因1:方向光未添加到场景
你创建了DirectionalLight但没有执行scene.add(dirLight),Three.js的灯光系统只会识别已添加到场景(或场景层级结构中)的灯光,未添加的灯光不会被纳入uniform更新流程,直接导致方向光数据不符合预期。
核心原因2:RawShaderMaterial不支持自动灯光uniform同步
RawShaderMaterial是原始着色器材质,和ShaderMaterial的核心区别在于:它不会自动处理Three.js内置的灯光逻辑——即使你设置了lights: true,也不会主动收集场景中的灯光数据、更新对应uniform值,更不会处理颜色空间转换(比如sRGB转线性空间)。
你当前看到的环境光uniform值3.14,是THREE.UniformsLib["lights"]的默认初始值,而非你添加到场景的AmbientLight的实际颜色值。
解决办法
方案1:改用ShaderMaterial(推荐,适配多数场景)
如果不需要完全自定义所有uniform与着色器逻辑,改用ShaderMaterial可以自动处理灯光的uniform同步和颜色转换:
// 替换RawShaderMaterial为ShaderMaterial _meshMaterial = new THREE.ShaderMaterial({ uniforms: uniforms1, vertexShader: terrainShader._VS, fragmentShader: terrainShader._FS, lights: true, side: THREE.DoubleSide, });
同时必须把方向光添加到场景:
const dirLight = new THREE.DirectionalLight(0x808080, 0.5); scene.add(dirLight); // 关键步骤:将灯光纳入场景管理
方案2:继续使用RawShaderMaterial,手动处理灯光数据
如果必须保留RawShaderMaterial,需要手动同步灯光数据到uniform,并处理颜色空间转换:
- 确保所有灯光都已添加到场景
- 在渲染循环或灯光参数变化时,手动更新uniform:
// 手动同步灯光数据到uniform的函数 function updateLightUniforms() { // 处理环境光(假设场景中只有一个) const ambientLight = scene.getObjectByProperty('type', 'AmbientLight'); const linearAmbientColor = ambientLight.color.convertSRGBToLinear(); uniforms1.ambientLightColor.value.set(linearAmbientColor.r, linearAmbientColor.g, linearAmbientColor.b); // 处理方向光(假设场景中只有一个) const dirLight = scene.getObjectByProperty('type', 'DirectionalLight'); const linearDirColor = dirLight.color.convertSRGBToLinear().multiplyScalar(dirLight.intensity); uniforms1.directionalLights.value[0].color.set(linearDirColor.r, linearDirColor.g, linearDirColor.b); // 同步方向光方向(需对应着色器中的空间转换逻辑) uniforms1.directionalLights.value[0].direction.copy(dirLight.position).normalize(); } // 在渲染循环中调用更新 function render() { updateLightUniforms(); renderer.render(scene, camera); requestAnimationFrame(render); }
注意:THREE.UniformsLib["lights"]的uniform是数组结构(支持多灯光),需要对应数组索引更新;同时你的着色器代码要匹配该结构来读取灯光数据,比如片段着色器中需声明:
uniform vec3 ambientLightColor; struct DirectionalLight { vec3 direction; vec3 color; }; uniform DirectionalLight directionalLights[ MAX_DIR_LIGHTS ];
内容的提问来源于stack exchange,提问作者Pravin Poudel
相关产品推荐
相关产品推荐

