基於Unity3D引擎的大地形生成研究

遊資網發表於2019-11-28
基於Unity3D引擎的大地形生成研究

之前文章中我們已經完成一套基於PC主機等高階平臺的地形系統基本的渲染,載入和資源結構。但是很顯然光有這些是遠遠不夠的,因為即使基本功能齊全,這套系統終究是要給人用的,而我們作為技術美術,除了實現所有的引擎底層必需的功能以外,也要把生產流程全部打通,先掛一下上一篇的地址,防止有新來的看官接不上:

MaxwellGeng:基於Unity3D引擎的大地形載入研究

題圖來自Lute Li使用World Creator製作的測試場景,感覺很有美感就放上了,實際上我們本篇將用很大篇幅介紹使用World Creator這款DCC的經歷,這是一款精緻快捷的地形開發軟體,效率優秀,效果可靠(起碼能達到AA級以上的遊戲要求),完全可以成為生產流程研發的測試工具。

我們在Unity引擎中開發生產工具鏈時,核心思想有以下三點,這三點一直貫穿本人的開發始末:

1.        儘可能使用自定義的載入和序列化,避免使用Unity內建的資源管理。

2.        儘可能開發執行時編輯工具,避免使用Unity Editor完成複雜功能。

3.        大道至簡,引擎內功能能少就少,凡是能在DCC中完成的工作不要試圖搬運進引擎。

第一條比較容易理解,比如上一篇文章中我們就曾講過,為了保證執行效能和生產效率,除了必須經過SRP渲染的貼花GameObject以外,完全放棄了Unity內建的資源管理,包括Resources,AssetBundle等,直接使用二進位制檔案儲存,而.Net提供的FileStream可以非常直白的計算位元組偏移和讀寫緩衝區大小,並且可以既讀又寫,因此資源匯入匯出部分的程式碼我們可以直接複用,API也可以變成傻瓜式的“傳入一張RenderTexture,傳出儲存到硬碟的資料”,消滅掉額外的記憶體碎片垃圾,例項化等消耗,因為自定義的資源管理系統在自由度上有絕對優勢,因此常常能在效能和生產效率雙方面碾壓內建資源管理方法。

儘可能使用執行時則是純粹的經驗之談,在Scene視窗中使用Unity Editor不僅提供的API不夠,比如一些複雜的如物理模擬等效果沒法實現,而且其生命週期具有不確定性,很容易出現奇妙的問題,相反,在執行時讓美術製作人員像玩遊戲一樣操作控制檯,優越性自然而然就可以體現出來。

引擎功能能少就少是我們最重要的一點,不像自研引擎,MPipeline是一款開源的渲染模組,在通用性上有很高的要求,因此對於一些細碎龐雜的功能我們在開發時要保證能少就少。

下面正式進入正題,由於我們設定將一張接近於無窮大的地圖,物理分割為多張固定大小的圖,如將16384m * 16384m的地圖分割成256張1024m * 1024m的大塊,每塊地形資料結構都是獨立儲存的,它們之間唯一關係就是在執行邏輯時經過統一的二叉樹。因此我們讀寫的時候可以隨意指定每次需要匯入的塊,而且可以一次性匯入多個相鄰在一起的塊。

按照Ghost Recon提供的規格,使用2 texel / m也就是半米一格的高度圖,表達材質分佈的Material Index Map則使用和高度圖同樣的大小,所以每1024m一格的地形將會使用2048 * 2048解析度的高度圖,因此如果需要製作一張大小為2048m * 2048m的地形,我們需要匯出一張4096解析度的高度圖,由於高度圖對精度要求要保證無損,因此無論儲存還是匯出時都不應該有任何壓縮,這裡在World Creator使用TIFF格式輸出,保證輸出的結果是完全無壓縮的R16_UNorm格式。

在World Creator中製作一個簡單的Voronoid Erosion Terrain:

基於Unity3D引擎的大地形生成研究

匯出時使用完全沒有壓縮的TIFF格式,這個格式在Unity中可以被正常讀為R16_UNorm:

基於Unity3D引擎的大地形生成研究
World Creator截圖

匯出到MPipeline中的渲染效果:

基於Unity3D引擎的大地形生成研究

可以看到效果非常接近,這說明這套高度圖匯入完全沒有問題,這個步驟也非常簡單,我們只需要注意讓DCC匯入規格與引擎內渲染規格統一即可。

