开学人倍忙,趁着第二周周末,我们继续图形相关的博客
Preface
今天我们来介绍一些理论方面的东西,为Monte Carlo 应用到我们的光线追踪器做铺垫
我们今天会介绍两章的东西,因为有一章内容太过简单
本篇目的原版内容 见相册
这个东西你点上去会有页数的,不要看混了
ready
看这一篇您需要具备以下知识
1. 了解重要性采样
2. 二重积分,基础微分
3. (半)球坐标系
4. 光线追踪基本原理
5. 立体角(solid angle),现在普及一下
首先类比二维空间的圆,假设我们在二维空间内定义了一个单位圆,我们截取圆上的一段弧AB,它对应的圆心角为∠α
而且我们知道弧长 = α*R,那么整个周长就是C = 2*π*R
那么我们三维空间,仍然有类似的定义
记粉色区域为A
立体角的单位是球面度(sr),1sr定义为球面上一块面积(A)为R的区域,从球心看过去的三维角度。
类比于二维圆上的圆弧和圆心角,那块面积区域为三维弧度,面积区域相对于球心在三维坐标系下的张角即为立体角
立体角计算
Ω = ∫∫(sinθ)dθdφ
A为三维弧度
其中,θ代表经度,φ代表维度
整个球面的立体角为
Ω = ∫dφ ∫(sinθ)dθ
Ω = 2π*2 = 4π
content
我们之前的光线追踪器中有一个过程是获取一个三维空间的随机方向,我们利用单位球体内的随机点来代表该方向,那么我们今天用Monte Carlo 来实现相同的效果
Chapter2 MC Integration on the Sphere of Directions
首先我们需要定义一个2D的pdf函数
我们假定下面这个积分适用于任意方向
∫cosθdθ
在MC积分下,我们应该做 cosθ/p(direction) 的采样
但是这里的direction在我们的环境中如何定义的呢?
我们需要在极坐标系下进行定义,p是关于θ和φ的一个函数
但是,不管你怎么整,一定要记住,
设计一个pdf函数,它的积分必须是1,并且pdf代表着该方向被采样的相对概率
我们看一下之前我们的随机函数(模板和异常可忽略)
template<typename T = lvgm::precision> const lvgm::vec3<T> random_unit_sphere() { if (typeid(T) == typeid(int)) { std::cerr << "integer doesn't have a random number from 0 to 1\n"; throw "integer doesn't have a random number from 0 to 1\n"; } lvgm::vec3<T> p; do { p = 2.0*lvgm::vec3<T>(rand01(), rand01(), rand01()) - lvgm::vec3<T>(1, 1, 1); } while (dot(p, p) >= 1.0); return p; }
这得到的是单位球体内部的随机三维点
如果我们要得到球体表面的三维空间点,那么我们只需要单位化一下即可
也就是return p的单位化向量
那么,能够代表这些球体表面点的pdf函数应该是什么呢?
作为单位球体表面点的均匀密度,用立体角的方式定义均匀密度
即单位立体角的球面度/整个球体对应的球面度,也就是1/球体面积 或者 1/4π
如果被积函数我们选取上面的cosθ,θ为随机方向与z轴的夹角,那么程序如下
void sphereMC() { auto pdf = []() {return 1 / (4 * π); }; size_t n{ 10000000 }; double sum{ 0 }; for (int i = 0; i < n; ++i) { dvec3 d = random_unit_sphere().ret_unitization(); double cosine = d.z()*d.z(); sum += cosine / pdf(); } stds cout << "I = " << sum / n << stds endl; }
答案是 4π/3,绝对没毛病
Chapter3 Light Scaterring
在上本书中,我们基于表面或者次表面实现散射光线,这是一个普适模型。
但是,更自然的方式是概率,该光线多大概率被吸收了?
设 光线反射概率为A
那么 光线被吸收的概率就为 1-A
这里的A其实代表之前材质中的albedo(latin for whiteness)。
Albedo代表着某些反射形式的反射比例
当我们实现玻璃材质的时候,albedo伴随着入射光线方向的变化而变化,进而计算相应变化的像素值
在大多数的基于物理的渲染器,我们将用一组波长表示浅色而不是RGB,我们用长中短波长来代表RGB
如果实现光散射,那么我们可以基于立体角设计一个pdf来描述光线散射方向分布。
我将其称为散射pdf:s(direction),这个散射pdf也会随着入射方向的变化而变化
所以这个表面色彩就数量(wavelength)而言有如下积分形式
color = ∫A * s(direction) * color(direction) dθ [公式1]
需要注意的是:A 和 s()都是依赖于观察方向的,当然,color也随着观察方向的变化而变化,A 和 s()也可能随着表面或体内部的位置而变化
如果我们将Monte Carlo应用到上面的积分的话,那么我们得到如下的统计估计公式
Color = (A * s(direction) * color(direction)) / p(direction) [公式2]
这里的p(direction)是方向参数随机模拟生成的一个pdf函数
对于Lambertian材质表面,我们假定其密度是呈余弦规律的。
so, 一个Lambertian表面的p()是正比于cosθ,而θ是光线方向和表面法线的夹角,还需要注意一点:所有设计的pdf函数在定义域内的积分必须是1
我们还知道,对于磨砂表面来说,入射光线和表面法线的夹角不会超过90°,所以,我们定义
对于 cosθ < 0 的情况,我们设定s(direction) = 0
所以有效区间为半球面,而基于半球的cos积分为π,这个怎么理解呢?
还记得already中的球面度吗?我们那时候说过那个区域A的微分形式(基于球坐标)为
dA = sinθ dθdφ
所以,半球面积 =
所以,Lambertian表面散射pdf为:
s(direction) = cosθ / π [公式3]
如果我们采样也使用同样的pdf函数,
即: p(direction) = cosθ/π [公式4]
那么分子分母可以消去,就得到了
Color = A * color(direction)
注:
书中表示的是 Color = A * s(direction),不是很明白意图
联立公式2、3、4,难道不是约分剩下color()了么??
这是我们原始的color函数中的设定,但我们现在需要概括一下完整的形式,以便我们可以向重要方向发送额外的光线,例如朝向灯光。
如果你看过其他相关书籍,你可能会看到双向反射分布函数(BRDF)描述的反射。 它的表示形式非常简单:
BRDF = A * s(direction) / cosθ [公式5]
例如,对于朗伯表面,BRDF = A / Pi。(联立公式3、5可得)
我们的表达方式和BRDF之间的转换很容易。而对于参与媒体(卷),我们的反照率通常被称为散射反照率,而我们的反照片通常被称为相位函数。
这一篇主要讲一些理论相关的东西,可能没什么直观感受,但是下一篇学习的时候就需要用到这些东西了,没感觉的也没关系,结合下一篇可能会体会更深刻一点
感谢您的阅读,生活愉快~