全局光照加速结构

Lumen学习笔记,有错误的地方欢迎指正

软件光线追踪

UE默认采用软件光线追踪,因为软件光线追踪可以无视平台和硬件的限制带来跟硬件光线追踪质量相近的结果,同时软件光线追踪采用的大量加速结构使得它在很多复杂的场景性能反而比硬件光线追踪高。

Ray Trace加速结构

Lumen里面软件光追用到的比较普遍的加速结构有三种,Hi-Z、MDF和GDF。

Hi-Z准确度最高,但却是三种加速结构里面最慢的一种,一般用于屏幕空间Ray Trace。

MDF准确度较高,速度中等,一般在ray即将到达object需要获取物体表面的Lighting Cache时使用。

GDF准确度较低,但拥有最快的tracing速度,GDF由多个低分辨率MDF通过一定计算得出的,GDF用于长距离的ray trace或者是远处物体(相对于屏幕)的ray trace。


UE加速方案如下

  1. 先用Screen Space Trace。基于Hi-Z走50步,如果能Trace到,直接获取结果。
  2. 如果Screen Space Trace失败,采用MDF,SDF Trace的距离为1.8米,Trace距离短,也就是只能Trace很近的物体,如果能Trace到返回Mesh ID,可以通过ID获取Surface Cache。
  3. 远处物体用GDF,如果需要高精度,先用GDF步进到一定距离再用MDF,如果精度低,直接用GDF一步到位获取结果。
  4. 如果GDF也失败了,从CubeMap采样。

UE一般混用这几种加速方案
image

Hi-Z(Hierarchical Z Buffer)

Hi-Z原理

Hi-Z是一种屏幕空间的算法,该算法记录一些列屏幕深度的MipMap,越下层的MipMap越精细,每个上层 MipMap里面的一个像素,都对应它下层Mip里面四个点的像素。
image

有了这种结构,我们可以仅仅通过判断上层粗糙结构与Ray有没有交点就可以直接决定要不要走下层结构的分支了。

Hi-Z能做什么?
SSGI屏幕空间加速求交

在做SSGI的过程中我们需要沿着Lobe的方向去发射Ray去获取第一个命中点的颜色,收集到这个颜色就可以计算这个颜色对我们要计算的Pixel的贡献了。
image
而这个过程如何从这么多三角形中找到第一个命中点呢?

最简单的方式就是固定步长步进,Ray每次步进一个固定长度,然后根据屏幕空间深度判断一下这时候的Ray在当前Pixel前还是后,如果Ray位置在Pixel后面说明已经打到该Pixel里某个三角形片段上了。
image

固定步长的方法虽然能够找到交点,但是速度太慢了,如果步长太小可能要走成千上万步,步长过大击穿太多物体可能会导致找不到第一个交点。

Hi-Z就是一种自适应步长的加速方案,在该方案中,不同级别的深度MipMap记录着该Pixel内所有物体的最浅深度,也就是离屏幕的最近距离,先用较粗糙的深度MipMap做光线求交,如果有交点则说明光线有可能和该Pixel内物体有交点,继续找更精细的MipMap,如果没有交点则代表Ray跟该Pixel内所有物体一定不相交。
image

该算法适应选择步长的过程有点像篮球里的试探步,一开始先从最低级的MipMap迈出一小步,发现没有打到交点
image
下一步就可以大胆一点了,向高一级粗糙一点的MipMap迈出一步,高层的MipMap的一步相当于底层MipMap的两个步,发现还是没有打到交点
image
下一步再大胆一点,在更高级的MipMap再走一步,最后发现和这一级的MipMap有交点了
image
发现已经有交点以后就不能这么鲁莽的迈一大步了,我们开始缩小步长,回退一级MipMap开始小步迈进
image
这时发现和这一级的MipMap仍然有交点,我们需要更小心了,再迈更小的步,如果已经是最底层的MipMap我们就保持最小步行进
image
最后的小布前进成功使我们找到了交点,这种步进的方式其实很类似于二分查找,最终以logn的复杂度远胜固定步长步进。

遮挡剔除

