宋曉峰
(四川大學(xué)計(jì)算機(jī)學(xué)院,成都 610065)
半透明物體的實(shí)時(shí)渲染是計(jì)算機(jī)圖形學(xué)中的重要研究課題之一,在游戲、虛擬現(xiàn)實(shí)、仿真模擬等領(lǐng)域有著重要應(yīng)用。傳統(tǒng)的半透明物體渲染算法需要根據(jù)到攝像機(jī)的距離對半透明物體進(jìn)行排序,然后由遠(yuǎn)到近依次進(jìn)行繪制,然而當(dāng)多個(gè)半透明物體之間遮擋關(guān)系比較復(fù)雜,或者單個(gè)半透明物體自身包含多層半透明面片時(shí),這種傳統(tǒng)方法不能得到正確的結(jié)果。為了解決這一問題,通常需要使用次序無關(guān)透明(Order Inde?pendent Transparency,OIT)渲染算法。
精確的OIT 算法一般使用深度剝離[1]或鏈表[2]來做像素級別的片元排序,雖然能夠得到精確的結(jié)果,但是效率低下且顯存消耗高。近年來,為了提升效率或節(jié)省顯存,一些啟發(fā)式OIT 算法相繼出現(xiàn)?;贙-Buf?fer 的OIT 算法[3-4]能夠有效控制顯存的消耗,但是對于存在大量半透明物體的復(fù)雜場景表現(xiàn)較差?;诩訖?quán)混合的OIT 算法[5-6]效率較高且易于實(shí)現(xiàn),但是結(jié)果存在很大誤差?;诰氐腛IT 算法[7-8]使用矩信息來重建透射率函數(shù),能夠取得較好的近似結(jié)果,但是由于存儲(chǔ)矩信息需要使用較高的精度,因而對顯存的消耗仍然較高。
本文提出了基于傅里葉級數(shù)的OIT 算法,此算法借鑒了Fourier Opacity Mapping(FOM)一文[9]中的算法思想,即使用傅里葉級數(shù)來近似半透明物體對光的吸收率函數(shù)。同時(shí),本文提出使用Lanczos-Local-Type σ-Averaging(簡稱σ-Averaging)方法[10]對FOM 的傅里葉近似方法進(jìn)行改進(jìn),很大程度地降低了Gibbs 效應(yīng)的影響。實(shí)驗(yàn)表明本文提出的OIT 算法可以得到較為準(zhǔn)確的結(jié)果,同時(shí)具有較高的效率和較低的顯存消耗,具有較大的實(shí)際應(yīng)用價(jià)值。
給定同一像素坐標(biāo)下的n個(gè)片元,片元顏色依次為l0,l1,…,ln-1,片元透明度為α0,α1,…,αn-1,片元深度為z0,z1,…,zn-1,則對所有片元進(jìn)行顏色混合之后的結(jié)果L可以使用公式(1)計(jì)算得出。
其中,T(z)是透射率函數(shù),表示從深度z處發(fā)出的光線,在穿過半透明物體之后,最終到達(dá)攝像機(jī)的光線的占比,其計(jì)算方法如公式(2)所示。從公式(2)可以看出,為了計(jì)算透射率,需要知道一個(gè)片元被其他片元的遮擋情況,這通常需要存儲(chǔ)片元的深度值,并對片元按照深度值排序之后依次進(jìn)行混合計(jì)算,因而直接使用公式(2)計(jì)算透射率的算法往往具有高昂的顯存消耗與計(jì)算代價(jià)。
為了能夠更加高效地計(jì)算透射率,本文算法使用了傅里葉級數(shù)的前m(m∈N*)項(xiàng)和來近似透射率函數(shù)T(z),計(jì)算方法如公式(3)所示。
其中Ak與Bk為傅里葉級數(shù)的系數(shù),其計(jì)算方法滿足公式(4)與公式(5)。公式(3-5)的具體證明過程可以參考Fourier Opacity Mapping 一文[9]。
相較于片元排序方法,使用傅里葉級數(shù)近似透射率函數(shù)的好處包括兩點(diǎn):①透射率的計(jì)算不依賴于半透明片元的執(zhí)行順序,不再需要對片元進(jìn)行排序,因而效率更高;②由于不需要對片元排序,因而不需要存儲(chǔ)片元深度及其材質(zhì)信息,作為替代,存儲(chǔ)的是具有更低顯存消耗的傅里葉級數(shù)系數(shù),因而節(jié)省了顯存消耗并降低了讀寫顯存的時(shí)間代價(jià)。
使用傅里葉級數(shù)來近似透射率函數(shù)會(huì)產(chǎn)生Gibbs效應(yīng),該效應(yīng)主要發(fā)生在透射率函數(shù)的階躍點(diǎn)附近,表現(xiàn)出明顯的過沖與下沖(如圖1 中綠色曲線所示),從而導(dǎo)致計(jì)算得到的透射率存在較大的誤差且波動(dòng)較大。為了減小誤差,本文采用了σ-Averaging 方法,該方法為傅里葉級數(shù)添加了一個(gè)σk系數(shù),能夠明顯地減弱Gibbs 效應(yīng)的影響(如圖1 中紅色曲線所示),σk系數(shù)滿足公式(6)。
圖1 Gibbs效應(yīng)以及σ-Averaging效果示意圖
在結(jié)合σ-Averaging 方法之后,本文使用公式(7)來計(jì)算透射率。
其中指數(shù)p∈R*用于調(diào)整σk的影響強(qiáng)度,p值越大,Gibbs 效應(yīng)越弱。然而p值過大時(shí),會(huì)導(dǎo)致階躍點(diǎn)處曲線過于平緩,反而會(huì)增大誤差。本文算法采用p=1.0,可以大大減弱Gibbs 效應(yīng)的影響,同時(shí)階躍點(diǎn)附近的誤差也可以接受。
本文渲染算法的實(shí)現(xiàn)分為以下四個(gè)步驟:
步驟1:渲染場景中的不透明物體,將渲染結(jié)果保存到紋理Tex0 中。此步驟中不透明物體的渲染可以使用任意渲染算法來實(shí)現(xiàn)。
步驟2:渲染場景中的半透明物體,結(jié)合公式(4)與公式(5),為每個(gè)像素計(jì)算傅里葉級數(shù)的系數(shù),并將系數(shù)值保存到紋理Tex1 中。由于每個(gè)像素都單獨(dú)對應(yīng)一個(gè)透射率函數(shù),因而每個(gè)像素都需要做一次傅里葉級數(shù)展開近似,即像素間的傅里葉級數(shù)系數(shù)相互獨(dú)立,需要分開保存。
對于單個(gè)像素而言,需要遍歷該像素下的所有片元,計(jì)算每個(gè)片元對傅里葉級數(shù)系數(shù)的貢獻(xiàn)量,即:
然后將每個(gè)片元的貢獻(xiàn)使用Blend One One 的方式累加到紋理Tex1 中,便可得到該像素下的最終系數(shù),即公式(4)與公式(5)的計(jì)算結(jié)果。
注意在步驟2 執(zhí)行渲染前需要關(guān)閉深度寫入與背向面剔除,這樣才能保證所有半透明片元不被丟棄。此外,由于此步驟執(zhí)行渲染只是為了計(jì)算傅里葉級數(shù)的系數(shù),因而無需進(jìn)行光照計(jì)算等任何無關(guān)操作,從而保證算法的高效性。
步驟3:再次渲染場景中的半透明物體,對于每個(gè)像素的每個(gè)片元,讀取步驟2 中生成的紋理Tex1。
使用公式(3)計(jì)算透射率,然后使用公式(1)計(jì)算該片元對像素顏色的貢獻(xiàn),即:
然后將每個(gè)片元的貢獻(xiàn)使用Blend One One 的方式累加到紋理Tex2 中,便可得到該像素下的最終顏色,即公式(1)的計(jì)算結(jié)果。注意此步驟與步驟2 類似,在執(zhí)行渲染前同樣需要關(guān)閉深度寫入與背向面剔除。
步驟4:讀取紋理Tex0 與Tex2,將兩張紋理顏色進(jìn)行合并,即可得到最終的渲染結(jié)果。紋理顏色的合并計(jì)算方法如公式(11)所示。
其中Ctrans是半透明物體的顏色,存儲(chǔ)在Tex2 紋理的RGB 通道中;Copaque是不透明物體的顏色,存儲(chǔ)在Tex0 紋理的RGB 通道中;K是為了歸一化而引入的項(xiàng),存儲(chǔ)在Tex2 紋理的Alpha 通道中,K的計(jì)算滿足公式(12)。
Ttotal是總透射率,滿足公式(13)。
本文實(shí)驗(yàn)所使用的硬件為NVIDIA GeForce GTX 1060 3GB GPU 以及Intel Core i5-7400 CPU。實(shí)驗(yàn)結(jié)果的渲染分辨率均為1600×900。
圖2 展示了原函數(shù)較為復(fù)雜的情況下σ-Averaging方法的效果,圖中綠色曲線是使用公式(3)做傅里葉級數(shù)近似的結(jié)果,紅色曲線是結(jié)合σ-Averaging 方法之后,即使用公式(7)做傅里葉級數(shù)近似的結(jié)果??梢钥闯觯?Averaging 方法明顯地削弱了Gibbs 效應(yīng),與原函數(shù)更加接近。
圖2 σ-Averaging方法效果示意圖(m=16, p=1.0)
表1 給出了使用與不使用σ-Averaging 方法這兩種情況下的傅里葉級數(shù)近似結(jié)果的誤差,誤差采用RMSE(Root Mean Squared Error,均方根誤差)作為衡量標(biāo)準(zhǔn)。從表1 可以看出使用σ-Averaging 方法的誤差明顯更低,且當(dāng)m取值較小時(shí),使用σ-Averaging 方法的優(yōu)勢更為明顯。注意由于OIT 算法只需要使用階躍點(diǎn)處的透射率,因而此實(shí)驗(yàn)中計(jì)算RMSE 時(shí)只考慮了階躍點(diǎn)。
表1 使用σ-Averaging 與不使用σ-Averaging 兩種情況下的傅里葉級數(shù)近似結(jié)果的誤差對比
此實(shí)驗(yàn)對比了WBOIT 算法[5]、MBOIT 算法[7]以及本文算法的渲染結(jié)果,實(shí)驗(yàn)中使用基于鏈表的OIT 算法[2]作為參考標(biāo)準(zhǔn),并使用RMSE 用于衡量渲染結(jié)果的誤差。本文在WBOIT 對比算法的實(shí)現(xiàn)中使用了Mc?guire 等人于2017 年提出的新的加權(quán)混合公式[6],在MBOIT 對比算法的實(shí)現(xiàn)中使用了四階矩。本文算法的實(shí)現(xiàn)中使用了傅里葉級數(shù)的前四項(xiàng),即m=4。
從圖3 可以看出,WBOIT 算法的渲染結(jié)果存在明顯的錯(cuò)誤,誤差較大。MBOIT 算法與本文算法的誤差較小,渲染結(jié)果與Ground-Truth 算法之間沒有明顯的差別。雖然MBOIT 算法的誤差小于本文算法,但是其顯存消耗更大且效率更低(見表2~5)。圖4 對比了渲染復(fù)雜模型時(shí)不同算法的渲染效果與RMSE,可見WBOIT 算法的誤差仍然最大,MBOIT 算法與本文算法的誤差相近。(算法性質(zhì)決定了MBOIT 算法在片元數(shù)目n取值較小時(shí)具有更小的誤差,n取值較大時(shí)其誤差與本文算法相近)。
圖3 不同算法的渲染結(jié)果對比
圖4 不同算法的渲染結(jié)果對比(復(fù)雜模型)
表2-表5 給出了不同場景下四種算法渲染一幀消耗的時(shí)間以及每個(gè)像素需要使用的顯存。實(shí)驗(yàn)使用了如圖5 所示的四組不同場景。從表中可以看出在不同場景下,本文算法的渲染用時(shí)與顯存消耗均僅高于WBOIT 算法,相比MBOIT 算法具有明顯優(yōu)勢。
表2 渲染效率與顯存消耗對比(場景1)
表3 渲染效率與顯存消耗對比(場景2)
表4 渲染效率與顯存消耗對比(場景3)
表5 渲染效率與顯存消耗對比(場景4)
圖5 實(shí)驗(yàn)所用場景示意圖
本文給出了一種實(shí)時(shí)的次序無關(guān)透明渲染算法,該算法使用傅里葉級數(shù)近似透射率函數(shù),并使用σ-Averaging 方法來減弱Gibbs 效應(yīng)。實(shí)驗(yàn)表明,本文算法既有較好的效果,又有較低的計(jì)算代價(jià)與顯存消耗,適用于實(shí)時(shí)渲染領(lǐng)域,具有很大的實(shí)際應(yīng)用價(jià)值。在未來的研究工作中,具有前景的改進(jìn)方向之一是尋找一組更合適的基函數(shù)來取代傅里葉基(例如使用小波基),可能進(jìn)一步提高算法的精確度,或者減少存儲(chǔ)消耗。