下面把前面的内容收束成一套可以直接对应 Shader 实现的完整 BRDF。
这里采用游戏引擎最常见的一套:
Metallic-Roughness PBR + Lambert Diffuse + Cook-Torrance GGX Specular
严格来说这不是完整的 Disney 2012 BRDF,但它就是 Unity、Unreal、glTF 等现代实时 PBR 的核心骨架。
1. 最终要算什么
对一个像素,一盏灯产生的直接光照:
\[L_o = (L_{diffuse}+L_{specular}) \times L_i \times (N\cdot L)\]
其中:
| 变量 | 来历 | 含义 |
|---|---|---|
| \(L_o\) | 最终计算 | 当前像素向摄像机反射的光 |
| \(L_i\) | 光源 | 光源颜色 × 强度 |
| \(N\) | Mesh/Normal Map | 表面法线 |
| \(L\) | 光源位置 | 像素 → 光源的单位向量 |
| \(V\) | Camera | 像素 → 摄像机的单位向量 |
最后的:
\[N\cdot L\]
就是最基本的 Lambert 余弦定律:
光越垂直照射表面,单位面积收到的能量越多。
【PBR思想:物理正确的入射光能量】
2. 美术真正提供的三个核心参数
通常材质贴图给:
\[BaseColor,\quad Metallic,\quad Roughness\]
其中:
BaseColor ← BaseColor Texture
Metallic ← Metallic Texture
Roughness ← Roughness Texture
Normal ← Normal Map
它们不是直接对应 D、F、G,而是进一步参与 BRDF。
3. 先准备几个几何向量
已经有:
\[N,L,V\]
再计算半程向量:
\[H=\frac{L+V}{|L+V|}\]
也就是:
光线方向和观察方向的中间方向。
为什么需要 H?
因为微表面模型认为:
只有法线方向刚好接近 H 的微小镜面,才能把 L 方向来的光反射进 V。
所以 H 是 Cook-Torrance 的重要几何变量。
4. Roughness → 微表面粗糙度 α
一般不会直接把 Roughness 塞进 GGX。
常见做法:
\[\alpha = Roughness^2\]
Roughness 来源:
\[Roughness = Texture_{roughness}\]
为什么平方?
因为直接线性使用 Roughness,视觉变化不够均匀。
平方之后:
美术拖动 Roughness 参数时,视觉响应更加符合直觉。
注意不同引擎具体映射可能略有区别。
【PBR思想:材质参数有统一、稳定的物理意义】
5. 计算 D:GGX 微表面分布
Cook-Torrance Specular:
\[f_{specular} = \frac{DGF} {4(N\cdot L)(N\cdot V)}\]
先看 D:
\[D_{GGX} = \frac{\alpha^2} {\pi \left[ (N\cdot H)^2(\alpha^2-1)+1 \right]^2}\]
变量:
| 变量 | 来历 |
|---|---|
| \(N\) | Mesh Normal / Normal Map |
| \(H\) | 根据 L 和 V 计算 |
| \(\alpha\) | \(Roughness^2\) |
| \(\pi\) | 数学常数 |
D 回答的问题:
当前表面上,有多少微小镜面正好朝着 H?
D 的物理意义
Roughness 很低:
微表面方向高度一致
///////////
于是满足正确方向的微表面非常集中。
结果:
高光小、尖、亮。
Roughness 高:
/\/\_/\/\_/\
微表面方向非常分散。
结果:
高光大、宽、弱。
所以:
\[Roughness\rightarrow\alpha\rightarrow D\]
【PBR思想:Microfacet 微表面理论】
这比 Blinn-Phong 的:
\[(N\cdot H)^{Shininess}\]
先进的地方就是:
Blinn-Phong 在人为画高光;
GGX 在模拟微观表面方向分布。
6. BaseColor + Metallic → F₀
接下来是 Fresnel。
先计算一个非常重要的量:
\[F_0\]
代表:
垂直观察材质时的基础镜面反射率。
对于普通非金属,常见近似:
\[F_0\approx0.04\]
也就是 RGB:
\[(0.04,0.04,0.04)\]
现代 Metallic Workflow 通常写:
\[F_0 = lerp(0.04,BaseColor,Metallic)\]
也可以展开:
\[F_0= 0.04(1-Metallic) + BaseColor\times Metallic\]
非金属
如果:
\[Metallic=0\]
那么:
\[F_0=0.04\]
例如红塑料:
BaseColor = 红色
Metallic = 0
Diffuse = 红色
Specular F0 ≈ 白色 4%
金属
如果:
\[Metallic=1\]
那么:
\[F_0=BaseColor\]
例如黄金:
BaseColor = 金黄色
Metallic = 1
Diffuse ≈ 0
Specular = 金黄色
因此金属反射本身具有颜色。
【PBR思想:金属和非金属遵循不同的真实光学行为】
7. F:Schlick Fresnel
有了 \(F_0\),计算:
\[F = F_0+ (1-F_0) (1-V\cdot H)^5\]
这就是常用的 Schlick Fresnel approximation。
变量来源:
| 变量 | 来源 |
|---|---|
| \(F_0\) | BaseColor + Metallic |
| \(V\) | Camera |
| \(H\) | L + V 得到 |
F 回答:
当前观察角度下,有多少光直接被表面镜面反射?
正面看:
\[V\cdot H\approx1\]
所以:
\[F\approx F_0\]
掠射角:
\[V\cdot H\rightarrow0\]
于是:
\[F\rightarrow1\]
也就是说:
几乎所有材质在非常倾斜的角度看过去,反射都会明显增强。
这就是水面、玻璃、塑料边缘变亮的原因。
【PBR思想:Fresnel 物理规律】
8. G:Geometry Shadowing / Masking
微表面不仅方向不同,它们还会互相遮挡。
因此需要:
\[G\]
回答:
即使某个微表面方向正确,它有没有被别的微表面挡住?
常见实时实现使用 Smith GGX:
\[G(N,V,L)= G_1(N,V)\times G_1(N,L)\]
一种常见形式:
\[G_1(N,X) = \frac{N\cdot X} {(N\cdot X)(1-k)+k}\]
其中:
\[k=\frac{(Roughness+1)^2}{8}\]
因此:
\[G= G_1(N,V) G_1(N,L)\]
这里:
Roughness
↓
k
N·V → Camera方向遮挡
N·L → Light方向遮挡
G 处理两件事情:
Masking
微表面反射出来的光被挡住
Shadowing
光进入微表面之前被挡住
【PBR思想:Microfacet 几何自遮挡】
9. 得到完整 Cook-Torrance Specular
现在终于把 D、F、G 合起来:
\[\boxed{ f_{specular} = \frac{D_{GGX}\times F\times G} {4(N\cdot L)(N\cdot V)} }\]
这就是核心。
可以直接记:
\[\boxed{CookTorrance=\frac{DFG}{4N_LN_V}}\]
其中:
Roughness
↓
α
├──→ D:微表面朝向分布
└──→ G:微表面互相遮挡
BaseColor + Metallic
↓
F0
↓
F:Fresnel反射
N / L / V
↓
影响 D、F、G
分母:
\[4(N\cdot L)(N\cdot V)\]
并不是随便加的修正项。
它来自微表面 BRDF 的几何变换和归一化:
把微表面法线空间中的能量转换成宏观表面的反射能量。
【PBR思想:BRDF 能量和概率分布正规化】
10. Specular 有了,还需要 Diffuse
对于最简单 Lambert:
\[f_{Lambert} = \frac{BaseColor}{\pi}\]
为什么除以:
\[\pi\]
因为漫反射向整个上半球散射。
如果不除 \(\pi\),把所有方向上的输出光积分起来,会凭空得到过多能量。
所以:
\[\frac{1}{\pi}\]
非常重要。
【PBR思想:能量守恒】
11. Fresnel 决定 Diffuse 还能分多少能量
现在假设:
\[F=0.2\]
说明约有 20% 的当前光能已经进入镜面反射。
那么剩下最多:
\[1-F=0.8\]
可以用于 Diffuse。
所以定义:
\[k_S=F\]
Specular 权重。
然后:
\[k_D=1-k_S\]
但金属不能有普通漫反射。
所以进一步:
\[\boxed{ k_D=(1-F)(1-Metallic) }\]
这是 Metallic-Roughness PBR 中非常核心的一步。
非金属
例如:
\[Metallic=0\]
于是:
\[k_D=1-F\]
镜面反射走掉多少能量,Diffuse 就相应少掉多少。
金属
如果:
\[Metallic=1\]
那么:
\[k_D=0\]
所以:
\[Diffuse=0\]
能量主要进入 Specular。
这就不是:
Diffuse 随便算一个
+
Specular 再随便算一个
而是:
Incoming Light
↓
Fresnel F
/ \
/ \
Specular 剩余能量
↓
× (1-Metallic)
↓
Diffuse
【PBR思想:能量守恒】
12. 完整 Diffuse BRDF
所以:
\[f_{diffuse} = k_D \frac{BaseColor}{\pi}\]
即:
\[\boxed{ f_{diffuse} = (1-F)(1-Metallic) \frac{BaseColor}{\pi} }\]
13. 最终完整 BRDF
现在:
\[BRDF = f_{diffuse} + f_{specular}\]
即:
\[\boxed{ BRDF = (1-F)(1-Metallic) \frac{BaseColor}{\pi} + \frac{DGF} {4(N\cdot L)(N\cdot V)} }\]
这基本就是你现在最值得记住的一条完整公式。
然后一盏灯真正贡献给像素的颜色:
\[\boxed{ L_o= BRDF \times L_i \times \max(N\cdot L,0) }\]
多盏灯就是求和:
\[L_o= \sum_i BRDF_i L_i (N\cdot L_i)\]
之后还可以加:
IBL
Emission
AO
Shadow
Reflection Probe
GI
最后:
HDR Color
↓
Tone Mapping
↓
屏幕
14. 把整个 Shader 数据流串起来
材质贴图
────────────────────────────
BaseColor ────────────────┐
│
Metallic ───┐ │
↓ ↓
F0 = lerp(0.04, BaseColor, Metallic)
│
↓
Fresnel
│
↓
F
│
┌────┴─────┐
↓ ↓
Specular Diffuse权重
(1-F)
│
× (1-Metallic)
↓
kD
Roughness
↓
Roughness²
↓
α
/ \
↓ ↓
GGX Geometry
D G
Camera ──→ V ───┐
│
Light ───→ L ────┼──→ H = normalize(L+V)
│
Normal ───→ N ───┘
↓
Cook-Torrance Specular
D × F × G
─────────────────
4(N·L)(N·V)
+
kD × BaseColor
──────────────
π
↓
BRDF
↓
× Light Radiance
↓
× N·L
↓
Pixel Lighting
15. 这套公式体现了哪些 PBR 思想
| PBR设计思想 | 在公式里的体现 |
|---|---|
| 微表面理论 | GGX \(D\) |
| 真实粗糙度 | Roughness → α → D/G |
| Fresnel规律 | \(F\) |
| 微观遮挡 | Geometry \(G\) |
| 金属/非金属模型 | Metallic |
| 物理基础反射率 | \(F_0\) |
| 能量守恒 | \(k_D=(1-F)(1-Metallic)\) |
| 漫反射正规化 | \(BaseColor/\pi\) |
| 入射能量符合余弦定律 | \(N\cdot L\) |
| 材质与灯光解耦 | BaseColor / Metallic / Roughness 有稳定意义 |
最后用一句话理解整套 BRDF
你可以把 Cook-Torrance PBR 想成:
Roughness 告诉我表面微观上有多乱;GGX 的 D 算多少微表面正好朝对方向;G 算这些微表面有没有被挡住;BaseColor + Metallic 决定 F₀;Fresnel 的 F 决定这个观察角度到底反射多少;剩余能量才能进入 Diffuse,最终共同组成这个像素的 BRDF。
最值得真正记住的是这三条:
\[\boxed{ F_0=lerp(0.04,BaseColor,Metallic) }\]
\[\boxed{ f_s=\frac{DGF}{4(N\cdot L)(N\cdot V)} }\]
\[\boxed{ BRDF=(1-F)(1-Metallic)\frac{BaseColor}{\pi}+f_s }\]
理解这三条以后,现代游戏 PBR 的主体框架基本就已经通了。