【GDC 2018】Clustered Forward Rendering and Anti-Aliasing in Detroit Become human

这里是底特律变人项目在GDC2018上关于其渲染技术的分享(之一),主要包含两个部分:

  1. 管线
  2. TAA

照例,对其中的技术要点做一个总结:

page-0001
page-0002
page-0003

工作室简介:

  1. 索尼独占工作室
  2. 擅长交互式戏剧游戏
  3. 200+员工
page-0004

大概3~5年发布一款新作

page-0005
page-0006

引擎的基本介绍:

  1. 针对PS主机做了大量优化
  2. 编辑是在maya中完成的
page-0007

Heavy Rain:

  1. PS3
  2. 前向
  3. 2x的MSAA
page-0008

Two Souls:

  1. PS 3
  2. 延迟渲染
  3. 伽马矫正
  4. PBR
  5. MLAA
page-0009

Sorcerer:

  1. PS4
  2. 延迟渲染,最多5个RT
  3. 对材质表现做了优化(采用Cook-Torrance公式实现高光反射)
page-0010

底特律的需求给出如上:

  1. 交互式戏剧
  2. 需要考虑性能
  3. 同时兼顾质量(废话)
page-0011

游戏特点:
1.城市

  1. 夜景众多
  2. 室内场景多
  3. 支持下雨跟下雪
page-0012
page-0013
page-0014
page-0015

效果图还是很赞的

page-0017

因为不是动作游戏,所以帧率要求会低一些,只要30fps(看看人家怎么挑选帧率目标的),可以用帧率来换表现。

另外一个要求是不要有加载界面。

page-0022

针对需求做了一番整理后发现大部分的特性都需要用到GBuffer:

  1. 基于法线的深度偏移
  2. 多层材质(皮肤、雨水等效果)
  3. 存储在顶点中的自遮挡信息(不是太了解)
  4. 眼睛渲染
page-0023
  1. 如果将这些特性都塞到RT中,可能会导致RT数目超标
  2. 同时不同材质对RT的需求不一样,设计上会存在冲突
  3. 延迟渲染在一些复杂逻辑下(比如上面列的两点?),可能性能会更差(没有展开介绍)

基于这几点考虑,最终还是想着走回前向:可以针对不同的特性,采用不同的渲染逻辑,从而规避了特性冲突的问题,同时由于分门别类的渲染,RT的消耗也不会太过分?

page-0031

自研引擎主要做了这些改动,今天主要聚焦在前两项。

page-0034

前面说了,前向的好处(主要还是Forward+的好处)是灵活高效,主要有三种渲染管线

page-0035

Tiled Rendering的基本介绍,值得关注的有两点:

  1. 带宽会更节省一点(谁不是呢?)
  2. 不支持半透(是因为只支持depth plane附近的像素,没有考虑半透在深度上的分布可能性)
page-0036
page-0037
page-0038

Forward+:

  1. 添加了tile的深度范围,剔除了部分范围之外的光源
  2. 支持半透(因为有了深度覆盖范围,所以分布在depth plane之外的半透物件也可以被考虑到了,就不知道这个覆盖范围是咋计算的,从上面描述来看,近平面是取的相机的,远平面则取一个最大值)
page-0039
page-0040
  1. cluster的深度覆盖范围不是线性的
  2. cluster在深度上做了划分,避免了Forward+的tile归类方法
  3. cluster数目高于tile数目
page-0041

之前有这么几个项目尝试了这个方案

page-0042
page-0043
page-0044

数据结构包括三个buffer:

  1. 包含cluster信息的buffer,3D数组格式,每个元素对应于一个cluster,存储了第一个light的索引与light的数目
page-0045
  1. 包含光照数据的buffer:一维数组,存储的是光源的基本信息,如类型、位置、颜色、衰减等,尺寸等于最大光源数目
page-0046
  1. 包含光源的间接索引数据,用的是16bit的格式,尺寸与光源最大密度有关
page-0047

下面看下Cluster数据怎么填充:

  1. 填充是通过CS完成的,大概位置在depth跟shadow pass之间(需要拿到depth来完成填充)
page-0048
  1. 每个cluster需要跟所有的光源进行比对以得到关联性(这里列了一些具体的tips与技巧)
page-0049

整个过程通过3个pass完成

page-0051
  1. 计算每个cluster关联的光源数目
page-0052
  1. 计算每个cluster中第一个光源的索引
page-0053

填充每个光源的数据

page-0054

cluster分为两层(目的是?)

page-0055

看下填充消耗

page-0056
page-0057
page-0058
page-0059
page-0060

针对上百个光源,大约花费1.23ms

page-0061

在lighting的时候,会基于当前像素的位置与深度来实现cluster的查找匹配

page-0062

