Phong

$$ I = \underbrace{I_a k_a}_{\text{环境光项 (Ambient)}} + \underbrace{I_d k_d (\vec{L} \cdot \vec{N})}_{\text{漫反射项 (Diffuse)}} + \underbrace{I_s k_s (\vec{R} \cdot \vec{V})^\alpha}_{\text{镜面高光项 (Specular)}} $$
  • 环境光项(Ambient):$I_a k_a$

  • $I_a$:环境光强度(Ambient light intensity)

  • $k_a$:材质的环境光反射系数(Ambient reflection coefficient)

  • 漫反射项(Diffuse):$I_d k_d (\vec{L} \cdot \vec{N})$

  • $I_d$:入射漫反射光的强度

  • $k_d$:材质的漫反射系数

  • $\vec{L}$:从表面点指向光源的单位方向向量

  • $\vec{N}$:表面该点处的法单位向量

  • 镜面高光项(Specular):$I_s k_s (\vec{R} \cdot \vec{V})^\alpha$

  • $I_s$:入射镜面光的强度

  • $k_s$:材质的镜面高光反射系数

  • $\vec{R}$:光线在表面处的反射单位向量

  • $\vec{V}$:从表面点指向观察者/摄像机的单位方向向量

  • $\alpha$:物体的反光度 / 粗糙度因子(Shininess / Specular exponent),$\alpha$ 越大高光点越小越亮。

Pong光照模型示意

1. Ambient

环境光

GLSL
float ambientStrength = 0.1;
vec3 ambient = ambientStrength * lightColor;
点击展开查看更多

2. Diffuse

入射光线越靠近物体法线漫反射越强

GLSL
// 计算漫反射值(光照向量 dot 法线)
// 注意会出现负值
float diff = max(dot(lightDir, Normal), 0.0);
// 合并
vec3 diffuse = diff * lightColor;
点击展开查看更多

3. Specular

视角向量越靠近出射光线镜面反射越强

GLSL
// 强度系数
float specularStrength = 0.5;
float shininess = 32
// 计算反射光方向向量(光照向量 dot 法线)
vec3 reflectDir = reflect(-lightDir, Normal);
// 计算镜面反射值(视角向量 dot 反射向量)
// shininess:此处pow的意义在于使光斑收敛更快(控制硬度)
float spec = pow(max(dot(viewDir, reflectDir), 0.0), shininess);
// 合并
vec3 specular = specularStrength * spec * lightColor;
点击展开查看更多

终. Phong

最终效果

GLSL
vec3 result = (ambient + diffuse + specular* objectColor;
点击展开查看更多

Blinn-Phong

“高光截断”问题

Phong光照模型Specular问题光线示意
在经典 Phong 模型中,当视线 $\vec{V}$ 与反射光 $\vec{R}$ 的夹角大于 90 度时(右图),点积($\vec{R} \cdot \vec{V}$)会变为负数并被强制截断为 0。如果物体的反光度(Shininess)较低(高光散射范围大、表面较粗糙),在物体的边缘或某些特定掠射角上,会看到高光突然中断,形成一条极其生硬的边界线(如图形被一刀切)
Phong光照模型Specular问题效果

解决方案:半程向量

Blinn-Phong半程向量光线示意
由于 $\vec{H}$ 是光线 $\vec{L}$ 和视线 $\vec{V}$ 的中间向量,只要光线和视线都在表面上方,法向量 $\vec{N}$ 与 $\vec{H}$ 的夹角几乎永远不会超过 90 度。因此,高光在物体边缘的衰减会变得非常平滑、自然,完美消除了 Phong 模型的截断走样。

$$ \overline{H} = \overline{L} + \overline{V} $$

代码实现

GLSL
vec3 halfwayDir = normalize(lightDir + viewDir);
spec = pow(max(dot(normal, halfwayDir)0.0), 1.0);
点击展开查看更多

效果

Blinn-Phong光照模型效果

顺带的优化

经典 Phong 的开销

计算反射向量 $\vec{R}$ 需要使用反射公式,这就意味着像素着色器中的每一个像素,都必须根据该点动态变化的法线 $\vec{N}$ 重新计算一次的 $\vec{R}$ 向量。

Blinn-Phong 的优化

半角向量 $\vec{H}$ 的计算只需要简单的向量加法和归一化。更重要的是,在一些特别的场景下,如方向光/太阳光 + 正交相机$\vec{L}$ 和 $\vec{V}$ 在全场景中是恒定的。 此时,$\vec{H}$ 是一个帧常量在整帧渲染中只需要计算一次

版权声明

作者: Cheyne Xie

链接: https://chaim.eu.org/posts/805b3207/

许可证: CC BY-NC-SA 4.0

This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. Please attribute the source, use non-commercially, and maintain the same license.

开始搜索

输入关键词搜索文章内容

↑↓
ESC
⌘K 快捷键