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

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,并处理颜色空间转换:

  1. 确保所有灯光都已添加到场景
  2. 在渲染循环或灯光参数变化时,手动更新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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 05:33:57