遮挡剔除同样是利用Hi-Z实现类似于二分加速的方案,由于视角的问题,其实场景里有很多物体是看不到的,所以我们可除掉这些看不到的Mesh的提交来减少Draw Call,这个过程就需要用到Hi-Z加速。
image
遮挡剔除的粒度是整个物体而不是像素,所以一般通过判断包围盒的深度来选择是否要进行剔除,而一个包围盒有的时候是很大的 ,比如我们近距离看一颗草的包围盒,下图草的包围盒覆盖了13*13个像素,我们总共需要判断169次屏幕深度和包围盒深度,哪怕有一次包围盒深度要小于等于屏幕空间深度(包围盒里可能有一小部分要比屏幕深度离相机更近),那就不能剔除掉这个物体,因为只要出现一次这种情况,那就说明这个物体有可能出现在屏幕内被我们看到。
image
可以用Hi-Z的方式去减少包围盒判断的次数,就比如生成一个更高级的MipMap里面存储低一级MipMap里面四个像素的离相机最远的深度,那么包围盒只要比最远深度还要远那就剔除掉,因为这种情况这个物体一定是不可见的,且我们只需要非常少的判断次数就能得到结果。
image
通常我们会一直找更高级别的MipMap直到该层级MipMap里面一个像素能完全包裹一个包围盒再做上面的判断,这样就最少一次就可以剔除掉物体了,但UE一般采用的是4×4的判断方式,因为极端情况下,如果包围盒中心恰好在屏幕正中心,而包围盒又占不满那一个Tixel,该包围盒就可能受到Tixel内其他位置的深度影响,本该被剔除却因为这种原因没被剔除,这就会导致遮挡剔除命中率降低。

image
最后需要考虑的就是实现上的问题了,因为要做剔除就需要知道深度,而深度要绘制了物体才能知道,这就好像是先有鸡还是先有蛋的问题。

为了解决这个问题,研究者们提出了很多Hi-Z遮挡剔除的方案,以下介绍几种

  1. 通过一个简单的CPU软光栅化得到一张简单的深度图用来指导Hi-Z做遮挡剔除,但CPU光栅化速度会比较慢。
  2. 利用前一帧的ZBuffer重投影后的信息再Compute Shader里指导Hi-Z做遮挡剔除, 这种方法存在两个问题,如果重投影个别像素在上一帧没有对应位置就会导致生成的ZBuffer存在漏洞,这导致高级别的深度MipMap几乎剔除不了任何物体,另一个问题会导致动态物体重投影区域产生延迟且快速移动物周围会产生物体突然出现的问题,因为动态物体这帧可见了但是按上一帧判断还是被剔除了。
  3. 《刺客信条大革命》提出了第3种方式的优化方案,采用Two Pass的方式,第一个Pass对大概300个occluders做光栅化来获取深度补全上一帧重投影导致的漏洞,通过补全后用上一帧重投影的ZBuffer和这一帧绘制的occluder生成一个尽量贴近当前帧实际情况的zbuffer指导Hi-Z做遮挡剔除,留下的物体存进容器A,被剔除的物体存进容器B,这样可以得到大概率不可被剔除的物体,第一个Pass是非保守Pass,好处是可以根据不是完全准确的ZBuffer得到部分需要保留的物体。第二个Pass绘制上一个Pass得到的A内的物体,然后用算出的ZBuffer信息再对B内的物体做遮挡剔除,第二个Pass目的是采用保守的方式找回第一个Pass错误剔除的物体。
  4. UE内不依靠硬件的Hi-Z遮挡剔除通过异步加载上一帧的ZBuffer+爆算部分这一帧的ZBuffer,通过这种方式算出来的ZBuffer仍需要回读到CPU里做剔除然后上交Draw Call,这种方式没办法使用GPU-Driven的原因是因为由于材质和物体信息没办法解耦,Texture需要每个Draw Call重新绑定,而通常一个场景有成千上百个Material。
  5. UE可通过硬件特性做粒度是像素级的Hardware occlusion query,这种方式会上交一种特殊的Draw Call,这种Draw Call只通
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值