第一次尝试之后发现shader复杂,用了过多的寄存器,导致性能下降。

page-0064

之后通过精细化管理做了优化:

  1. 尽量使用标量寄存器,避免浪费
  2. 尽可能的实现数据复用(目的何在?)
page-0065
  1. 在TAA开启的时候,降低阴影贴图采样的次数(PCF)
  2. 编译器循环采样2x4这里没看懂
  3. 远距离情况下,减少阴影贴图采样数目(常规操作)到1
page-0068
  1. 增加depth pass减少shading浪费
  2. 将lighting从PS改成部分使用VS
  3. 尽可能的将IBL放到后续的延迟pass一次性完成(避免分cluster执行,毕竟是全局效果,浪费多)
page-0069

这里看下优化细节,先是光照计算的优化:

  1. 一共四种类型灯光(projector应该是将某个光源按照贴图投影到场景里)
  2. 采样的话,有阴影贴图跟投影贴图两种
  3. 最开始的时候,需要通过一个4次的循环来对每种光源做单独处理
  4. 后面改成移除循环,一次性完成所有光源的处理(区别在哪里?)
page-0070

原始循环的逻辑如上图所示

page-0071

其中方向光阴影计算对寄存器(参数多,逻辑复杂)的占用高

page-0072

将之从循环中提出来,从而不用循环的每一步都需要耗费这么多寄存器(是吗?)

page-0073

光源的可见性计算逻辑:

  1. 基于portal/zone来实现
  2. 可以用于剔除掉不可见的光源
  3. 通过bit field存储
  4. 最后这个没看懂
page-0074

基于剔除,这里可以增加一个提前退出的判断环节(shader消耗真的能降低吗?)

page-0075

同样的思路,增加其他的剔除条件(看起来是逐像素的)

page-0076

统合到流程里

page-0077
page-0078
page-0079
page-0080
page-0081
page-0082

这里应该是具体的可以提前退出的debug视角,只是不确定颜色代表的是啥意思

page-0085

透明度的优化:

  1. 消耗很高,需要处理
  2. 对于玻璃来说,可以只计算IBL(效果不会有问题吗?)
  3. 粒子则做更狠(每个面片只shading中间点,类似于VS shading,通过SH存储的数据来计算,跳过其他光照计算,采用半分辨率渲染方案等)
page-0086

头发处理比较复杂,性能问题也相对比较严重

page-0087

首先是有个accumulation pass,采用1/16的分辨率渲染(会不会比较糊?)

page-0088

这个debug view不知道显示的是overdraw还是啥

page-0089

基于前面的透明度累加,再做一次绘制得到对应的depth数据(直接逐发丝获取depth肯定是不行的,逐面片呢?也会需要多层反复,所以干脆复用前面的数据,是个好想法)

page-0090
page-0091

还有其他的几个pass:

  1. 因为头发是双面可见的,因此分为前后方向的两次渲染
  2. 还需要一个motion vector pass(用于TAA?)
page-0092
page-0093

发现有些计算其实不分成cluster来处理会更好:

  1. SSR(全屏处理,跟光照没啥关系,其实大部分的后处理应该都是吧)
  2. IBL光照
  3. 这俩都需要法线跟粗糙度数据
page-0094

debug的一些信息

page-0095

镜子这里通常采用的是平面反射,即将场景额外绘制一遍,这里针对镜子的优化貌似是针对的cluster的数据填充(光源列表信息吗?),但是不是太明白其精妙之处(毕竟随着玩家视角的变化,会导致cluster划分的变化才是)。

这里针对平面反射倒是有一个没有尝试过的想法:

  1. 约束参与反射的物件,其中为每个镜子设置一个cubemap,远处就用这个cubemap遮挡
  2. 在镜子处渲染一个cubemap,运行时根据反射射线取用,不确定场景拉伸效果会否有问题,还需要实测确认一下。
  3. 在上述绘制好的静态场景上,叠加动态的物件,比如角色,从而每帧只需要承担角色的绘制消耗,即可实现此前每帧都需要重绘场景两次的效果。
page-0097

体积光能跟着沾光,走延迟的话,是需要做全屏的ray marching的,做Clustered Forward的话,应该可以约束最小单位为cluster(是这样吗?)

同样的逻辑,贴花也是。

照这样看来,如果全屏的操作较多,但实际上只有部分区域需要的话,而且考虑到移动端的Tiled Chip架构的话,同样的效果下,延迟渲染确实不见得会是最佳的渲染管线了(延迟渲染主要的优势就是多光源支持成本低,假设通过精细化管理,收束住每盏灯的消耗从每个物件到只有表面的一层可见像素,可能延迟渲染的这一点优势就被很大的抵消了,不知道后面有没有详细的对比数据)。

page-0098
page-0099
page-0100

