Ray Tracing
光线追踪概述
光线追踪的目标:
-
光栅化很难实现全局的效果,光线追踪可以
包括soft shadow, gossy reflection, indirect illumination
-
光栅化比较快,但渲染质量较低,一般应用于实时渲染
光线追踪渲染质量高,但渲染速度慢,一般应用于离线渲染
Whitted-Style Ray Tracing
Whitted-Style基本想法
图形学中对光线的假设
- 光线沿直线传播
- 光线与光线间不存在碰撞
- 光线从光源出发到达眼睛,但光路也具有可逆性,可以假设光线从眼睛出发到达光源
光线投射Ray Casting
步骤:
-
从相机出发,向每个像素发射一条eye ray,延申该射线,找到最近接触的物体,记录该接触点,之后再接触到的物体就代表被遮挡住了
-
从光源出发,向接触点发射shadow ray,如果接触不到则代表在阴影中,如果接触到了,计算接触点的shading,写到对应像素上
Whitted-Style Ray tracing是在Ray Casting上更进一步
一条eye ray在接触点会发生镜面反射和折射,进而得到两条新的光线继续计算。原始的eye ray我们称为primary ray,反射和折射得到的eye ray我们称为secondary rays,secondary rays的强度会减弱
对于光源,我们要从光源向每个接触点发出shadow ray,计算每个接触点的shading
每个shading point除了local shading,还会受到从他发出的反射光线,折射光线的影响,计算如下
该种Ray Tracing存在假设:
- 眼睛和光源都是点,不具有体积,无法处理面光源
- 所有eye ray的反射都是镜面反射
求光线和物体的交点
求解概述
光线我们用一个起点和一个方向来定义,可以得到光线的方程
求光线和一个隐式表面的交点
找到同时满足两个方程的解即可
光线和三角形的交点
想法:我们先判断光线是否和三角形所在平面有交点,若有交点,再判断交点是否在三角形内
第一种算法
对于平面,我们用一个点和一个法线来定义
是解出的方程
得到了平面的方程,就与光线方程联立解出来即可知道交点情况
接着,判断交点是否在三角形内用叉乘方法即可
第二种算法Moeller Trumbore Algorithm
用三角形的重心坐标来写出平面方程,与光线方程联立求解后,如果重心坐标的三个分量都大于0,则在三角形内部
光线和三角形网格的交点
最基础的方法:对于一根光线,遍历每一个三角形看其是否与光线有交点
加速的方法:
我们用一个Bounding Volumn,简称BVol来包住我们的目标物体
存在这样的情况,如果光线连BVol都碰不到,则不可能碰到我们的目标物体
我们定义一个bounding box为:三对平面的交集,且每一对平面都是相互平行的,也就是一个长方体
我们经常用axis-aligned bounding box,简称AABB,来作为BVol,bounding box的每一条边都和一条坐标轴平行
求光线和三角形网格的交点,我们可以先试图解决更简单的:
求光线和AABB的交点
我们讨论光线与每一对平面的相交情况,对于每一对对面都可以得到一组和
我们在这里暂时假设光线是直线,则存在的情况
我们用和分别来表示光线进入和离开BVol的时间,结合两对平面来看,可以得到
也就是光线进入BVol时,它进入了所有的平面,离开BVol时,离开了一个平面。(我们不考虑光线与平面平行的情况)
如果,则光线穿过了BVol
但光一定是射线,我们考虑或小于0的情况,可以得到以下的结论
我们应用AABB来作为BVol,是因为平面和轴平行,则更容易求解光线方程和平面的交点
BVol加速
Uniform Grid
我们先把整个场景放入一个大bounding box,再把bounding box分成均匀的格子
我们对每一个物体判断它占据了哪些grid
一条光线进入bounding box,我们判断光线是否与grid相交
如果相交,则继续判断grid内是否有物体,如果有物体再判断光线是否与物体相交
当场景内物体密度比较大,物体数量和grid数量的比例较大,对与grid相交做测试就比较有效,uniform grid的方法就比较高效
但如果密度比较小则效率较低
Spatial Partitions
Spatial partitions运用了不均匀的bounding volumn划分,如果一个划分内物体数量较少,则不需要继续划分,如果较多,则继续划分,保证了划分内物体的密度
KD-Tree是其中一种常用划分算法
我们把整个bounding box按照二叉树的方式进行划分,每次划分都将所有叶子节点分为两半,如果一个叶子节点中物体数量较少了,则不需要划分了
划分方式依次为x, y, z轴方向(三维情况),这样保证了空间基本划分均匀
可以得到一个二叉树结构的bounding box,树的信息如下
最后的最小划分都是在叶子节点
以下是一个KD Tree的示例
存在问题:
- 我们很难判断一个三角形是否与一个划分相交
- 物体可能存在于多个叶子节点中,这样bounding box效率不高
Object Partition
BVH: Bounding volumn hierarchy
BVH对场景内的物体进行划分,每次对每个叶子节点分为两个部分,并重新计算bounding box,这样保证了一个物体在且只会在一个叶子节点中
而且这样是根据物体边界求bounding box,非常简单
为了划分更加均匀,我们可以采用以下策略
- 每次对最长的轴平分
- 找到排序在中位的物体,进行划分,使两个划分中的物体数量差不多,保证两个子节点更加平衡。用到快速选择算法就可以在O(n)时间内找到中位物体
BVH是一个递归的算法,步骤为:
- 光线从最大的bounding box开始求交,如果相交,则与bounding box的所有子节点求交
- 如果当前求交的划分是叶子节点且相交,则光线与划分内每个物体求交,并记录最近相交的物体。
如果不是叶子节点,相交就继续与该节点的子节点求交,否则则返回 - 所有求交完成后,得到整个环境中最近相交的物体
伪代码如下
Radiometry
Radiometry用于精准测量光照
光通量radiant flux: 单位时间内放出的辐射能,相当于辐射的功率,单位为lm流明,也叫power
立体角solid angle:
我们定义二维空间中的弧度是
则立体角就是三维空间中角度的延申,整个球的立体角共有
在球坐标系中,确定的和可以确定球面上一个点,和可以画出球面上一个近似方形的面积,这块面积就是微分面积,得到的立体角就是微分立体角,具体计算如下
光强radiant intensity:单位立体角上的光通量,单位为cd坎德拉
irradiance辐照量: 单位面积上的power
光以球状向外辐射,在传播的过程中,球的面积变大,irradiance逐渐衰减
radiance辐亮度:单位面积单位立体角上的power
我们通过限制住面积和立体角,得到了一条光线
radiance是单位面积上的intensity,也是单位立体角的irradiance
我们也可以理解为,某点的irradiance就是该点在单位球上对radiance积分
可以写出radiance和irradiance的转换式子
The Rendering Equation
对于在shading point的反射光,我们可以这样理解:
的radiance入射后,被某个区域吸收为irradiance,再向反射radiance
bidirectionla reflectance distribution function(BRDF)
BRDF定义了, 一个的shading point从接收到的radiance,会有多大比例转换为向反射的radiance,也就是下图中的
反射方程:一个shading point接受从所有方向来的radiance,他们都对一个特定方向的有一定比例的反射影响,比例由BRDF确定,将所有影响累加起来,则得到了方向的反射情况
反射方程解决了光栅化存在的问题
- 面光源:面光源就是多个点光源发出的radiance的累加
- 间接光照:间接光照就是经过至少两次反射才射入眼睛的光,间接光照也被纳入反射方程的考虑中
渲染方程:在反射方程上更进一步,一个点不仅能反射从别处来的光,自己还能发光,加在一起就得到了完整的向外发出的光
反射光的积分区域只有shading point的半球,另一半球来的光照不到shading point
渲染方程可以通过一定转换,变成如下形式
是光的反射矩阵,是光
这种形式的实际含义在于,radiance = 直接照入眼睛的光 + 一次反射的光 + 两次反射的光 + …
这种形式也代表着,利用渲染方程解决了,一个shading point,从其他地方得到的所有的,经过了任意次反射的光的irradiance,转换成的进入到相机的radiance,也就是全局光照
Path Tracing
Path Tracing概述
Whitted-Style Ray Tracing只在镜面上做镜面反射和折射,如果在粗糙面上就停止传播
存在的问题
-
无法实现 glossy reflection,在glossy材质上不能只做简单的specular reflection
-
无法实现粗糙面上的漫反射导致的环境光
渲染方程是更准确的对shading的描述,所以path tracing就采用了渲染方程
但渲染方程需要解决两个问题
- 在单位球上的积分
- 递归定义,要知道一个shading point接受的入射光,要先知道另一个shading point发出的光
Monte Carlo
Monte Carlo是为了解决不好用解析方式解决的定积分的问题,而采用数值方法来计算
方法:在积分区域以一个特定的概率密度函数采样,对采样结果做加权平均
Monte Carlo积分公式如下
解决问题
积分
我们用Monte Carlo来解决单位球上的积分
我们用均匀分布作为PDF,即,来对立体角采样
对于间接光照,我们可以分类讨论,直接加上,就得到如下的算法
光线数量爆炸
光线数量爆炸的原因有两个
第一个是一条入射光会得到多条反射光
如果在一个shading point上的入射光会反射出多条光线,反射出去的一条光线,又反射出多条光线,最后光线数会以指数增长到爆炸
所以Path tracing的想法就是,假定每一条光线在反射时,只会朝一个随机方向反射。如果这条光线碰到物体或光源,则进行计算,否则忽略掉
算法如下
这样相当于在相机上的一个像素到光源间连了一条折线路径,但这样随机选择一条路径肯定不准确,所以我们在一个像素上,设置多个采样点,一个像素上发出多条光线,再取他们的平均radiance即可
算法如下,是在一个像素中做了一个Monte Carlo积分
第二个导致光线数量爆炸的原因是递归定义
这个算法存在递归,因为一条光线可能不停的反射,永远不会停
我们用Russian Roulette的方式来限制光线反射的次数
我们有一个固定的概率P_RR,每次在光反射时,取一个数
如果这个数比P_RR小,则光线不再反射,否则继续反射,且反射的radiance结果和直接光照都要除以P_RR
这样保证了radiance的期望仍是Lo
反射算法如下
效率低下
Path tracing有很多浪费的path,我们从shading point发出的path是随机方向的,对于直接光照,光源越小,path达到光源的概率越小
对于直接光照,我们可以从光源出发向外发射,而非从shading point出发,来做Monte Carlo积分,积分区域是光源面积,这样path的利用率更高
我们需要把渲染方程上的在shading point上的在单位球上的积分变成光源面积上的积分
单位球的和光源的有如下关系,就是,向圆心方向的投影再除以圆半径平方
用这个关系就可以转换渲染方程
然后再以path tracing的思想,只取一条路径即可
这部分直接光照是不需要Russian Roulette方法的,间接光照才需要
所以我们将Path Tracing继续改进,得到如下算法
但从光源向shading point发出光线,存在光源和shading point之间有阻挡物的情况,我们需要在计算直接光照前,从shading point处看向光源,看是否有阻挡物,没有才计算直接光照
其他光线追踪技术
无偏性与相合性
无偏性:采样估计值的期望与真实值相同
否则即有偏
如果有偏,但采样量趋于无穷时,估计值趋向于真实值,则称为consistent,相合性
Bidirectional Path Tracing
BDPT Bidirectional Path Tracing
是无偏的估计
路径一半从相机出发,一半从光源出发,最后连到一起
BDPT适用于,当shading point比较难找到光源,即光路复杂的场景。
但BDPT实现难度较高而且运行速度慢
Metropolis Light Transport
Metropolis Light Transport MLT
MLT是无偏估计
应用了Markov Chain Monte Carlo
在应用Monte Carlo时,当选用的PDF与被积函数的形状一致时,方差最小
Markov Chain Monte Carlo保证了,对于任意的被积函数,使用的PDF与被积函数的形状一致
MLT是一个局部的方法,在每个像素内,利用一条找到光源的路径作为种子,其他路径都是由对这个种子进行微小的扰动生成的
MLT也非常适用于解决复杂的光路,如下述两种情况
第一种是光源比较难找到
第二种是caustics
但MLT方法,很难分析一个图像收敛的情况,并不知道渲染需要花多少时间,而普通的Monte Carlo方法是可以的。在动画中,可能存在上一帧和下一帧噪声差别大的情况,并不适用于动画
Photon Mapping
Photon Mapping是一个有偏的估计
适用于SDS路径
Photon Mapping分为两步
第一步是photon tracing,从光源开始向外发出光子,光子正常折射、反射,直到碰到diffuse面,则停止在diffuse面上
第二步是photon colletion,从相机开始向外发出光线,光线正常折射、反射,得到各个shading point,直到与光子相遇则停止
相当于一个要找到diffuse面的BDPT
然后需要做density estimation,对于每个shading point,用nearest neighbor的算法找到离shading point最近的N个光子,并计算这N个光子占据的面积大小,这样就可以得到这个shading point的photon density
density越高的地方应该越亮,否则越暗
density本来应该用来计算,但我们现在用的是,存在偏差,所以渲染出的图像有一定模糊,而在一定时,当从光源总共打出的光子越多,就会越小,越接近,与也会越来越接近,与当打出的光子数量无限多时,趋向于,渲染出的图像无偏,所以Photon Mapping是consistent的
渲染中,渲染出的图像是模糊,代表方法是有偏的,否则才是无偏的
Verte Connection and Merging
Verte Connection and Merging VCM
结合了BDPT和Photon Mapping,如下图中第二种情况,当从光源出发的光子比较靠近从相机出发的光子时,两个光子并没有方法连接在一起,这种时候就用density estimation的方法来计算shading,否则就用BDPT的方法连在一起。这种方法在BDPT产生的噪声和photon mapping产生的模糊之间做了取舍
Instant Radiosity
Instant Radiosity IR,也叫many-light rendering
思想就是,从光源向外任意方向发出多条光线,光线触碰到物体时,称接触点为vitual point light VPL,在渲染shading point时,我们把所有VPL当作光源,计算所有VPL给这个shading point带来的直接光照,这样实际上是计算了间接光照
Instant Radiosity适用于漫反射场景,但不能渲染glossy材质
而且存在问题,渲染时可能会出现光点,这是因为在对VPL做Monte Carlo积分时,我们需要把原来对立体角积分转换为对光源面积积分,存在除以,当VPL离shading point太近时,这个项趋于0,计算得到的shading就无限大
透镜实现的ray tracing
whitted-style ray tracing和path tracing都是用的小孔成像的相机
我们现在可以用棱镜成像的相机来实现ray tracing,就能得到模糊的效果
实现的方式如下
- 确定好感光片大小,光圈大小和焦距
- 选择想要的focal plane,然后根据物距计算像距,摆放好感光片
- 然后从每一个像素开始在光圈上采样,任意选择若干点,从像素向所有采样点发出光线,再计算每条光线的radiance即可
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律