張國棟 王 波 朱長德 熊桂芳 郭 澍
(1.南京信息工程大學(xué)遙感與測繪工程學(xué)院,江蘇 南京 210044;2.航天遠(yuǎn)景科技(南京)有限公司,江蘇 南京 210046)
“數(shù)字海洋”是由“數(shù)字地球”衍生而來的,構(gòu)建“數(shù)字海洋”基礎(chǔ)信息框架是我國重大海洋計劃之一。近年來,隨著地理信息科學(xué)、遙感(Remote Sensing,RS)、計算機(jī)技術(shù)、虛擬現(xiàn)實(Virtual Reality,VR)的快速發(fā)展,數(shù)字海洋已無法滿足國家日益增長的需求?!叭S海洋”的發(fā)展與完善是“數(shù)字海洋”的最高目標(biāo),對我國海洋科學(xué)研究、海洋國防安全、海洋資源管理、海洋信息服務(wù)和海洋決策支持等具有非常重要的意義。海浪作為海洋的“頭發(fā)”,其重要性不言而喻,海浪模擬是一個復(fù)雜的過程,且與計算機(jī)技術(shù)息息相關(guān)。目前,各國學(xué)者對海浪的研究建模方法可分為基于流體力學(xué)的建模方法、基于海浪譜的建模方法、基于幾何模型的建模方法、基于動力模型的建模方法、基于分形的建模方法[1]。柏林噪聲(Perlin Noise)建模方法生成的視覺元素看起來更自然,是基于幾何模型使用頻率較高的一種方法。1983年,Perlin[2]因不滿當(dāng)時計算機(jī)產(chǎn)生不自然的紋理效果,首次提出Perlin噪聲,并于1985年在SINGGRPH上公開發(fā)表該算法,憑此獲得了奧斯卡科技成果獎。隨后該方法被用于構(gòu)造海浪高度場。Johanson[3]通過引入投影網(wǎng)格的概念,在后空間構(gòu)造海面網(wǎng)格,并通過疊加Perlin噪聲來構(gòu)造海面高度場。宋歌等[4]使用Perlin噪聲擾動的方式來模擬實現(xiàn)視點遠(yuǎn)處的海洋運(yùn)動。
Unity是一個由Unity Technologies研發(fā)的、讓用戶方便快捷地創(chuàng)建三維視頻游戲、建筑可視化、實時三維動畫、創(chuàng)建三維地形等多平臺的綜合性開發(fā)游戲平臺。Unity不僅能在Windows、Linux、MacOS等主流平臺上運(yùn)行,還可將其開發(fā)的產(chǎn)品發(fā)布到Windows、WebGL、Android等平臺 上,Unity Web Player插件也支持發(fā)布網(wǎng)頁游戲及網(wǎng)頁瀏覽,是一個全面且功能強(qiáng)大的專業(yè)引擎。Robert[5]使用Unity平臺來模擬海岸環(huán)境的空間和位置。王懷兵等[6]使用Unity自帶的粒子系統(tǒng)進(jìn)行船行波的三維仿真試驗。劉雪梅等[7]提出利用Perlin噪聲構(gòu)造分形,網(wǎng)格頂點采用位移映射算法,在Unity3D中生成地形。歐陽勁夫等[8]使用Unity3D引擎來模擬光的反射和折射,利用可視化編程插件來制作水面水體著色器,從而實現(xiàn)對水面波浪的模擬,該方法雖實現(xiàn)了低性能耗損,但也存在生成的水體細(xì)節(jié)表現(xiàn)不足等問題。綜上所述,本研究在Unity3D平臺中,通過創(chuàng)建海面網(wǎng)格,然后使用Perlin噪聲生成海面高度場,使用高次插值函數(shù)對生成的高度場進(jìn)行平滑擬合,解決由海浪波峰過于尖銳導(dǎo)致的失真問題,在光影效果上使用Shader Graph渲染管線,采用菲涅爾效應(yīng)進(jìn)行線性插值,來生成海面顏色,然后通過法線進(jìn)行貼圖,生成真實狀態(tài)的海洋場景。
海浪的生成先通過三維Perlin噪聲進(jìn)行疊加來產(chǎn)生分形Perlin噪聲,將產(chǎn)生的高度場映射到海面網(wǎng)格,然后添加波面紋理和光照,從而生成海浪模型。主要包括海面網(wǎng)格的構(gòu)建、生成高度場、渲染紋理。
Unity創(chuàng)建的海面網(wǎng)格方便快捷,可分為以下三個步驟。
1.1.1 網(wǎng)格基礎(chǔ)組件。先打開Unity3D軟件,在Hierarchy中創(chuàng)建一個空物體(Game Object),并將其重命名為Perlin Waves。在inspector的Add Component中添加Mesh Renderer組件,該組件可對生成的網(wǎng)格模型進(jìn)行渲染。創(chuàng)建完Game Object后,在project中創(chuàng)建C#腳本,腳本名要與創(chuàng)建的物體名相同,否則運(yùn)行時會出現(xiàn)錯誤。
1.1.2 網(wǎng)格屬性。打開剛創(chuàng)建的C#文件,定義海面網(wǎng)格所需的變量,即海面寬度x、海面長度z、海面網(wǎng)格的分辨率Di mens ions。Unity坐標(biāo)系采用左手坐標(biāo)系,即用左手食指和大拇指擺出“L”的手勢,且食指向上,大拇指指右,然后伸出中指,此時中指會指向正前方。大拇指、食指、中指分別對應(yīng)x、y、z軸的正方向,即海面網(wǎng)格的長和寬用z和x表示。
1.1.3 計算網(wǎng)格。由1.1.2中定義的變量來計算網(wǎng)格的點(verts)、UV值(uvs)及三角形(tries)。網(wǎng)格的點是用來計算生成的三角形,UV值是u、v紋理貼圖坐標(biāo)的簡稱,其定義了圖片上每個點的位置信息,三角形顯然就是用來形成海面網(wǎng)格的。其中,各個值的計算方法如下。
點的計算首先要計算索引值,其計算公式見式(1)。
頂點的計算公式見式(2)。
UV坐標(biāo)計算公式見式(3)至式(5)。
三角形計算見式(6)。
式中:index為格網(wǎng)索引值;Di mens i ons為生成的海浪的分辨率,分辨率越大代表著海浪細(xì)節(jié)表現(xiàn)得越充分;uvs為海浪的偏移,即海浪在某時刻的位置;vec為海浪頂點高度;tries為生成的海浪三角網(wǎng)格。
Unity中的網(wǎng)格全是由一個個三角形相互連接構(gòu)建而成的,所以三角形的生成與存儲非常重要,可通過Mesh.vertices函數(shù)對其進(jìn)行保存。
基礎(chǔ)網(wǎng)格構(gòu)建完畢后,保存腳本文件,然后返回Unity中運(yùn)行,從而生成一個網(wǎng)格模型。由于在編寫腳本文件時只聲明了海面網(wǎng)格,并沒有對網(wǎng)格高度進(jìn)行計算,所以只能得到一個沒有波動的三角海面網(wǎng)格(見圖1)。
1.2.1 Perlin噪聲算法。Perlin噪聲算法是Ken Perlin提出的一種強(qiáng)大算法,該算法常用于生成隨機(jī)數(shù),從而被廣泛應(yīng)用于電影、游戲等領(lǐng)域中。在游戲領(lǐng)域中,該算法用于生成各種波形、起伏不平的材質(zhì)、紋理等,如《我的世界》游戲中的地形就是用該算法生成的。除此之外,該算法還可生成火焰、云等效果。在電影領(lǐng)域中,該算法主要用來生成水面波浪。從本質(zhì)上講,Perlin噪聲函數(shù)是一個隨機(jī)數(shù)生成器,但其與普通的隨機(jī)數(shù)生成器有所不同。Perlin噪聲函數(shù)是用一個整數(shù)作為參數(shù),然后返回一個基于該參數(shù)的隨機(jī)數(shù)。為了引入噪聲函數(shù)的相關(guān)概念,用三次函數(shù)對其進(jìn)行插值即可形成連續(xù)的噪聲函數(shù)。
1.2.2 高度場生成。使用二維Perlin噪聲建立海浪高度場,通過Perlin噪聲建立海浪高度場的步驟如下。
①定義一個晶格結(jié)構(gòu)。構(gòu)建一個二維平面,同時生成每個頂點的“偽隨機(jī)”梯度向量,即每個頂點都生成一個偽隨機(jī)梯度向量。偽隨機(jī)是指對任意組相同的輸入,必定得到相同的輸出,且其不是完全隨機(jī)的,只是在生成函數(shù)不變的前提下,每個坐標(biāo)的梯度向量都是確定不變的。梯度向量是指該頂點相對單元正方形內(nèi)某點的影響是正向還是負(fù)向的。二維Perlin噪聲的梯度向量一般用(-1,1)、(0,1)、(1,1)、(-1,0)、(1,0)、(-1,-1)、(0,-1)、(1,-1)這八個向量來表示。采用這些特殊梯度向量是為了避免“鏡像現(xiàn)象”。二維情況下的晶格是一個正方形。只要確定左下P0(x0,y0)和右上P1(x1,y1)兩個點的坐標(biāo),就可確定其所在晶格。
②確定梯度向量,得到點積。由步驟①得到晶格,輸入一個點P(x,y),該點即為給定點,可用floor函數(shù)求得P0點坐標(biāo),見式(7)、式(8)。
式中:x0、y0是P0點橫縱坐標(biāo);floor函數(shù)為向下取整函數(shù),如a=2.2,則floor(2.2)=2.000 000。
根據(jù)給定的點P可得到晶格的頂點坐標(biāo),即P0(x0,y0)、P(1x1,y1)、P(2x2,y0)、P(3x0,y1)。然后在頂點處生成隨機(jī)梯度向量,即g00、g01、g10、g1(1見圖2)。
圖1 海面網(wǎng)格
圖2 晶格結(jié)構(gòu)和梯度向量
接著進(jìn)行點積運(yùn)算,先要確定晶格頂點到P點的距離向量,用dist i,j來表示,見式(9)。
式中:di st為距離向量;i、j分別取0或1,如i=0,j=0,則P0(x0,y0)到P的距離向量用dist00來表示。則點積計算見式(10)至式(13)。
式中:s、t為點積結(jié)果。當(dāng)兩個向量的夾角小于90°時,點積結(jié)果為正;當(dāng)兩個向量夾角大于90°時,點積結(jié)果為負(fù);當(dāng)兩個向量夾角等于90°時,點積結(jié)果為0。
③插值,得到噪聲。一般選擇緩和曲線作為插值函數(shù),并代入坐標(biāo)進(jìn)行線性插值計算。使用緩和曲線計算插值因子時,噪聲函數(shù)的起點和終點的變化比較緩慢,且中間部分變化明顯,也就是說當(dāng)接近固定點時,變化速率變緩。1985年,Perlin首次提出Perlin噪聲時,使用的緩和曲線為y=3x2-2x3。該緩和曲線的一階導(dǎo)數(shù)滿足連續(xù)性,但其二階導(dǎo)數(shù)在晶格頂點處(x=0或1)不為0,呈現(xiàn)明顯的不連續(xù)性。所以,Perlin在2002年發(fā)表的論文中,將其改進(jìn)為y=6x5-15x4+10x3,該函數(shù)無論是一階導(dǎo)還是二階導(dǎo)都滿足連續(xù)性(見圖3)。且函數(shù)越是高階,可導(dǎo)函數(shù)的曲線就越平滑,本研究選取y=6x5-15x4+10x3作為插值函數(shù),進(jìn)行噪聲平滑處理。
使用緩和曲線計算插值因子的步驟如下。
首先分別計算出x、y方向的加權(quán)因子,見式(14)、式(15)。
然后使用加權(quán)因子分別對x、y方向進(jìn)行線性插值,先對x方向進(jìn)行線性插值,見式(16)、式(17)。
最后對y方向進(jìn)行線性插值,得到最終的噪聲值,見式(18)。
得到的最終插值圖像見圖4。
使用Shader Graph進(jìn)行紋理渲染。Shader Graph是在Unity 2018版本后推出的一款通過可視化界面的節(jié)點連接來實現(xiàn)著色器的創(chuàng)建及編輯的可編程式渲染管線工具。相較于Unity Shader,Shader Graph的渲染管線不用編寫復(fù)雜的代碼,其圖形化編輯界面也更加友好。
Shader Graph有兩種打開方式,一是打開Unity編輯器,在創(chuàng)建項目時選擇Universal Render Pipeline來創(chuàng)建項目,通過這種方式創(chuàng)建的項目可直接使用Shader Graph,不再進(jìn)行配置。二是創(chuàng)建一個默認(rèn)的3D模板,然后安裝shader graph和URP渲染管線。其渲染過程如下。
1.3.1 海浪顏色設(shè)置。設(shè)置兩個顏色,分別記為A和B,使用線性插值及菲涅爾效應(yīng)得到海面顏色(見圖5)。
圖3 插值函數(shù)對比
圖4 2D Perlin函數(shù)插值圖像
圖5 顏色光照設(shè)置
1.3.2 設(shè)置海浪偏移。先設(shè)置海浪紋理進(jìn)行貼圖,然后對其UV值進(jìn)行設(shè)置,世界坐標(biāo)、像素值以及UV值的對應(yīng)關(guān)系為:X-R-U、Y-G-V、Z-B、WA。在Unity中,海平面處于XZ平面,需要R、B對應(yīng)U、V。接著設(shè)置偏移量,通過改變時間,來改變貼圖的移動方向。由于一張UV貼圖不能體現(xiàn)出海面波浪效果,所以要建立兩個方向相反的UV貼圖。最后將兩條渲染管線貼圖效果進(jìn)行法線融合,將結(jié)果連接到Normal中(見圖6)。
1.3.3 設(shè)置海浪平滑。只要創(chuàng)建一個平滑屬性,連接到Smoothness,就可在屬性面板進(jìn)行設(shè)置。
圖6 偏移設(shè)置
為了驗證Perlin噪聲算法生成的海面及添加光照后的效果,進(jìn)行仿真試驗。根據(jù)本研究提出的方法,在Windows10 64位操作系統(tǒng)、Unity3D 2020.3.32f1c1平臺中,利用C#語言在Visual Studio 2019中編寫腳本,天空盒使用系統(tǒng)自帶的sky box,最終生成的海浪效果如圖7所示。圖7(a)為Normal Strength=4、Tilling=0.08時的海面,圖7(b)為Normal Strength=4、Tiling=0.2時的海面,圖7(c)為Normal Strength=8、Tilling=0.08時 的 海 浪 形 態(tài),圖7(d)為Normal Strength=8、Tilling=0.2時的海浪形態(tài)。從圖7(a)和圖7(b)可以看出,在法線強(qiáng)度相同的前提下,Tilling越大,海浪越密集。由圖7(a)和圖7(c)可知,當(dāng)偏移指數(shù)相同時,Normal Strength越大,海浪的顏色越深,細(xì)節(jié)表現(xiàn)越明顯。當(dāng)Normal Strength相同時,Tilling指數(shù)越大,海浪的波紋越密集,海浪起伏變緩。
Unity3D處理光照和陰影比較方便,通過向場景中添加兩個平行光,可真實地表現(xiàn)出白天和夜晚狀態(tài)下的海面效果,添加光照生成的海面效果如圖8所示,圖8是在相同Normal Strength和Tilling參數(shù)下不同時間的海浪。圖8(a)為添加光照,顯示為白天效果;圖8(b)為關(guān)閉光照,顯示為夜晚效果。
圖7 不同參數(shù)下的海浪形態(tài)
圖8 不同時間的海面
本研究利用Unity3D平臺,從海面網(wǎng)格的創(chuàng)建出發(fā),利用Perlin噪聲生成海面高度場及海面渲染三個模塊,對海面建模仿真進(jìn)行研究,調(diào)整光照與法線強(qiáng)度,可方便快速且真實地表現(xiàn)出海面。雖在各個模塊都要考慮其仿真效果和真實感,但并沒考慮在自然環(huán)境下(降雨、風(fēng)等)的仿真效果,以及沒有采用實時數(shù)據(jù)對海面進(jìn)行建模,針對上述問題,該方法還有待進(jìn)一步研究。