延迟渲染需要在前面阶段,将计算的内容保留在N张G-buffer中,但是网上的文章只是提及了G-buffer应该压缩,并且尽量少用,没有说明G-buffer所占带宽应该是多少,我将在下面介绍G-buffer所占显存带宽的详细计算方法
G-buffer的存储内容
为了减少G-buffer的内容,现在基本会对G-buffer内容进行压缩
我原来有段时间很喜欢玩《killing floor2》这个游戏,是拿ue3引擎做的,
(《killing floor》的发展史和虚幻引擎发展有着密不可分的关系,一代在当时就有很好的效果)
下面这张图是《killing floor2》的G-buffer存储方法
可以看到除了深度模板视图,总共用了4张RT去存储G-buffer信息
G-buffer所占显存带宽的计算
首先每张RT有RGBA四个通道,每个通道是8bit,那么总共是4*8=32bit的通道信息
如果屏幕是1920*1080p的,一张RT整张屏幕存储的通道信息就为1920*1080*4*8bit
如果游戏流畅运行需要60fps(《杀戮空间2》是射击游戏,需要高刷新率),那么在一秒中一张RT所传递的信息就为
1920*1080*4*8*60bit=3981312000bit/s,大概是0.46GB
那么《杀戮空间2》用了四张G-buffer,单一次单向传输就用了将近2G/s的带宽
它的发售时间为2016年末,那时候平常游戏玩家用的卡的带宽在148.8GB/s
但是需要看游戏的最低要求配置,是GeForce GTS 250,这张显卡的显存频率为
1100MHz,显存位宽为256bit,带宽粗略为35G/s,但是显卡需要这个带宽去处理别的事情,可见显存带宽的宝贵性
关于移动端延迟渲染的障碍
移动端的瓶颈在带宽
带宽是电量消耗和发热的大客户。带宽是一种共享资源,因此使用过多会以不可预知的方式限制整个系统的性能。访问外部存储器需要大量功率,因此减少带宽使用可降低功耗,移动端GPU和CPU是共享内存的,因此 GPU 的高带宽使用会降低 CPU 性能
手机游戏的性能优化,要以极低的配置目标做优化,那我们选择一个几年前的手机去做计算
小米6的内存是LPDDR4X 1866MHZ,32bit 双通道
所以内存带宽是,1866 * 32 / 8 * 2 * 2
算下来大概为30 GB/s
再算上屏幕缓冲区加上深度缓冲区,读写宽带,overdraw,cpu内存读取等开销
总共用30GB/s的带宽,可见移动端的开销是非常紧迫的
这时候上延迟渲染就很难了
不过,在ue5.1中,在关闭静态光的情况下, 使用三张G-buffer支持了桌面端全部的shadingmodel, 并在源码里预留了第四张gbuffer的开关
关于延迟渲染和ssaa与msaa
这个问题的争议比较大,我对这个问题的结论是,可以实现,但是效果可能不正确
延迟渲染和ssaa
ssaa是放大屏幕分辨率,最后再缩放,采样多个映射的子像素点进行插值
在前向渲染中,最后结果都在高分辨率的颜色缓冲区中,在高分辨率的颜色缓冲区中采样再进行插值计算,得到最后的结果
再延迟渲染中,在最后的光照计算后,也得到的是高分辨率的颜色缓冲区,也可以进行插值计算,得到最后的结果,但是在计算光照之前,需要多张高分辨率的G-buffer去存储信息,这个开销巨大
延迟渲染和msaa
msaa是在ssaa的基础上发展而来的,通过测试的子像素才能复制中心像素的颜色,一个像素只计算一次,最后再写入颜色缓冲区
再延迟渲染中,这个像素周围的信息已经丢失了,无法进行采样了,那么有没有办法解决这个问题呢
当然有办法了
在计算得到每一张G-buffer的时候,执行一遍子像素测试,这时候的每一张G-buffer都是取完插值的结果,这时候就保留了每一个像素的周边情况,最后再和光照做计算就没问题
但是,插值得到保留法线和深度的G-buffer可能插值不正确
所以msaa完全可以用延迟渲染,但是计算结果可能不正确