Lambert光照模型

Lambert光照模型简介

Lambert光照模型是一种简单的漫反射光照模型,由Johann Heinrich Lambert在18世纪提出。它描述了理想漫反射表面的光照行为,即光线在所有方向上均匀散射。

基本原理

Lambert定律指出:

  • 表面反射的光强与入射光方向和表面法线夹角的余弦成正比
  • 反射光在所有观察方向上是相同的(各向同性)

数学表示

Lambert漫反射光照公式:

\[I_d = I_p \cdot k_d \cdot (\mathbf{L} \cdot \mathbf{N})\]

其中:

  • $I_d$: 漫反射光强
  • $I_p$: 入射光强
  • $k_d$: 漫反射系数(表面颜色)
  • $\mathbf{L}$: 指向光源的单位向量
  • $\mathbf{N}$: 表面法线单位向量

实现方法

在着色器中实现Lambert光照的基本步骤:

  1. 计算表面法线$\mathbf{N}$
  2. 计算指向光源的向量$\mathbf{L}$并归一化
  3. 计算点积$\mathbf{L} \cdot \mathbf{N}$
  4. 应用漫反射公式计算最终颜色
// GLSL示例代码
vec3 calculateLambert(vec3 normal, vec3 lightDir, vec3 lightColor, vec3 surfaceColor) {
    float diff = max(dot(normal, lightDir), 0.0);
    return lightColor * surfaceColor * diff;
}

特点与应用

  • 简单高效,适合实时渲染
  • 适用于粗糙、无光泽的表面(如纸张、布料等)
  • 常与Phong或Blinn-Phong镜面反射模型结合使用
  • 是许多更复杂光照模型的基础

局限性

  • 无法表现镜面高光
  • 无法表现菲涅尔效应
  • 无法表现次表面散射效果
  • 在掠射角度($\mathbf{L} \cdot \mathbf{N}$接近0)时表现不自然

扩展与改进

  1. 半Lambert模型:通过重新映射点积结果改善掠射角度表现 \(I_{half} = 0.5 \cdot (\mathbf{L} \cdot \mathbf{N}) + 0.5\)

  2. 环境光项:添加环境光项$I_a$来模拟间接光照 \(I_{total} = I_a + I_d\)

  3. 距离衰减:考虑光源距离的影响 \(I_d = \frac{I_p}{d^2} \cdot k_d \cdot (\mathbf{L} \cdot \mathbf{N})\)

光照衰减实现细节

  1. 衰减公式: 实际应用中常使用更稳定的衰减公式: \(\text{attenuation} = \frac{1}{k_c + k_l \cdot d + k_q \cdot d^2}\) 其中:
    • $k_c$: 常数项(通常1.0)
    • $k_l$: 线性项
    • $k_q$: 二次项
  2. 不同类型光源的衰减
    • 点光源:使用完整的二次衰减
    • 聚光灯:额外考虑角度衰减
    • 平行光:通常不考虑距离衰减
  3. GLSL实现: ```glsl // 点光源衰减计算 float calculateAttenuation(float distance, float constant, float linear, float quadratic) { return 1.0 / (constant + linear * distance + quadratic * (distance * distance)); }

// 在光照计算中应用 float atten = calculateAttenuation(length(lightPos - fragPos), 1.0, 0.09, 0.032); vec3 result = (ambient + diffuse + specular) * atten;


4. **衰减系数调整**:
   - 近距离光源:增大二次项系数
   - 远距离光源:增大线性项系数
   - 常用预设:
     - 近距离: (1.0, 0.09, 0.032)
     - 中距离:(1.0, 0.07, 0.017) 
     - 远距离:(1.0, 0.04, 0.007)

## Phong光照模型

Phong模型在Lambert漫反射基础上增加了镜面反射项,由Bui Tuong Phong于1975年提出。

### 数学表示

$$
I = I_a + I_d + I_s = k_a + k_d(\mathbf{L} \cdot \mathbf{N}) + k_s(\mathbf{R} \cdot \mathbf{V})^n
$$

其中:
- $\mathbf{R}$: 反射光向量
- $\mathbf{V}$: 视线向量
- $n$: 镜面反射指数(控制高光锐利度)
- $k_s$: 镜面反射系数

### 实现方法

```glsl
vec3 calculatePhong(vec3 normal, vec3 lightDir, vec3 viewDir, 
                   vec3 lightColor, vec3 surfaceColor, float shininess) {
    // 漫反射项(Lambert)
    float diff = max(dot(normal, lightDir), 0.0);
    
    // 镜面反射项
    vec3 reflectDir = reflect(-lightDir, normal);
    float spec = pow(max(dot(viewDir, reflectDir), 0.0), shininess);
    
    return lightColor * (surfaceColor * diff + spec);
}

局限性

  1. 计算反射向量$\mathbf{R}$开销较大
  2. 当视线与反射方向夹角大于90°时,镜面项会突然消失
  3. 高光形状不够自然

Blinn-Phong光照模型

