《原神》主机版渲染技术要点及解决方案
阴影的实现可以分为动态阴影和烘焙阴影。对于动态阴影,采用8级CSM方案覆盖800米视线,其中前四个阴影每帧更新一次,后四个阴影依次更新(即依次每四帧更新一次)。
软阴影使用泊松随机样本模式的PCF,每个像素对应的样本数为11,会导致计算消耗高。为了减少这个块的消耗,用一个掩膜图来标记屏幕上每个区域的阴影属性,软阴影PCF只计算半影中的像素。
遮罩贴图使用屏幕分辨率的1/4 x 1/4。正常情况下,判断掩膜图中的一个像素是否属于半影(绘制并输出掩膜图),需要判断该像素在屏幕分辨率下所覆盖的16个像素的遮挡情况,然后进行积分输出(视频中未显示,所谓的积分输出是指平均值吗?)当前像素的半影判断结果,但是这种方法会有很高的消耗。为了进一步提高计算效率,我们决定采用抽样调查算法,按照一定的模式从16个子像素中选取样本进行判断。这种方法会有一定的误差(有些应该是软阴影被误认为硬阴影)。为了减少误差,掩膜图在这里会被模糊(扩大半影的半径),从而在一定程度上。
整个遮罩贴图的生成和虚化消耗约0.3ms,而整个阴影计算的GPU消耗约为1.3~1.7ms,优化后的开关的阴影质量肉眼基本无法分辨。
阴影只能表现光照上宏观的单层遮挡效果,无法模拟细微的多层(多光源效果)效果。例如,在阴影中的地面上,如果只使用阴影,将无法模拟其他物体在地面上的投影,从而使物体看起来是悬浮的。这些缺陷可以通过环境遮挡方案来解决,而《原神》提供了多种AO方案,可以针对不同的场景进行选择。
HBAO是horizon based ambient occlusion的缩写(另外这里需要注意的是,我们通常说的HDAO(高清环境光遮挡)和HBAO是等价的,但前者是AMD给的名字,后者是NVidia给的名字)。这是一个非常常规的AO方案,通过对屏幕空间的后期处理,可以为物体提供更加细腻的细节。其基本实现原理是:通过采样各个方向的深度得到最大遮挡角,通过累加各个方向最大遮挡角的正弦得到AO。这种算法的质量优于SSAO,逻辑更物理、更真实,但其性能消耗会更高。业界通常使用其优化版HBAO+。有关详细信息,请参考之前关于AO实现算法的综述:环境遮挡技术方案概述。
AO体积是为静态对象开发的AO方案。与HBAO相比,AO容积可以产生更大的遮挡效果。如上图所示,HBAO算法对于这种阴影效果类似的AO是无能为力的,所以这里需要增加额外的AO体积算法逻辑。
AO卷的实现逻辑可以参考之前做的一个AO算法概述来分享。
《原神》AO体的使用方案是离线烘焙静态物体的AO数据,然后根据操作时的烘焙数据计算出最终的遮挡效果。
静态物体的阴影可以通过lightmap+AO Volume来实现,而动态物体的阴影如果仅仅依靠HBAO会显得过于粗糙,但是如果再增加一张阴影贴图来应对这种情况的话就太浪费了。《原神》的做法是通过Capsule AO给动态物体(比如人物)添加更细致的阴影效果。
胶囊AO的具体实现原理可以参考前面对AO算法的总结来分享。简单来说,这个算法是通过使用多个胶囊来模拟角色(胶囊会随着角色骨骼的位置等发生变化。),然后通过计算胶囊在待渲染位置上半球投影面积的比例,输出环境光AO(或阴影),计算主光源AO(通过计算胶囊在以渲染位置为轴方向,以某个角度为锥角的圆锥体上的比例。
为了提高AO计算的性能,《原神》所有的AO计算都以1/2的分辨率进行。计算完成后,为了进一步柔化效果,减少缺陷,这里会增加一个双线性模糊处理(水平+垂直)。最后,在使用它时将需要一个额外的上采样过程(这可以通过直接使用分辨率为1/2的map来完成)。
在模糊处理的过程中,每个像素需要混合周围多个像素的值。可以看出,如果使用传统的PS,每个像素将需要多个映射样本,这些采样结果实际上可以在其他相邻像素的计算中重用。因此,为了进一步提高计算性能,《原神》的方法是将模糊处理放入计算着色器中。
具体来说,相邻像素的采样结果存储在本地数据共享中,模糊时再检索,一次完成四个像素的模糊计算,输出结果。
《原神》使用的渲染管道是集群式延迟光照(详见之前的分享:集群式正向渲染)。场景分为16个切片,每个切片的大小为64x64像素,最多可支持1024个本地光源。
上图是多个本地光源的时间效果。可以看到局部光源也有实时阴影,但并不是所有的局部光源都会添加投影(这个应该是美术生可以控制的)。这里支持实时阴影的本地光源数量不超过65,438+000。
整体阴影效果是烘焙静态阴影和动态阴影的结合(假设使用了阴影贴图,但是计算消耗会很高,很难从给定的材质推断出做了什么优化)。
对于局部光源的静态阴影,需要烘焙相应的阴影贴图。因为光源多,每盏灯都是烤的,会导致硬盘上空间占用大。因为阴影贴图是深度贴图,所以不能通过块压缩来压缩。为了解决这个问题,《原神》团队设计了另一套压缩思路。
具体思路(参考Siggraph 2019的文章一个可扩展的实时多明暗渲染系统)给出如下:
这种方案的表现是室内场景的精度压缩比在0.2 ~ 0.3左右(即从10k压缩到2 ~ 3k,效果上可能会有轻微的瑕疵),高精度模式压缩比在0.4 ~ 0.7(瑕疵基本肉眼难以分辨)。
体积雾计算方法本身可以达到神射线效果,但是这样达到的神射线效果可能不明显(因为体素数量少,这种方法输出的纹理分辨率比较低,而且因为雾的浓度可能不足以产生神射线,所以神射线效果不会明显)。在这里,《原神》的团队旨在让上帝射线效果看起来更好。用一个额外的光线行进通道来实现上帝光线,增加了一些额外的参数,这些参数将用于进一步调整光线行进后的上帝光线效果,从而产生更漂亮的艺术效果(虽然不是物理的)。
视频中显示的反射探头和环境探头的场景都是随着24小时的时间不断变化的,而传统的反射图都是离线捕捉的,所以通常不可能随时间变化。那么这种性能是如何实现的呢?
对于反射探头,这里的做法是烘焙一组mini GBuffer贴图(包含法线/深度/反照率等信息)而不是直接烘焙一张环境贴图,然后根据当时的光照数据实时生成一张反射立方体贴图。和传统的反射探头一样,艺术生也可以在场景中放置大量这样的探头。
环境地图的实时生成主要通过以下步骤完成:
整个过程由计算着色器完成。在Compute Shader中,6个表面可以同时被多个线程处理,而由于单个反射立方体贴图的更新实际上是很昂贵的,为了减少单帧的压力,反射立方体贴图的更新被分散到多个帧中,每个帧中只更新一个探针,所有探针都通过时间旋转来更新。
反射探头更新后,获得当前探头的光场数据,从这个光场中提取环境探头的光照数据。由于环境探头的低频特性,这里可以用SH系数来保存整个光场,进一步降低内存消耗。
光场提取也是通过Compute Shader实现的,一次完成六个面的计算。
完成以上步骤后,可以获得随时间动态变化的光照信息,但仍存在一些问题:
针对这些问题,《原神》给出了以下解决方案:
此外,为了避免室内室外过渡区域的硬切割,我们还对这里的过渡区域进行了平滑处理。以下是根据内部网格生成的遮罩贴图:
反思与反思。当使用环境探针时,AO数据也将被考虑在内,这可以有效地减少漏光问题。
PS4 Pro上SSR的开销约为1.5ms,为了增强显示质量,增加了一个时间滤波器来混合历史数据。另外,为了快速得到各种粗糙度下的反射结果,为SSR生成了类似Hi-Z的缓冲图。
这个原文比较详细,就不赘述了。