BxDF 详解
BxDF 详解
目录
- BxDF 基本概念
- LambertianDiffuseBRDF(漫反射)
- PhongSpecularBRDF(高光反射)
- MirrorSpecularBRDF(镜面反射)
- BSDF 混合机制
- 在渲染中的应用
BxDF 基本概念
什么是 BxDF?
BxDF(Bidirectional Reflectance Distribution Function,双向反射分布函数)描述了光线如何在表面上反射的物理规律。
物理意义:给定入射方向 wo 和出射方向 wi,BxDF告诉我们:
- 有多少光线从
wo方向反射到wi方向 - 反射光线的颜色和强度
BxDF 的三个核心函数
class BxDF {
// 1. PDF:概率密度函数
virtual float pdf(const vec3& wo, const vec3& wi, const vec3& n) const = 0;
// 2. eval:BRDF值(反射率)
virtual vec3 eval(const vec3& wo, const vec3& wi, const vec3& n) const = 0;
// 3. sampleDir:采样反射方向
virtual vec3 sampleDir(const vec3& wo, const vec3& n) const = 0;
};
渲染方程
L o ( p , ω o ) = L e ( p , ω o ) + ∫ Ω f r ( p , ω i , ω o ) L i ( p , ω i ) ( ω i ⋅ n ) d ω i L_o(p, \omega_o) = L_e(p, \omega_o) + \int_{\Omega} f_r(p, \omega_i, \omega_o) L_i(p, \omega_i) (\omega_i \cdot n) \, d\omega_i Lo(p,ωo)=Le(p,ωo)+∫Ωfr(p,ωi,ωo)Li(p,ωi)(ωi⋅n)dωi
蒙特卡洛近似:
L o ( p , ω o ) ≈ L e ( p , ω o ) + 1 N ∑ i = 1 N f r ( p , ω i , ω o ) L i ( p , ω i ) ( ω i ⋅ n ) p ( ω i ) L_o(p, \omega_o) \approx L_e(p, \omega_o) + \frac{1}{N} \sum_{i=1}^{N} \frac{f_r(p, \omega_i, \omega_o) L_i(p, \omega_i) (\omega_i \cdot n)}{p(\omega_i)} Lo(p,ωo)≈Le(p,ωo)+N1i=1∑Np(ωi)fr(p,ωi,ωo)Li(p,ωi)(ωi⋅n)
其中:
- L o L_o Lo:出射辐射亮度
- L e L_e Le:自发光辐射亮度
- f r f_r fr:BRDF(双向反射分布函数)
- L i L_i Li:入射辐射亮度
- p ( ω i ) p(\omega_i) p(ωi):采样方向的概率密度函数(PDF)
LambertianDiffuseBRDF(漫反射)
物理原理
漫反射遵循兰伯特余弦定律:反射光强度与入射角的余弦成正比。
反射光强 ∝ cos ( θ ) = n ⋅ ω i \text{反射光强} \propto \cos(\theta) = \mathbf{n} \cdot \omega_i 反射光强∝cos(θ)=n⋅ωi
1. PDF 计算
float pdf(const vec3& wo, const vec3& wi, const vec3& n) const {
if (dot(n, wi) < 0.f) return 0.f; // 背面,无效
return 1.0f / M_PI; // 投影面积空间的均匀分布
}
为什么是 1/π?
- 半球在平面上的投影面积是
π - 在投影面积空间中均匀采样
- 与BRDF的归一化一致
能量守恒验证:
∫ Ω 1 π ( n ⋅ ω i ) d ω i = 1 \int_{\Omega} \frac{1}{\pi} (\mathbf{n} \cdot \omega_i) \, d\omega_i = 1 ∫Ωπ1(n⋅ωi)dωi=1
2. BRDF 评估
vec3 eval(const vec3& wo, const vec3& wi, const vec3& n) const {
return radiance / M_PI;
}
兰伯特BRDF公式:
f r ( ω i , ω o ) = ρ π f_r(\omega_i, \omega_o) = \frac{\rho}{\pi} fr(ωi,ωo)=πρ
其中:
- ρ \rho ρ 是反照率(albedo),即材质颜色
- π \pi π 是归一化因子
能量守恒验证:
∫ Ω ρ π ( n ⋅ ω i ) d ω i = ρ \int_{\Omega} \frac{\rho}{\pi} (\mathbf{n} \cdot \omega_i) \, d\omega_i = \rho ∫Ωπρ(n⋅ωi)dωi=ρ
计算积分:
∫ Ω ( n ⋅ ω i ) d ω i = ∫ 0 2 π ∫ 0 π / 2 cos ( θ ) sin ( θ ) d θ d ϕ = π \int_{\Omega} (\mathbf{n} \cdot \omega_i) \, d\omega_i = \int_0^{2\pi} \int_0^{\pi/2} \cos(\theta) \sin(\theta) \, d\theta d\phi = \pi ∫Ω(n⋅ωi)dωi=∫02π∫0π/2cos(θ)sin(θ)dθdϕ=π
所以:
ρ π × π = ρ ✓ 能量守恒 \frac{\rho}{\pi} \times \pi = \rho \quad \checkmark \text{ 能量守恒} πρ×π=ρ✓ 能量守恒
3. 方向采样
vec3 sampleDir(const vec3& wo, const vec3& n) const {
// 在单位圆盘上均匀采样
vec2 offset = 2.f * vec2(genRandomFloat(), genRandomFloat()) - vec2(1, 1);
// 将正方形映射到圆盘(平方根映射)
vec2 disk;
if (abs(offset.x) > abs(offset.y)) {
float r = offset.x;
float theta = M_PI / 4.f * (offset.y / offset.x);
disk = r * vec2(cos(theta), sin(theta));
} else {
float r = offset.y;
float theta = M_PI / 2.f - M_PI / 4.f * (offset.x / offset.y);
disk = r * vec2(cos(theta), sin(theta));
}
// 投影到半球
float z = sqrt(1 - disk.x * disk.x - disk.y * disk.y);
vec3 localDir = vec3(disk.x, disk.y, z);
// 转换到世界坐标系
return toWorld(localDir, n);
}
采样步骤:
- 在单位圆盘上均匀采样:使用平方根映射避免中心聚集
- 投影到半球: z = 1 − x 2 − y 2 z = \sqrt{1 - x^2 - y^2} z=1−x2−y2
- 转换到世界坐标:使用切线空间变换
为什么这样采样?
- 确保在半球上均匀分布
- PDF =
1/π - 避免拒绝采样,效率高
漫反射特点
| 特性 | 值 |
|---|---|
1/π |
|
| BRDF | radiance / π |
| 采样 | 圆盘投影到半球 |
| 能量守恒 | 完全抵消 |
| 应用场景 | 纸张、墙壁、布料等粗糙表面 |
PhongSpecularBRDF(高光反射)
物理原理
Phong模型是一种经验模型,用于模拟光滑表面的镜面反射。它基于半程向量(halfway vector)来计算高光强度。
核心思想:
- 当观察方向与完美反射方向接近时,高光强度最大
- 使用指数参数控制高光的集中程度
半程向量
半程向量是入射方向和出射方向的角平分线:
h = ω i − ω o ∥ ω i − ω o ∥ \mathbf{h} = \frac{\omega_i - \omega_o}{\|\omega_i - \omega_o\|} h=∥ωi−ωo∥ωi−ωo
几何意义:
- 当 ω i \omega_i ωi 是完美反射方向时, h \mathbf{h} h 与法向量 n \mathbf{n} n 重合
- n ⋅ h \mathbf{n} \cdot \mathbf{h} n⋅h 越接近1,高光越强
1. PDF 计算
float pdf(const vec3& wo, const vec3& wi, const vec3& n) const {
if (dot(n, wi) < 0.f) return 0.f; // 背面,无效
const vec3 h = normalize(wi - wo); // 半程向量
const float nh = dot(n, h);
return (alpha + 1.0f) * pow(nh, alpha) / (2.0f * M_PI);
}
Phong分布公式:
p ( h ) = α + 1 2 π ( n ⋅ h ) α p(\mathbf{h}) = \frac{\alpha + 1}{2\pi} (\mathbf{n} \cdot \mathbf{h})^\alpha p(h)=2πα+1(n⋅h)α
参数说明:
- α \alpha α:高光指数(shininess)
- α = 1 \alpha = 1 α=1:宽大、柔和的高光
- α = 100 \alpha = 100 α=100:尖锐、明亮的高光
- ( n ⋅ h ) α (\mathbf{n} \cdot \mathbf{h})^\alpha (n⋅h)α:高光强度随角度衰减
- α + 1 2 π \frac{\alpha + 1}{2\pi} 2πα+1:归一化因子
能量守恒验证:
∫ Ω α + 1 2 π ( n ⋅ h ) α d ω h = 1 \int_{\Omega} \frac{\alpha + 1}{2\pi} (\mathbf{n} \cdot \mathbf{h})^\alpha \, d\omega_h = 1 ∫Ω2πα+1(n⋅h)αdωh=1
2. BRDF 评估
vec3 eval(const vec3& wo, const vec3& wi, const vec3& n) const {
const vec3 h = normalize(wi - wo);
const float nh = dot(h, n);
const float spec = pow(nh, alpha);
const float normFactor = (alpha + 2.0f) / (2.0f * M_PI);
return radiance * spec * normFactor;
}
Phong BRDF公式:
f r ( ω i , ω o ) = k s α + 2 2 π ( n ⋅ h ) α f_r(\omega_i, \omega_o) = k_s \frac{\alpha + 2}{2\pi} (\mathbf{n} \cdot \mathbf{h})^\alpha fr(ωi,ωo)=ks2πα+2(n⋅h)α
参数说明:
- k s k_s ks:镜面反射系数(材质颜色)
- ( n ⋅ h ) α (\mathbf{n} \cdot \mathbf{h})^\alpha (n⋅h)α:高光强度
- α + 2 2 π \frac{\alpha + 2}{2\pi} 2πα+2:归一化因子
为什么归一化因子是 α + 2 2 π \frac{\alpha + 2}{2\pi} 2πα+2?
PDF归一化: α + 1 2 π \frac{\alpha + 1}{2\pi} 2πα+1(半程向量空间)
BRDF归一化: α + 2 2 π \frac{\alpha + 2}{2\pi} 2πα+2(入射方向空间)
两个空间的雅可比行列式不同,所以归一化因子也不同。
3. 方向采样
vec3 sampleDir(const vec3& wo, const vec3& n) const {
const float u = genRandomFloat();
const float v = genRandomFloat();
// 计算球坐标
const float phi = 2.0f * M_PI * u;
const float cosTheta = pow(v, 1.0f / (alpha + 1.0f));
const float sinTheta = sqrt(1.0f - cosTheta * cosTheta);
// 转换为笛卡尔坐标
auto h = vec3(sinTheta * cos(phi), sinTheta * sin(phi), cosTheta);
h = toWorld(h, n);
// 根据反射定律计算出射方向
const vec3 wi = wo - 2.0f * dot(wo, h) * h;
return normalize(wi);
}
采样步骤:
-
在半程向量空间中采样:
- ϕ = 2 π u \phi = 2\pi u ϕ=2πu(方位角,均匀分布)
- cos θ = v 1 / ( α + 1 ) \cos\theta = v^{1/(\alpha+1)} cosθ=v1/(α+1)(极角,Phong分布)
-
转换到世界坐标系:
h = toWorld(h, n); -
根据反射定律计算出射方向:
wi = wo - 2(wo·h)h
为什么 cos θ = v 1 / ( α + 1 ) \cos\theta = v^{1/(\alpha+1)} cosθ=v1/(α+1)?
这是逆变换采样的结果。
Phong分布的累积分布函数(CDF):
CDF ( θ ) = 1 − cos α + 1 ( θ ) \text{CDF}(\theta) = 1 - \cos^{\alpha+1}(\theta) CDF(θ)=1−cosα+1(θ)
逆变换:
v = CDF ( θ ) = 1 − cos α + 1 ( θ ) v = \text{CDF}(\theta) = 1 - \cos^{\alpha+1}(\theta) v=CDF(θ)=1−cosα+1(θ)
cos α + 1 ( θ ) = 1 − v \cos^{\alpha+1}(\theta) = 1 - v cosα+1(θ)=1−v
cos ( θ ) = ( 1 − v ) 1 / ( α + 1 ) \cos(\theta) = (1 - v)^{1/(\alpha+1)} cos(θ)=(1−v)1/(α+1)
由于 v v v 和 1 − v 1-v 1−v 都是均匀分布,可以简化为:
cos ( θ ) = v 1 / ( α + 1 ) \cos(\theta) = v^{1/(\alpha+1)} cos(θ)=v1/(α+1)
Phong 高光参数的影响
| alpha 值 | 高光特性 | 应用场景 |
|---|---|---|
| 1-10 | 宽大、柔和的高光 | 塑料、橡胶 |
| 10-50 | 中等高光 | 油漆、皮革 |
| 50-200 | 尖锐、明亮的高光 | 金属、玻璃 |
MirrorSpecularBRDF(镜面反射)
物理原理
镜面反射是理想化的镜面反射,光线只在一个方向上反射,即完美反射方向。
核心特点:
- 只有一个反射方向(完美反射定律)
- 反射角等于入射角
- 包含Fresnel效应(角度相关的反射率)
1. PDF 计算
float pdf(const vec3& wo, const vec3& wi, const vec3& n) const {
if (dot(wi, n) < 0.f) return 0.f; // 背面,无效
return 1.0f; // Delta分布
}
Delta分布:
镜面反射的PDF是Delta分布(狄拉克δ函数),因为只有一个反射方向。
p ( ω ) = δ ( ω − ω r ) p(\omega) = \delta(\omega - \omega_r) p(ω)=δ(ω−ωr)
其中 ω r \omega_r ωr 是完美反射方向。
为什么是1.0?
- Delta分布在完美反射方向上可以是任何值
- 选择1.0是为了简化计算
- 避免复杂的Delta函数处理
蒙特卡洛积分中的处理:
∫ Ω f ( ω ) δ ( ω − ω r ) d ω = f ( ω r ) \int_{\Omega} f(\omega) \delta(\omega - \omega_r) \, d\omega = f(\omega_r) ∫Ωf(ω)δ(ω−ωr)dω=f(ωr)
在代码中:
// 采样方向就是完美反射方向
vec3 wi = sampleDir(wo, n);
// PDF = 1.0
float pdf = 1.0;
// 蒙特卡洛估计
vec3 contribution = eval * Li * cosTheta / pdf;
= eval * Li * cosTheta / 1.0
= eval * Li * cosTheta
2. BRDF 评估
vec3 eval(const vec3& wo, const vec3& wi, const vec3& n) const {
const float cosTheta = dot(wi, n);
const vec3 fresnelSchlick = radiance + (vec3(1.0f) - radiance) * pow(1.0f - cosTheta, 5.0f);
return fresnelSchlick / cosTheta;
}
镜面反射BRDF公式:
f r ( ω i , ω o ) = F ( ω o ) cos ( θ o ) f_r(\omega_i, \omega_o) = \frac{F(\omega_o)}{\cos(\theta_o)} fr(ωi,ωo)=cos(θo)F(ωo)
其中:
- F ( ω o ) F(\omega_o) F(ωo) 是Fresnel反射率
- cos ( θ o ) = n ⋅ ω o \cos(\theta_o) = \mathbf{n} \cdot \omega_o cos(θo)=n⋅ωo 是出射角的余弦
Fresnel-Schlick 近似
vec3 fresnelSchlick = radiance + (vec3(1.0f) - radiance) * pow(1.0f - cosTheta, 5.0f);
数学表达式:
F ( θ ) = F 0 + ( 1 − F 0 ) ( 1 − cos θ ) 5 F(\theta) = F_0 + (1 - F_0) (1 - \cos\theta)^5 F(θ)=F0+(1−F0)(1−cosθ)5
参数说明:
- F 0 = radiance F_0 = \text{radiance} F0=radiance:垂直入射时的反射率(材质颜色)
- cos θ = n ⋅ ω o \cos\theta = \mathbf{n} \cdot \omega_o cosθ=n⋅ωo:出射角的余弦
- 5 5 5:Schlick近似的指数
为什么是5次方?
- 这是Schlick提出的经验公式
- 近似Fresnel方程的精确解
- 计算效率高,效果好
Fresnel 效应
Fresnel效应描述了反射率随角度变化的现象:
| 入射角 | 反射率 | 现象 |
|---|---|---|
| 0°(垂直) | F 0 F_0 F0 | 材质固有反射率 |
| 30° | F 0 + 0.5 ( 1 − F 0 ) F_0 + 0.5(1-F_0) F0+0.5(1−F0) | 反射率增加 |
| 60° | F 0 + 0.94 ( 1 − F 0 ) F_0 + 0.94(1-F_0) F0+0.94(1−F0) | 反射率显著增加 |
| 90°(掠射) | 1.0 | 几乎完全反射 |
实际例子:
- 水面:垂直看下去透明,掠射看像镜子
- 玻璃:垂直看透明,掠射看反射
- 金属:所有角度都有较强反射
3. 方向采样
vec3 sampleDir(const vec3& wo, const vec3& n) const {
return normalize(wo - 2.0f * dot(wo, n) * n);
}
完美反射定律的向量形式:
ω i = ω o − 2 ( ω o ⋅ n ) n \omega_i = \omega_o - 2(\omega_o \cdot \mathbf{n})\mathbf{n} ωi=ωo−2(ωo⋅n)n
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)