渲染杂谈:early-z、z-culling、hi-z、z-perpass到底是什么?

之前一直被这几个和深度缓存(z-buffer)相关的概念搞得神魂颠倒。今天在翻阅《Real-Time Rendering》时碰巧碰巧看到了这部分的讲解。硬着头皮看了看,姑且算是讲几个概念分清楚了。以我的记性估计下周就全忘了,所以打算顺手记下来。

这四种技术本质上都是解决传统渲染管线中的同一个问题——过度绘制(OverDraw) 。一个经典的渲染管线通常会依次经历顶点阶段、光栅化、片元阶段和逐像素处理。其中片元阶段会进行复杂的光照计算,是整个管线的性能瓶颈。而在逐像素阶段会对计算出来的片元值进行各种测试以判断这个片元会不会最终显示到屏幕上。这就带来了一个矛盾:明明我在片元阶段花费了最大的力气计算出结果,但马上的逐像素阶段就可能将这个结果直接舍弃。而事实上逐像素阶段的深度测试(z-test)会舍弃大量片元,对于较为复杂的场景甚至会丢弃80%之多。如果我们能在片元阶段之前进行深度测试提前丢弃掉那些不需要绘制到屏幕上的片元,那么就可以减少大量片元计算提升效率。early-z、z-cull、hi-z、z-perpass都是为了解决这个问题而产生的不同技术。

1. early-z

early-z的解决方式非常简单,就是直接修改传统渲染管线,在光栅化和片元阶段中间,加入一个early-z阶段。这个阶段进行的操作和原本逐像素处理阶段的z-test(为了与early-z区别,这个阶段也会被成为late-z)操作完全一样,现代的gpu已经都开始包含这样的硬件设计。

但是early-z有以下两个主要的缺点:

  • 一旦进行了手动写入深度值、开启alpha test或者丢弃像素等操作,那么gpu就会关闭early-z直到下次clear z-buffer后才会重新开启(不过现在的gpu也在逐渐优化,使其更智能开关early-z)。之所以gpu会选择关闭early-z是因为上述那些操作可能会在片元阶段与late-z阶段之间修改深度缓存中的深度值,导致提前的early-z的结果并不正确。我们也可以在fragment shader中使用layout(early_fragment_tests)来强制打开early-z。
  • early-z的优化效果并不稳定,最理想条件下所有绘制顺序都是由近及远,那么early-z可以完全避免过度绘制。但是相反的状态下,则会起不到任何效果。所以有些时候为了完全发挥early-z的功效,我们会在每帧绘制时对场景的物体按照到摄像机的距离由远及近进行排序。这个操作会在cpu端进行,当场景复杂到一定程度,频繁的排序将会占用cpu的大量计算资源。

2. z-culling

z-culling和early-z一样都是gpu硬件层面的优化,所以之前我一直混淆两者是同一种东西。两者最明显的区别是early-z是以pixel quad为单位(既以4个像素为一组,因为深度缓存内的数据是按Z字形排列的)逐个像素进行比较,而z-culling是以tile(比如16*16像素)为单位进行整体比较。这里又涉及到tile的概念,虽然我看到的资料中并没有提到,但是我认为这里的tile和tile based rendering(TBR)中的tile是同一概念。也就是说这种技术应该只应用于使用TBR架构的移动端gpu中。其主要方式取得当前tile所对应的的深度缓冲区中的Zmax和Zmin,如果该tile当前深度的最小值Znim,则说明整个tile都处于最前面,保留整个tile,并因此可以省去该tile对应片元在late-z阶段对深度缓冲区的读取操作,直接写入就可以。对于其它情况,则交给后续的深度处理进行更细致的判断。由于z-culling通常用于TBR架构gpu,所以它也和TPR架构一样保持了对gpu带宽的敏感性。因此不同于early-z,z-culling并不会对深度缓存进行写入,也不会对深度缓存进行直接读取。它所需要的比对数据(Zmax和Zmin)都会储存在on-chip缓存中的某个固定区域,特点即是容量小但速度快。由于z-culling对深度缓存是只读的,因此不会因为手动写入深度值、开启alpha test或者丢弃像素等操作对其有影响,这刚好解决了early-z的第一个缺点。总结来说,z-culling利用TBR架构进行了非常粗粒度的提前深度测试,但不会带来额外的对于深度缓存进行读写消耗,因此也比z-early具有刚多的适用范围。

