本文由@淺墨_毛星雲 出品,轉載請註明出處
CSDN版文章鏈接: https://blog.csdn.net/poem_qianmo/article/details/103447558
知乎專欄版文章鏈接:https://zhuanlan.zhihu.com/p/95917609
之前在【GPU精粹與Shader編程】系列中寫過一篇《真實感皮膚渲染技術總結》,這篇文章則是它的番外篇,主要關注於真實感水體渲染技術。
本文將對遊戲開發以及電影業界的真實感水體渲染技術從發展史、知識體系、波形模擬技術以及着色技術等多個方面進行較爲系統的總結,文末也對業界優秀的水體實時渲染開源庫進行了盤點。
一、總覽:水體渲染技術發展史
真實感水體的渲染和模擬,一直是計算機圖形學和遊戲開發領域的核心難點之一。而在水體渲染中,最核心的部分爲波形的渲染技術,即如何模擬出逼真的水面波浪的流動變化。按時間分佈,近50年水體波形渲染的主流技術發展可以總結列舉如下:
-
凹凸紋理貼圖(Bump Mapping) [Schachters 1980]
-
正弦波(Sinusoids Wave)[Max 1981]
-
分形噪聲(Fractal noise)[Perlin 1985]
-
Gerstner 波(Gerstner Wave)[Fournier 1986]
-
快速傅立葉變換(Fast Fourier Transform)[Mastin 1987]
-
歐拉方法(Eulerian approaches)[Kass 1990]
-
拉格朗日方法(Lagrangian approaches)[Stam 1995]
-
歐拉-拉格朗日混合方法(Hybrid approaches)[Brien 1995]
-
分形布朗運動(Fractal Brownian Motion,FBM)[Addison 1996]
-
程序化形狀(Procedural Shape)[Ebert 1999]
-
空間-頻譜混合方法(Spatial -Spectral Approaches) [Thon 2000]
-
基於體素的方法(Voxel-Based NSE Solutions) [Yann 2003]
-
頂點高度位移貼圖(Vertex Height Map Displacement)[Yuri 2005]
-
二維波動方程(2D Wave Equation)[Nishidate 2005]
-
屏幕空間網格(Screen Space Mesh)[Muller 2007]
-
波動粒子(Wave Particles)[Yuksel 2007]
-
矢量位移貼圖(Vector Displacement Map) [2009]
-
流型圖(Flow Map)[Vlachos 2010]
-
離線FFT貼圖烘焙(Offline FFT Texture)[Torres 2012]
-
離線流體幀動畫烘焙(bake to flipbook)[Bowles 2017]
-
水波小包方法(Water Wave Packets)[Jeschke 2017]
-
水面小波方法((Water Surface Wavelets)[Jeschke 2018]
-
淺水波浪模擬(Water Wave Simulation)[Grenier 2018]
需要注意的是,上面列出的時間點,可能並不是嚴格意義上的該技術提出的時間點,而是該技術在論文或會議上被提出,被大衆熟知,被引入到水體渲染技術中的時間點。
接下來,先看一些近年遊戲中的真實感水體渲染畫面,然後對這裏列出的水體主流渲染技術中的主要方法,按流派和內容分別進行總結。
二、近年遊戲業界的真實感水體的渲染畫面
首先是《神祕海域4》中清澈的海島淺灘:
然後是《盜賊之海》中波濤洶湧的海洋:
接着是《孤島驚魂5》中陰天的池塘:
還有《戰神4》中深邃的海面:
以及《刺客信條:奧德賽》中平靜的海灘:
這邊也放一個繼承了《刺客信條》系列水體渲染技術的《怒海戰記(Skull & Bones)》的gameplay視頻:
https://youtu.be/fCgYA65tAYY?t=125
要實現如上3A遊戲級別的水體渲染,其實是有章可循的,對應的核心方法在本文以及下面的這張思維導圖中都有進行總結。
三、水體渲染的知識體系思維導圖
本文配套的水體渲染的知識體系思維導圖如下:
OK,下面開始正文。
四、水體渲染的波形模擬技術
按照流派進行分類,可將上文總結的水體渲染波形模擬的二十三種方法分爲如下幾類:
1.線性波形疊加方法
-
正弦波(Sinusoids Wave)[Max 1981]
-
Gerstner 波 (Gerstner Wave) [Fournier 1986]
2.統計模型方法
-
快速傅立葉變換(Fast Fourier Transform)[Mastin 1987]
-
空間-頻譜混合方法(Spatial -Spectral Approaches)[Thon 2000]
3.波動粒子方法
-
波動粒子方法((Wave Particles) [Yuksel 2007]
-
水波小包方法(Water Wave Packets)[Jeschke 2017]
-
水面小波方法(Water Surface Wavelets)[Jeschke 2018]
4. 基於物理的方法
-
歐拉方法(Eulerian approaches)[Kass 1990]
-
拉格朗日方法(Lagrangian approaches) [Stam 1995]
-
歐拉-拉格朗日混合方法(Hybrid approaches)[Brien 1995]
5.預渲染方法
-
頂點高度位移貼圖(Vertex Height Map Displacement) [Yuri 2005]
-
流型圖(Flow Map)[Vlachos 2010]
-
離線FFT貼圖烘焙(Offline FFT Texture) [Torres 2012]
-
離線流體幀動畫烘焙(bake to flipbook)[Bowles 2017]
6.其他方法
-
凹凸紋理貼圖(Bump Mapping)[Schachters 1980]
-
分形噪聲(Fractal Noise)[Perlin 1985]
-
分形布朗運動(Fractal Brownian Motion,FBM)[Addison 1996]
-
程序化形狀(Procedural Shape)[Ebert 1999]
-
基於體素的方法(Voxel-Based Solutions) [Yann 2003]
-
二維波動方程(2D Wave Equation)[Nishidate 2005]
-
屏幕空間網格(Screen Space Mesh)[Muller 2007]
-
淺水波浪模擬(Water Wave Simulation)[Grenier 2018]
下面將對其中比較常見的方案進行盤點。
4.1 線性波形疊加方法
線性波形疊加方法的主要思路是累加不同的線性波形函數以構造波浪表面。可以將其理解爲波動現象在深水中引起水顆粒運動的一種解析解。
圖 水顆粒運動的圖示。波浪中的任何點都沿圓形軌跡移動,靠近表面的半徑較大,而在水中更深的半徑呈指數減小。突出顯示了兩個橙色點,可以發現他們的運動軌跡都是圓形。(圖片來自https://wikischool.org/divided_light)
業界主流的波形函數主要分爲正弦波(Sinusoids Wave)和Gerstner波(Gerstner Wave)兩種,下面分別進行說明。
4.1.1 正弦波(Sinusoids Wave)[Max 1981]
作爲比較早期的水面波形模擬方案,正弦波(Sinusoids Wave)的特點是平滑,圓潤,適合表達如池塘一樣平靜的水面。
圖 Unity下實現的基於正弦波(Sinusoids Wave)的水體
1981年,Max[Max 1981]首先提出了採用高低振幅的正弦波曲線的序列組合來模擬水面起伏的想法。將水體表面採用高度進行建模,則基於正弦波(Sinusoids Wave)的方法在時間t的每個點(x,z)上計算的高度y = h(x,z,t)的通用公式爲:
其中:
-
Nw是波的總數
-
Ai是第i個波的振幅
-
是波矢量
-
是其脈衝值(pulsation)
-
y0是自由表面的高度
正弦波(Sinusoids Wave)目前在水體渲染領域已經很少直接使用,業界往往青睞於使用它的進化版Gerstner波。
4.1.2 Gerstner 波(Gerstner Wave) [Fournier 1986]
作爲正弦波的進化版,Gerstner 波(Gerstner Wave)的特點是波峯尖銳,波谷寬闊,適合模擬海洋等較粗獷的水面。
圖 Unity下實現的基於Gerstner波的水體
Gerstner 波(Gerstner Wave)也常被稱爲Trochoidal Wave,在流體動力學中,其爲週期表面重力波(periodic surface gravity waves)的歐拉方程的精確解,由Gerstner在1802 年初次發現,並在1863年由Ranine獨立重新發現。在1986年由Fournier等人引入水體渲染領域。
圖 Gerstner Waves波形
圖 Gerstner Waves水顆粒的運動軌跡爲圓形
選擇一組波矢量ki,振幅Ai,頻率ωi和相位φi,對於,Gerstner Waves的通用公式爲:
Gerstner Waves由於計算量可控,性價比高,在遊戲水體渲染領域的應用較爲廣泛。不少3A遊戲了採用Gerstner Wave作爲水體渲染的基礎實現。如下文Wave Particles部分也會提到的《神祕海域3》,即是採用了Gerstner Wave + Wave Particles的水體渲染方案組合。
4.2 統計模型方法
4.2.1 快速傅立葉變換(Fast Fourier Transform , FFT)[Mastin 1987]
作爲目前電影業界廣泛採用的海洋表面渲染解決方案,基於快速傅立葉變換(Fast Fourier Transform , FFT)的水體渲染方法的特點是真實感出色,全局可控,細節豐富,但計算量相對較大。
自1986年[Mastin 1987]將基於FFT的水體渲染方法引入水體渲染領域,以及2001年Tessendorf著名的水體總結文章《Simulating Ocean Water》[Tessendorf 2001]對其的推廣之後,至今其仍然是電影工業模擬海洋表面的標準解決方案。
圖 Unity下實現的基於FFT的水體
傅里葉變換(Fourier transform)是一種線性積分變換,用於信號在時域和頻域之間的變換。而快速傅里葉變換 (Fast Fourier Transform,FFT), 是一種可在O(nlogn)時間內完成離散傅里葉變換(Discrete Fourier transform,DFT)的高效、快速計算方法集的統稱。最初的快速傅里葉變換方法早在1805年就已由高斯推導出來,並於1965年由Cooley和Tukey重新提出,並漸漸被大衆所熟知。從此,對快速傅里葉變換(FFT)算法的研究便不斷深入,數字信號處理這門新興學科也隨FFT的出現和發展而迅速發展。根據對序列分解與選取方法的不同而產生了FFT的多種算法。
FFT的基本思想是把原始的N點序列,依次分解成一系列的短序列。充分利用DFT計算式中指數因子 所具有的對稱性質和週期性質,進而求出這些短序列相應的DFT並進行適當組合,達到刪除重複計算,減少乘法運算和簡化結構的目的。
關於FFT的算法細節這裏就不展開講了,放兩張經典的總結圖:
基於FFT的水體渲染方法,也常被各類文獻稱爲基於頻譜(spectrum-based)的方法,其核心思想是基於FFT構造出水體的表面高度。具體而言,該方法使用從理論或測量統計數據獲得的海浪頻譜(最常見的頻譜爲[Tessendorf 2001]使用的Phillips頻譜)來描述海洋表面,結合大量的正弦波的疊加在頻域中生成波型的分佈,然後執行逆FFT,將數據轉到空間域,經過運算生成位移貼圖(displacement map)。最終,由位移貼圖導出表面法線貼圖,以及其他相關數據,如代表白沫區域的Folding Map。
圖 基於FFT的水體渲染流程 [NVIDIA 2004]
採用FFT的水體渲染方法從90年代開始廣泛用於電影製作(離線渲染),從2000年代開始廣泛用於遊戲(實時渲染)。離線渲染和實時渲染的選擇,主要在於當時硬件計算能力可以承受多少分辨率的高度圖的實時運算。早期的遊戲,如Crysis,由於硬件計算量的限制,採用了64 x 64的高度圖分辨率。而由於硬件的發展,目前512 x 512的分辨率的計算量已經在實時渲染中較爲普遍。而電影工業中採用FFT生成的高度圖,由於可以採用離線渲染,以及品質的要求,分辨率一般較大,如早在1997年的《泰坦尼克號》的海洋渲染的渲染,就已經採用了2048 x 2048分辨率的高度圖。
圖 著名電影《泰坦尼克號》中,基於FFT方法離線渲染的海洋,採用2048 x 2048分辨率的高度圖
4.3 波動粒子方法
4.3.1 波動粒子(Wave Particle) [2007]
波動粒子(Wave Particle)方法最初由Yuksel於2007年[Yuksel 2007]提出,該方法的核心思想是採用粒子代表每一個水波,並允許波反射以及與動態對象的相互作用。這種方法將動態模擬三維水波的複雜度降維到模擬在平面上運動的粒子系統的級別。
波動粒子(Wave Particle)方法結合了線性疊加方法的靈活性和基於FFT方法的穩定性和視覺細節,其可控制性和性能,以及出色的交互表現,是模擬實時水體交互的不錯方案。
圖 Wave Particle (圖片來自[Yuksel 2007])
需要注意的是,波動粒子(Wave particles)的作用不只是代表波浪的位置。它們還可以帶有描述其形狀和行爲的其他屬性,例如振幅(amplitude)和半徑(radius)。
當相鄰波動粒子之間的距離大於半徑的一半時,該方法會將一個波動粒子轉換爲三個新的波動粒子。新的波動粒子直接從現有波動粒子中吸收能量(即振幅)。從而減小了現有波動粒子的振幅,而整體波峯的總振幅保持不變。三個子粒子的振幅和擴散角度變爲父粒子的三分之一,而新粒子的半徑與父波動粒子保持相同。如下圖所示。
圖 (a)和(b)分別是波動粒子的初始位置和它們形成的波峯(c)和(d)是波粒經過一定距離後的位置和波動粒子形狀(圖片來自[Yuksel 2010])
因爲在波動粒子系統中,假設每個波動粒子在兩側都具有兩個相同的相鄰粒子,所以當一個波動粒子細分時,其會在兩側產生兩個新的波動粒子,如下圖所示。
圖 具有相同擴散角度的兩個相鄰波動粒子之間的距離(圖片來自[Yuksel 2010])
另外,Wave Particles方法還可以與現有各種方案進行結合和改進。
2007年Yuksel提出的原版Wave Particles的波動粒子的生成源來自點狀的粒子波源。對此,《神祕海域3》對其進行了改進方案。在《神祕海域3》中,並沒有使用點狀粒子波源,而是在環形區域中放置隨機分佈的粒子源,以近似開放水域的混沌運動,從而產生一個可平鋪的向量位移場(vector displacement field)。
圖 《神祕海域3》中基於隨機分佈wave particles粒子源的波浪模擬方法
《神祕海域4》中則採用了多分辨率Wave Particles方案,從另一個角度對Wave Particles方法進行了改進。
圖 《神祕海域4》中的多分辨率wave particles
4.3.2 水波小包方法(Water Wave Packets)[SIGGRAPH 2017]
在波動粒子(Wave Particles)的基礎上, Jeschke和Wojtan[2017]於SIGGRAPH 2017引入了以理論羣速度(theoretical group speed)傳播的水波小包(Water wave packets )方法。該方法繼承了基於頻譜的方法的優點,如數值穩定性和理論上準確的波速。同時,他們通過將全局餘弦波分解成一系列更短的波分量,從而避免了基於頻譜的方法的複雜性。
圖 水波小包方法(Water Wave Packets)的paper demo [SIGGRPAPH 2017]
圖 水波小包方法(Water Wave Packets)的原理圖示
圖 水波小包方法(Water Wave Packets)渲染效果圖
4.3.3 水面小波方法(Water Surface Wavelets) [SIGGRAPH 2018]
隨後的[SIGGRAPH 2018],Jeschke等人對Water Wave Packets進行了改進,提出了新的水面小波方法(Water Surface Wavelets)。水面小波方法(Water Surface Wavelets)基於歐拉方法,自由度與空間區域有關,與波動本身無關。因此,該方法可以和GPU更好的結合,因爲計算複雜度是恆定的,因爲不隨粒子的數量而變化。不過該方法由於提出時間較新,性能也沒有太大優勢,所以目前還沒有聽說有實際的實時渲染項目在使用。
圖 Water Surface Wavelets paper Demo [SIGGRPAPH 2018]
圖 水面小波方法(Water Surface Wavelets)渲染效果圖 [SIGGRPAPH 2018]
4.4 基於物理的方法
基於物理的水體模擬方法一般比較昂貴,由於可以離線渲染,所以在電影工業中具有很好的運用。由於現階段很難用於實時渲染,這邊僅進行一個綜述性的總結。
基於物理模型的水體模擬方法的核心是對Navier-Stokes方程(Navier-Stokes Equations,NS方程)進行求解。Navier-Stokes方程是一組描述液體和空氣之類的流體物質的方程,描述作用於液體任意給定區域的力的動態平衡。除了水體模擬之外,其還可以用於模擬天氣,水流,氣流,恆星的運動。
Navier-Stokes方程如下:
-
u爲流體速度矢量(fluid velocity vector)
-
p爲流體壓力(fluid pressure)
-
ρ爲流體密度(fluid density)
-
ν爲運動粘度係數(kinematic viscosity coefficient)
-
∇爲梯度微分(gradient differential)
-
∇2爲拉普拉斯算子(Laplacian operators)
常用的求解NS 方程的方法有歐拉方法(Eularian Method)和拉格朗日方法(Lagrangian Method)兩種:
-
歐拉方法(Eularian Method)是一種基於網格的方法。它從研究流體所佔據的空間中各個固定點處的運動着手,分析被運動流體所充滿的空間中每一個固定點上流體的速度、壓強、密度等參數隨時間的變化,以及由某一空間點轉到另一空間點時這些參數的變化。
-
拉格朗日方法(Lagrangian Method)是一種基於粒子的方法。它從分析流體各個微粒的運動着手,即研究流體中某一指定微粒的速度、壓強、密度等參數隨時間的變化,以及研究由一個流體微粒轉到其他流體微粒時參數的變化,以此來研究整個流體的運動。最常用的拉格朗日方法是光滑粒子流體力學(Smoothed Particle Hydrodynamics,SPH)方法,其核心渲染思想爲流體模擬產生粒子,然後多邊形化粒子以產生波。
圖 基於SPH方法的水體渲染表現
圖 Houdini下的流體模擬
除了獨立的兩種方法之外,還有結合兩者的歐拉-拉格朗日混合方法(Eularian-Lagrangian Hybrid approaches),其主要思想是使用歐拉方法來模擬流體的主體,並使用拉格朗日方法來模擬諸如泡沫,噴霧或氣泡之類的細小細節。
FX Guide上有一篇關於電影業界使用流體模擬方法的不錯文章,感興趣的朋友可以瞭解一下:https://www.fxguide.com/fxfeatured/the-science-of-fluid-sims/
另外,也可以採用bake to flipbook方法,將離線的流體模擬,烘焙成flipbook幀動畫,用於實時渲染。
4.5 預渲染方法
4.5.1 流型圖(Flow Map)
流型圖(Flow Map),也常被稱爲矢量場圖(Vector Field Map),本質上是一種基於矢量場平移法線貼圖的着色技術,或者可以理解爲一種UV動畫,由VALVE的Vlachos在SIGGRAPH 2010上的talk《Water Flow in Portal 2》被大衆所熟知。值得一提的是,VALVE在2010年就超前地使用了Houdini來製作flow map。
圖 原版Flow Map的算法原理[SIGGRAPH 2010]
圖 基於Houdini的Flow Map創作工作流[SIGGRAPH 2010]
Flow Map除了用於水體的渲染以外,任何和流動相關的效果都可以採用Flow Map,如沙流,以及雲的運動等效果。
圖 基於Flow Map的水體渲染 @Unity
圖 基於Flow Map的水體渲染 @UDK
Flow Map的核心思想是預烘焙2D方向信息到紋理,以在運行時基於UV採樣,對流動感進行模擬。
圖 基於Flow Map的形變
Flow Map的典型使用代碼如下所示:
//get and uncompress the flow vector for this pixel
float2 flowmap = tex2D( FlowMapS, tex0 ).rg * 2.0f - 1.0f;
float cycleOffset = tex2D( NoiseMapS, tex0 ).r;
float phase0 = cycleOffset * .5f + FlowMapOffset0;
float phase1 = cycleOffset * .5f + FlowMapOffset1;
// Sample normal map.
float3 normalT0 = tex2D(WaveMapS0, ( tex0 * TexScale ) + flowmap * phase0 );
float3 normalT1 = tex2D(WaveMapS1, ( tex0 * TexScale ) + flowmap * phase1 );
float flowLerp = ( abs( HalfCycle - FlowMapOffset0 ) / HalfCycle );
float3 offset = lerp( normalT0, normalT1, flowLerp );
4.5.1.1 Flow Map變體:《神祕海域3》Flow Map + Displacement
另外,Flow Map可以和其他渲染技術結合使用,比如《神祕海域3》中的Flow Map + Displacement:
4.5.1.2 Flow Map變體:《堡壘之夜》Flow Map + Distance Fields + Normal Maps
以及《堡壘之夜》中的Flow Map + Distance Fields + Normal Maps [GDC 2019, Technical Artist Bootcamp Distance Fields and Shader Simulation Tricks]
4.5.1.3 Flow Map變體:《神祕海域4》Flow Map + Wave Particles
或者《神祕海域4》中的Flow Map + Wave Particles[SIGGRAPH 2016, Rendering Rapids in Uncharted 4],都是進階模擬水體表面流動與起伏效果的不錯選擇。
圖 《神祕海域4》中的Flow Map + Wave Particles。通過將flow map與波浪粒子(wave particle grids)網格配合使用,可以非常精確地控制波浪的方向。在此示例中,採用一個循環的flow map來構成漩渦
如下爲《神祕海域4》中Flow + Wave Particles的僞代碼:
timeInt = time / (2.0 * interval)
float2 fTime = frac(float2(timeInt, timeInt * .5)
posA = pos.xz - (flowDir/2) * fTime.x * flowDir
posB = pos.xz - (flowDir/2) * fTime.y * flowDir
gridA0 = waveParticles(posA.xz, freq0,scale0)
gridA1 = waveParticles(posA.xz, freq1,scale1)
…
gridB0 = waveParticles(posB.xz, freq2,scale0)
gridB1 = waveParticles(posB.xz, freq3,scale1)
…
float3 pos0 = gridA0 + gridA1 + gridA2 + gridA3
float3 pos1 = gridB0 + gridB1 + gridB2 + gridB3
pos = blend(pos0, pos1, abs((2*frac(timeInt)-1)))
pos.y += heightMap.eval(uv)
4.5.2 離線FFT貼圖烘焙(Offline FFT Texture)
離線FFT烘焙(Offline FFT Texture)方法最初由《刺客信條3》團隊開始採用[Torres 2012]而進入大衆視野,思路爲基於離線FFT預渲染出一系列高度圖,烘焙得出一系列法線貼圖或矢量位移貼圖(vector displacement maps),並在運行時進行採樣。FFT的週期性質可以讓烘焙得出的貼圖非常適合做tiling。
圖 基於離線FFT烘焙的《刺客信條4》的水面表現
圖 基於離線FFT烘焙的《刺客信條3》的水面表現
4.6 其他方法
除了上述5大類方法之外,還有一些其他的常見水體渲染方法,可以總結如下:
-
凹凸紋理貼圖(Bump Mapping)[Schachters 1980]
-
分形布朗運動(Fractal Brownian Motion,FBM)[Addison 1996]
-
程序形狀(Procedural Shape)[Ebert 1999]
-
分形噪聲(Fractal Noise)[Gonzato 2000]
-
基於體素的方法(Voxel-Based Solutions) [Yann 2003]
-
屏幕空間方法(Screen Space Mesh)[Muller 2007]
-
矢量位移貼圖(Vector Displacement Map)[2009]
其中,凹凸紋理貼圖(Bump Mapping)比較早期的水體模擬方案,主要思想是擾動參與光照計算的法向量,並通過凹凸紋理的連續移動來模擬海浪的隨機運動。目前凹凸紋理貼圖幾乎是實時水體渲染的必備貼圖之一。
而分形噪聲(Fractal Noise)方法核心思想是基於不同頻率Perlin噪聲的疊加,混合出分形噪聲,以構建海面高度場。
矢量位移貼圖(Vector Displacement Map)的核心思想則是使用空間中的向量的顏色通道在方向與大小上置換對應幾何體的頂點。
圖 一個標準的矢量位移貼圖(Vector Displacement Map) @Arnold Render
圖 基於矢量位移貼圖(Vector Displacement Map)的水體渲染 @Arnold Render
其他的方案相對而言比較小衆,都有對應paper,篇幅原因這裏就不展開總結了。
這邊放一個令人印象深刻的SIGGRAPH 2017上 ,Crest Ocean System基於動態程序化形狀(Procedural Shape)的水體渲染demo,可以允許玩家和海洋進行互動:
五、水體渲染的着色技術
關於水體渲染的Shading部分,首先要提到的是,目前遊戲業界的主流方案都不是基於物理的。
到達水面的光線除了在水體表面發生反射之外,還有部分光線進入水體內部,經過吸收和散射後再次從水體表面射出,即水體的次表面散射現象(Sub-Surface Scattering, SSS)。基於物理的渲染中,求解次表面散射最標準的方法是求解BSSRDF(Bidirectional Surface Scattering Reflectance Distribution Function,雙向表面散射反射分佈函數)。
但在光柵圖形學中,求解BSSRDF需要很大的計算量,所以實時渲染業界大多數的水體渲染,依舊是非基於物理的經驗型渲染方法。
《神祕海域3》在2012年SIGGRAPH上的技術分享中有一張分析水體渲染技術非常經典的圖,如下。
對此,我們可以將水體渲染的要點總結爲:
-
漫反射(Diffuse)
-
鏡面反射(Specular)
-
法線貼圖(Normal Map)
-
折射(Reflection)
-
通透感(Translucency)
-
基於深度的查找表方法(Depth Based LUT Approach)
-
次表面散射(Subsurface Scattering)
-
-
白沫(Foam/WhiteCap)
-
流動表現(Flow)
-
水下霧效(Underwater Haze)
其中,漫反射,鏡面反射,法線貼圖,折射等都是比較常見的技術,而流動表現(Flow)上文已有涉及,這裏都不再贅述。
下文將對水體渲染的難點,通透感(Translucency),白沫(Foam/WhiteCap)渲染分別進行總結。
5.1 水體通透感(Translucency)的表現方案
關於水體通透感(Translucency)的表現方案,可以將業界主流方案總結爲如下三個流派:
-
LUT方法(Look-Up-Table Approach)
-
次表面散射近似方法(Sub-Surface Scattering,SSS Approximation Approach)。
-
混合型方案。 即同時將LUT與次表面散射近似兩種方案結合使用的方法。典型的例子如《刺客信條3》
5.1.1 基於深度的查找表方法(Depth Based LUT Approach)
Depth Based-LUT方法的思路是,計算視線方向的水體像素深度,然後基於此深度值採樣吸收/散射LUT(Absorb/Scatter LUT)紋理,以控制不同深度水體的上色,得到通透的水體質感表現。
其中,視線方向的水體像素深度值計算思路如下圖中的藍色箭頭所示的橘褐色區間:
圖 藍色箭頭所示的橘褐色區間爲視線方向的水體像素深度
5.1.2 次表面散射近似方法(Sub-Surface Scattering Approximation Approach)
可用於水體通透感表現的次表面散射(Sub-Surface Scattering,SSS)的近似方案有很多種,這邊推薦兩種:
-
[SIGGRAPH 2019] Crest Ocean System改進的《盜賊之海》SSS方案。
-
[GDC 2011] 寒霜引擎的Fast SSS方案。
圖 有無次表面散射的水體表現對比
5.1.2.1 [SIGGRAPH 2019] Crest Ocean System改進的《盜賊之海》SSS方案
經過Crest Ocean System改進的《盜賊之海》的SSS方案可以總結如下:
-
假設光更有可能在波浪的一側被水散射與透射。
-
基於FFT模擬產生的頂點偏移,爲波的側面生成波峯mask
-
根據視角,光源方向和波峯mask的組合,將深水顏色和次表面散射水體顏色之間進行混合,得到次表面散射顏色。
-
將位移值(Displacement)除以波長,並用此縮放後的新的位移值計算得出次表面散射項強度。
對應的核心實現代碼如下:
float v = abs(i_view.y);
half towardsSun = pow(max(0., dot(i_lightDir, -i_view)),_SubSurfaceSunFallOff);
half3 subsurface = (_SubSurfaceBase + _SubSurfaceSun * towardsSun) *_SubSurfaceColour.rgb * _LightColor0 * shadow;
subsurface *= (1.0 - v * v) * sssIndensity;
col += subsurface;
其中,sssIndensity,即散射強度,由採樣位移值計算得出。
圖 《Crest Ocean System》中基於次表面散射近似的水體表現
圖 《盜賊之海(Sea of Thieves)》中基於次表面散射近似的水體表現
圖 《盜賊之海(Sea of Thieves)》中基於次表面散射近似的水體表現
5.1.2.2 [GDC 2011] 寒霜引擎的Fast SSS方案
[GDC 2011]上,Frostbite引擎提出的Fast Approximating Subsurface Scattering方案,也可以用於水體渲染的模擬。
具體方案和代碼如下所示:
5.2 白沫的渲染方案
白沫(Foam),在有些文獻中也被稱爲Whitecap,White Water,是一種複雜的現象。即使白沫下方的材質具有其他顏色,白沫也通常看起來是白色的。出現這種現象的原因是因爲白沫是由包含空氣的流體薄膜組成的。隨着每單位體積薄膜的數量增加,所有入射光都被反射而沒有任何光穿透到其下方。這種光學現象使泡沫看起來比材質本身更亮,以至於看起來幾乎是白色的。
圖 海洋中的白沫
對於白沫的渲染而言,白沫可被視爲水面上的紋理,其可直接由對象交互作用,浪花的飛濺,或氣泡與水錶面碰撞而產生。
白沫的渲染方案,按大的渲染思路而言,可以分爲兩類:
-
基於動態紋理(dynamic texture)
-
基於粒子系統(particle system)
按照類型,可以將白沫分爲三種:
-
浪尖白沫
-
岸邊白沫
-
交互白沫
而按照渲染方法,可將白沫渲染的主流方案總結如下:
-
基於粒子系統的方法[Tessendorf 2001]
-
基於Saturate高度的模擬方法 [GPU Gems 2]
-
基於雅可比矩陣的方法 [Tessendorf 2001]
-
屏幕空間方法 [Akinci 2013]
-
基於場景深度的方法 [Kozin 2018][Sea of Thieves]
-
基於有向距離場的方法 [GDC 2018][Far Cry 5]
這邊對其中比較典型的幾種進行說明。
5.2.1 浪尖白沫:[Tessendorf 2001] 基於雅克比矩陣的方法
Tessendorf在其著名的水體渲染paper《Simulating Ocean Water》[Tessendorf 2001]中提出了可以基於雅克比矩陣(Jacobian)爲負的部分作爲求解白沫分佈區域的方案。據此,即可導出一張或多張標記了波峯白沫區域的Folding Map貼圖。
《戰爭雷霆(War Thunder)》團隊在CGDC 2015上對此的改進方案爲,取雅克比矩陣小於M的區域作爲求解白沫的區域,其中M~0.3...05。
另外,《盜賊之海(Sea of Thieves)》團隊在SIGGRPAPH 2018上提出,可以對雅可比矩陣進行偏移,以獲得更多白沫。且可以採用漸進模糊(Progressive Blur)來解決噪點(noisy)問題以及提供風格化的白沫表現。
圖 《盜賊之海》基於雅可比矩陣偏移 + 漸進模糊(Progressive Blur)的風格化白沫表現
5.2.2 浪尖白沫:[GPU Gems 2] 基於Saturate高度的方法
《GPU Gems 2》中提出的白沫渲染方案,思路是將一個預先創建的泡沫紋理在高於某一高度H0的頂點上進行混合。泡沫紋理的透明度根據以下公式進行計算:
-
其中,H_max是泡沫最大時的高度,H_0是基準高度,H是當前高度。
-
泡沫紋理可以做成序列幀來表示泡沫的產生和消失的演變過程。這個動畫序列幀既可以由美術師進行製作,也可以由程序生成。
-
將上述結果和噪聲圖進行合理的結合,可以得到更真實的泡沫表現。
5.2.3 岸邊白沫:[2012]《刺客信條3》基於Multi Ramp Map的方法
《刺客信條3》中的岸邊白沫的渲染方案可以總結爲:
-
以規則的間距對地形結構進行離線採樣,標記出白沫出現的區域。
-
採用高斯模糊和Perlin噪聲來豐富泡沫的表現形式,以模擬海岸上泡沫的褪色現象。
-
由於白沫是白色的,因此在R,G和B通道中的每個通道中都放置三張灰度圖,然後顏色ramp圖將定義三者之間的混合比率,來實現稠密、中等、稀疏三個級別的白沫。要修改白沫表現,美術師只需對ramp圖進行顏色校正即可。如下圖所示:
5.2.4 交互白沫:[SIGGRAPH 2018]《盜賊之海》基於場景深度的交互白沫渲染
《盜賊之海(Sea of Thieves)》團隊在SIGGRPAPH 2018的talk上也提到了白沫的渲染方案,可以總結如下:
-
放置一個top-down的相機,用於渲染場景深度,通過比較場景深度和水深來得到白沫mask,即: half4 foamMask =1 - saturate(_FoamThickness* (depth - i.screenPos.w ) ) ;
-
最終,將foamMask和基礎texture做blend。
-
盜賊之海中,得到相對深度後,還會對白沫mask做漸進模糊(progressively blur),以得到風格化的白沫表現。
圖 《盜賊之海(Sea of Thieves)》中的交互白沫
圖 《盜賊之海(Sea of Thieves)》中的交互白沫
5.2.5 浪尖白沫&岸邊白沫:[GDC 2018]《孤島驚魂5》基於有向距離場的方法
GDC 2018上《孤島驚魂5》團隊分享的白沫渲染技術也不失爲一種優秀的方案,主要思路是基於單張Noise貼圖控制白沫顏色,結合兩個offset採樣Flow Map控制白沫的流動,並基於有向距離場(Signed Distance Field,SDF)控制岩石和海岸線處白沫的出現,然後根據位移對白沫進行混合。
六、業界優秀水體渲染開源庫盤點
時間來到2019年,已有不少3A級別的水體渲染技術以免費&開源的方式湧現了出來,這裏將進行一個盤點。
如果要實現一個高品質的水體實時渲染解決方案,以下的這六個開源庫會讓你事半功倍。
6.1 Crest Ocean System
Crest Ocean System是Unity下開源的高品質海洋渲染框架,已經在兩屆SIGGRAPH(SIGGRAPH 2017、SIGGRAPH 2019)上進行了技術分享。
源代碼傳送門:https://github.com/crest-ocean/crest
demo視頻:https://www.youtube.com/watch?v=ekng3c43Y1E
除了開源免費版,Crest Ocean System目前也已推出LWRP的付費版:https://assetstore.unity.com/packages/tools/particles-effects/crest-ocean-system-lwrp-urp-141674
6.2 CryEngine內置水體
之前在【GPU精粹】系列文章中也提到過,CryEngine作爲比較老牌的引擎,其內置的水體渲染表現在各大遊戲引擎的內置水體中,可謂是頂尖級別的。CryEngine現在也已經開源。
源代碼傳送門:
demo視頻:https://www.youtube.com/watch?v=tZthI6M07iM
6.3 UE4 Dynamic Water Project
Dynamic Water Project 是Unreal引擎下一款不錯的開源水面交互解決方案,對於可交互水體而言是不錯的參考。
源代碼傳送門:
https://github.com/marvelmaster/UE4_Dynamic_Water_Project/tree/master/Reactive_Water_V3_4-20
6.4 Ceto Ocean system
Ceto也是Unity引擎下的另一個不錯的水體渲染開源庫。
源代碼傳送門:https://github.com/Scrawk/Ceto
6.5 NVIDIA UE4 WaveWorks
GDC 2017上,NVIDIA和Unreal Engine合作推出了WaveWorks,以集成到Unreal Engine 4.15引擎中的形式放出。
源代碼傳送門:https://github.com/NvPhysX/UnrealEngine/tree/WaveWorks
demo視頻:https://www.youtube.com/watch?v=DhrNvZLPBGE&list=PLN8o8XBheMDxCCfKijfZ3IlTP3cUCH6Jq&index=11&t=0s
6.6 Unity LWRP BoatAttack
BoatAttack是Unity在2018年5月13日開源的基於LWRP的項目,經歷了幾個版本的開發週期,具有令人印象深刻的水體表現,可謂是Unity引擎下非常優質的水體渲染參考。
源代碼傳送門:https://github.com/Verasl/BoatAttack
demo視頻:https://www.youtube.com/watch?v=7v9gZK9HqqI
七、總結
本文對遊戲以及電影業界的真實感水體渲染技術從發展史、知識體系等多個方面進行了較爲系統的總結,文末也對業界優秀的水體實時渲染開源庫進行了盤點。
不妨用配套的思路導圖作爲本文的收尾:
本文的GitHub版
可以將這篇文章理解爲【GPU精粹與Shader編程】系列的番外篇,所以它和【GPU精粹與Shader編程】系列文章一樣,也收錄在了Game-Programmer-Study-Notes這個GitHub Repo中。
本文的GitHub版本傳送門:
https://github.com/QianMo/Game-Programmer-Study-Notes
Reference
[1] FX Guide 2012, Assassins Creed III The tech behind or beneath the action,https://www.fxguide.com/fxfeatured/assassins-creed-iii-the-tech-behind-or-beneath-the-action/
[2] SIGGRAPH 2001, Tessendorf J. Simulating ocean water[J]. Simulating nature: realistic and interactive techniques.
[3] SIGGPRAPH 2019, Multi-resolution Ocean Rendering in Crest Ocean System
[4] GDC 2008, Fast Water Simulation for Games
[5] GDC 2012, Water Technology of Uncharted
[6] GDC 2018, Water Rendering in FarCry 5
[7] Jeschke S, Wojtan C. Water wave packets[J]. ACM Transactions on Graphics(TOG), 2017
[8] 2010, Yuksel C. Real-time water waves with wave particles[M]. Texas A&M University
[9] SIGGRAPH 2016, Rendering rapids in Uncharted 4
[10] GDC 2019, Technical Artist Bootcamp Distance Fields and Shader Simulation Tricks
[11] https://zhuanlan.zhihu.com/p/21573239
[12] SIGGRAPH 2010, Water Flow in Portal 2
[13] GPU Gems2, Using Vertex Texture Displacement for Realistic Water Rendering
[14] SIGGRAPH 2013, Oceans on a Shoestring Shape Representation, Meshing and Shading
[15] SIGGRAPH 2018, The Technical Art of Sea of Thieves
[16] GDC 2015, An Introduction to Realistic Ocean Rendering through FFT
[17] CGDC 2015, Ocean simulation and rendering in War Thunder
[18] NVIDIA 2004, Ocean Surface Simulation nvidia
[19] SIGGRAPH Asia 2012, Real-time Animation and Rendering of Ocean Whitecaps
[20] TOG 2017, Water Wave Packets
[21] NVIDIA 2004, Ocean Surface Simulation nvidia
[22] GDC 2017, From Shore to Horizon Creating a Practical Tessellation Based Solution
[24] https://www.youtube.com/watch?v=hzw-NOKeSRY
[25] https://www.youtube.com/watch?v=iBBQzs-7Ac4
[26] https://www.fxguide.com/fxfeatured/the-science-of-fluid-sims/
[27] https://graphicsrunner.blogspot.com/2010/08/water-using-flow-maps.html
[28] 題圖來自《盜賊之海》