浅谈HiZ-buffer
最近在做GPU-Driven Rendering Pipleline相关的技术,在整个pipeline中裁剪是其中非常重要的一环,基于GPU的遮挡裁剪也是众多裁剪算法的一种,它充分利用compute shader并行计算的威力,在加速遮挡查询的同时,可以降低查询的延迟。在实现基于GPU的遮挡裁剪时,我们会使用到一种称为Hierarchical Z-buffer的技术,他是整个遮挡查询的关键所在。那么什么是Hierarchical Z-buffer呢?它的优势又是什么呢?今天就简单解释一下HiZ-buffer的基本原理,在实际的使用过程中,虽然不同游戏使用了不同的优化方法,但是其核心的原理都是一样的。
我们假设如下图所示的场景,该图是横切面图,相机是从Z0看向Z1。下面我们就通过该例子来看下,如何使用Hierarchical Z-Buffer来将绿色的物体判定为被遮挡 ,从而将其裁剪掉。
上图中z = 0是近裁剪面,z = 1是远裁剪面。首先我们将遮挡物(红色和蓝色)进行光栅化,得到一个z-buffer,如下图竖着的那根灰色的线就代表了光栅化后的深度值。
接下来就是最重要的一步,下采样z-buffer,得到一串mipmap层级贴图(该mipmap层级图就称为Hierarchical Z-buffer,或者abbreviated HiZ-buffer)
在下采样的过程中,我们使用的是max操作,也就是说两个相邻的像素下采样为一个像素时,使用两者中最大的那个的值作为下一层级的值。如下图所示:
由上图可以看出,每一次下采样,都是对上一层级的保守估计,到了第4级就只剩下一个深度值了。由于下采样的时候用的是max操作,所以如果一个物体在level 2中深度值判定为被遮挡,那么它肯定在level 1中也是被遮挡的。
得到HiZ-buffer之后,我们就可以基于它来进行遮挡裁剪了:
计算得到绿色物体的AABB包围盒,该包围盒的x-max/min和y-max/min用来决定采样哪一层级的HiZ-buffer(也就是看哪一层级的尺寸能够涵盖包围盒的所有像素),在本例中该AABB包围盒符合level 2,所以我们选择采样level2,从而得到一个z-buffer的保守估计。接下来我们比较aabb.zmin跟我们采样到的深度值,得知aabb.zmin < z-buffer.sample,所以绿色物体是被遮挡的,应该被裁剪掉。
以上的方法就是基于Hierarchical Z-buffer的遮挡裁剪。可以看出如果没有HiZ-buffer,我们将不得不采样四个样本才能确定一个物体是否被遮挡了,HiZ-buffer大大减少了纹理采样的次数,提高了遮挡查询的效率。
我们在文章开头提到了基于GPU的渲染管线,现在该技术也是比较热门的一个概念,我在实际的工作中也将其用在了地形的渲染当中,如果后面有时间,会专门写一系列文章来谈一下GPU-Driven Rendering Pipeline。