接下來是材質,相比於高度圖的匯入,材質系統的複雜程度就要高的多了,這套使用Index Map作為材質媒介的工作流程,在大幅度簡化渲染的情況下,也嚴重增加了工具的複雜程度,因為這並不是一個已經存在很久的通用的工作流程,所以我們必須定製一套工具。

Indexmap的原理十分簡單,用R8_UNorm格式的貼圖儲存使用的材質索引,其中每一張材質都由兩套貼圖按比例混合而成,之所以要這樣做,是因為這種兩兩按比例混合的方法是比較適合對自然景觀進行還原的,同時這樣也非常適合按層來進行疊加的方法,可以隨時修改,比如這裡我們拿出兩張參考圖,分別來自黃土高原和張掖的丹霞地貌:

基於Unity3D引擎的大地形生成研究

基於Unity3D引擎的大地形生成研究

之所以要用這兩張參考圖,是因為這兩張圖都非常明顯的表現出了一個地貌的一個重要特點,那就是地貌材質“大聚居,小雜居”,從巨集觀上看,整個地貌稜角分明,該是黃土的就不會長草,該是草皮的就不會大片出現黃土,丹霞地貌也同樣,可以看得出同一種顏色基本“抱團”在一起,但是在兩種材質交融的部分則表現出非常豐富的混合效果。當然,這樣地貌的形成需要經過種種侵蝕和風化以及植被的生長,這些屬於地質學內容,不在我們討論範圍內,而需要我們著重討論的則是如何將這樣的過程表現出來。

在World Creator中,材質的分佈就正是遵循了這樣的自然規律,同一種材質分佈聚集在其中的一塊,每一種材質都以層的形式進行疊加分佈。而每一個畫素,也就是一個0.5m * 0.5m的地塊內有且只有一種材質。每兩種材質的邊緣是“硬切”的,也就是隻有會用上一篇文章中講過Bilinear Interpolation的方法實現過渡。

為契合這樣的流程,我們首先要在Unity中完成材質編輯,畢竟材質是引擎的第一手資源,直接決定了渲染效果,這是有必要在引擎內完成編輯和匯出的:

基於Unity3D引擎的大地形生成研究

工具佈置基本比較簡單,和普通材質並沒有什麼兩樣,無非就是Albedo Normal Smoothness Metallic Occlusion這些PBR選項,然後將材質繪製到Render Texture上實現預覽。

在完成材質編輯和預覽後,我們需要匯出材質,World Creator使用了XML檔案作為貼圖的索引,所以對於我們而言只需要用指令碼解析XML並把新貼圖名字填寫進去即可:

基於Unity3D引擎的大地形生成研究

因為World Creator的貼圖追求精簡,所以並沒有使用完整PBR流程,這裡只需要填入Albedo Normal即可,匯出後啟動軟體可以看到結果令人滿意:

基於Unity3D引擎的大地形生成研究

接下來我們在World Creator內隨便擺佈一下材質分佈,當然,本人不是專業的地編,不好看在所難免:

基於Unity3D引擎的大地形生成研究

這幅截圖表現出了兩個問題,那就是邊緣接縫鋸齒感嚴重和貼圖重複嚴重。要解決這兩個問題實際並不是難事。先來說一下重複感的問題,World Creator中已經提供了Eliminate Tilling,效果不錯:

基於Unity3D引擎的大地形生成研究

在引擎中消除重複感的方法我們則是使用了一張隨機的UV Map的方法讓貼圖進行隨機取樣。隨機生成的原理是這樣的,把一張貼圖的取樣縱橫各切3刀,劃分為4x4的塊,然後對這16個塊進行隨機的排列組合,之後再對每個隨機排列以後的塊進行隨機翻轉和旋轉,這套運算可以在Compute Shader內完成,因此我們在遊戲開始時啟動一個Dispatch Pass將隨機結果儲存到一張128 x 128的貼圖內,因為我們是8米一張貼圖的分佈,這意味著在256米以內很難出現重複的分佈,極大的增加了貼圖分佈的隨機性,隨機貼圖的生成程式碼如下:

基於Unity3D引擎的大地形生成研究

在投影VT的Shader中讀取這張貼圖,並對比隨機前後效果:

基於Unity3D引擎的大地形生成研究
原始效果

基於Unity3D引擎的大地形生成研究
隨機排列後

