1. 程式人生 > >Anti-alias的前世今生-常用反走樣演算法總結

Anti-alias的前世今生-常用反走樣演算法總結

Anti-alias,簡稱AA,在圖形學中廣泛地用於提升渲染質量。經過幾十年的發展,AA也從離線渲染逐步普及到了實時渲染的領域。本系列文章將總結一下在實時渲染中使用的AA方法的前世和今生。本片集中討論硬體提供的AA方法。

圖1. 一個畫素內部的取樣點。16個紅圈表示16個取樣點,藍色和黃色是覆蓋了這個畫素的兩個三角形。

SSAA

Super Sampling Anti-Aliasing是最直觀的一種AA方法。實現方法之一就是渲染一個大圖,然後downsample,這相當於在每個最終畫素內部做了一個均勻 分佈取樣。更通用的描述是,每個畫素分佈多個取樣點(可以均勻分佈、Poisson分佈、隨機分佈、抖動分佈等),每個取樣點都有獨立的color和 depth,pixel shader在每個取樣點都執行一遍。如圖1的情況,會得到1個白色,1個淺藍色和14個黃色的取樣點。最後這個畫素的值是這16個取樣點的平均,也就是 ((1, 1, 1) +  (0.77, 0.77, 1) + 14 * (1, 1, 0)) / 16 = (0.98, 0.98, 0.125)。在這些方法中,SSAA質量最好,畢竟是個最暴力的方法。在D3D 10.1+上可以選擇per-sample或者per-pixel執行pixel shader,也就是直接支援了SSAA。

效能統計(取樣數為N,下同):每個畫素裡PS執行次數為N,佔用空間N個color + N個depth。

MSAA

SSAA需要在每個取樣點都執行一次PS並儲存color和depth,時間和空間開銷都是驚人的。Multi-Sampling Anti-Aliasing的出現極大地改善了這點。MSAA在每個畫素只執行一次PS,輸出顏色寫入所有通過depth-stencil測試的取樣本 中。在Shader Model 3之前,PS的輸入一定取自畫素的中心;後來加入了centric插值,PS的輸入屬性就可以是三角形所覆蓋的所有采樣點的中心:

來自http://www.confettispecialfx.com/multisample-anti-aliasing

如圖1的情況,沒有centric插值的話,藍色三角形的兩個取樣點將都得到純藍的顏色(外差而得),最終畫素的顏色就是(2 * (0, 0, 1) + 14 * (1, 1, 0)) / 16 = (0.875, 0.875, 0.125)。有centric插值的話就是個更正確的淺藍色((1, 1, 1) + (0.77, 0.77, 1)) / 2 = (0.885, 0.885, 1),最終畫素顏色是(2 * (0.885, 0.885, 1) + 14 * (1, 1, 0)) / 16= (0.98, 0.98, 0.125)。如下圖所示:

效能統計:每個畫素裡PS執行次數為每個覆蓋到該畫素的三角形一次,佔用空間N個color + N個depth。

CSAA

MSAA雖然解決了計算的問題,但儲存量還是很大,尤其是取樣率到了8以上。NVIDIA在G80及以上的GPU增加了Coverage Sampling Anti-Aliasing的方法。CSAA解耦了color/depth的buffer和coverage的buffer,可以用較少的color /depth空間來儲存原先高取樣數才能得到的質量。比如圖1的情況,用CSAA 16x來渲染,就會把一個畫素分成左上、右上、左下和右下4塊區域,每塊區域有4個coverage取樣點,但共享同一個color和depth。對於圖 1的情況,結果就是,(0.25 * (0.885, 0.885, 1)  + 0.25 * (0.885, 0.885, 1) + 3.75 * (1, 1, 0)) / 4 = (0.98, 0.98, 0.125)。

效能統計:每個畫素裡PS執行次數為每個覆蓋到該畫素的三角形一次,佔用空間M個color + M個depth,M小於N。

總結

這三種方法是常見的硬體直接支援的AA方法,下篇文章將講述各種基於post process的AA方法。

上一篇文章Anti-alias的前世今生(一)介紹了硬體支援的AA方法,本篇將重點闡述新興的基於post process的AA。

