最近在做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。