液體渲染:一種屏幕空間方法

液體渲染:一種屏幕空間方法

341 人贊了文章

本文介紹一種液體粒子模擬的屏幕空間渲染(Screen Space Fluid Rendering, 簡稱SSF)[1]方法。這種方法沒有Mesh重建的過程,實現簡單而高效,在遊戲等對實時性有嚴格要求的領域中有廣泛的應用前景。

幾天前看到了西半球飯桶實現的基於位置的流體(Position Based Fluids),原答案沒有做粒子液體的表面的重建。恰巧我最近以學習管線渲染和初嘗模擬演算法為契機,也對這篇論文做了復現,本文是對粒子模擬渲染部分的補充。

https://www.zhihu.com/video/993905167569403904


傳統方法

計算機圖形學中,歐式網格和拉氏粒子是兩種主要的流體離散方法。無論是哪一種方法,都需要先重建液體表面,再進行渲染著色,以得到最終圖像。(液體外的其他流體各有渲染方法,如渲染煙霧可用體渲染。在此不談)

液體表面重建,直到近幾年以前,一直是移動立方體方法(Marching Cubes)[3]的天下。移動立方體法發表距今已經有30年了。這種方法使用了水平集(Level Set)的思想(水平集可以理解為高維上的等高線),將液體表面定義為液體密度等於某個小常數C的點集。Marching Cubes方法將空間離散為等大的立方體網格,檢查每個網格上8個頂點的液體密度情況。

論文[3]中的15種頂點和重建形態

若網格上一條邊的兩個端點密度值跨過閾值C,則演算法認為這條邊上存在一個表面Mesh的頂點。上圖中,被標記的頂點密度大於C,否則小於C。將每個網格構造的多邊形拼接,即可得到整個液體表面的Mesh。油管上有一個很棒的演示動畫,把構造表面的過程可視化為一個立方體在空間中掃描的過程。可以理解演算法名字中「移動(Marching)」一詞的來歷。(視頻版權受限,無法搬運,抱歉!)

歐式流體天生就是網格模擬,可以直接應用Marching Cubes。對粒子形態的拉式流體,空間中一點的密度是通過周圍粒子攜帶的密度值計算得到的。最常使用的SPH方法將粒子表達為有限半徑空間內的質量分布 m=int{W(m{r})dV}, quad{Vert m{r} lt h Vert} ,半徑h稱為核半徑。

圖片來源Neutrino-SPH Dynamic Simulation System[4]

直接使用SPH計算密度重建得到的液體表面會有很強的粒子感。Adam等人提出使用流體的局部區域信息重構粒子數量和大小,Yu等人提出使用在液體不同區域使用橢球形的粒子替代球形粒子,都取得了很好的重建效果。可以看到,液體平靜的表面基本不再有粒子狀的偽像(artifact),浪尖等細節處也被還原得更加精細。

左:球形粒子,右上:Adam,右下: Yu

屏幕空間渲染

傳統方法的效果優良,但是實現麻煩,複雜度高。例如Yu的方法,不僅使用了PCA處理粒子形狀的變換矩陣,還需要為渲染重建一次鄰居搜索哈希網格,代價比較高昂。

屏幕空間渲染(Screen Space Fluid Rendering, 簡稱SSF)則給出了粒子渲染的一種新思路。這個演算法不涉及液體網格表面的匹配和重建,實現相對簡單得多。在不追求全局光照的實時管線渲染應用中,它的效果還比較令人滿意。這個演算法也是Position Based Fluids原論文中使用的渲染演算法。

粗略地講,屏幕空間渲染首先利用Point Sprite渲染粒子,將液體在屏幕空間的深度和厚度記錄在兩張二維紋理上。深度紋理記錄了屏幕上某點的液體表面到攝像機的距離,厚度紋理記錄了表面之下液體的厚度。然後對深度紋理進行平滑,並從平滑後的深度紋理中還原表面法線。得到法線後便可以計算反射/折射,對錶面進行最終的著色了。

渲染用紋理和流程

深度紋理

