WebGL中实现平行光和环境光需在着色器中手动计算:1.定义uniform光源参数;2.环境光直接与材质色相乘;3.用Lambert模型计算平行光漫反射;4.叠加两项并输出。注意法线归一化、空间一致性及uniform正确传入。

在 WebGL 中添加平行光(Directional Light)和环境光(Ambient Light),关键在于着色器(vertex/fragment shader)中手动实现光照计算,因为 WebGL 本身不提供内置光照系统。你需要在 fragment shader 中计算光照贡献,并与材质颜色混合。下面分步骤说明核心实现方式。
1. 在着色器中定义光源与材质参数
平行光有方向(vec3)和颜色(vec3),环境光只有颜色(vec3)。通常在 fragment shader 开头声明为 uniform:
uniform vec3 u_ambientLight; uniform vec3 u_directionalLightColor; uniform vec3 u_directionalLightDir; // 注意:应为世界空间中的单位向量,指向光源(不是朝向)
⚠️ 注意:u_directionalLightDir 是从片元指向光源的方向(即光的传播方向),例如太阳光从上往下照,可设为 vec3(0.0, -1.0, 0.0);务必归一化(CPU 端传入前 normalize,或 shader 中用 normalize())。
2. 计算环境光(简单叠加)
环境光不依赖法线或位置,直接与材质基色(如 v_color 或 u_diffuseColor)相乘:
立即学习“Java免费学习笔记(深入)”;
vec3 ambient = u_ambientLight * v_color;
其中 v_color 是插值得到的顶点颜色(或你用的漫反射颜色),环境光项通常较弱(例如 u_ambientLight = vec3(0.1))。
3. 计算平行光的漫反射(Lambert 模型)
标准 Phong/Lambert 光照中,漫反射强度 = max(dot(N, L), 0.0),N 是世界空间单位法线,L 是归一化的光方向向量:
- 确保顶点着色器输出的世界法线(
v_normal)已归一化(插值后需在 fragment shader 再次 normalize) - L 应与 N 同一空间(推荐统一用世界空间)
- 代码示例:
vec3 norm = normalize(v_normal); vec3 lightDir = normalize(u_directionalLightDir); float diff = max(dot(norm, lightDir), 0.0); vec3 diffuse = diff * u_directionalLightColor * v_color;
4. 合并光照结果并输出
将环境光与漫反射光相加(忽略镜面光时),再约束到 [0,1] 范围:
vec3 result = ambient + diffuse; gl_FragColor = vec4(result, 1.0);
如果需要伽马校正或 HDR 处理,后续再扩展;基础光照至此完成。
不复杂但容易忽略:法线变换必须用法线矩阵(inverseTranspose(modelViewMatrix)),不能直接用 modelView;uniform 值需在 JavaScript 主程序中通过 gl.uniform3fv() 正确传入;光照方向向量建议在 CPU 端预先 normalize,减少 GPU 开销。


