这里是所有光照的计算消耗:

  1. 124盏灯,32个IBL(咋这么多,都是啥?)
  2. 总体消耗加起来是15.42ms(60帧有望,不知道还有没有其他消耗,也不知道同样的效果下,延迟渲染消耗咋样)
page-0101
page-0102
page-0103
page-0104

后面还可以进一步优化其性能:
1.减少cluster填充的时间消耗

  1. 对深度的分布做更为细致的处理,目前处理还是稍微有点简单
  2. 在cluster填充的时候,就可以做一些剔除,削减后续的计算消耗
  3. 针对VR可以做数据复用
page-0106

锯齿问题的产生不能想着通过提升分辨率来解决,此外,HDR跟PBR会加剧锯齿问题。

page-0107

据此问题的解决主要有三种思路:

  1. 增加采样数
  2. 后处理,如MLAA
  3. 在着色的时候处理(?)
page-0108

多采样比如MSAA算法,也是有消耗的,shading消耗增加,同时只能处理形状锯齿,高光锯齿没有办法解决。

page-0111

后处理则主要有如下三种,今天要介绍的TAA是基于UE的TAA算法优化而来。

page-0115

这里对TAA的算法实现思路做了总结:

  1. 每一帧会对投影矩阵做一个随机偏移,使得画面在垂直于深度方向有一个抖动
  2. 将多帧的结果累加到一起
  3. 需要通过运动向量来追踪到某个像素在上一帧的位置,上面这个累加最理想的状况下是只发生在相同的世界空间位置,拿错了就会导致残影
  4. 为了把错误的数据筛选出来,还需要一套合理的算法
page-0116

TAA作用在物件绘制完成之后,出于结果稳定性考虑,需要放在后处理之前(?下图是UE的渲染pass排序,可以看到,TAA是放在DOF之后的,为啥DOF跟Motion Blur会有前后的差别呢?),因此对于Bloom、DOF以及运动模糊等后处理带来锯齿是无能为力的

对于一些需要特殊处理的后处理,比如SSR以及体积光等需要通过多帧累加来实现降噪的应用情景,就特别适合使用TAA来提升品质。

page-0117

8步抖动(每8帧重复一次抖动的offset)

page-0121

TAA的运动向量其实是通过在shader中对前后两帧的MVP矩阵的变换结果作差得到的,由于只能存储一层数据,因此正常情况下我们其实是只记录不透明物体,但是如果需要的话(比如前面的半透效果过于重要,或者虽然是半透但实际上是按照不透绘制,比如前面说过的头发),我们也可以针对这类物体做单独开关,记录下透明物体的运动向量,这样带来的后果,就是半透背后的不透物体的运动向量数据就无法保存了,因此是否要开启,需要评估其中的得失。

因为前面的计算逻辑是两帧作差,所以为了能够得到准确的运动向量,除了需要记录前后两帧的MVP矩阵,还要同时记录前后两帧的动画数据:

  1. 布料、蒙皮数据
  2. 植被受风力影响的数据
  3. 顶点动画数据
page-0123

为了得到有效数据,这里用了三种方案:

  1. 来自于UE TAA的相邻数据剔除方案
  2. 基于深度差异的剔除方案
  3. 基于速度相似性的剔除方案
page-0124

相机只是旋转的情况下,前后两帧画面的像素基本上是一一对应的,但是如果移动的话,就会出现同一个物件在屏幕空间覆盖范围的变化,导致对应关系被打破(真的会有问题吗?为啥只有skin需要做这个处理?),所以在相机缩放(拉近拉远)的时候,需要相应降低TAA的力度(对应帧在累加时的权重),避免效果的异常。

page-0125

整体消耗为1.14ms,确实低(不知道SSR消耗多少,推测可能高过TAA)。

page-0126

TAA会引入一个问题,就是雨雪效果可能会被TAA模糊掉,这个特效消失的问题在UE的演讲中有对应的解决方案。

对于雨打在物体表面上的效果,则可以基于雨水的法线强度来调整TAA的强度,从而避免模糊掉不必要的细节,下面几张图做了生动的解释。

page-0127
page-0128
page-0129
page-0130
page-0131

TAA的问题:

  1. 部分后处理会因此存在异常(比如DOF跟运动模糊,就会出现效果错位出圈的问题)
  1. 深度数据其实不需要抖动(不知道抖动了是否有其他的副作用?看下面的描述是,抖动了,但是却没有做TAA累加,所以导致颜色跟深度不匹配吗?)
  2. 轮廓线等正常的边界会被当成锯齿模糊掉
page-0132

DOF的问题如何解决呢?

  1. 对深度也做TAA累加(从而解决颜色跟深度不匹配导致的DOF的抖动效果?)
  2. 通过对COC的尺寸进行缩小来减少泄漏(不知道具体是啥表现。。)
