目录
- Lecture 15: Ray Tracing 3 (Light Transport & Global Illumination)
- Lecture 16: Ray Tracing 4 (Monte Carlo Path Tracing)
- Lecture 17: Materials and Appearances
- Microfacet BRDF
- Lecture 18: Advanced Topics in Rendering
- Biased vs. Unbiased Monte Carlo Estimators
- Bidirectional Path Tracing(BDPT)
- Metropolis Light Transport(MLT)
- Photon Mapping
- Vertex Connection and Merging
- Instant Radiosity(many-light approaches)
- Advanced Appearance Modeling
- participating media 散射介质 云雾渲染
- 毛发渲染
- 颗粒材质
- 半透明 Translucent
- 次表面散射 subsuface scattering
- 布料
- 表面细节
- 程序化生成的表面
Lecture 15: Ray Tracing 3 (Light Transport & Global Illumination)
能量一直在向外辐射,那么场景为什么不是越来越亮
因为物体接收到能量也会反射能量
辐[射]照度 irradiance
辐[射]照度表示单位面积上接受的光线在垂直方向上的辐射能量
E ( x ) ≡ Φ ( x ) d A E(x) \equiv \dfrac{\mathrm \Phi(x)}{\mathrm d A} E(x)≡dAΦ(x)
单位为 W m 2 \dfrac{W}{m^2} m2W 或者 l m m 2 = l u x \dfrac{lm}{m^2} = lux m2lm=lux
这里要求的是光线在垂直方向上的辐射能量,与光栅化中的 Lambert’s Cosine Law 类似
其实为了和之后的公式对比理解的话,我觉得也可以认为统计的这个光线的通量与面积不垂直
只要对这个面积乘一个 cos θ \cos\theta cosθ 就好了
那么就可以写成 E ( x ) ≡ Φ ( x ) d A cos θ E(x) \equiv \dfrac{\mathrm \Phi(x)}{\mathrm d A \cos\theta} E(x)≡dAcosθΦ(x)
当光逐渐向外传播时,变小的是 Irradiance 而不是 Intensity
也就是说,变小的是单位面积上的光通量,而单位立体角上的光通量是不变的
考虑这个单位立体角,在半径比较小的时候,对应的面积也小,在半径比较大的时候,对应的面积也大
Radiance 辐[射]亮度
Radiance 辐[射]亮度 Light Traveling ALong A Ray 单位立体角单位面积内或发射,或反射,或传送,或接受的能量
L ( p , w ) ≡ d 2 Φ ( p , w ) d w d A cos θ L(p,w) \equiv \dfrac{\mathrm d^2 \Phi(p,w)}{\mathrm d w \mathrm d A \cos\theta} L(p,w)≡dwdAcosθd2Φ(p,w)
单位 W s r m 2 \dfrac{W}{sr m^2} srm2W 或 c d m 2 = l m s r m 2 = n i t \dfrac{cd}{m^2} = \dfrac{lm}{sr m^2} = nit m2cd=srm2lm=nit
可以理解为一个单位面向某一个方向发出的能量
这里之所以能这么写,是使用了
E
(
x
)
≡
Φ
(
x
)
d
A
cos
θ
E(x) \equiv \dfrac{\mathrm \Phi(x)}{\mathrm d A \cos\theta}
E(x)≡dAcosθΦ(x) 的定义,也就是计算
L
L
L 和
E
E
E 的时候考虑到面积法向与光线方向不重合
Intensity, Irradiance, Radiance 之间的关系
Intensity 单位立体角所发射的能量
Irradiance 单位面积上接受的光线在垂直方向上的辐射能量
Radiance 单位立体角单位时间内或发射,或反射,或传送,或接受的能量
所以单纯从量纲上看,就有:
Radiance =
单位立体角的 Irradiance
单位面积的 Intensity
怎么理解 Radiance = 单位立体角的 Irradiance
从一个角度看,Radiance 是一个单位面积向某一个方向发出的能量
从另外一个角度看,Radiance 是一个单位面积从某一个方向接受的能量
类似地,Irradiance 也即是单位面积接受的能量,但是 Irradiance 是从各个方向接受的能量,而 Radiance 只是从一个方向
怎么理解 Radiance = 单位面积的 Intensity
感觉这个更好理解了,就是点到面
Radiance 是 Irradiance 微分
在一个半球对 Radiance 在半球上积分,就得到 Irradiance
前面好像也没有说这个 p 是什么?
这么一看的话,感觉应该是位置的意思
BRDF & The Rendering Equation
反射可以理解为从某个方向进来然后反射到某个方向去的能量。可以用 BRDF(反射方程)来描述这个过程。
就考虑某一个微小面积 dA 从某各微小立体角 dw 接收到的 Irradiance,会被如何分配到各个不同的立体角上面去。
更具体地说,我们知道某一个单位面积接收到了多少能量,也就是知道了 E
更进一步,对于反射,对于反射中的入射光,我知道从入射方向 w i w_i wi 上过来了多少能量 d E ( w i ) = L ( w i ) cos θ d w i \mathrm d E(w_i) = L(w_i) \cos\theta \mathrm d w_i dE(wi)=L(wi)cosθdwi
我始终没搞懂这个 PPT 这里为什么要写 d L d E \dfrac{\mathrm d L}{\mathrm d E} dEdL
而不是 L d E \dfrac{L}{\mathrm d E} dEL
分母是 d E \mathrm d E dE 我倒是理解,如果设 E E E 是面积 A 从半球的立体角接收到的能量,那么对立体角微分,就得到面积 A 从某一个立体角接收到的能量
那为什么不直接写成 L L L 呢?因为 Radiance 是单位面积单位立体角嘛
然后 d E = L cos θ d w \mathrm d E = L \cos \theta \mathrm d w dE=Lcosθdw 嘛
其实我写 d E \mathrm d E dE 也相当于在用 L L L 嘛,只是我现在知道这个入射方向 w i w_i wi,那么我把 L L L 与 w i w_i wi 一乘,就是这个方向来的单位面积的能量嘛,然后就是面积法向与方向之间有个角度所以加 cos θ \cos \theta cosθ
但是出去的时候自然就是考虑 L L L 啊,我就不知道为什么他说是 d L \mathrm d L dL
我再看了一下别人的解释
https://zhuanlan.zhihu.com/p/393371982
别人也说是
所以,P 点接受的辐照度和 PO 方向的辐亮度的比值是一个固定值,其只和 P 点表面的属性,入射光线 LP 以及出射光线 PO 相关,和光源 L 或其他的任何值都无关。我们把入射光线 w i w_i wi 记作 ,出射光线记作 w o w_o wo,那么我们把这个反射比率用函数 f ( p , w i , w o ) f(p,w_i,w_o) f(p,wi,wo) 表示。
这个函数即双向反射分布函数,BRDF。
然后别人也指出了一个隐含的条件就是,这个出射的 L L L 中的单位面积就是指的是打到与光路相垂直的单位面积
这就更加让我感觉合理了……因为入射的时候考虑的单位面积是着色点的单位面积,所以有 cos θ \cos \theta cosθ;出射的时候认为计算的单位面积,或者说让别人接受的单位面积是垂直于光路的,所以没有 cos θ \cos \theta cosθ
再看到了
https://www.cnblogs.com/wickedpriest/p/13184433.html
从图中可以看到,所谓的BRDF就是从ωi方向发射一束光,打在平面某一个顶点上,在ωr的方向上的辐射亮度和顶点的辐射强度之比。
其中dL(ωr)是表面反射到ωr方向的反射光的微分辐射亮度,表面反射到ωr的反射光的辐射亮度为L(ωr),来自于表面上半球所有方向入射光的贡献,用dL(ωr)是为了特指来自ωi方向的入射光贡献的辐射亮度。
dE(ωi)是表面从ωi方向的入射光的微分辐射强度,表面接收到的辐照强为E,用dE(ωi)特指来自于方向ωi的入射光。
他这个从 L 到 dL 的解释姑且还能接受,但是从 E 到 dE 的解释……看过那个半球的图,感觉还是用那个半球来解释可能会好一些
然后他后面解释了,dE dL 的写法是因为测量仪器的关系
嗯……很合理
就,干脆都用 L 也不是不行
就像这个 PPT 都是用的 L
后面又看到了有一个弹幕的解释
加d就是把很大一份分成很多很小一份,这一小份是根据夹角或者面积或其他来分的,本公式都是立体角,但是每个立体角也会导致其他变量不一样,比如cos值。说的高大上就是微分
然后再结合刚刚看到的那个博客
我感觉我似乎终于懂了……
首先,我们是从四面八方接受光线,所以输入 E
然后我们要向四面八方发散,所以输出 L
然后我们把这个 E 分成很多份,现在我们要知道入射方向的这一份,所以 E 是对立体角微分得到 dE, d E ( w i ) \mathrm d E(w_i) dE(wi) 就是入射方向的这一份
然后输出 L,因为它本身其实就是单位面积单位立体角,所以本身就是指定一个方向的,所以本身我们就是输出 L ( w o ) L(w_o) L(wo)
但是这个 L ( w o ) L(w_o) L(wo) 反射的能量来自 E E E,也就是来自各个入射方向的能量
现在我们把这个 L ( w o ) L(w_o) L(wo) 分成很多份,现在我们要知道来自入射方向贡献的这一份,所以我们用 d L ( w o ) \mathrm dL(w_o) dL(wo) 来代表入射方向贡献的这一份
感觉终于合理了……
再看一遍这页 PPT
他就是把这个分成很多份的
L
(
w
o
)
L(w_o)
L(wo) 积分嘛,那我们之前的
d
L
(
w
o
)
\mathrm dL(w_o)
dL(wo) 来代表入射方向贡献的这一份,所以我们对所有的入射方向积分,也就是对这个半球积分的话,得到的就是这个
L
(
w
o
)
L(w_o)
L(wo)
BRDF 的递归问题
假设在某一个状态,我已经知道了 L i ( p , w i ) L_i(p,w_i) Li(p,wi),材质为 f r ( p , w i → w r ) f_r(p,w_i \rightarrow w_r) fr(p,wi→wr),然后我可以计算出这一点的 L r ( p , w r ) L_r(p,w_r) Lr(p,wr)
但是这个出射的光线又会打到别的物体上,别的物体可能又会把这条光线反射回来,进而让我的 p p p 点的 L i ( p , w i ) L_i(p,w_i) Li(p,wi) 发生变化
我的 L i ( p , w i ) L_i(p,w_i) Li(p,wi) 发生变化,那么又要重新计算一次 L r ( p , w r ) L_r(p,w_r) Lr(p,wr),然后如此递归……
BRDF 的通用化
在解决这个递归问题之间,先将 BRDF 的方程通用化
早期,由于翻译问题,BRDF 方程被翻译为渲染(绘制)方程 Rendering Equation
BRDF 的方程通用化得到渲染方程 Rendering Equation
通用化的点在于,考虑到物体可能自发光,所以将自发光的项加入 BRDF
L o ( p , w o ) = L e ( p , w o ) + ∫ Ω + L i ( p , w i ) f r ( p , w i , w o ) ( n ⋅ w i ) d w i L_o(p,w_o) = L_e(p,w_o) + \int_{\Omega+}L_i(p,w_i)f_r(p,w_i,w_o)(n \cdot w_i)\mathrm d w_i Lo(p,wo)=Le(p,wo)+∫Ω+Li(p,wi)fr(p,wi,wo)(n⋅wi)dwi
Ω + \Omega+ Ω+ 表示向外的方向组成的半球
n ⋅ w i n \cdot w_i n⋅wi 对应 cos θ \cos\theta cosθ 这项,方便计算
不同形式的渲染方程
如果只有一个点光源,那么渲染方程写为
L r ( p , w r ) = L e ( p , w r ) + L i ( p , w i ) f ( p , w i , w r ) ( n ⋅ w i ) L_r(p,w_r) = L_e(p,w_r) + L_i(p,w_i)f(p,w_i,w_r)(n \cdot w_i) Lr(p,wr)=Le(p,wr)+Li(p,wi)f(p,wi,wr)(n⋅wi)
如果有多个点光源,那么渲染方程写为
L r ( p , w r ) = L e ( p , w r ) + ∑ L i ( p , w i ) f ( p , w i , w r ) ( n ⋅ w i ) L_r(p,w_r) = L_e(p,w_r) + \sum L_i(p,w_i)f(p,w_i,w_r)(n \cdot w_i) Lr(p,wr)=Le(p,wr)+∑Li(p,wi)f(p,wi,wr)(n⋅wi)
如果有一个面光源,那么渲染方程写为
L r ( p , w r ) = L e ( p , w r ) + ∫ Ω + L i ( p , w i ) f ( p , w i , w r ) ( n ⋅ w i ) d w i L_r(p,w_r) = L_e(p,w_r) +\int_{\Omega+}L_i(p,w_i)f(p,w_i,w_r)(n \cdot w_i)\mathrm d w_i Lr(p,wr)=Le(p,wr)+∫Ω+Li(p,wi)f(p,wi,wr)(n⋅wi)dwi
到这里跟前面应该是一样的吧
然后他就要说怎么解这个方程
我们观察到这个方程是递归的,然后有一个数学上的直觉就是,对于这个方程我们是需要迭代求解的,而迭代求解一个方程有一些有用的方法
具体到操作上,就是认为这个入射的光线和出射的光线的 Radiance 函数是一样的
就,其实入射的光线和出射的光线的方向不必要一样,因为出射的时候是向半球出射嘛,所以无所谓
这里是为了求值,所以令两个函数是一样的
原来是
L r ( p , w r ) = L e ( p , w r ) + ∫ Ω + L i ( p , w i ) f ( p , w i , w r ) ( n ⋅ w i ) d w i L_r(p,w_r) = L_e(p,w_r) +\int_{\Omega+}L_i(p,w_i)f(p,w_i,w_r)(n \cdot w_i)\mathrm d w_i Lr(p,wr)=Le(p,wr)+∫Ω+Li(p,wi)f(p,wi,wr)(n⋅wi)dwi
现在代入 L i = L r L_i = L_r Li=Lr,得到
L r ( x , w r ) = L e ( x , w r ) + ∫ Ω + L r ( x ′ , − w i ) f ( x , w i , w r ) ( n ⋅ w i ) d w i L_r(x,w_r) = L_e(x,w_r) +\int_{\Omega+}L_r(x',-w_i)f(x,w_i,w_r)(n \cdot w_i)\mathrm d w_i Lr(x,wr)=Le(x,wr)+∫Ω+Lr(x′,−wi)f(x,wi,wr)(n⋅wi)dwi
x x x 表示着色点, x ′ x' x′ 表示外界反射光的物体点, L r L_r Lr 的方向是从 x ′ x' x′ 到 x x x,而一般记录 w w w 使用的方向都是从 x x x 出发,所以写成 − w i -w_i −wi 表示从 x ′ x' x′ 到 x x x
其中 L r ( x , w r ) L_r(x,w_r) Lr(x,wr) 和 L r ( x ′ , − w i ) L_r(x',-w_i) Lr(x′,−wi) 都是未知的,其他都是已知的
上式进一步化简得到
I ( u ) = e ( u ) + ∫ I ( v ) K ( u , v ) d v I(u) = e(u) + \int I(v) K(u,v) \mathrm d v I(u)=e(u)+∫I(v)K(u,v)dv
更进一步化简成
L = E + K L L = E + KL L=E+KL
感觉很合理……这里的 L L L 相当于原来的 I ( u ) I(u) I(u), K L KL KL 相当于 ∫ I ( v ) K ( u , v ) d v \int I(v) K(u,v) \mathrm d v ∫I(v)K(u,v)dv,相当于对 I ( u ) I(u) I(u) 做了一个变换
从物理意义来说, K K K 就相当于一个反射操作符
但是具体到这个积分怎么变成矩阵方程……或者说这不是矩阵?
对这个 L = E + K L L = E + KL L=E+KL 就是一个经典的迭代方程
移项:
I L − K L = E IL-KL = E IL−KL=E
合并同类项:
( I − K ) L = E (I - K)L = E (I−K)L=E
移项:
L = ( I − K ) − 1 E L = (I-K)^{-1}E L=(I−K)−1E
对 ( I − K ) − 1 (I-K)^{-1} (I−K)−1 在 K = 0 K = 0 K=0 处泰勒展开,得
L = ( I + K + K 2 + K 3 + . . . ) E L = (I + K+ K^2 + K^3 + ...)E L=(I+K+K2+K3+...)E
即
L = E + K E + K 2 E + K 3 E + . . . L = E + KE + K^2E + K^3E+... L=E+KE+K2E+K3E+...
如果光线一次都不弹射直接打到人的眼睛里,那么看到的就是光源E;如果光线弹射一次后打到人的眼睛里,看到的就是直接光照KE(包括阴影);如果弹射两次,看到的就是间接光照;如果弹射多次就是间接光照的叠加。反射本身就是一种间接光照。
光栅化可以做的就是 E + KE,后面的项会更难做
光线多次弹射的效果
为什么光线弹射次数少的时候玻璃是黑的,而光线弹射次数多的时候玻璃就亮了?
因为光线弹射次数少的时候留在玻璃内部出不来,例如一层玻璃至少需要弹射两次
Lecture 16: Ray Tracing 4 (Monte Carlo Path Tracing)
蒙特卡罗积分
基本的思想是,在各处采样,认为某次采样得到的函数值 * 区间长度得到的矩形面积近似于积分的面积,多次采样得到的矩形面积的平均值近似于积分的面积
定义随机变量 X i ∼ p ( x ) X_i \sim p(x) Xi∼p(x)
定义概率密度函数 ∫ a b f ( x ) d x \int_a^b f(x) \mathrm d x ∫abf(x)dx
那么蒙特卡洛积分公式为 F N = 1 N ∑ i = 1 N f ( X i ) p ( X i ) F_N = \dfrac{1}{N}\sum_{i=1}^{N}\dfrac{f(X_i)}{p(X_i)} FN=N1∑i=1Np(Xi)f(Xi)
一开始看这个积分公式,可能与我们的“多次采样矩形面积,取平均值近似于积分的面积”这个思想不太搭
于是我们可以取一个均匀分布的例子
假设随机变量满足 X i ∼ p ( x ) = 1 b − a X_i \sim p(x) = \dfrac{1}{b-a} Xi∼p(x)=b−a1
那么蒙特卡洛积分公式变为 F N = b − a N ∑ i = 1 N f ( X i ) F_N = \dfrac{b-a}{N}\sum_{i=1}^{N}f(X_i) FN=Nb−a∑i=1Nf(Xi)
如果 f ( X i ) f(X_i) f(Xi) 是从 a 到 b 的,这也就是黎曼积分的公式
看上去,似乎,黎曼积分是蒙特卡洛积分的一个特例?
但是我没搜到别人这样说
蒙特卡罗积分的
-
采样点越多,方差越小
-
在 x 上采样,就在 x 上积分
全局光照
Whitted-Style Ray Tracing
Whitted-Style Ray Tracing 的做法:
-
一直发生反射或折射
-
光线击中漫反射表面则停止
但是这里不一定是对的
首先,光线打到光泽 glossy 物体上,不单单发生了镜面反射也发生了漫反射
Utah 茶壶
其次,这里的反射折射只发生在能够反射折射的物体上
而光线打到漫反射的物体上就停了,所以没有考虑到漫反射的物体之间的光线,也就是说没有考虑到一个漫反射的物体会被另外一个漫反射的物体照亮
例如,右图中,靠左的木块的左面被红墙漫反射的光线击中,呈现红色
这也叫做 color bleeding
cornell box
使用蒙特卡罗积分来解渲染方程
假设先不考虑自发光项
假设先只考虑直接光照
L o ( p , w o ) = ∫ Ω + L i ( p , w i ) f r ( p , w i , w o ) ( n ⋅ w i ) d w i L_o(p,w_o) = \int_{\Omega+}L_i(p,w_i)f_r(p,w_i,w_o)(n \cdot w_i)\mathrm d w_i Lo(p,wo)=∫Ω+Li(p,wi)fr(p,wi,wo)(n⋅wi)dwi
已知蒙特卡洛积分为 F N = 1 N ∑ i = 1 N f ( X i ) p ( X i ) F_N = \dfrac{1}{N}\sum_{i=1}^{N}\dfrac{f(X_i)}{p(X_i)} FN=N1∑i=1Np(Xi)f(Xi)
这里的 f ( x ) = L i ( p , w i ) f r ( p , w i , w o ) ( n ⋅ w i ) f(x) = L_i(p,w_i)f_r(p,w_i,w_o)(n \cdot w_i) f(x)=Li(p,wi)fr(p,wi,wo)(n⋅wi), 半球的立体角是 2 π 2\pi 2π,认为采样到任意一个立体角的概率是均匀的 p ( w i ) = 1 / 2 π p(w_i) = 1/2 \pi p(wi)=1/2π
那么对渲染方程应用蒙特卡洛积分得到 L o ( p , w o ) ≈ 1 N ∑ i = 1 N L i ( p , w i ) f r ( p , w i , w o ) ( n ⋅ w i ) p ( X i ) L_o(p,w_o) \approx \dfrac{1}{N}\sum_{i=1}^{N}\dfrac{L_i(p,w_i)f_r(p,w_i,w_o)(n \cdot w_i)}{p(X_i)} Lo(p,wo)≈N1∑i=1Np(Xi)Li(p,wi)fr(p,wi,wo)(n⋅wi)
这里有一个记号上的冲突,对于 L(p,w) 来说,p 是着色点 p,对于 p(X) 来说,p 是概率
伪代码:
shader(p, w0)
Randomly choose N directions wi-pdf
Lo = 0.0
For each wi
Trace a ray r(p, wi)
If ray r hit the light
Lo += (1 / N) * L_i * f_r * cosine / pdf(wi)
Return Lo
这里是解决了一步,也就是只考虑了直接光照
具体看 If ray r hit the light
这里,就是直接将着色点与光源连线,所以是只考虑了直接光照
为了考虑间接光照,就考虑这个光线打到其他物体的时候该怎么办
光线打到其他物体,其实就是其他物体反射过来了光线
那么我需要获取到其他物体的颜色
shade(p, w0)
Randomly choose N directions wi-pdf
Lo = 0.0
For each wi
Trace a ray r(p, wi)
If ray r hit the light
Lo += (1 / N) * L_i * f_r * cosine / pdf(wi)
Else If ray r hit an object ar q
Lo += (1/N) * shade(q, -wi) * f_r * cosine / pdf(wi)
Return Lo
简单的蒙特卡洛积分计算遇到的问题
反射数量爆炸
第一个问题,反射光线的数量会爆炸
假设我对一个点,使用蒙特卡洛积分采样 100 个点,那么也就是我从这个着色点发出 100 根方向随机的光线,每一根光线打到其他物体之后,调用其他物体的 shade,每一次 shade 又是 100 次采样,那么这原来的这 100 根光线调用的 100 次 shade 总共要 100 * 100 次采样……以此类推,光线的数量会爆炸
为了解决这个问题,对于蒙特卡洛积分,我只用一根光纤进行采样,因为 1 的指数还是 1
伪代码:
shade(p, w0)
Randomly choose ONE directions wi-pdf(w)
Lo = 0.0
For each wi
Trace a ray r(p, wi)
If ray r hit the light
Lo += L_i * f_r * cosine / pdf(wi)
Else If ray r hit an object ar q
Lo += shade(q, -wi) * f_r * cosine / pdf(wi)
Return Lo
到这里的做法就是路径追踪 path tracing
如果 N != 1,确实会出现指数爆炸,称为分布式路径追踪 distributed ray tracing
但是对蒙特卡洛积分使用一个采样点的误差肯定大,所以我对某一个像素内部取不同的位置,多次从摄像机向这个像素内部的随机点投射光线,获得颜色,取平均
ray_generatin(camPos, pixel)
Uniformly choose N sample position within the pixel
pixel_radiance = 0.0
For each sample in the pixel
Shoot a ray r(camPos, cam_to_sample)
If ray r hit the scene at p
pixel_radiance += 1 / N * shade(p, sample_to_cam)
Return pixel_radiance
循环递归,俄罗斯轮盘赌
第二个问题,shade 可能陷入循环的递归中
例如 A 发出光线打到 B,B 发出光线又打到 A,A 又发出光线又打到 B……如此循环
一个常见的解决方法是限制递归次数
但是问题是,如果限制递归次数,那么与现实情况的无数次反射相比,得到的提前终止的光线的能量就会变小
对这个能量的问题的一个解决方法就是俄罗斯轮盘赌 Russian Roulette RR
以概率 p 射出光线,返回值为 Lo/p
以概率 1-p 不射出光线,返回值为 0
那么这时,返回值的期望为 E = p ∗ L o / p + ( 1 − p ) ∗ 0 = L o E = p * Lo/p + (1-p) * 0 = Lo E=p∗Lo/p+(1−p)∗0=Lo
这样得到的结果虽然有噪声,但是期望是对的
shade(p, w0)
Manually specify a probability P_RR
Randomly select ksi in a uniform dist, in [0, 1]
If(ksi > P_RR) return 0.0
Randomly choose ONE directions wi-pdf(w)
Lo = 0.0
For each wi
Trace a ray r(p, wi)
If ray r hit the light
Lo += L_i * f_r * cosine / pdf(wi) / P_RR
Else If ray r hit an object ar q
Lo += shade(q, -wi) * f_r * cosine / pdf(wi) / P_RR
Return Lo
采样效率与有效性问题
对任意点 p 贡献最大的是直接光照,但是光线随机采样,可能打不到光源
很多光线被浪费掉了
那么一个想法就是,我现在不随机地发出光线了,我直接向光源发出射线,也就是我直接在光源上采样
所谓在光源上采样就是设概率密度函数是在光源上定义的 p d f = 1 / A pdf = 1/A pdf=1/A,这里的微元是 dA
但是渲染方程中的积分是在立体角上积分的
蒙特卡洛积分要求积分是在 x 上采样在 x 上积分的
所以我们需要协调这个光源面积与着色点立体角这两个变量不一致的矛盾
既然现在我们已经确定是在光源上采样了
所以我们只能把渲染方程写成以光源面积为积分变量的形式
那么我们就需要知道 dw 和 dA 之间的关系
立体角定义是,在单位球上投影的面积,于是我们只需要知道光源的 dA 在以着色点为球心的单位球上的投影就好了
d w = d A cos θ ′ ∣ ∣ x ′ − x ∣ ∣ 2 \mathrm d w = \dfrac{\mathrm d A \cos \theta'}{||x' - x||^2} dw=∣∣x′−x∣∣2dAcosθ′
对 dA 乘以 cos θ ′ \cos \theta' cosθ′ 得到正对着着色点的面积
除以 ∣ ∣ x ′ − x ∣ ∣ 2 ||x' - x||^2 ∣∣x′−x∣∣2 是将面积缩放到单位球的坐标系中
我感觉可以想象成,原来的面积距离着色点是 ∣ ∣ x ′ − x ∣ ∣ 2 ||x' - x||^2 ∣∣x′−x∣∣2,相当于位于半径为 ∣ ∣ x ′ − x ∣ ∣ 2 ||x' - x||^2 ∣∣x′−x∣∣2 的球上
渲染方程变为:
L o ( p , w o ) = ∫ Ω + L i ( p , w i ) f r ( p , w i , w o ) cos θ d w i = ∫ A L i ( p , w i ) f r ( p , w i , w o ) cos θ cos θ ′ ∣ ∣ x ′ − x ∣ ∣ 2 d A L_o(p,w_o) = \int_{\Omega+}L_i(p,w_i)f_r(p,w_i,w_o)\cos\theta\mathrm d w_i \\ = \int_A L_i(p,w_i)f_r(p,w_i,w_o)\dfrac{\cos\theta \cos \theta'}{||x' - x||^2}\mathrm d A Lo(p,wo)=∫Ω+Li(p,wi)fr(p,wi,wo)cosθdwi=∫ALi(p,wi)fr(p,wi,wo)∣∣x′−x∣∣2cosθcosθ′dA
那么现在我们将这个直接光照的改动之后的方法,放到我们之前的总结的路径追踪的方法中
对于直接光照,我们直接对光源进行蒙特卡洛积分,不使用俄罗斯轮盘赌
对于间接光照,我们对着色点进行蒙特卡洛积分,使用俄罗斯轮盘赌
shade(p, w0)
# Contribution from the light source
Uniformly sample the light at x' (pdf_light = 1 / A)
L_dir = L_i * f_r * cos(theta) * cos(theta') / |x' - p|^2 / pdf_light
# Contribution from other reflectors
L_indir = 0.0
Test Russian Roulette with probability P_RR
Uniformly sample the hemisphere toward wi (pdf_hemi = 1 / 2pi)
Trace a ray r(p, wi)
If ray r hit a non-emitting object at q
L_indir = shade(q, -wi) * f_r * cos(theta) / pdf_hemi / P_RR
Return L_dir + L_indir
这里与之前的写法变化在于 Test Russian Roulette
就是包含了可能提前终止
non-emitting object
表示不是光源
这里还要考虑光源是否被挡住
shade(p, w0)
# Contribution from the light source
Uniformly sample the light at x' (pdf_light = 1 / A)
Shoot a ray from p to x'
If the ray is not blocked in the middle
L_dir = L_i * f_r * cos(theta) * cos(theta') / |x' - p|^2 / pdf_light
# Contribution from other reflectors
L_indir = 0.0
Test Russian Roulette with probability P_RR
Uniformly sample the hemisphere toward wi (pdf_hemi = 1 / 2pi)
Trace a ray r(p, wi)
If ray r hit a non-emitting object at q
L_indir = shade(q, -wi) * f_r * cos(theta) / pdf_hemi / P_RR
Return L_dir + L_indir
还有一些问题,比如在蒙特卡洛积分中,点光源的采样概率怎么计算
可以设为面积很小的面光源?
Ray Tracing 理解为光线传播方法的集合
未解决问题
(1)半球均匀随机采样合理吗?(不合理,法线分布函数)
(2)蒙特卡罗积分方法中的pdf函数,不考虑均匀概率分布,而是考虑一个不均匀的,那么该怎么选择(重要性采样 importance sampling)
(3)随机数序列重要吗?(不合理,低差异序列 low discrepancy sequences)
(4)结合采样半球和光源?(nultiple imp. sampling)
(5)穿过一个像素上的所有光线得出的Radiance结果,为啥平均?(pixel reconstruction filter)
(6)gamma校正、HDR、颜色空间?
(7)path tracing 仍然是入门介绍。
以前介绍的 Ray Tracing 是 Whitted-style ray tracing
现代的方法比如
Unidirectional & bidirectional path tracing 单向/双向路径追踪
Photon mapping 光子映射
Metropolis light transport 梅特罗波利斯光传输
Vertex Connection and Merging(VCM)
Unified points, beams and paths(UPBP)
Lecture 17: Materials and Appearances
Material == BRDF
Diffuse Material
对于漫反射材质,其实满足以下假设:
(1)任一方向入射光都会均匀无损耗的反射到半球的任意方向;
(2)半球任意方向的入射光的Radiance都一样大小的情况下,同时在(1)的前提下,就能满足任意方向的入射Radiance都相等、等等于任意方向的出射Radiance;
就是说这个假设下,物体不吸收光
(3)在(1)(2)的假设下,如下图,因为物体不吸收光,所以 L o ( w o ) = L i L_o(w_o) = L_i Lo(wo)=Li 计算出的应该是 fr=1/π;
(4)但是如果材质有颜色,则会有光的吸收,则fr=1/π*ρ,这里fr是一个三维向量,代表对rgb不同颜色通道有不同的反射率。
Glossy Material
从一个点入射之后,在一个范围内反射
有点像镜面反射,但是又没有完全镜面反射
Ideal reflective/refractive material
既发生折射又发生反射
观察右图,可以发现,反射或者折射的光被吸收了一部分,所以会呈现颜色
他这里就是一个规律性的认识,就是,吸收了光的能量才会显示出不同的颜色
Perfect Specular Reflection
这里是假设入射光和反射光的方向都是从着色点向外,推出来的计算
其中 θ \theta θ 是方向向量和法线方向的夹角, ϕ \phi ϕ 是方向向量的方位角
Specular Refraction 折射
焦散,有些光线聚焦在某处,有些光线分散,得到的一些光斑
Snell’s Law 折射定律
折射率越大,玻璃越亮
但是我没有找到一个合理的解释
之后我想到,或许是使用菲涅尔公式来看
想要计算折射角的余弦
当根号下的数小于 0 时折射不可能发生,也就是只有反射,也就是全反射
只有在 η i η t > 1 \dfrac{\eta_i}{\eta_t} > 1 ηtηi>1 时才有可能发生全反射,也就是光线打到更密的地方的时候才可能发生全反射
BRDF R 表示反射
BTDF T 表示折射
BSDF S 表示既有反射又有折射,认为他们都是散射
一般说的 BRDF 也包含反射和折射
snell’s window
入射角太大的光线从空气进入水面之后发生了全反射
于是在水底看到的来自空气中的画面只有没有发生全反射的那部分
菲涅尔公式
绝缘体
入射角度越大,发射的能量越多
S P 指的是极化的光线,暂时不用考虑
也就是你视线与玻璃垂直的时候你可以看到玻璃后面的物体,但是实现与玻璃近似平行的时候,你就看不到玻璃后面,反而看到的是玻璃反射的物体
导体:
可见,为什么古代会用金属作为镜子,因为金属在不同入射角的情况下反射的能量都挺高
正确的菲涅尔公式是计算了两个极化的光,然后把这两个光加起来平均
但是公式有点复杂,可以做一个近似 Schlick’s approximation
就是找一个近似的曲线来拟合
Microfacet Material 微表面模型
从远处看,看到的是一个粗糙的,平整的表面
在近处看,看到的是一个镜面反射的,凹凸的表面
从远处看看到的是材质,从近处看看到的是几何
Microfacet BRDF
如果微表面的法线方向比较集中,得到的就是 glossy 材质
如果微表面的法线方向比较分散,得到的就是 diffuse 材质
也就是使用表面的法线分布来代表物体表面的材质
f ( i , o ) = F ( i , h ) G ( i , o , h ) D ( h ) 4 ( n , i ) ( n , o ) f(i,o) = \dfrac{F(i,h)G(i,o,h)D(h)}{4(n, i)(n, o)} f(i,o)=4(n,i)(n,o)F(i,h)G(i,o,h)D(h)
其中 F ( i , h ) F(i,h) F(i,h) 表示菲涅尔项,表示多少光线被反射
D ( h ) D(h) D(h) 表示法线分布
h h h 表示半程向量,因为反射的时候入射光线和反射光线是以法向量为对称的,所以如果发生的反射,那么入射光线和反射光线的半程向量应该是靠近法向量的,所以我们可以使用半程向量去与法向量之间作比较,越接近则越反射
这里 D ( h ) D(h) D(h) 老师讲成了查询,也就是查询在所有的微表面中,有多少微表面是法向量接近半程向量的,这个占比就表明了物体表面材质在宏观上对这个半程向量所表示的情况的反射行为
G ( i , o , h ) G(i,o,h) G(i,o,h) 表示几何项,考虑微表面之间的互相遮挡
当光线几乎与物体表面平行入射的时候,容易发生微表面之间的互相遮挡
这种光线方向也称为 grazing angle
想象对于一个球,如果没有几何项,在球的边界,光线方向几乎是 grazing angle,那么球的边界会非常亮(我猜是因为底下的分母接近 1?)如果有了几何项就不会这么亮
各向同性/各向异性材质 BRDFs
各向异性的一个直接表现就是法线的分布具有方向性
而从物理含义来说,就是我沿着不同的方向角看过去,得到的材质表现是不一样的
也就是 f r ( θ i , ϕ i ; θ r , ϕ r ) ≠ f r ( θ i , θ r , ϕ r − ϕ i ) f_r(\theta_i, \phi_i;\theta_r,\phi_r) \ne f_r(\theta_i, \theta_r,\phi_r-\phi_i) fr(θi,ϕi;θr,ϕr)=fr(θi,θr,ϕr−ϕi)
这个公式的写法……不知道为什么要用差值
例子
尼龙的各向异性指的是在横竖上
天鹅绒是有一条条分布的纤维,可以人为地拨到一边,创建一个各向异性
BRDF 函数的属性
Non-negativity 非负
Linearity 线性,分量可拆后积分后求和
Reciprocity principle 互易,出射入射调转方向后,相等
Energy conservation 能量守恒
对各向同性材质,还满足:
沿着不同方向角得到的函数值是一样的
之后老师才讲了 f r ( θ i , θ r , ϕ r − ϕ i ) f_r(\theta_i, \theta_r,\phi_r-\phi_i) fr(θi,θr,ϕr−ϕi) 是什么意思,这是指 BRDF 只与相对的方位角有关
只考虑相对方位角的话,也应该满足光路可逆性
测量真实的 BRDF
一个爪子抓光源,一个爪子抓摄像机,物体放在中心,两个爪子绕着物体旋转,就可以得到各个入射角下的菲涅尔项
实验方法的伪代码:
枚举所有 wo
枚举所有 wi
...
BRDF 有四个输入参数,那就是四维,输入数据会很多
如果认为是各向同性,那么可以只考虑相对方位角,那么维度可以变为三维
如果考虑到光路可逆性,数据量可以减少一半
还有一些更聪明的策略,比如我可以只采样一些点,猜出另外一些点
测量 BRDF 的挑战
更准确的测量 grazing angle 对菲涅尔项的研究很重要
使用高频采样以得到高频反射
考虑反光 retro reflection
随空间变化的反射项
表示 BRDF
要求:
表达紧凑
正确表达测量数据
对任意方向都有效查询
重要性采样的良好分布
Lecture 18: Advanced Topics in Rendering
当前工业应用,最靠谱,最常用的还是;路径追踪 Path Tracing
Biased vs. Unbiased Monte Carlo Estimators
无偏估计:无论样本多少,计算结果的期望都是正确值,如路径追踪PT,双向路径追踪BDPT,MLT
有偏估计:计算结果的期望是与正确期望有一定偏差
一致性的有偏估计:少样本有偏,样本趋于无穷大时,计算结果收敛于正确值,如光子映射Photon Mapping
Bidirectional Path Tracing(BDPT)
双向路径追踪 计算流程:
(1)从光源发出随机光线,直到diffuse物体表面点pl;
(2)从相机发出光线,直到diffuse物体表面pc;
(3)连接pl与pc,计算pl照亮pc的结果。
特点:
(1)适用于视线不能直接看到光源的场景;
(2)实现困难,收敛速度较慢。
所谓"视线不能直接看到光源的场景",感觉应该是“光源没有直接照到场景中的大部分物体”
Metropolis Light Transport(MLT)
Metropolis 是人名,不是大都会的意思
(1)使用马尔科夫链蒙特卡洛积分 Markov Chain Monte Carlo(MCMC),从当前采样方向获取下一采样方向(在当前样本周围找一个样本)(在一个方向周围找一个方向),并且符合PDF分布重要性采样;
因为当你的 pdf 和你的采样函数的形状是一致的时候,蒙特卡洛积分效果最好,也就是方差最小
(2)擅长复杂光路;
右图是表示水底的焦散光斑
水底的焦散光斑要被看到,光线需要经过水面折射,到达漫反射的水底,再反射回水面,折射到人眼
经过了镜面反射 - 漫反射 - 镜面反射,也成为 SDS
(3)每一个像素都是局部的,比较难以收敛,各像素收敛速度不一致,画面较脏,这一帧与下一帧收敛情况不一样,不用于渲染动画。
Photon Mapping
其中一种计算流程:
(1)从光源打出大量的光子,并停留到diffuse表面;
(2)从相机发射出光线,直至打到diffuse表面pc点;
(3)每个pc点,收集diffuse表面附近固定的N个光子;
(4)计算N个光子覆盖的diffuse表面的面积A,光源发射总光子数固定的情况下,面积A越小,该相机光线所在像素点越亮。
特点:
(1)有偏估计、两趟算法;
本来要计算光子密度是需要计算某一个微元上的光子数量的,也就是计算 d N d A \dfrac{\mathrm d N}{\mathrm d A} dAdN
但是现在因为我们不可能发出足够的光子,使得每一个微元上的光子数量都足够到满足正确的分布,实际上,某些微元有光子,某些微元没有
但是 d N d A ≠ Δ N Δ A \dfrac{\mathrm d N}{\mathrm d A} \ne \dfrac{\Delta N}{\Delta A} dAdN=ΔAΔN
这样就产生一个问题,如果 Δ A \Delta A ΔA 取得太小,噪声就会很大;如果 Δ A \Delta A ΔA 取得太大场景就会变得模糊
之所以是取 N 个临近光子,再算这 N 个光子的面积,而不是取某一点为中心的一个面积 Δ A \Delta A ΔA,统计这个面积上的光子数量 Δ N \Delta N ΔN,是因为为了保证这是一个一致性的有偏估计
在光子数量很多时,能够保证 Δ A \Delta A ΔA 趋于 0;相反,如果一开始确定一个 Δ A \Delta A ΔA,那么不管光子数量如何, Δ A \Delta A ΔA 都不变,没有渐进性
(2)擅长Specular-Diffuse-Specular(SDS)路径和焦散(caustics);
(3)当光源打出的光子数量很大时,收集N个光子所覆盖的面积A越小、越接近pc点真实的亮度,也越精确。(一致性的有偏估计)
Vertex Connection and Merging
BDPT 双向路径追踪 和 Photon Mapping 光子映射的结合
双向路径追踪不是从起点和终点各打一条射线到两个点,然后我们再把这两个点连接起来嘛
如果这两个点挨得很近的话,这两点之间就没有必要再用光线连接了
而是将这两点直接合并
而判断是否能将两点连接使用的就是光子映射的方法
嗯……这里有点没懂,不知道具体是怎么对应到光子映射的
Instant Radiosity(many-light approaches)
思想:将场景中每一个被光直接照亮的点都当成一个虚拟光源。
算法:
首先从光源随机发射光线,击中物体的点设置为虚拟光源 Virtual Point Light(VPL)
然后使用这些虚拟光源渲染场景
优点:速度很快,易于渲染漫反射场景
缺点:
-
在接近 VPL 的地方会出现亮点(因为再对直接光源采样的时候,在投射光源面积的时候,除以了着色点到光源的距离,如果着色点到光源的距离很小,值就会很大)
-
不能处理 glossy 材质
Advanced Appearance Modeling
- 非表面模型
participating media 散射介质
头发 毛发 纤维 BCSDF
Granular material 颗粒材质
- 表面模型
Translucent material 半透明 BSSRDF
布料
Detailed material non-statistical 有细节度 BRDF
- 程序化外观
participating media 散射介质 云雾渲染
定义在空间中
一束光打在空间中的一个冰晶,按照一定空间分布散射
使用相位函数来定义散射的分布
渲染方法:
(1)选择一个云雾散射的模型;
(2)随机生成一条从相机连接到光源的折线;
(3)对每一个折点,利用散射模型渲染,获得最终照射到相机的结果。
毛发渲染
不同毛发渲染模型
有色高光 无色高光
Kajiya-Kay Model
把头发定义成一个圆柱
光线打到圆柱上会散射
人为地入射光线分为两种
-
散射的形状是一个锥形
-
向四面八方散射
相当于 diffuse + specular
但是这样得到的效果并不好
Marschner Model
有一部分被反射 R
有一部分穿入头发发生折射,再穿出来
折射一次记为 T,想要看见折射进入的光线,那么这个光线应该穿出来,记为 TT
还有一种光线,入射之后折射进入头发内部,在头发内壁反射,再折射出来,记为 TRT
模型假设
圆柱外部是 cuticle 角质层
圆柱内部是 cortex(absorbs) 皮质 包含色素,光线被部分吸收
人的毛发与动物的毛发
人的毛发和动物的毛发相比还是有区别的
更细地解剖毛发结构
外层角质层
中间皮质 吸收光线
内层 medulla 髓质 容易发生散射
人和动物的毛发都有这三层结构,但是人的毛发的髓质细,动物的毛发的髓质很粗
Double Cylinder Model
为了准确描述髓质,提出了双层圆柱模型
在光路类型上,除了原来的 R TT TRT
还有 TT 经过髓质会发生散射,记为 TTs,TRT 经过髓质会发生散射,记为 TRTs
颗粒材质
为了避免定义每一个颗粒的显式表面,转而使用程序化的定义
半透明 Translucent
其实这个意思是,从一个表面进入,从另外一个表面出来
次表面散射 subsuface scattering
表述次表面散射 subsuface scattering 的渲染方程为 BSSRDF 是 BRDF 的演伸
BRDF 认为从一个点入射就从这个点出射
但是 BSSRDF 认为,从一个点入射,可以从另外一点出射
所以 BSSRDF 四个参数, x i , w i x_i,w_i xi,wi 表示入射点和入射方向, x o , w o x_o,w_o xo,wo 表示出射点和出射方向
所以我在考虑某一个点某一方向 x o , w o x_o,w_o xo,wo 的出射强度的时候,不单单要考虑某一点各个入射方向,也要考虑光线在物体表面各个点入射在 x o x_o xo 出射,所以既要对立体角积分又要对面积积分
Dipole Approximation
真实的光源在物体表面的下方,如果再设置一个虚拟光源在物体表面上方,就可以得到近似次表面的效果
但是也没说为什么……
布料
Fibers 缠绕成 股 Ply
股缠绕成 Yarn
渲染方法:
-
物体表面
-
把表面渲染转化成体积渲染,渲染布就好像渲染云一样
-
渲染每一根纤维
表面细节
在微表面模型中,表面由高光的微笑特征和统计意义上的法线构成
f ( i , o ) = F ( i , h ) G ( i , o , h ) D ( h ) 4 ( n , i ) ( n , o ) f(i,o) = \dfrac{F(i,h)G(i,o,h)D(h)}{4(n,i)(n,o)} f(i,o)=4(n,i)(n,o)F(i,h)G(i,o,h)D(h)
其中 D ( h ) D(h) D(h) 表示法线分布的函数
如果能够将
D
(
h
)
D(h)
D(h) 的函数定义为在统计意义上符合一定分布,但是又具有一定细节,就能得到表面细节的材质
表面细节的计算困难
因为表面细节的法线变化很大,所以反射方向可能很多,光线在反射的时候很难打到光源,导致很难收敛
既然单根光线很容易偏,我就不用单根光线,而是使用一片区域
从一个像素覆盖的面积投射到物体表面一个面积,取到物体表面这块投射的面积上的微表面的分布 p-NDF,然后
然后这里ppt 就没有说了,难道是根据 p-NDF 算出半程向量?
一束白光打到金属表面,看上去是白色的,但是实际上是不同颜色的点,这就是光的波动性造成的
如果考虑到光的波动性,算出来的 p-NDF 还会不一样
程序化生成的表面
噪声纹理