Jim Blinn对Phong模型的改进,使用半角向量替代反射向量计算。

改进点

  1. 用半角向量$\mathbf{H}$代替反射向量$\mathbf{R}$: \(\mathbf{H} = \frac{\mathbf{L} + \mathbf{V}}{||\mathbf{L} + \mathbf{V}||}\)
  2. 镜面项公式变为: \(I_s = k_s(\mathbf{N} \cdot \mathbf{H})^n\)

优势

  1. 计算效率更高:避免了反射向量的计算
  2. 视觉效果更平滑:没有Phong模型的突然消失问题
  3. 高光更自然:特别是对于低多边形模型
  4. 物理更准确:更接近微表面理论

实现方法

vec3 calculateBlinnPhong(vec3 normal, vec3 lightDir, vec3 viewDir,
                        vec3 lightColor, vec3 surfaceColor, float shininess) {
    // 漫反射项(Lambert)
    float diff = max(dot(normal, lightDir), 0.0);
    
    // 镜面反射项(Blinn-Phong)
    vec3 halfwayDir = normalize(lightDir + viewDir);  
    float spec = pow(max(dot(normal, halfwayDir), 0.0), shininess);
    
    return lightColor * (surfaceColor * diff + spec);
}

颜色空间:sRGB与线性空间

sRGB颜色空间

  1. 定义:sRGB是标准的RGB颜色空间,由HP和微软于1996年制定
  2. 特性
    • 非线性编码,近似gamma=2.2的曲线
    • 直接对应显示器的响应曲线
    • 广泛用于图像存储和显示设备
  3. 数学表示: 对于$C_{linear} \leq 0.0031308$: \(C_{srgb} = 12.92 \times C_{linear}\) 否则: \(C_{srgb} = 1.055 \times C_{linear}^{1/2.4} - 0.055\)

线性颜色空间

  1. 定义:颜色值与物理光强呈线性关系的空间
  2. 特性
    • 颜色值直接对应实际光强度
    • 适合进行光照计算和物理模拟
    • 需要gamma校正才能在标准显示器上正确显示
  3. 重要性
    • 光照计算必须在线性空间进行才能得到正确结果
    • 纹理需要在线性空间采样
    • 混合/过滤操作需要在线性空间执行

空间转换

  1. sRGB到线性空间
    • 通过逆sRGB转换或gamma≈1/2.2的幂运算(去gamma校正)
    • 纹理采样时可使用硬件sRGB扩展自动转换
    • 数学表示:$C_{linear} = C_{srgb}^{2.2}$
  2. 线性空间到sRGB
    • 通过sRGB转换或gamma≈2.2的幂运算(gamma校正)
    • 通常在最终输出前应用
    • 数学表示:$C_{srgb} = C_{linear}^{1/2.2}$

注意:

  • 精确的sRGB标准使用分段线性+幂函数转换
  • 实际应用中常用近似gamma=2.2的幂运算简化计算

Gamma校正

Gamma校正是连接线性空间和sRGB空间的桥梁,用于正确处理颜色值的非线性显示特性。

基本概念

  1. CRT显示特性:传统显示器对输入电压的响应呈非线性关系(约V^2.2)
  2. 人眼感知:人眼对暗部变化更敏感,与显示器的非线性响应相匹配
  3. 线性工作流:在渲染计算中使用线性颜色空间,最后通过gamma校正转换到显示空间

数学原理

Gamma校正公式:

\[C_{out} = C_{in}^{1/\gamma}\]

其中:

  • $C_{in}$:线性空间颜色值
  • $C_{out}$:显示空间颜色值
  • $\gamma$:通常取值2.2

逆Gamma校正(线性化):

\[C_{linear} = C_{display}^{\gamma}\]

实现方法

  1. 手动Gamma校正
    // 在片段着色器最后添加
    fragColor.rgb = pow(fragColor.rgb, vec3(1.0/2.2));
    
  2. sRGB纹理
    // 使用GL_SRGB8_ALPHA8格式的纹理
    // 硬件会自动在采样时进行线性化
    
  3. 帧缓冲区设置
    // 使用sRGB帧缓冲区
    glEnable(GL_FRAMEBUFFER_SRGB);
    

现代应用

  1. HDR渲染:gamma校正与色调映射结合使用
  2. PBR工作流:必须使用线性空间和gamma校正
  3. 移动设备:虽然现代屏幕更线性,但仍需考虑gamma校正

注意事项

  1. 纹理资源应根据用途选择正确的颜色空间
  2. 光照计算必须在线性空间进行
  3. 最后输出前应用gamma校正
  4. UI元素通常不需要gamma校正

模型比较与选择建议

特性 Lambert Phong Blinn-Phong
计算开销 最低 中等 中等
视觉效果 平坦 锐利高光 柔和高光
物理准确性 中等 较高
适用场景 粗糙表面 需要精确高光 大多数情况

实际应用建议:

  1. 优先使用Blinn-Phong模型
  2. 对性能极度敏感的场景可考虑Lambert
  3. 需要特定艺术风格时可考虑Phong