SSAA、MSAA、CSAA這些方法雖然硬體直接支援,但帶來的額外開銷不可小視。一方面是它們對儲存空間帶來的衝擊是驚人的。尤其在非桌面平臺 上,記憶體本來就不多,如果還需要AA的話就吃不消了。如果同時使用了MRT和AA,視訊記憶體開銷更是天文數字。另一方面,這些方法對“edge”的考量都是 primitive的邊界,不管這個edge是否真的需要AA,所以會浪費很多計算量。

GPU Gems 2的第九章Deferred Shading in S.T.A.L.K.E.R.在 遊戲界第一次宣傳了Deferred Shading的概念,同時也提到了Deferred框架無法使用硬體MSAA的問題。雖然Deferred Lighting部分解決了該問題,但再次渲染一邊場景的代價還是不小的。更重要的是,由於Deferred框架的引入,人們終於開始正視MSAA的實際 上造成了很多時間和空間的浪費。於是乎這幾年基於post process的AA蓬勃發展,大有取而代之的氣勢。

Edge AA

Edge AA就是Deferred Shading in S.T.A.L.K.E.R提出的方法,根據鄰居的depth和normal的差異程度做一個邊緣檢測,每個畫素可以得到一個權重,表示“像邊緣的程度”:

根據這個權重,就可以需要做反走樣的buffer把鄰居畫素的顏色拿來插值,得到AA的效果。具體shader可以參考點選開啟連結

在GPU Gems 3第19章Deferred Shading in Tabula Rasa中,NCsoft對Edge AA做出了一些小改進,邊緣檢測不再依賴於影象解析度,更加穩定。

Directionally Edge AA

Edge AA開創了post process AA的時代,但它的質量還是不足以與硬體AA抗衡的程度。AMD在HPG09上的論文A Directionally Adaptive Edge Anti-Aliasing Filter改 進了Edge AA,不再採用獨立的edge點來決定AA混合的方式,而是根據edge點周圍的狀況確定出isoline,然後根據isoline的垂直方向來確定混合 的方向。這樣一個邊界就會沿著朝向來混合,還原出更加精確的sub-pixel資訊。這種方法進入了AMD的驅動,只要開啟Adaptive AA就會自動啟用。

MLAA

Adaptive Edge AA提出了以線代替點的研究方向,但isoline的計算量畢竟比較大,啟用了之後對渲染效能下降明顯。Morphological Antialiasing再次在這個方向作出了努力。它不計算isoline,而是把edge分門別類,總結成Z、U、L等幾種特定的形狀,而Z和U都可 以分解成L。

最終根據L劃出一個三角形,確定混合區域。這樣就省去了所有繁重的計算,提高AA速度。在AMD較新的驅動裡,MLAA取代了Directionally Edge AA成為Adaptive AA的首選。MLAA的框架又派生出多個不同的方法:

CPU MLAA

Intel在HPG09上的Morphological Antialiasing一文是在CPU上實現的。程式碼用了非常深的分支來判斷edge形狀,完全是針對CPU優化的,不適合GPU硬體,也不適合實時渲染的情況。

GPU MLAA

SIGGRAPH 2010 poster的Practical morphological antialiasing on the GPU, 通過建立SAT來判斷edge形狀,需要log(width)+log(height)個pass。在確定了L之後,需要查詢一個預計算的512×512 R32F的紋理,裡面每個texel對應了一個特定大小的L所需要混合的面積。也就是邊長最大是512個畫素。可以看出這種方法非常暴力,雖然可能比讀回 CPU快,但開銷還是很大。

Jimenez’s MLAA

GPU Pro 2裡的文章Practical Morphological Anti-Aliasing提出了一個更實用的GPU MLAA方法,命名為Jimenez’s MLAA以 示區分。在這種MLAA裡,Z和U不需要分解成更簡單的L,直接用一個預計算的表來做查詢。每個畫素根據自己在形狀裡的位置在查詢表裡尋找需要混合的各個 畫素。720p的解析度下,這種方法在一般的情況下能達到Xbox 360上3.79ms,Geforce 9800 GTX+上0.44ms。同等條件下8x MSAA需要5ms。

FXAA

NVIDIA在Graphics SDK 11裡 面提供了一個稱為Fast Approximate Anti-Aliasing的方法。該方法很接近於MLAA,但只識別長邊,而不識別形狀。有了長邊之後,就可以根據邊和畫素的求交來估算每個畫素中 sub-pixel的覆蓋率,並進行AA混合。後來Timothy Lottes還發展出了FXAA II,質量有所下降,速度提高了,在Xbox 360上,720p的解析度可以做到2.0ms。

