BxDF 详解

目录

  1. BxDF 基本概念
  2. LambertianDiffuseBRDF(漫反射)
  3. PhongSpecularBRDF(高光反射)
  4. MirrorSpecularBRDF(镜面反射)
  5. BSDF 混合机制
  6. 在渲染中的应用

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)(ωin)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=1Np(ωi)fr(p,ωi,ωo)Li(p,ωi)(ωin)

其中:

  • 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);
}

采样步骤

  1. 在单位圆盘上均匀采样:使用平方根映射避免中心聚集
  2. 投影到半球 z = 1 − x 2 − y 2 z = \sqrt{1 - x^2 - y^2} z=1x2y2
  3. 转换到世界坐标:使用切线空间变换

为什么这样采样?

  • 确保在半球上均匀分布
  • PDF = 1/π
  • 避免拒绝采样,效率高

漫反射特点

特性
PDF 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} nh 越接近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(nh)α

参数说明

  • α \alpha α:高光指数(shininess)
    • α = 1 \alpha = 1 α=1:宽大、柔和的高光
    • α = 100 \alpha = 100 α=100:尖锐、明亮的高光
  • ( n ⋅ h ) α (\mathbf{n} \cdot \mathbf{h})^\alpha (nh)α:高光强度随角度衰减
  • α + 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(nh)α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(nh)α

参数说明

  • k s k_s ks:镜面反射系数(材质颜色)
  • ( n ⋅ h ) α (\mathbf{n} \cdot \mathbf{h})^\alpha (nh)α:高光强度
  • α + 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);
}

采样步骤

  1. 在半程向量空间中采样

    • ϕ = 2 π u \phi = 2\pi u ϕ=2πu(方位角,均匀分布)
    • cos ⁡ θ = v 1 / ( α + 1 ) \cos\theta = v^{1/(\alpha+1)} cosθ=v1/(α+1)(极角,Phong分布)
  2. 转换到世界坐标系

    h = toWorld(h, n);
    
  3. 根据反射定律计算出射方向

    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(θ)=1cosα+1(θ)

逆变换:

v = CDF ( θ ) = 1 − cos ⁡ α + 1 ( θ ) v = \text{CDF}(\theta) = 1 - \cos^{\alpha+1}(\theta) v=CDF(θ)=1cosα+1(θ)

cos ⁡ α + 1 ( θ ) = 1 − v \cos^{\alpha+1}(\theta) = 1 - v cosα+1(θ)=1v

cos ⁡ ( θ ) = ( 1 − v ) 1 / ( α + 1 ) \cos(\theta) = (1 - v)^{1/(\alpha+1)} cos(θ)=(1v)1/(α+1)

由于 v v v 1 − v 1-v 1v 都是均匀分布,可以简化为:

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+(1F0)(1cosθ)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(1F0) 反射率增加
60° F 0 + 0.94 ( 1 − F 0 ) F_0 + 0.94(1-F_0) F0+0.94(1F0) 反射率显著增加
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=ωo2(ωon)n

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