可见性算法的目的是丢弃隐藏面,
对于GPU可以节省CPU传入顶点信息的带宽&顶点ALU&Fragment ALU的消耗,
对于CPU可以减少DC(物件被剔除了)
有三种方式可以实现可见性算法
1.object-space coherence:
物件级别的剔除,粒度最大
传统Ray casting剔除就是这种方法
2.image-space coherence
屏幕空间像素级别剔除,粒度最小
传统ZBuffer剔除就是这种方法(Zbuffer的缺点包括不支持半透明剔除,因为半透明不写入深度。并且需要ZPrePass,会增加DC)
3.temporal coherence
是利用上一帧的可见性信息,来加速这一帧的可见性运算
Greene93论文中的提出方法利用了上面三种方式
利用八叉树空间细分 octree spatial subdivision ray tracing来做到object-space coherence剔除
将物件放入八叉树中,在视椎体中进行相交测试,如果相交,我们再把物件primitive细分,然后递归进行相交测试,把通过测试的primitive提交DrawCall
利用Z pyramid Z金字塔来做到image-space coherence剔除
首先ZPrePass画出一张ZBuffer原始分辨率的,再对这张Zbuffer进行降采样来构建Mip Chain,但是不能利用GL默认的生成MipChain方法,每小一个级别相当于4个像素变一个像素,我们需要选择四个像素中Z最远的像素
作为当前mip级别的像素,
个人理解:构建一套mipchain,相当于对屏幕划分不同大小的Tile,
先选取最粗级别的mipmap,也就相当于最大的Tile
先将polygon的每个顶点选取最近的顶点(Greene93中的方法2)与该Tile像素作比较,就相当于polygon最近的顶点与这个tile中最远的像素作比较,如果polygon最近的顶点都比整个tile中最远的深度还要远,就说明整个Polygon都是隐藏的,都在别人后面
如果在前面,就换上一级别粒度更小的进行测试,直到原始Zbuffer(mip0)
为什么要生成mipmap不直接用原始ZBuffer比较呢?
因为有大量Polygon连最粗级别mip都不会通过,而且粗级别mip分辨率低,要比原始分辨率省(带宽?)
Greene93中的方法2就是将每个polygon中最近顶点与Z比较
Greene93中的方法1是需要算出每个polygon在每个mip级别也就是一个Tile的大小中的最近深度(也就是一个像素的大小)进行比较,
方法2比方法1粒度更细,剔除精度更高,但是算出每个polygon在每个mip级别一像素范围中的最近深度也很昂贵,需要按需选择
该方法一般用compute shader将polygon信息传入Buffer,得出运算结果后返回可见的Polygon给CPU,在进行DC提交
如果用GPU Driven可以直接用于GPU剔除
The overhead of generating the HiZ mip chain and dispatching the culling process is the real bottleneck though, there’s little difference between 900 bounds and 10,000 bounds.
https://www.nickdarnell.com/hierarchical-z-buffer-occlusion-culling/
该方法最昂贵的地方在于降采样mipmap(需要采样作比较),和剔除的部分
文中维护了上一帧的visible octree node列表用于这一帧的可见性算法
好处:
If there is sufficient frame-to-frame
coherence, most of the visible geometry will already be rendered,so the Z-pyramid test will be much more effective than when we start from scratch.
所以文中方法的一套流程就是
1.进行octree spatial subdivision ray tracing,并利用上一帧visible octree node结果加速次运算,粗粒度的先剔除物件与部分polygon
2.然后用Z pyramid进行细粒度的剔除,cs返回一个可见polygon的buffer
3.CPU提交DC
两种方法都有消耗多的地方
octree spatial subdivision
需要花费CPU时间进行细分与相交测试
Z pyramid
需要ZprePass 增加一倍DC
降采样增加带宽,增加GPU ALU消耗
需要ReadBack Zbuffer,“Z Query”,使CPU等待GPU计算结果,并且增加TileMemory->SystemMemory读回带宽开销,,但是如果使用 GPU Driven,在GPU中剔除&提交DC,就不会有这个问题
如果遮挡关系不是那么复杂,如果不能剔除很多东西,使用这种方法权衡利弊
参考:
Hierarchical Z-Buffer Visibility(Siggraph 1993)
https://www.nickdarnell.com/hierarchical-z-buffer-occlusion-culling/
------wolf96 2019/9/15