深度紋理是整個演算法的核心。深度指的是液體表面到攝像機的距離。我們使用的是Y軸向上的攝像機,則深度可以認為是被渲染物理的Z坐標。渲染時,開啟深度測試,這樣我們就能保證處於表面的粒子覆蓋內部的粒子。

深度紋理。越白距離攝像機越遠

深度紋理是使用Point Sprite渲染的。所謂Point Sprite,就是將粒子以Point形式渲染,這樣會將粒子渲染成一個正方形。為了渲染成圓形,在Fragment Shader中讀取PointCoord,discard圓以外的像素即可。同時要注意以下兩點

  1. 要在Vertex Shader中根據粒子深度正確地計算並設置Point大小,以符合透視規律。
  2. 要反應球形粒子不同位置的深度差異,因此需要結合粒子位置和PointCoord計算深度值。

厚度紋理

厚度紋理記錄了表面下液體的厚度。著色時考慮液體厚度,能夠增加液體的層次感。根據Beer-Lambert定律,約厚的液體透光率越低。

厚度紋理。越白越厚

厚度紋理也是利用Point Sprite渲染的。與深度紋理一樣,也需要根據粒子深度調整渲染Sprite的大小。不同的是,渲染時關閉深度測試,開啟加法混合,從而使得重疊的粒子厚度能夠疊加。同時,要根據PointCoord正確地計算每個像素的厚度值,反應球形粒子四周薄,中間厚的特點。

法線還原

得到深度紋理就可以還原表面法線了。法線儲存在一張RGB三通道24bits的二維紋理上。

三維空間中的參數曲面 m{P}(s,t)=(x,y,z) 上一點的法向量可由公式 m{n}=frac{partial{m{P}}}{partial s} 	imes frac{partial{m{P}}}{partial t} 給出。實際上,兩個偏導給出了切平面上的兩個不平行的向量,因此叉乘可以得到這個平面的法向量。

紋理坐標就是曲面參數。已知攝像機參數,又可以從紋理坐標可以還原液體表面X,Y坐標,同時紋理中記錄了Z坐標,因此可以利用公式計演算法線。偏導使用使用一階差分計算

frac{partial{m{P}}}{partial s} approx min ( m{P}(s+Delta s,t), m{P}(s-Delta s,t))

上面的近似取了前向差分和後向差分的較小值。這是因為深度紋理上有許多深度不連續的地方。使用單獨使用前向或後向差分都會導致不正確的結果。

深度不連續處的差分處理。左:錯誤的法向量還原,右:正確的法向量還原

法向量重建結果。三維坐標映射到RGB

可以發現法線紋理的粒子形狀分明。這當然不是我們所希望的。因此有必要先對深度紋理進行平滑,再從平滑後深度中重建法向量。

直接平滑法向量也是一種可行的做法。但因為粒子的深度信息未變,而計算著色時,需要使用粒子位置做光線追蹤操作,因此會損失一些精確性。另外,因為法向量是三維的,而深度是標量,平滑法向量的計算量也比較大。

深度平滑

沒平滑的直接渲染得到的畫面會有很強的粒子感。

無平滑的最終渲染結果

我們可以使用雙邊濾波(Bilateral Filtering)先對深度紋理進行平滑。雙邊濾波可以很好的保留深度的不連續性。其他一些模糊演算法,例如高斯模糊,則會錯誤地把本在兩個不同深度的表面模糊成一塊。

平滑深度紋理。左:高斯模糊,右:雙邊濾波

雙邊濾波是一個複雜度為 O(r^2) 的演算法,r是平滑半徑。測試中發現,當r大於15個像素的時候,就會對實時性產生顯著影響了。然而,粒子大小常常不止15像素。一種方法是,使用雙邊濾波演算法的一次近似,[2]中有描述。但這種方法會帶來一些Artifact。因此我採用的方法是使用小平滑半徑平滑多次,從而以較小的複雜度近似達到大平滑半徑的效果。

平滑後法線。左:平滑後,右:平滑前

表面著色

