引言
光照是计算机图形学的灵魂。虽然现代引擎使用复杂的 PBR (Physically Based Rendering),但理解经典的光照模型仍然是基础。 经典光照模型通常由三部分组成: \[ Color = Ambient + Diffuse + Specular \]
1. 漫反射 (Diffuse) - Lambert
漫反射模拟的是粗糙表面(如砖墙、布料)对光的散射。 光线照射到表面后,向四面八方均匀反射。 强度取决于光线方向 \(\vec{L}\) 与表面法线 \(\vec{N}\) 的夹角。
\[ I_{diffuse} = \max(0, \vec{N} \cdot \vec{L}) \]
- 当光线垂直表面 (\(\theta = 0^\circ\)),\(\cos\theta = 1\),最亮。
- 当光线平行表面 (\(\theta = 90^\circ\)),\(\cos\theta = 0\),无光。
- 背面光照会被 \(\max(0, \dots)\) 截断为 0。
2. 镜面反射 (Specular) - Phong
镜面反射模拟的是光滑表面(如金属、塑料)的高光 (Highlight)。 它取决于观察方向 \(\vec{V}\) 和反射方向 \(\vec{R}\) 的夹角。
\[ \vec{R} = \text{reflect}(-\vec{L}, \vec{N}) \] \[ I_{specular} = (\max(0, \vec{R} \cdot \vec{V}))^{shininess} \]
- Shininess (光泽度): 指数越高,高光点越小越亮(越光滑)。
3. 改进模型 - Blinn-Phong
Phong 模型有一个缺点:计算反射向量 \(\vec{R}\) 比较昂贵。 Jim Blinn 提出了一种优化:使用半程向量 (Halfway Vector) \(\vec{H}\)。 \(\vec{H}\) 是光线方向 \(\vec{L}\) 和观察方向 \(\vec{V}\) 的中间向量。
\[ \vec{H} = \text{normalize}(\vec{L} + \vec{V}) \] \[ I_{specular} = (\max(0, \vec{N} \cdot \vec{H}))^{shininess} \]
- 优点: 计算 \(\vec{H}\) 比 \(\vec{R}\) 快。
- 效果: 高光看起来更柔和、更真实,是 OpenGL/DirectX 固定管线的默认选择。
4. 环境光 (Ambient)
为了模拟间接光照(光线在墙壁间反弹),经典模型简单地加上一个常数颜色。 \[ I_{ambient} = K_a \] 这是一种非常粗糙的近似,现代游戏通常使用全局光照 (GI) 或环境光遮蔽 (AO) 来替代。
Shader 代码示例 (HLSL/GLSL)
// 输入: N (法线), L (光照方向), V (观察方向)
vec3 N = normalize(Normal);
vec3 L = normalize(LightDir);
vec3 V = normalize(ViewDir);
// Diffuse
float diff = max(dot(N, L), 0.0);
// Specular (Blinn-Phong)
vec3 H = normalize(L + V);
float spec = pow(max(dot(N, H), 0.0), 32.0);
// Result
vec3 color = (ambient + diff + spec) * objectColor;总结
- 点积再次成为主角,用于计算光照强度。
- Blinn-Phong 是对 Phong 的一种高效近似,至今仍被广泛使用。
- 理解这些模型有助于你调整材质参数,或者手写 Shader。