切換
舊版
前往
大廳
主題

Bokeh(2)

Lumi | 2017-07-28 22:06:50 | 巴幣 4 | 人氣 298

由於對上一篇的結果還是不怎麼滿意,就在認真考慮實作Scatter法的時候找到了CryENGINE 3 決勝時刻:先進戰爭的投影片,這才發現Bokeh特效的眉角數一數二的多,對於Gather法還有許多改善的技巧可以用。上回的Bokeh實作只有三個步驟,這回增加到七個,複雜程度不只倍增,差點生不出來。不過還是照慣例只簡單敘述新的處理步驟:

1. 計算CoC
在儲存CoC用的texture中,增加了儲存光線擴散後的衰減程度。

2. Downsampling
Physically based rendering會在極端角度下反射回能量極高的光線,造成物體邊緣的某幾顆像素特別亮,攝影機可能只需移動不到一個像素寬就能造成像素閃爍。而Bokeh計算需要將原始的HDR圖片縮小成1/4大小,移動攝影機時同樣也容易造成閃爍。尤其Bokeh效果會把原本細小的亮處擴大,使得閃爍非常明顯。

▲攝影機只是稍微退後,某些亮處就改變了

由上圖可以看出,模糊範圍比起上回的實作還要大許多,這也使得閃爍明顯到讓人很煩躁,因此這回特別加了downsampling步驟。為了計算1/4 texture中的每個像素,得對原始圖片做13次採樣。另外在縮小CoC texture時,為了避免瑕疵而選擇半徑最大的像素。



▲改善後Bokeh的結果相當穩定

3. Tile CoC
將CoC以20x20像素為單位切割成許多Tile,找出Tile中最小與最大的CoC,計算結果會用於下個步驟決定採樣的半徑。在CryEngine與先進戰爭的投影片中雖然只有簡單敘述,但要讓最後的畫面不會看到一塊一塊的Tile還得下許多功夫。

4. Main Pass
上回的採樣點座標是先用C++計算出來,將座標寫死在shader內,這回改成在shader內即時計算。使用同心圓式7x7次的採樣,但修改演算法使採樣形狀變成六邊形,光圈值離f/8越遠越接近圓形,同時形狀會稍微旋轉。
▲從上到下依序為f/8、f/4、f/2

另外加了些上回沒考慮到的要素,光線擴散後的能量會隨著CoC的半徑衰減,靠近攝影機的物體較能遮蔽遠處的物體,還有背景重建(background reconstruction)。另外把前景與背景都輸出到同一張圖上,降低一點記憶體用量。

▲無背景重建,只計算比目前像素還靠近攝影機的採樣點

▲加入背景重建

5. Prefilter
6. Median filter
步驟5和6是作為取代上回的LOD法的對策,上回對main pass生出的1 / 4大小texture做mipmap,使用更低解析度的像素只會讓畫面品質降低,而且採樣半徑越大就得用越低的解析度來彌補採樣數不足的問題。這回增加的prefilter步驟會做一次3x3採樣的模糊,接著的median filter也是做3x3採樣,但是取中位數(median),用來填補各採樣點中的空隙。

▲Main pass後若不做任何改善


▲Prefilter + Median filter
7. Combine
增加了Tile CoC之後,前/背景的weight計算還得考慮採樣半徑大小,才能順利和中景合併。放大Bokeh結果至視窗大小時使用了GPU Gems 2的Bicubic Filter,但偶爾還是會出現惱人的鋸齒。

▲最後結果


為了改善許多小細節的品質,這Bokeh從原本不便宜的特效變成超昂貴的特效,現在超想換新顯卡...。接下來還想弄反鋸齒,以前的OpenGL程式是用FXAA,但它和PBR不怎麼合。現在最常見的反鋸齒方法又超複雜的,搞不好下一篇又要難產了。

創作回應

更多創作