这里有一个疑问,为什么early-z不像z-culling一样,对深度缓存只读,来避免收到手动写入深度值、开启alpha test或者丢弃像素等操作的影响?其中一个解释是,在z-culling阶段后,那些没有被优化的片元在late-z阶段会读取深度缓存进行细粒度的测试,完成后再更新写入新的深度缓存。同时也会更新z-culling会访问的on-chip缓存。由于z-culling访问的是on-chip的所以不会带来额外开销,所以整体上只有对深度缓存进行一次读一次写。而对于early-z来说,如果在early-z阶段只读取深度缓存而不写入的话,那么在late-z阶段就需要重新读取然后写入,以更新深度缓存。这就相当于两次读一次写,带来了额外的开销。不过也看到有人说late-z阶段对深度缓存的读写是无论如何都会进行的,所以此处存疑。

还需要说明的是,z-culling和early-z都可以不依赖于对方单独存在,当然两者也可以共存。当两者共存的时候,会先进行z-culling做粗粒度的筛选,再进行early-z做细粒度的排除。在有些资料中也会把z-culling成为HiZ(没错,就是最后要讲的hi-z),这要是不弄混就怪了。

3. z-perpass

和上面两种技术不同,z-perpass是一种软件技术。它主要是配合early-z使用,来减少开始提到的early的第二个缺点——效果不稳定。其做法是将场景做两个pass的绘制。第一个pass仅写入深度,不做任何复杂的片元计算,不输出任何颜色。第二个pass关闭深度写入,并将深度比较函数设为“相等”。我在开篇有提到过度绘制的主要矛盾——经过大量运算的片元,很大概率会在之后被丢弃掉。那么对于第一个pass由于只写入深度,不在片元做任何计算,所以即便之后会被丢弃,也并不可惜。也就是说无论场景中的物体以怎样的顺序绘制,我们都可以以很小的代价提前绘制好当前场景的深度缓存。那么在第二个pass时,early-z就可以用这个深度缓存中的值和当前深度值进行比较,只绘制深度相等的片元,任何其他的片元都可以直接丢弃,因此第二个pass要把深度比较函数设为“相等”。同时当前的深度缓存已经是完全正确的结果了,因此第二个pass也不需要对深度缓存做任何更新,便可以关闭深度写入。

z-perpass必须配合early-z才能发挥效果,如果没有early-z的话,第二个pass的深度测试依旧在片元后,因此所有片元都会在片元阶段进行复杂计算。z-perpass的思想和延迟渲染管线(defered render pipeline,下面也会提到)有些相似,差别在于:第一,z-perpass的第一个pass只计算深度,并且结果直接存储在深度缓存。而延迟渲染会同时计算更多其他的屏幕空间数据,并将这些数据存储在额外的framebuffer中,需要更大的缓存(也就是GBuffer)。第二,z-perpass的第二个pass依旧需要对全场景的各个物体进行绘制(至少顶点阶段是如此),而延迟渲染的第二个pass类似于后处理本质上只绘制了一个屏幕大小的矩形。

4. hi-z

hi-z全名Hierarchical Z,和z-perpass一样也是一种软件技术,据说这项技术最早是在《刺客信条:大革命》中使用的。其核心原理是利用上一帧的深度图和摄像机矩阵,来对当前帧的场景做剔除,对于剔除后的物体进行绘制新的深度图和GBuffer,然后再用新的深度图和当前摄像机矩阵再对当前帧的场景做剔除,对剔除后的物体进行绘制更新刚刚的深度图和GBuffer。之所这种看起来十分复杂的方法能提高效率,是因为每一帧的绘制都已上一帧的绘制结果为基础。我们假设相邻两针差距不会特别大,那么以上一帧的深度图作为结果来对当前帧可见的物体进行筛选,可以得到绝大部分。而对于少量两针不一样的物体,进行第二次深度绘制,由于第二次绘制的少量不一样的物体所带来的的计算量很小,因此可以带来性能上的提升。这种基于前一帧的迭代式的对场景物体进行剔除,便可以在一定程度上减少过度绘制。不过由于我也没有实现过这种算法,所以对这种算法实际带来的效果存疑。

值得注意的是,这里提到了Gbuffer,那么说明hi-z技术是基于延迟渲染管线。而延迟渲染管线本身也是在减少各种由其他原因(包括但不限于深度测试这个原因)导致的过渡绘制。其目的就是希望无论拥有多少模型多少光源,整个场景渲染的复杂度都O(1)。延迟渲染管线本身也是个庞大的话题,可能以后会结合Unity刚刚正式更新的Scriptable Render Pipeline也写点东西。

终于把这四种技术讲完了,除了这四种在名字容易让人混淆的技术外,其实还有一些东西没有提到。对于TBR(或者TBDR)架构的gpu,因为其提供了提前优化的潜能所以各家硬件厂商也会有自己独特的针对于过度绘制的优化,比如PowerVR的HSR(Hidden Surface Removal)和Arm的APK(Forward Pixel Kill)。这些技术可以配合early-z等技术来更高效的避免过度绘制。

本文转自:https://blog.csdn.net/yinfourever/article/details/109822330
转载此文目的在于传递更多信息,版权归原作者所有。

最新文章