• 【计算机图形学】光线追踪 Ray Tracing


    光线追踪 Ray Tracing

    光栅化无法实现软阴影、磨砂镜面反射、间接照明、光线弹射不止一次的情况

    光栅化的速度很快,但是质量并不高;光线追踪是非常准确的,但是非常缓慢。所以一般情况下,光栅化是实时的 real-time,光线追踪是离线的 offline

    一帧画面用光线追踪来渲染需要一万个 CPU 小时(10K CPU core hours)

    光线 Light Rays

    1. 光沿直线传播
    2. 两束光线相遇不会发生碰撞
    3. 光线从光源最终到达观察者的眼睛(可逆性)

    光线投射 Ray Casting

    1. 对每一个像素的一束光线进行追踪来生成图像
    2. 把光线送入光源检查阴影

    针孔相机模型 Pinhole Camera Model

    求到第一个交点后,连接交点与光源得到另一个光线

    判断新的光线与光源有没有被阻挡,如果有那么就在阴影里.

    Recursive (Whitted-Style) Ray Tracing

    在这里插入图片描述

    每个像素的颜色由反射经过的所有点提供,各个点占比不同.

    计算交点

    Ray Equation

    光线由初始位置与方向向量来定义

    Ray Equation:
    r ( t ) = o + t d 0 ⩽ t < ∞ \mathbf{r}(t)=\mathbf{o}+t\mathbf{d}\quad 0\leqslant t<\infin r(t)=o+td0t<

    与隐式表面的交点

    Ray r ( t ) = o + t d 0 ⩽ t < ∞ \mathbf{r}(t)=\mathbf{o}+t\mathbf{d}\quad 0\leqslant t<\infin r(t)=o+td0t<

    Sphere p : ( p − c ) 2 − R 2 = 0 \mathbf{p}:(\mathbf{p}-\mathbf{c})^2-R^2=0 p:(pc)2R2=0

    Solve for intersection: ( o + t d − c ) 2 − R 2 = 0 (\mathbf{o}+t\mathbf{d}-\mathbf{c})^2-R^2=0 (o+tdc)2R2=0

    a t 2 + b t + c = 0 ,  where  a = d ⋅ d b = 2 ( o − c ) ⋅ d c = ( o − c ) ⋅ ( o − c ) − R 2 t = − b ± b 2 − 4 a c 2 a

    at2+bt+c=0, where a=ddb=2(oc)dc=(oc)(oc)R2t=b±b24ac2a" role="presentation" style="position: relative;">at2+bt+c=0, where a=ddb=2(oc)dc=(oc)(oc)R2t=b±b24ac2a
    at2+bt+c=0, where a=ddb=2(oc)dc=(oc)(oc)R2t=2ab±b24ac
    Ray: r ( t ) = o + t d , 0 ≤ t < ∞ \mathbf{r}(t)=\mathbf{o}+t \mathbf{d}, 0 \leq t<\infty r(t)=o+td,0t<

    General implicit surface: p : f ( p ) = 0 \mathbf{p}: f(\mathbf{p})=0 p:f(p)=0

    Substitute ray equation: f ( o + t d ) = 0 f(\mathbf{o}+t \mathbf{d})=0 f(o+td)=0

    Solve for real, positive roots

    与三角形网格的交点

    判断光线与每个三角形是否相交

    Ray equation: r ( t ) = o + t d , 0 ≤ t < ∞ \mathbf{r}(t)=\mathbf{o}+t \mathbf{d}, 0 \leq t<\infty r(t)=o+td,0t<

    Plane equation: p : ( p − p ′ ) ⋅ N = 0 \mathbf{p}: (\mathbf{p}-\mathbf{p}^{'})\cdot \mathbf{N}=0 p:(pp)N=0

    Solve for intersection:

    S e t   p = r ( t )   a n d   s o l v e   f o r   t ( p − p ′ ) ⋅ N = ( o + t d − p ′ ) ⋅ N = 0 t = ( p ′ − o ) ⋅ N d ⋅ N  Check:  0 ≤ t < ∞ Set \ \mathbf{p}=\mathbf{r}(t) \ and \ solve\ for\ t \\

    (pp)N=(o+tdp)N=0t=(po)NdN Check: 0t<" role="presentation" style="position: relative;">(pp)N=(o+tdp)N=0t=(po)NdN Check: 0t<
    Set p=r(t) and solve for t(pp)N=(o+tdp)N=0t=dN(po)N Check: 0t<
    Möller Trumbore Algorithm 是一种更快更便捷更直观的求解交点方式
    O → + t D → = ( 1 − b 1 − b 2 ) P → 0 + b 1 P → 1 + b 2 P → 2 \overrightarrow{\mathbf{O}}+t \overrightarrow{\mathbf{D}}=\left(1-b_{1}-b_{2}\right) \overrightarrow{\mathbf{P}}_{0}+b_{1} \overrightarrow{\mathbf{P}}_{1}+b_{2} \overrightarrow{\mathbf{P}}_{2} O +tD =(1b1b2)P 0+b1P 1+b2P 2

    [ t b 1 b 2 ] = 1 S → 1 ∙ E → 1 [ S → 2 ⋅ E → 2 S → 1 ⋅ S → S → 2 ∙ D → ] \left[

    tb1b2" role="presentation" style="position: relative;">tb1b2
    \right]=\frac{1}{\overrightarrow{\mathbf{S}}_{1} \bullet \overrightarrow{\mathbf{E}}_{1}}\left[
    S2E2S1SS2D" role="presentation" style="position: relative;">S2E2S1SS2D
    \right] tb1b2 =S 1E 11 S 2E 2S 1S S 2D

    其中
    E → 1 = P → 1 − P → 0 E → 2 = P → 2 − P → 0 S → = O → − P → 0 S → 1 = D → × E → 2 S → 2 = S → × E → 1

    E1=P1P0E2=P2P0S=OP0S1=D×E2S2=S×E1" role="presentation" style="position: relative;">E1=P1P0E2=P2P0S=OP0S1=D×E2S2=S×E1
    E 1=P 1P 0E 2=P 2P 0S =O P 0S 1=D ×E 2S 2=S ×E 1
    解出来后,需要进行验证: t > 0 , b 1 ⩾ 0 , b 2 ⩾ 0 , b 3 ⩾ 0 t>0,b_1\geqslant 0,b_2\geqslant 0,b_3\geqslant 0 t>0,b10,b20,b30

    Bounding Volumes

    如果对每个三角形都检测是否相交,速度会非常的慢。现在引入 Bounding Volumes 的方法,它使一个物体完全被包含,如果光线没有穿过 Bounding Volumes,那么光线也不可能穿过物体。

    通常,我们用轴对齐的盒子,Axis-Aligned Bounding Box (AABB) (轴对齐包围盒),包围盒的任何一面都沿 x , y x,y x,y z z z 轴。

    对于 2D 情形,两个对面 (沿一个轴方向的两个面称为一个对面) 线段的交集即为进入物体的线段。

    也可以认为,进入所有对面的最晚时间到出所有对面的最早时间为光线进入物体的时间。

    所以三维情况同理,有
    t e n t e r = m a x { t m i n } , t e x i t = m i n { t m a x } t_{enter} = max\{t_{min}\}, t_{exit} = min\{t_{max}\} tenter=max{tmin},texit=min{tmax}
    如果 t e n t e r < t e x i t t_{enter} < t_{exit} tenter<texit ,那么光线也不一定进入了物体:

    1. 如果 t e x i t < 0 t_{exit} < 0 texit<0,那么包围盒在光线的背后,没有相交
    2. 如果 t e x i t ⩾ 0 , t e n t e r < 0 t_{exit} \geqslant 0, t_{enter} <0 texit0,tenter<0,光源就在盒内,有相交

    总结,光线与包围盒相交当且仅当 t e n t e r < t e x i t   ∧   t e x i t ⩾ 0 t_{enter} < t_{exit} \ \land \ t_{exit}\geqslant 0 tenter<texit  texit0.

    为什么要用轴对齐包围盒?

    img src=" width="200">

    利用分量即可计算出 t t t
    t = p x ′ − o x d x t=\frac{\mathbf{p}_{x}^{\prime}-\mathbf{o}_{x}}{\mathbf{d}_{x}} t=dxpxox

    建立加速网格 Build Acceleration Grid

    1. 找到包围盒

    2. 生成网格

    3. 将每个物体边界所在的网格标记

    4. 按光线方向顺序遍历网格,对每个网格测试与网格内所有物体的相交情况

    如果我们用非常稀疏的网格,我们需要对很多物体进行相交判断;如果我们用非常密的网格,我们需要对很多网格进行判断。所以如何确定网格是决定速度的十分关键的问题。

    空间划分 Spatial Partitions

    Oct-Tree Pre-Processing

    八叉树预处理就是对于每个三维空间,切三刀变成八分,然后对每一份继续切.

    KD-Tree Pre-Processing

    KD-Trees 数据结构

    内部节点存储:

    • 分割轴: x , y x,y x,y z z z
    • 分割位置:分割平面沿轴坐标
    • 孩子:指向孩子结点的指针
    • 没有物体存储在内部结点

    叶子节点:

    • 物体列表

    实现加速的过程

    在这里插入图片描述

    如何判断一个三角形是否与一个包围盒有交点是比较难实现的;一个物体可能出现在多个叶子结点里.

    物体划分 Object Partitions

    空间划分的结果可能导致一个物体可能出现在多个叶子结点里,所以这里我们引入物体划分来解决这个问题

    Bounding Volume Hierarchy (BVH)

    1. 找到包围盒
    2. 递归地将对象集分割成两个子集
    3. 重新计算子集的包围盒
    4. 直到每个包围盒内物体的数量足够少时停下
    5. 把物体存储在叶子结点中

    怎样进行合理的分割呢?

    • 选择一个维度来分割
    • 启发式方法 1:总是选择最长的轴来划分
    • 启发式方法 2:从中间物体位置来划分

    BVHs 数据结构

    内部节点存储:

    • 包围盒
    • 孩子:指向孩子结点的指针

    叶子节点:

    • 包围盒
    • 物体列表
    Intersect(Ray ray, BVH node) {
        if (ray misses node.bbox) return;
        if (node is a leaf node)
        test intersection with all objs;
        return closest intersection;
        hit1 = Intersect(ray, node.child1);
        hit2 = Intersect(ray, node.child2);
    	return the closer of hit1, hit2;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    这种方法不用判断三角形是否与一个包围盒有交点,实现起来比较容易.

    Surface Area Heuristic (SAH)

    BVH 方法一般按照物体数量来均等划分,即节点上物体的数量都相等,但是遇到一些特殊情况:

    显然,有更好的划分方法:

    那么,我们是如何评估划分的好坏的呢?我们用找到最近相交点所耗费的时间来评估。

    对于叶子结点,耗费时间 C C C 满足
    C = ∑ i = 1 N C i s e c t ( i ) = N C i s e c t C=\sum^N_{i=1}C_{isect}(i)=NC_{isect} C=i=1NCisect(i)=NCisect
    其中 C i s e c t ( i ) C_{isect}(i) Cisect(i) 是得到物体 i i i 与光线交点所需时间。对于非叶子结点
    C = C t r a v + p A C A + p B C B C=C_{trav}+p_AC_A+p_BC_B C=Ctrav+pACA+pBCB
    其中 C t r a v C_{trav} Ctrav 是穿过一个内部节点所耗费的时间, C A C_A CA C B C_B CB 是找到与左右子树最近相交点所耗费时间, p A p_A pA p B p_B pB 是光线与左右孩子结点相交的概率。

    这里如果要计算 C C C 并得到其全局最优解,就需要后序遍历出它所有子节点的 S A H \mathrm{SAH} SAH 值,这目前是不可行的,所以我们用估计的局部最优解来代替,这种方法称为局部贪婪的 S A H \mathrm{SAH} SAH
    C = C t r a v + p A N A C i s e c t + p B N B C i s e c t C=C_{trav}+p_AN_AC_{isect}+p_BN_BC_{isect} C=Ctrav+pANACisect+pBNBCisect
    一次划分把物体集合 N N N 划分为集合 A A A 与集合 B B B S N , S A , S B S_N,S_A,S_B SN,SA,SB 是总集合和两个集合的包围盒表面积, N A , N B N_A,N_B NA,NB 是两个集合中物体的数量。

    对于物体 A A A 与物体 B B B,光线穿过 B B B 的同时穿过 A A A 的概率可以用它们的表面积定义
    P ( h i t   A ∣ h i t   B ) = S A S B P(\mathrm{hit}\ A|\mathrm{hit}\ B)=\frac{S_A}{S_B} P(hit Ahit B)=SBSA
    最后得到 Surface Area Heuristic (SAH):
    C = C t r a v + S A S N N A C i s e c t + S B S N N B C i s e c t C=C_{\mathrm{trav}}+\frac{S_{A}}{S_{N}} N_{A} C_{\mathrm{isect}}+\frac{S_{B}}{S_{N}} N_{B} C_{\mathrm{isect}} C=Ctrav+SNSANACisect+SNSBNBCisect
    其中,一次划分把物体集合 N N N 划分为集合 A A A 与集合 B B B S N , S A , S B S_N,S_A,S_B SN,SA,SB 是总集合和两个集合的包围盒表面积, N A , N B N_A,N_B NA,NB 是两个集合中物体的数量。

    在这里插入图片描述

    那么如何进行划分的采样呢,我们知道只有当 N A , N B N_A,N_B NA,NB 发生改变时, C C C 才会改变,所以我们只考虑使 N A , N B N_A,N_B NA,NB 改变了的所有划分

    根据物体质心的位置判断物体属于那一划分区,但是如果我们有 N N N 个物体,那么沿三个轴划分就有 3 N − 3 3N-3 3N3 个平面,这样的开销太大,得不偿失。

    在这里插入图片描述

    我们可以用一种高效的近似方法,把物体空间划分为 B B B 个桶( B B B 一般比较小: B < 32 B<32 B<32

    算法如下:

    For	each axis: x,y,z:	
    	initialize buckets	
        For	each primitive p in node:	
        	b = compute_bucket(p.centroid)		# 计算物体p在哪一个桶b中
            b.bbox.union(p.bbox);				# 桶b与物体p的包围盒结合
            b.prim_count++;						# 桶b物体数加一
        For	each of	the	B-1	possible partitioning planes evaluate SAH	
    Execute	lowest cost partitioning found (or make node a leaf)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    辐射度量学 Basic Radiometry

    辐射能量 Radiant Energy

    电磁辐射的能量。单位为焦耳,用符号表示:
    Q [ J = J o u l e ] Q[J=Joule] Q[J=Joule]

    辐射通量 Radiant Flux (Power)

    单位时间内发射、反射、传输或接收的能量:
    Φ ≡ d Q   d t [   W = W a t t ] [ lm ⁡ =  lumen  ] ∗ \Phi \equiv \frac{\mathrm{d} Q}{\mathrm{~d} t}[\mathrm{~W}=\mathrm{Watt}][\operatorname{lm}=\text { lumen }]^{*} Φ dtdQ[ W=Watt][lm= lumen ]

    辐射强度 Radiant Intensity

    点光源发出的单位立体角的功率

    I ( ω ) ≡ d Φ d ω [ W s r ] [ lm ⁡ s r = c d =  candela  ] I(\omega) \equiv \frac{\mathrm{d} \Phi}{\mathrm{d} \omega}\\ \left[\frac{\mathrm{W}}{\mathrm{sr}}\right]\left[\frac{\operatorname{lm}}{\mathrm{sr}}=\mathrm{cd}=\text { candela }\right] I(ω)dωdΦ[srW][srlm=cd= candela ]

    立体角 Solid Angle

    Ω = A r 2 \Omega=\frac{A}{r^2} Ω=r2A

    一个球体的立体角为 4 π 4\pi 4π steradiance.

    d A = ( r d θ ) ⋅ ( r sin ⁡ θ d ϕ ) = r 2 sin ⁡ θ d θ d ϕ dA=(rd\theta)\cdot(r\sin\theta d\phi)=r^2\sin\theta d\theta d\phi dA=(rdθ)(rsinθdϕ)=r2sinθdθdϕ
    微分立体角:
    d ω = d A r 2 = sin ⁡ θ d θ d ϕ d\omega = \frac{dA}{r^2}=\sin\theta d\theta d\phi dω=r2dA=sinθdθdϕ

    各向同性的光源


    Φ = ∫ S 2 I   d ω = 4 π I I = Φ 4 π \Phi =\int_{S^{2}} I \mathrm{~d} \omega =4 \pi I \\ I =\frac{\Phi}{4 \pi} Φ=S2I dω=4πII=4πΦ

    辐射照度 Irradiation

    辐射照度是每单位面积上入射到一个表面点上的功率。
    E ( x ) ≡ d Φ ( x ) d A [ W m 2 ] [ lm ⁡ m 2 = lux ⁡ ] E(\mathbf{x}) \equiv \frac{\mathrm{d} \Phi(\mathbf{x})}{\mathrm{d} A} \\ {\left[\frac{\mathrm{W}}{\mathrm{m}^{2}}\right]\left[\frac{\operatorname{lm}}{\mathrm{m}^{2}}=\operatorname{lux}\right]} E(x)dAdΦ(x)[m2W][m2lm=lux]

    实际上, A A A 并不是照射面积,而是照射的有效面积,即需要求投影
    E = Φ A cos ⁡ θ , θ = < l , n > E=\frac{\Phi}{A\cos \theta}, \quad \theta = E=AcosθΦ,θ=<l,n>
    在这里插入图片描述

    随着距离的增加,辐射强度是不变的(立体角不变),辐射照度在逐渐衰减

    辐射亮度 Radiance

    辐射亮度是描述光在环境中的分布的基本场量,渲染完全是关于辐射亮度的计算的。

    辐射亮度是一个表面每单位立体角、每投影单位面积发射、反射、透射或接收的功率。

    在这里插入图片描述

    L ( p , ω ) ≡ d 2 Φ ( p , ω ) d ω d A cos ⁡ θ [ W s r   m 2 ] [ c d m 2 = lm ⁡ s r   m 2 =  nit  ] L(\mathrm{p}, \omega) \equiv \frac{\mathrm{d}^{2} \Phi(\mathrm{p}, \omega)}{\mathrm{d} \omega \mathrm{d} A \cos \theta} \\ {\left[\frac{\mathrm{W}}{\mathrm{sr}\ \mathrm{m}^{2}}\right]\left[\frac{\mathrm{cd}}{\mathrm{m}^{2}}=\frac{\operatorname{lm}}{\mathrm{sr\ m}^{2}}=\text { nit }\right]} L(p,ω)dωdAcosθd2Φ(p,ω)[sr m2W][m2cd=sr m2lm= nit ]

    • 辐射亮度是单位立体角的辐射照度
    • 辐射亮度是单位投影面积的辐射强度

    入射辐射亮度 Incident Radiance

    入射辐射亮度是到达表面的每单位立体角的辐射照度

    在这里插入图片描述

    L ( p , ω ) = d E ( p ) d ω cos ⁡ θ L(\mathrm{p}, \omega)=\frac{\mathrm{d} E(\mathrm{p})}{\mathrm{d} \omega \cos \theta} L(p,ω)=dωcosθdE(p)

    出射辐射亮度 Exiting Radiance

    出射表面辐射亮度是每单位投影面积离开表面的辐射强度

    在这里插入图片描述

    L ( p , ω ) = d I ( p , ω ) d A cos ⁡ θ L(\mathrm{p}, \omega)=\frac{\mathrm{d} I(\mathrm{p}, \omega)}{\mathrm{d} A \cos \theta} L(p,ω)=dAcosθdI(p,ω)

    Irradiance vs. Radiance

    辐射照度:面元 d A \mathrm dA dA 单位面积接受的所有方向 (半球) 上的所有能量

    辐射亮度:面元 d A \mathrm dA dA 单位面积从“方向” d ω \mathrm d\omega dω 接受到的能量
    d E ( p ) = L i ( p , ω ) cos ⁡ θ d ω E ( p ) = ∫ H 2 L i ( p , ω ) cos ⁡ θ d ω \mathrm d E(\mathrm{p}) =L_{i}(\mathrm{p}, \omega) \cos \theta \mathrm{d} \omega \\ E(\mathrm{p}) =\int_{H^{2}} L_{i}(\mathrm{p}, \omega) \cos \theta \mathrm{d} \omega dE(p)=Li(p,ω)cosθdωE(p)=H2Li(p,ω)cosθdω
    单位半球: H 2 H^2 H2

    Bidirectional Reflectance Distribution Function (BRDF)

    方向 $\omega $ 的辐射亮度被 d A \mathrm dA dA 接受并转化为辐射照度 E E E,再转换为任意方向的辐射亮度 L L L.

    入射微分辐射照度: d E ( ω i ) = L ( ω i ) cos ⁡ θ i d ω i dE(\omega_i)=L(\omega_i)\cos \theta_i d\omega_i dE(ωi)=L(ωi)cosθidωi

    出射微分辐射亮度: d L r ( ω r ) dL_r(\omega_r) dLr(ωr)

    双向反射分布函数 BRDF 表示从每个入方向反射到每个出方向的光的数量。
    在这里插入图片描述

    f r ( ω i → ω r ) = d L r ( ω r ) d E i ( ω i ) = d L r ( ω r ) L i ( ω i ) cos ⁡ θ i   d ω i [ 1 s r ] f_{r}\left(\omega_{i} \rightarrow \omega_{r}\right)=\frac{\mathrm{d} L_{r}\left(\omega_{r}\right)}{\mathrm{d} E_{i}\left(\omega_{i}\right)}=\frac{\mathrm{d} L_{r}\left(\omega_{r}\right)}{L_{i}\left(\omega_{i}\right) \cos \theta_{i} \mathrm{~d} \omega_{i}}\left[\frac{1}{\mathrm{sr}}\right] fr(ωiωr)=dEi(ωi)dLr(ωr)=Li(ωi)cosθi dωidLr(ωr)[sr1]

    L r ( p , ω r ) = ∫ H 2 f r ( p , ω i → ω r ) L i ( p , ω i ) cos ⁡ θ i   d ω i L_{r}\left(\mathrm{p}, \omega_{r}\right)=\int_{H^{2}} f_{r}\left(\mathrm{p}, \omega_{i} \rightarrow \omega_{r}\right) L_{i}\left(\mathrm{p}, \omega_{i}\right) \cos \theta_{i} \mathrm{~d} \omega_{i} Lr(p,ωr)=H2fr(p,ωiωr)Li(p,ωi)cosθi dωi

    渲染方程 The Rendering Equation

    加上一个自身发出的光的项,得到渲染方程
    L r ( p , ω r ) = L e ( p , ω o ) + ∫ Ω + L i ( p , ω i ) f r ( p , ω i , ω r ) ( n ⋅ ω i )   d ω i L_{r}\left(\mathrm{p}, \omega_{r}\right)=L_e(\mathrm p, \omega_o)+\int_{\Omega+} L_{i}\left(\mathrm{p}, \omega_{i}\right)f_{r}\left(\mathrm{p}, \omega_{i} , \omega_{r}\right) (n\cdot \omega_i)\mathrm{~d} \omega_{i} Lr(p,ωr)=Le(p,ωo)+Ω+Li(p,ωi)fr(p,ωi,ωr)(nωi) dωi
    假设所有方向都指向外部

    其中 K ( u , v ) K(u,v) K(u,v) 是光线传输算子、反射操作符

    L = E + K L I L − K L = E ( I − K ) L = E L = ( I − K ) − 1 E L = ( I + K + K 2 + K 3 + … ) E L = E + K E + K 2 E + K 3 E + …

    L=E+KLILKL=E(IK)L=EL=(IK)1EL=(I+K+K2+K3+)EL=E+KE+K2E+K3E+" role="presentation" style="position: relative;">L=E+KLILKL=E(IK)L=EL=(IK)1EL=(I+K+K2+K3+)EL=E+KE+K2E+K3E+
    LILKL(IK)LLLL=E+KL=E=E=(IK)1E=(I+K+K2+K3+)E=E+KE+K2E+K3E+

    这样处理后,得到的 L L L 可以看作不同光线弹射次数的分解

    路径追踪 Path Tracing

    求解渲染方程

    在这里,我们忽略物体本身发光,即渲染方程为
    L r ( p , ω r ) = ∫ Ω + L i ( p , ω i ) f r ( p , ω i , ω r ) ( n ⋅ ω i )   d ω i L_{r}\left(\mathrm{p}, \omega_{r}\right)=\int_{\Omega+} L_{i}\left(\mathrm{p}, \omega_{i}\right)f_{r}\left(\mathrm{p}, \omega_{i} , \omega_{r}\right) (n\cdot \omega_i)\mathrm{~d} \omega_{i} Lr(p,ωr)=Ω+Li(p,ωi)fr(p,ωi,ωr)(nωi) dωi
    由蒙特卡洛方法求积分,我们知道
    ∫ a b f ( x ) d x ≈ 1 N ∑ k = 1 N f ( X j ) p ( X k ) X ∼ ( x ) \int_a^bf(x)\mathrm dx \approx \frac{1}{N}\sum_{k=1}^N\frac{f(X_j)}{p(X_k)}\qquad X\sim (x) abf(x)dxN1k=1Np(Xk)f(Xj)X(x)
    所以,我们可以这样计算渲染方程
    L o ( p , ω o ) = ∫ Ω + L i ( p , ω i ) f r ( p , ω i , ω o ) ( n ⋅ ω i ) d ω i ≈ 1 N ∑ i = 1 N L i ( p , ω i ) f r ( p , ω i , ω o ) ( n ⋅ ω i ) p ( ω i )

    Lo(p,ωo)=Ω+Li(p,ωi)fr(p,ωi,ωo)(nωi)dωi1Ni=1NLi(p,ωi)fr(p,ωi,ωo)(nωi)p(ωi)" role="presentation" style="position: relative;">Lo(p,ωo)=Ω+Li(p,ωi)fr(p,ωi,ωo)(nωi)dωi1Ni=1NLi(p,ωi)fr(p,ωi,ωo)(nωi)p(ωi)
    Lo(p,ωo)=Ω+Li(p,ωi)fr(p,ωi,ωo)(nωi)dωiN1i=1Np(ωi)Li(p,ωi)fr(p,ωi,ωo)(nωi)

    计算的算法采用递归思想,如果我们沿某个方向发射光线,打在光源上,那么正常处理;如果打在物体上,递归调用。

    shade(p, wo)
    	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 at q
    			Lo += (1 / N) * shade(q, -wi) * f_r * cosine / pdf(wi)
    	Return Lo
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    但是上面算法并不合适,如果我们每次计算光线需要 N N N 次采样,如果由 r r r 条光线要计算,那么就要进行 N N N 次才样。这种指数级的增长是不合理的,因此我们取 N = 1 N=1 N=1 来解决这个问题:

    shade(p, wo)
    	Randomly choose ONE direction wi~pdf(w)
    	Trace a ray r(p, wi)
    	If ray r hit the light
    		Return L_i * f_r * cosine / pdf(wi)
    	Else If ray r hit an object at q
    		Return shade(q, -wi) * f_r * cosine / pdf(wi)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    但是如果只做一次采样必然会造成非常大的噪声,因此我们选择多条路径来计算

    只需通过每个像素跟踪更多路径,并平均它们的亮度

    ray_generation(camPos, pixel)
    	Uniformly choose N sample positions 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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    但是,在 shade 函数中,我们进行了递归调用,所以需要设置好递归边界,即什么时候要进行弹射。因为实际上,光线是无限进行弹射的,但是计算机当然不能完全实现,所以需要一种方法来确定递归边界,并且让结果合理。

    俄罗斯轮盘赌 Russian Roulette (RR) 方法来解决这个问题:规定由概率 P P P 会弹射光线,并且返回的辐射亮度为 L o / P Lo/P Lo/P ,那么就有 1 − P 1-P 1P 的概率返回 0;这样的话我们最终的期望会是
    E = P × L o / P + ( 1 − P ) × 0 = L o E=P\times Lo / P+(1-P)\times 0=Lo E=P×Lo/P+(1P)×0=Lo
    在大数定律下,当路径足够多时,结果仍然是正确的,同时也有了递归边界。

    shade(p, wo)
    	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 direction wi~pdf(w)
    	Trace a ray r(p, wi)
    	If ray r hit the light
    		Return L_i * f_r * cosine / pdf(wi) / P_RR
    	Else If ray r hit an object at q
    		Return shade(q, -wi) * f_r * cosine / pdf(wi) / P_RR
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    如果我们在半球上均匀采样,如果光源很小,那么有可能“浪费”很多采样,因为可能仅有几条光线会到达光源。为了解决这个问题,我们改为在光源进行采样

    对光源均匀采样,此时 p d f = 1 / A pdf=1/A pdf=1/A,但是渲染方程中是对立体角进行积分,所以我们要找到光源面元 d A \mathrm dA dA 与立体角 d ω \mathrm d\omega dω 间的关系。由上图我们可以得到
    d ω = d A cos ⁡ θ ′ ∣ ∣ x ′ − x ∣ ∣ 2 \mathrm d \omega =\frac{\mathrm dA\cos \theta^{'}}{||x^{'}-x||^2} dω=∣∣xx2dAcosθ
    所以渲染方程改写为
    L o ( x , ω o ) = ∫ Ω + L i ( x , ω i ) f r ( x , ω i , ω o ) cos ⁡ θ d ω i = ∫ A L i ( x , ω i ) f r ( x , ω i , ω o ) cos ⁡ θ cos ⁡ θ ′ ∥ x ′ − x ∥ 2   d A

    Lo(x,ωo)=Ω+Li(x,ωi)fr(x,ωi,ωo)cosθdωi=ALi(x,ωi)fr(x,ωi,ωo)cosθcosθxx2 dA" role="presentation" style="position: relative;">Lo(x,ωo)=Ω+Li(x,ωi)fr(x,ωi,ωo)cosθdωi=ALi(x,ωi)fr(x,ωi,ωo)cosθcosθxx2 dA
    Lo(x,ωo)=Ω+Li(x,ωi)fr(x,ωi,ωo)cosθdωi=ALi(x,ωi)fr(x,ωi,ωo)xx2cosθcosθ dA
    在之前,我们认为光线是“意外地”在半球的采样上照射到了光源,但是引入这个方法后,我们认为辐射亮度来自两个部分:

    1. 光源(直接光源采样得到,不需要进行轮盘赌)
    2. 其他反射光(利用轮盘赌计算)
    shade(p, wo)
        # Contribution from the light source.
        Uniformly sample the light at x’ (pdf_light = 1 / A)
        L_dir = L_i * f_r * cos θ * cos θ’ / |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 θ / pdf_hemi / P_RR
        Return L_dir + L_indir
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    但是如果着色点与光源之间正好被某个物体挡住了怎么处理

    只需要增加一个判断即可

    shade(p, wo)
        # Contribution from the light source.
        L_dir = 0.0
    	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 θ * cos θ’ / |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 θ / pdf_hemi / P_RR
        Return L_dir + L_indir
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    路径追踪正确吗

    左图是相机拍摄的真实场景,右图是全局光照的路径追踪,可以说…几乎百分之百正确!

    一些其他问题

    • 如何进行均匀地采样?
    • 如何选择 p d f pdf pdf 呢?——重要性采样理论,针对性对某种形状的采样方法
    • 随机数有好坏之分吗?(low discrepancy sequences)
    • 采样光源与采样半球是否可以结合?(multiple imp. sampling)
    • 为什么一个像素上的所有路径简单平均就得到了像素的辐射亮度?(pixel reconstruction filter)
    • 算出的辐射亮度是不是就是颜色?——No,也不是线性关系(gamma correction,curves,color space)
  • 相关阅读:
    在NLP中一下常见的任务,可以用作baseline;MRPC,CoLA,STS-B,RTE
    XSS(Cross-site Script,跨站脚本)漏洞笔记
    列表以及字典的练习
    PHP去除字符串前或后的字符或空格
    LeetCode - 1419 数青蛙
    适合弱电行业用的项目管理系统,找企智汇项目管理系统!
    SpringBoot启动流程源码分析
    大学生HTML作业节日网页 HTML作业节日文化网页期末作业 html+css+js节日网页 HTML学生节日介绍 HTML学生作业网页视频
    基于SSM+Vue的医院医患管理系统
    Web(六)CSS3语法-CSS样式规则
  • 原文地址:https://blog.csdn.net/m0_57714486/article/details/126291177