赞
踩
UE4.24的Roadmap里可以看到SSGI(Screen Space Global Illumination,屏幕空间全局光照)已经发布,这是一个非常廉价的实时GI方案,适合要求不那么高,不支持光追的硬件或性能敏感的应用场景。先建个简单的场景,镜花水月的看看效果对比:
可以看到左边是关闭SSGI之后,远半部BoxScene一片死黑;右边开启SSGI之后,远半部BoxScene内部已经被照亮。
SSGI开启选项:控制变量为 r.SSGI.Enable ,0关闭SSGI,1开启SSGI,默认值为0
质量选项:控制变量为r.SSGI.Quality ,默认值为4,取值范围为{1,2,3,4},值越大质量越高,当然性能会成反比
SSGI RT分辨率: 控制变量为r.SSGI.HalfRes,0为否,1为是,默认值为0,即关闭HalfResolution,用Half Resolution会提高SSGI的性能,使处理的像素减少到原来的1/4,但同时也会降低SSGI的质量,增加噪点
SSGI是否使用使用无漏光的SceneColor : 控制变量为r.SSGI.LeakFreeReprojection,取值范围为{0,1} ,默认值为0。这是SSGI选项中唯一一个会有点疑问的变量——实际上它并不能解决漏光,它确定的是:你要用上一帧的SceneColor或是用当前帧的TAA History来做为当前的SSGI的输入数据。因为TAA的History基于移动指数方式混合了更多的前帧数据,只是相对来说后者可能导致更多的漏光罢了。
SSGI的实现分为4步,共计7个Pass,其中第3步的Denoiser实现不表,其它部分共4个Pass,步骤如下:
HZB Texture的mipmap生成则是存储上一级mip对应的4个相邻像素中的z的最大值。
上述的SceneColorTexture和HZB Texture均使用上一帧的数据做为输入。上一部分我们提到过r.SSGI.LeakFreeReprojection的值会影响到这两项数据的来源:如果r.SSGI.LeakFreeReprojection为1,则使用的是原生的上一帧的SceneColor,否则使用的是TAA的History。
SSGI在大的渲染流程中被调用早于Lighting相关的Pass,也早于TAA相关的PASS,大胆推测一下这么设计的原因:不使用本帧数据而使用上一帧的数据作为输入的目的,一是因为SSGI发生在Lighting之前,如果使用当前帧的数据则Buffer中无光照信息(但这不应该是大的问题,因为他们可以把此Pass放到Lighting相关Pass之后),二是因为使用前帧数据能有效的保证SSGI充分获得TAA的好处而不出现闪烁(SSGI Pass不能放在本帧的TAA PASS之后——它可能带来新的Aliasing问题,这样就需要在其后面添加新的AA PASS)。
评论有同学指出使用TAA History还有一个重要的作用:实现多次反弹 。最简单的场景:试想相机完全静止的时候,第三帧时获取到的第二帧History数据中带第一次反弹的信息,再次执行RayCast就相当于第二次反弹,以此类推,第N+1帧即可部分N次反弹的效果。如果直接使用的是上一帧的TAA之前SceneColor而非History,则就只会有单次反弹了……如果相机非完全静止,则History可能带来前帧累积错误反弹
这个PASS的实现有几个值得注意的地方,一一列举如下
1.它基本上沿袭了SSAO的光线发射方式,光线发射在屏幕空间的同轴圆。这儿为了只采样上半球的空间用了一个简单的tricky ,z = sqrt(1-x^2-y^2)) ..这样z始终保持取值范围为[0,1],即始终在正半球~
2.它的RayCast过程也颇为有趣,其RayCast过程不光是step不均匀(普通优化手段,用于产生非grid状的cast结果)。UE4的Scene Space RayCast step是打包执行的,一次执行4步 ,并且每隔两步就增加其采样目标纹理的mip level。其中打包的部分可以理解为充分利用GPU的向量化执行特性的优化。。代码经过整理且加上了注释,如下:
每执行2步就增加mip level的做法带来一个结果:离光线原点越远的地方,采样到的mip level越低,结果越模糊,即离光线越远,采样到的原始scene color的范围越大(低级的mip相当于高级mip更大范围内像素颜色的加权平均值),其实挺合理(类似于ConeTracing的做法,缺点是SceneColor部分会带来漏光,而Ambient部分则是阴影泄漏)。
C++部分
C++代码入口在RenderScreenSpaceDiffuseIndirect中。
Shader部分
SSRTPrevFrameReduction.usf(实现数据准备mip生成)
SSRTDiffuseIndirect.usf(具体的RayCast Pass的实现,其中raycast核心函数为
CastScreenSpaceRay)
DiffuseIndirectComposite.usf(SSGI的合成实现)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。