DLAA

另一個在GDC11上公開的AA方法稱為Directionally Localized Anti-Aliasing(前面介紹的Jimenez’s MLAA和FXAA也在GDC11的時候公開的,這也扎堆)。這種方法比較另類,它在垂直方向模糊後的影象上做水平方向邊緣檢測,得到的結果blend回去就得到AA後的影象。

左圖為AA之前的,右圖是經過DLAA的

DLAA還是比較快的,在Xbox 360上,720p需要2.2ms。

本篇介紹了幾種基於post process的AA方法,下一篇講討論如何把硬體AA和post process AA結合起來。

上篇文章講述了幾種基於post process的AA方法,有沒有可能將post process AA和hardware AA結合起來呢?本篇要講的正是這樣的hybrid AA。

首先補充一下,對於MSAA的計算浪費,可以從下面的對比圖看出來:

MSAA需要計算的edge

真正需要計算AA的edge

有了這個對比,大家應該有了直觀感受,MSAA實際上把很多計算量浪費在了實際上不必要AA的畫素上了。如果樣本數高,浪費會更嚴重。

上一篇提到的那些基於post process的方法其實都在做一件事情:試圖通過pixel資訊估計出sub-pixel級別的幾何,然後做AA。Edge AA是通過獨立點來估計,MLAA是通過L形來估計,FXAA和DLAA是通過線段來估計。Hybrid AA的方法想表達的是,為什麼要“估計”,而不是乾脆就先存出sub-pixel的幾何?

SRAA

Subpixel Reconstruction Anti-Aliasing是 NVIDIA的研究員在I3D2011上發表的新方法。它寄予的事實是,shading的變化頻率一般低於幾何的變化頻率,所以可以在較低解析度上 shading,而用較高解析度恢復幾何。SRAA的基本流程為,在Deferred Shading的框架中,渲染一個高解析度(或者帶MSAA)的G-Buffer,但在shading的時候僅在普通的解析度(或者沒有MSAA)的情況 下做。累積的結果通過G-Buffer重建sub-pixel資訊,來進行類似MLAA的AA計算。這種方法結合了MSAA和MLAA,但可以用較低的樣 本數做到較高的MSAA才能得到的效果,同時不增加shading的計算量。SRAA由於原理問題,只能用在Deferred框架中(不過對於現代的遊戲 來說這不是個大問題)。

GPAA

Geometric Post-process Anti-Aliasing是Humus獨立提出來的AA方法。基本思路是在渲染幾何之後在此用線框模式渲染一遍,這時候可以得到每個三角形在每個pixel的覆蓋率:

通過這個覆蓋率,計算AA就輕而易舉了,結果比較如下:

這種方法的代價是多了一遍線框渲染,但可以用於Forward和Deferred兩種框架。杯具的是,Humus的twitter上說這種方法實際上在1996年就被別人申請專利了。

Adaptive AA

Intel在SIGGRAPH 2010的course Deferred Rendering for Current and Future Rendering Pipelines上 提到了一種很簡單很暴力的AA方法,在edge的地方per-sample計算,在non-edge的地方per-pixel計算。和基於post process的方法一樣,這需要執行一個邊緣檢測,並在stencil中標記出來,然後就可以分別計算了。下圖中紅線標記的地方就是檢測出來的 edge:

這種方法的結果會和SSAA一樣,同時沒有MSAA重複計算的毛病。

五點梅花排列法(Quincunx):

最後介紹一種很神卻很簡單的反鋸齒演算法……

五點梅花排列法也要做取樣運算,但它只需要建立一份等尺寸的記憶體副本,降低了空間複雜度。那麼五點梅花排列法如何取樣呢,大家看下面兩幅圖就明白了:

  沒錯,就是這麼簡單。原場景按常規做3D繪製,完成後投影到幀緩衝,額外再投影一份到副本記憶體。然後其中一份影象沿著鏡頭的橫縱軸向做平移後,開始做取樣計算,逐畫素重新整理該幀影象。該演算法的反鋸齒效果直逼四倍解析度反鋸齒運算。

 



總結

Hybrid AA綜合了hardware AA和post process AA的優點(或者說,缺點)。優點是可以用低於hardware AA的記憶體開銷和計算量達到一樣的效果。缺點是需要修改原有的圖形渲染流水線。

本系列總結了三類不同的空間AA方法,希望對大家有所幫助。