可以看到效果有了明顯的提升,但依然有一些小瑕疵,那就是在兩塊隨機UV接縫處有很明顯的裂隙,這讓貼圖有了一種磚塊感,然而我們並不想要這種感覺,所以只需要在對Tile Map取樣的時候加一個隨機的UV偏移,就能消除掉規整的裂隙了:

基於Unity3D引擎的大地形生成研究


取樣程式碼如下:

基於Unity3D引擎的大地形生成研究


這裡的Noise Texture就是外部傳入的一個固定的噪波圖,而NoiseTillingTexture則是前邊實時生成的UV Map,這裡個人建議Noise Texture使用Substance Designer中Cloud節點生成的RG通道的隨機圖,因為Cloud節點生成的隨機較為圓潤且分佈不規律,比較容易表現出邊緣錯落的感覺。

完成之後在引擎裡測試隨機取樣的效果:

基於Unity3D引擎的大地形生成研究


可以看到,幾乎完全沒有人類肉眼可見的重複感,這還是整個地形只用了一張貼圖的情況,效果令人滿意。這種廉價的Trick方法,比起ShaderToy上IQ大神的Hash演算法來說,隨機程度肯定遠遠不如的,但是IQ大神的方法每次取樣起碼要採3張貼圖,而我們這種方法則卻不增加取樣個數,唯一增加的一張Noise Texture取樣也會馬上得到複用。

解決了重複的問題以後就需要解決不同材質接縫處的問題了。之前提到我們使用了2 texels / m的規格儲存高度圖和材質圖,這意味著材質之間的切割感是肉眼可見的,那就避免不了鋸齒感的誕生:

基於Unity3D引擎的大地形生成研究


使用Bilinear進行插值取樣後雖然效果好很多,但是依然有比較明顯的鋸齒感:

基於Unity3D引擎的大地形生成研究

Billinear Interpolation


為了消滅鋸齒感,Ghost Recon PPT中提到了在Bilinear Interpolation之前對UV進行隨機的擾動,我們也同樣使用了這樣的方法解決問題,同時因為取樣都在同一個Dispatch Kernel內,所以完全可以複用剛才使用的噪波圖的取樣:

基於Unity3D引擎的大地形生成研究


取樣效果:

基於Unity3D引擎的大地形生成研究


走到這裡時,整個流程就只剩下最後一步了,那就是如何讓引擎接受World Creator匯出的結果,也就是讓MPipeline中的工具完成從Splat Map到Material Index Map的轉變,這裡我們首先需要從World Creator中正確匯出一張Splat Map,注意,由於圖片格式限制,一張Splat Map只能容納4套材質的分佈表現,所以我們一次只能輸出4套材質的分佈,如果選擇超過4套材質,World Creator會自動匯出多張Splat Map:

基於Unity3D引擎的大地形生成研究


在引擎內匯入Splat Map,注意,格式必須是非壓縮的線性格式,防止出現意外:

基於Unity3D引擎的大地形生成研究


因為每一張Splat Map的每一個通道與每一種材質都是一對一固定死的,在完成材質編輯以後改動幅度比較小,所以我們可以選擇在每一種材質下指定對應的通道和貼圖,這樣每次美術人員在匯出貼圖後直接把貼圖暴力複製到資料夾裡就可以進引擎一鍵重新整理,非常方便:

基於Unity3D引擎的大地形生成研究


最終匯入效果:

基於Unity3D引擎的大地形生成研究


基於Unity3D引擎的大地形生成研究


可以看到巨集觀效果還是近處效果都基本達到了我們的需求,實現了與DCC的資料同步。

最後總結一下,我們制定的這套工作流程有很多優秀的特點,如通用性,魯棒性強,匯入匯出的高度圖,材質分佈圖格式與各種DCC都非常容易契合;如解耦程度高,在制定流程時並沒有像某些工具一樣竭盡所能的把功能在引擎內整合,避免使遊戲引擎臃腫龐大,保留了修改和相容其他流程的可行性。但同時這套流程目前完成度還很低,比如Virtual Texture最主要的無限貼花功能,則還依然停留在渲染Demo階段,暫未成功打通Houdini Engine;Time of Day, Realtime GI等等高階效果表現也還在TODO List上,我們將會在接下來的文章中一步一步把這些難題克服。

相關閱讀:基於Unity3D引擎的大地形載入研究

作者:MaxwellGeng
專欄地址:https://zhuanlan.zhihu.com/p/89396980


相關文章