Path Tracing
渲染方程
对于渲染方程我们很难通过直接的方式求解,但是可以通过蒙特卡洛积分的方法将积分转化为采样的方式得到最终结果的值
对于任何一个单一的像素,我们将相应的fx
px
值求出,对于一个球面pdf均匀取值p=1/A,从而得到直接光照的算法
直接光照着色算法:
选取方向 初始化结果
循环
该点与所选定的方向连接成一条光线(射线)
如果与光源相遇
计算求和式
结束
这仅是对于直接光照而言,加上了对于物体的反射,反射后类似于是新光源从而修正后的算法
算法至此完了吗?
很显然算法现在还存在有问题
1. 指数爆炸
rays = Nbounces
很显然当光线弹射两次以上,计算量就变得超级大,很难计算
解决 底数为设置为一, 1n 依旧是1 于是随机取一个方向的光线 用n为一计算蒙特卡洛积分
对于每次着色都随机选取一个方向发出一根光线,虽然结果非常noisy 但是穿过一个像素可以多次路径追踪 最后平均,同时对于光线的生成对于一个像素 任意的取N个方向 从视点连一根光线到采样的位置 如果光线打到场景中的一个位置 就算出这一点的着色 (注意出射方向需要改变)
**2. 递归出口 **
对于原算法还没有考虑停止的条件,问题出现在光线的弹射次数 自然情况下光线显然不会停,但是计算机很难达到这种效果,而事先定义好弹射次数会导致能量损失的问题
解决方法:俄罗斯轮盘赌——在一定的概率下停下
取一定的概率p打出下一条光线
最终结果L0/p 1-p的概率不打出光线 结果为0
最终期望:E = p*L0/p +(1-p)*0 = L0 //你会发现结果没变仍然是正确的结果
这是个十分巧妙的解法,不仅解决了出口问题,最终期望还可以保持不变
算法至此基本没有什么问题了,是正确的
但是不够高效,低采样率就会比较noisy ,由于均匀的方向采样,能够打到光源的光线就十分有限,光源太小会导致大部分的光线都被浪费
为了不浪费光线 需要对于蒙特卡洛积分方法修正 积分变量需要替换一下 从光源上采样才能使光线不至于浪费
然后重写渲染方程
蒙特卡洛积分中的pdf
取值为1/A
对于一个像素着色来源于两个方面
- 光源的直接照射(不需要RR)
- 其他非光源物体
其中还有一个小问题 光线传播的过程中是否有物体遮光,从p点线光源连线 如果没有物体遮挡 继续计算
reflection.norm() - col.distance) < EPSILON
代码实现时由于精度的问题,采用了两个 向量的模大小比较,在小于EPSILON
时判定两束光线相等
GAMES101-现代计算机图形学入门-闫令琪