page-0133
page-0134
page-0135
page-0136

这里给了几张图,要全屏播放仔细观看才能发现问题,上一张图脸部边缘要光滑一些,这一张图边缘则像是有绒毛之类的效果,看起来应该是远处的DOF借了脸部的数据导致。

正常的DOF会进行深度剔除,模糊的时候,会刨除掉深度差异大的数据,但是这个算法在TAA对深度做了抖动之后,就会存在问题,将本来不应该采到的数据也采进去了,从而导致了类似的问题。

page-0137

同样的,Motion Blur也是只对背景模糊,不对前景模糊,所以问题是相似的,解法也一样。

这里也介绍了运动模糊的一些细节:

  1. 一些模糊算法,其实都可以降分辨率来执行(其实DOF也是可以的吧)以提升效率
  2. 运动模糊覆盖的区域需要排除掉深度不连续的地方(难道不是前面把深度纳入TAA就行了?或者说,纳入TAA之后,依然会被认为需要参与到Motion Blur?所以Motion Blur需要单独处理?)
page-0138
page-0139
page-0140
page-0141
page-0142

这里给了效果的对比图。

page-0143
page-0144
page-0145
page-0146
  1. TAA其实是可以很好的与checkboard rendering模式结合起来的,多帧混合+空间降分辨率,正好实现性能与效果的兼顾

这里解释一下,checkboard rendering(部分文章会简称为CBR)是彩虹六号的技术分享中介绍的一种性能优化技术,这种技术通过减少单帧需要shading的像素数目(采用类似MSAA的shading pattern,不过不同的是,MSAA是作用在单个像素的多个sample上,而这里是直接作用在像素上),之所以叫checkboard rendering,是因为真正参与shading的像素是类似于国际象棋棋盘上的黑色(或白色),而白色(或黑色)像素则是通过算法插值得到,具体可以参考【GDC 2016】Rendering Rainbow Six Siege

  1. checkboard rendering在相邻像素之间的jitter pattern需要保持一致
  2. 4k分辨率对后处理来说是一个很大的性能负担, 所以这里的做法是将checkboard的resolve放在后处理之后
page-0147

这里应该有个视频

page-0148

在部分场景下,TAA的效果还有所不足,比如高光表面

page-0149

着色锯齿通过增加shading次数的方法太耗了

page-0150

通过对法线进行filtering(给了参考文章)来降低shading噪声,相当于移除高频细节只保留低频数据。

page-0151

这里还有一个更高效的版本。

page-0152

效果测试发现还是挺不错的,雨水的细节可以得到较好的保留。

page-0153
page-0154
page-0155

这里给了效果比对图片。

page-0156

除此之外,还有其他的一些可以借助时间的累加来提升效果的特性:Shadow(PCF)、HBAO(周边多像素的射线发射),SSR,SSSSS,体积光等

page-0157

蓝噪声特点介绍:

  1. 在能量上不存在聚集的突刺,具有最小的低频组件(?)
  2. 参考Inside的渲染介绍
page-0158
page-0159

这里针对蓝白噪声做了比对不知道结论是啥。

page-0160

之前有人提出过通过8taps的泊松圆盘pattern来控制shadow map的采样点(相邻)偏移以得到更好的性能与效果。

这里提出了一种新的方法,直接基于一张16x16的蓝噪声贴图数据来对相邻像素的采样偏移进行旋转,不知道跟前者比较起来收益在哪?

page-0161

这里是具体的执行细节。

page-0162
page-0163
page-0164

展示了效果。

page-0165

同样的,对5S也描述了其实现细节,不过之前对5S的实现方案了解不多,这里就不展开了,后面有需要再回来补充。

page-0166
page-0167
page-0168
page-0169
page-0170
page-0171

HBAO的,通过对tracing射线的方向做随机处理,叠加TAA来提升效果。

page-0172

这里说,按照上面的说法,是不能得到预期的效果的(为啥?)

这里采取的策略是增加一个grainy blur pass来优化HBAO的效果,Grainy blur是一种高效的模糊算法,只采样若干个相邻像素(极端情况下也可以只采样一个)做混合,通过uv抖动+TAA来提升品质,具体可以参考毛星云的高品质后处理:十种图像模糊算法的总结与实现

page-0173
page-0174
page-0175
page-0176
page-0177

这里是具体的效果对比图

page-0178
page-0179

实际效果比对。

page-0180

SSR基于寒霜15年的talk与Surge中的SSR方案实现

page-0181
page-0182
page-0183
page-0184
page-0185
page-0186
page-0187
page-0188
page-0189
page-0190
page-0191
page-0192
page-0193
page-0194
page-0195
page-0196
page-0197
page-0198
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容