背景
在大世界游戲里,植被(biome)是自然環境非常重要的組成部分,雖然UE4里的也有比較不錯的地形+植被系統,但相比國外AAA級游戲的效果,還是有不少的差距,簡介如下:
- UE4的植被分為(Folige Type)和(Grass Type),都是通過HierarchicalInstancedStaticMeshComponent來進行實例渲染,但生成方式不同
- Folige Type可以帶有碰撞信息,通過Foliage Paint tool或Procedural Foliage Volumes 預先生成和放置,再跟隨場景讀取時加載。
- Grass Type自己不帶碰撞,根據所在的Material Layer和設置預生成密度圖,在運行時根據攝像機來生成視野周圍的Grass。
- 兩種方式在擺放上都會有不少的限制
- 當一塊地表上出現多種Foliage或Grass時,還是會產生不同類型植被之間的競爭和重疊的情況
- Folige Type在特別是石塊,樹木,草體都存在的情況下,增減修改都會變的很麻煩
- 布局上還是要人為的控制,一旦場景地形要修改,就要重新各種刷新或配置Foliage Type,Grass Type也要跟着刷Material Layer來改變。
- Procedural Foliage Volumes可以一定程度上減少Paint的工作量,但可控的參數過少。
所以植被的過程化系統無論是表現上,性能上,還是迭代的便利性上,都是非常重要的部分。近兩年GDC上,Ubisoft在
Tom Clancy’s Ghost Recon: Wildlands和Far Cry 5(后簡稱FC5)的過程化植被生成上都有不錯的分享。這里我把Houdini的植被系統實現分為三部分來分享,在基礎管線部分主要是Houdini的植被系統與UE4的植被系統如何做銜接,過程化地形部分本節先會分析FC5的實現機制,下一節介紹如何在Houdini和UE4環境下實現類似功能。
Far Cry 5的植被系統概述
- 植被的分層結構:每個地塊有一個生態組(Main Biome),而主生態組又包含若干的子生態組(Sub Biome)。FC5里把一個Sub Biome結構稱為Recipes,每個Recipes由代表不同的區域和種類來命名,比如biome_moutiain_forest,代表的是山上的樹林。而一個Recipes里則是若干個Species組成,每個Species代表的是Recipes對應區域和生態里一個植物或物件種類的生成。
- Houdini與分層的聯系:每個Species其實都是一個Generate Terrain Entities的Houdini HDA節點,把HDA節點一個接一個的連在一起組成Recipes(Sub Biome),而所有的Recipes再連接在一起成為一個Main Biome。每個HDA可以讀取地形Mask信息和它的配置參數,輸出自己對應的植被的擺放信息,而連在后面的HDA會根據前面HDA留下的信息,通過HDA內置的參數和算法,確定是否會覆蓋前一個HDA的生成信息。
- 地形數據信息:根據地形的高度信息,生成不同的Mask信息,以及用戶手繪的數據
- 包括Occlusion,Flow,Slope,Curvature,Illumination等通過高度生成的信息,以及海拔,經緯度,風向等人工輸入的信息
- 湖泊,道路,柵欄,電線桿,峭壁等其他過程化生成的Mask信息也會被導出保存為2D貼圖,確保植被不會生成到這些區域。
每個Speicies對應的
Generate Terrain Entities都是同一個HDA節點,只是根據對應不同植被實體有不同的參數設置,除了實體擺放功能外,還可以根據擺放后的實體信息影響地形並輸出到地形數據上,以及定義每個Speicies的生存能力(Viability):
- Species的Entities功能 :生成地形上特定種類的實體,包括樹,灌木,花草,岩石等等
- Viability : 每種物體在根據區域有自己的生存力,以及對應的生存范圍和生存優先度,來避免物件之間重疊和穿插。
- Age:樹木有自己的Age(年齡),根據Viability生成SDF的來決定。根據Age來控制樹的高低。
- Size : 同一種類的樹木有幾種不同的Size,小樹傾向在外圍,大樹傾向在中心,同一Size可以這種植被的變化(枯樹等)。也可以用Age來替代Viability來控制Size
- Scale:在不同的Size等級之間里通過Scale來平滑過渡。
- Color: 每個植被實例可以根據地形或自身屬性來改變的顏色變化,比如通過水體的SDF來控制草體Species的顏色。
- Density:樹木密度,可以根據樹的大小設置不同密度。
- Rotation:根據地形坡度,水源信息以及風力來改變草體的旋轉和方向。
- Transform : 沒有特意講到,應該就是Transform信息
- Group : 同樣沒有特意講到,可能就是Houdini的Group信息。
- Species的寫回Terrain功能 : 布置的資源也可以影響到地形的信息。
- Terrain Color:地表植被信息可以給予地形貼圖一個Tint Color,這個顏色也會通過shader影響到代表上草體的顏色,在地形貼圖有限的情況下增加變化。
- Terrain Textures : 輸出樹根部分的貼圖ID,以及混合系數,配置到Terrain Material的Layer Texture上,做到地表和樹根的融合效果。
- Terrain Data Output : 可以把Species的數據包裝輸出,比如把Age或Viability寫入到一個屬性,再由后面的Species讀取。
- Terrain Deformation:植被信息會影響到地形HeightMap的變化,比如樹根部分會讓周圍地表隆起。
整個FC5 Biome的核心就是這個名為Generate Terrain Entities的HDA節點。
- 輸出到編輯器:所有實體的信息會以Entity Point Cloud的方式輸出到引擎編輯器,每個Point除了位置信息屬性,還有對應的實體實例引用,以及前面提到的HDA中生成的類似Size,Scale,Color等信息傳送到編輯器,編輯器里再根據這些信息在場景里生成對應的資源。
所以,要實現FC5類似的植被系統,Houdini和UE4里需要做的功能主要有:
- 根據地形的HeightData生成各種Mask信息,以及其他過程化工具生成Mask的回讀功能
- 類似Generate Terrain Entities里的HDA功能
- HDA所生成的點雲和Terrain信息回讀到UE4里改變之前的配置
本節會先對FC5的文檔做需求分析,在下節提供具體的Houdini的實現方法。基礎篇里涉及如何在UE4里把HDA輸出的數據運用到場景里。
地形數據生成
上文提到,過程和生成Biome使用的地形數據主要來源有以下兩個部分:
- 在Houdini里基於Heightmap生成
- 游戲編輯器中輸出的2D Mask數據
基於Heightmap生成各種特性Mask的功能,在使用WorldMachin做地形時就經常被使用,Houdini作為WM的替代品也有對應的節點。使用這下圖這3個節點,或者基於他們的內部實現自己整合一個節點就可以生成
Occlusion,Flow,Slope,Curvature,Illumination等信息了。
而像在編輯器里過程化生成的湖泊,電線桿等信息,就是設置一個公共的資源目錄保存對應的Mask,在每次編輯器里調用過程化工具生成時,使用Python腳本加載對應Mask圖,使用Mask By Object節點生根據場景成Mask,再用Python把過程化場景的信息作為Mask保存起來。或者是把每次過程化生成的信息保存,然后在統一Cook時輸出Mask信息到2D貼圖里。
總體來說,地形數據的生成和導入,都是比較成熟技術,沒有太大的難度,后面還是聚焦在植被的生成方法上。
地形的植被實體生成
下圖是FC5的層級結構示意
實際整個Main Biome,就像下圖這樣一個個的代表特定植被的Species的連接在一起。
每個Species都是一個Generate Terrain Entiies的HDA節點
接下來通過文檔里HDA的截圖分析需求。下圖是HDA的主面板。
圖上半部分是植被,地形數據列表和顯示選項等,生成參數的配置在下半部分,有Entities和Terrain兩個頁簽。里面有擺放植被和輸出地形信息的功能。
- Viability
Entities頁簽上首先就是Species的Viability的設置,
Main Biome就是大量Species節點串連起來的結果,下圖的示例是兩個Species串聯,Viability的值則是從Terrain Attribute Data里讀取的,也就是之前生成和導入的Terrain Mask。下圖中SpeciesA的Viability是從Occlusion的mask取值,他的Viability值的倍數為1,而SpeciesB是從Flow Mask里做Viability的取值,Viability的值的倍數為2。並使用Ramp圖標來做漸變和裁剪效果。最后途中樹木的擺放效果也是因為B的Viability值比A的Viability高,所以Mask重合的部分的B樹會替換掉A樹。
因為SpeciesA和B在樹的種類,密度,大小上並不一樣,Point Cloud並不會完全重疊在一起,而是類似下圖這樣的分布關系,所以不能只通過的植被對應的Point的位置信息和Viability來做判斷,還需要讓每個Entity Point有Viability Radius,下圖中,因為B的Viability值比
A低,所以當他們的范圍有重疊時,B的樹就會被A替換掉。
此外,每個
Species還有Priority和Priority Radius的設置,計算最終的擺放前,先會用Priority做比較,當Priority一樣時再用Viability值做比較。
有些植被還有它特定的生存習性,地形數據除了從Heightmap計算或外部讀取外,還需要可以人工的在houdini里控制生成范圍,再把多個地形數據的混合出結果,例如下圖得到就是在一定海拔高度范圍內,沿着flow Line生長的植被Mask。也可以把之前編輯器導出或保存的例如湖泊,道路,懸崖等Mask信息導入Specie的地形數據里作為剔除Mask使用,確保植被不會生成到這些不應該生成的位置上。
通過在每
Species的Terrain Attribute里增加不同的數據來混合,就可以得到類似特定位置的Sub Biomes的生成位置信息了。
- Size和Scale
即便是同一個
Species里的同一種植被,因為生長環境和時間的不同,也會有大小(Size)的區分。自然界中,通常小樹會長在樹林的邊緣,而大樹更傾向在樹林的中央。需要用Size來控制不同生長程度的植被的大小,再使用Scale增加一些隨機的變化,讓整個森林更加自然。下圖增加了5級的Size后,雖然有了一定的變化,但還是會有階梯狀的感覺。
在Size級別之間增加了Scale后,階梯感就消失了。
使用Size和Scale設置,有了不同比例的同種類樹木后,就要想辦法把合適大小(Age)樹木布置到場景里。
- Age
如何在正確的位置擺放對應Size和Scale的植被,是通過讓植被的Age與Size對應,來選擇擺放多大尺寸的樹木。前文也提到,自然的樹林是邊緣的樹齡小,中心的樹齡大的分布。通過面板上的Age Max Distance的值,基於Viability的Volume值收縮一定距離后再生成SDF,作為Age使用。再根據Age對Size的Influence和Age Ramp,得到對應樹木的Size。
通過Age Ramp對應不同的Size的分布
- Density
通常是使用Houdini的Scatter設置一定的密度值,再將Viability的Mask轉為Point Could。但默認的方式轉換,每個Point自身沒有Size信息,當密度過大,或者Scatter不同Size的植被時,很容易會出現同一種植被相互疊加的情況。所以這里要將Size轉算為Density值,Size越大,Density越小。
如下圖所示,Size越小,
Density越大。同時也可以讀取其他的Terrain Data來影響Density值。
- Color
地形信息也會對植被的顏色產生影響,例如讀取水的SDF值,根據顏色的Ramp來對水塘附近的植被產生顏色變化。
- Rotation
自然界植被還會受到環境的影響,產生一定的旋轉效果。比如在斜坡上的植被會沿着坡度有一定傾斜和旋轉,河邊的草體會更朝向水的方向,以及會受到風力的影響傾斜等等。這個在Houdini里實現比較簡單。
植被對地形的影響
Species HDA的另外一個功能就是可以根據植被來影響地形數據。這些功能和地形制作部分比較相似。
- Terrain Defromation
植被的Mask可以影響到對應地形的高度,這樣可以模擬出樹根隆起的效果。
- Terrain Texture
可以將與樹根部分貼圖對應的Terrain Texture ID輸出給地形材質,讓地形圖層部分使用的貼圖與樹根貼圖對應,而做出融合效果。
- Terrain Data Output:
向下圖這種在黃松(
Ponderosa)周圍擺放石塊(Rock)的效果,是后面的Rock的Species依賴前面Ponderosa
Species的生成結果。
實現方式就是把
Ponderosa的viability值輸出,再Rock Species里再讀取。
根據
Ponderosa的Viability Mask Scatter得到Rock的Entity Point。
除了V
iability外,也支持Age的輸出。
FC5的每平方公里的場景有60w左右顆植被。整個游戲有100平方公里。
- Terrain Color
由於Terrain Texture總數有限制,需要根據
通過地形數據生成Tint Color,在地形渲染時讓Tint color作用到
Terrain Texture上產生地表變化。
同樣,在地表上擺放的植被的shader,也可以受到Tint color的影響。
總結
通過植被系統輸出下圖中數據到編輯器,不但可以自動化的生成植,還可以根據植被信息進一步增強地表渲染效果。
FC5的整個植被系統的需求分析就到這里,除了一些細節功能外,Houdini方面並沒有太多的技術難點,下一節,會針對UE4 Houdini Engine對應UE植被系統的管線,以及如何在Houdini里實現相關功能進行展開。
<wiz_tmp_tag id="wiz-table-range-border" contenteditable="false" style="display: none;">