有了深度紋理,可以還原每個像素在攝像機空間的坐標。有了法向量紋理,可以計算著色。我們綜合考慮液體表面的折射和反射,計算每個像素最終的顏色。

光線在液體表面的傳播情況

首先我們可以計算表面的折射方向和反射方向,並通過反向追蹤光線,得到折射光和反射光的顏色。下面的公式中,折射方向沒有嚴格地按照折射定律計算,而是把出射光向法線靠近得到。

反射方向 m{I}_i=-m{I}_o+2m{n}

折射方向 m{I}_r=-m{I}_o-0.2cdot m{n}

計算出射光顏色,不僅要考慮光線追蹤得到的顏色,還要考慮折射光線所穿過的液體的顏色。Beer-Lambert定律解釋了為什麼一杯水是透明的,游泳池泛著藍光,而大海是深沉的碧藍。根據Beer–Lambert定律,液體的透光量隨液體的厚度呈指數衰減。我們使用修改的Beer-Lambert定律計算折射光的顏色。設液體厚度為T,透光量為A,液體本徵顏色 I_f ,令

I_{r}^{}=AI_{r}+(1-A) I_fA=max?(e^{-0.5 T},0.2)

出射光的顏色是反射顏色和折射顏色的混合,混合的比例由菲涅爾定律給出。菲涅爾定律的計算量較大,計算機圖形學中常常使用Schlick公式代替。Schlick公式根據出射光與法線的夾角給出了反射率

R(θ)=R_0+(1-R_0 ) (1-cos?θ )^5 , ??_0=left(frac{??_1???_2}{??_1+??_2}
ight)^2

其中n1和n2分別是水和空氣的折射率。

於是我們終於得出最終的渲染結果。

左:最終渲染,右:反射顏色,折射顏色,厚度染色後折射顏色

可能的改進

還有許多地方能夠改進屏幕空間渲染的效果。下面列出幾條我能想到的

  1. 實現陰影和焦散。焦散的實現可參考[6]
  2. 改進平滑演算法。雙邊濾波演算法保留深度的不連續性的同時,也一定程度上保留了粒子邊界。
  3. 借鑒[5]的思想,渲染到深度紋理時,將粒子渲染為橢球形,而不是球形。

腳註

項目地址:naeioi/PBF-CUDA

這是我第一次做管線渲染,也是第一次做物理模擬。項目的選題很大程度上受到了 @Raymond Fei [7]的影響。有任何描述錯誤,或需要補充說明的部分,請不吝指出!


[1] W. J. van der Laan, S. Green, and M. Sainz, 「Screen space fluid rendering with curvature flow,」 in Proceedings of the 2009 symposium on Interactive 3D graphics and games - I3D 』09, 2009, p. 91.

[2] Screen Space Fluid Rendering for Games - Nvidia

[3] W. E. Lorensen and H. E. Cline, 「Marching cubes: A high resolution 3D surface construction algorithm,」 in Proceedings of the 14th annual conference on Computer graphics and interactive techniques - SIGGRAPH 』87, 1987, pp. 163–169.

[4] Neutrino-SPH Dynamic Simulation System

[5] J. Yu and G. Turk, 「Reconstructing surfaces of particle-based fluids using anisotropic kernels,」 ACM Trans. Graph., vol. 32, no. 1, pp. 1–12, Jan. 2013.

[6] C. Wyman and S. Davis, 「Interactive Image-Space Techniques for Approximating Caustics,」 in Proceedings of the 2006 Symposium on Interactive 3D Graphics and Games, 2006, pp. 14–17.

[7] 不可壓平滑粒子流體動力學演算法GPU並行加速及其應用研究

推薦閱讀:

渲染管線里為什麼geometry stage在tessellation stage的後面而不是前面?
電腦渲染不給力?雲渲染啊!
計算機圖形學,下一步如何提高?
如何在影視渲染中使用PBR流程
相見恨晚——Thea渲染器官方畫廊作品賞析

TAG:計算機圖形學 | 計算機科學 | 渲染 |