這一部分結合PDG來談談Houdini的地形工具。前半部分會講一些我對Houdini地形工具的理解,算是作為學習筆記記錄在此。後半部分會根據官方的教程整理出在Unity引擎中的實現步驟,比較繁瑣,熟悉的直接無視就好。

過程化生成工具

目前主流的過程化生成工具都是兩種思路,一種基於Node,另一種基於Layer。後者最大的好處在於可以快速上手,而且有一個所見即所得的編輯邏輯,例如Photoshop,Substance Painter都是這樣。而基於Node的工具則需要使用者具有很清晰的邏輯,知道自己用這個節點要幹什麼,但這同時也大大便利了後期的修改和簡化,通過修改每個節點的參數即可達到不同的效果。目前的Substance Designer,Houdini,blender都是基於Node的思路。

舉個例子,在這篇文章中我們製作一個地形demo按照這樣的順序:

每個部分都由Houdini的數個節點組成,這些節點都有具體的參數來負責具體的功能,可以很方便的修改得到最終效果。同時,PDG模塊可以將這些HDA模塊統一在一個HDA下管理,分別控制不同的步驟,非常方便。

但是這並不代表基於Node就是好的,例如上面的layout繪製,比起根據節點一個個去計算,直接創建Editable Node去在引擎中刷地形是最快最方便的。

另外推薦一下官網上的Houdini Masterclass(可能要科學上網),詳細的講了H17中Terrian的製作步驟

地形侵蝕

Houdini的erosion演算法使用了hydro和thermal這兩套結合,熟悉UE4的可以理解為將它原生的erosion和hydro erosion結合。

在erosion的解算節點中可以詳細的看到在Houdini中erosion的做法,每一幀都先使用thermal去計算一個大致的腐蝕效果,然後根據water mask和height mask去做hydro erosion計算水的腐蝕,最後再去計算一個水的蒸發效果。

具體的腐蝕模擬可以看這篇論文:Fast Hydraulic and Thermal Erosion on the GPU

另外值得一提的是Houdini的Erosion是基於OpenCL的,所以應該也是可以用GPU加速的,但是嘗試修改env文件並沒有成功...如果可以用HDK實現那肯定能大大提高速度。

引擎測試

根據官網上給出的教程,這裡我自己實現了一下,發現很多坑....(吐槽一句Houdini Engine for Unity真的太難用了)

地形筆刷:

在一個subnet下建立兩個geo節點,一個作為繪製,一個作為導出。整個subnet會用HDA導出在引擎中使用

先用一個grid節點作為整塊地形圖,將size和rows作為參數

之後為我們的筆刷工具創建兩個屬性,density和scale,一個決定密度分布,一個決定繪製大小。並使用random節點對scale做一個小範圍的隨機(當然也可以直接用rand函數),筆刷則用edit節點實現

另一側,創建tube幾何體作為我們的山體,Height和Radius Scale是傳出的參數:

我們用copytopoint節點將這個tube替換掉上面scatter後的grid,製造出山體的layout分布:

attribwrangle用來傳遞scale參數,scatter則受density參數影響

最後將grid和這個merge一下即可輸出

然後是Exporter部分的做法,這邊直接用了一個Object Merge取得幾何體,然後用ROP節點輸出到文件夾下。注意路徑一定要用相對路徑

ROP(Render Operators)

將整個subnet打包為HDA輸出,作為我們之後的地形筆刷工具

在Node屬性下激活Editable Nodes作為筆刷

參數選擇之前painting節點下grid的size和row、tube節點下的radius scale和height以及Export節點中ROP的save操作和輸出文件路徑

在Unity下使用我們剛剛輸出的HDA,點選options中的Enable Editable Node Tools

之後便可以使用筆刷工具在視窗里繪製了

筆刷這裡有我們之前創建好的兩個屬性,density和scale

(吐槽一句這個筆刷超級反人類的,而且不!支!持!撤!回!

做好之後就可以點擊右下角的export保存出去了

轉換為地形:

上面繪製的只是一個大致的分布,這種效果肯定是無法放到遊戲里的,而且純粹的幾何體也無法使用Houdini的各種heightfield工具,因此我們新建一個subnet來轉換它為heightfiled文件,並對其初步處理

使用heightfield_project處理幾何體為heightfield

可以看到很多邊緣過渡部分都很不自然,具體的細節我們放到之後的Erosion部分做,先做些簡單的處理讓其更自然

blur的作用是減少地形銳利部分,distort對整體地表添加一個雜訊,而slump則使山脊過渡部分更自然

清除掉slump的mask即可輸出為HDA了

Resolution是heightfield節點的size,effects下的都是上面blur和distort的參數

處理後的效果已經能看了,但是明顯少了很多細節,因此我們需要使用強大的erode節點

地形侵蝕:

Houdini的erosion演算法在上面講過,這裡直接講在Houdini中的做法

在SOP_HDA下複製我們之前創建的get_terrian_layout(獲取PDG output的那個)節點,按照如下圖連接heightfiled節點:

節點連接(1. 在heightfield_file刪掉layering的layer name 2. 在mask節點那調整好分層比例)
Erode初步效果

如果是初次接觸Houdini,可能對erode節點不熟悉,Houdini的侵蝕效果是根據下方的time line來推進模擬的,這裡我們拉動下方的動畫條來看看模擬之後的效果

35幀時的模擬效果

為了方便之後在引擎中調整,使用Time-Shift節點來控制侵蝕效果。記得按住Ctrl+Shift左鍵點擊Frame屬性刪除關聯

使用maskclear清除掉mask,這裡為了顯得不那麼程序化,利用distort by noise做一些變形,最後還是用一個NULL節點標記輸出

之後老辦法Shift+C把剛才連的節點聚合起來,HDA輸出

參數分別來自於timeshift、erode和distort節點

回到我們之前創建的Level_creation_top中的topnet下,在創建好的的hdaproceesor節點下再創建一個hdaprocessor,並將我們上面創建的HDA傳入

然後就可以開始Dirty and Cook了嗎?不對,一定要勾選這個!(血的教訓QAQ,運行時發現一直無法創建geometry...)

最終顯示結果

最後整理下整個topnet節點輸出成HDA就可以開始在引擎中測試了,記得把所有hdaprocessor節點中HDA File路徑下的JOB更替成HEU_ENVPATH_JOB

按之前的辦法把TOP節點的HDA拖入場景。可以看到右邊屬性中有我們之前在Houdini中設置的layotu參數,把我們之前從Unity中導出的layout bego再傳入

創建PDG鏈接,按下Cook等待結果(erode節點因為eode time較大會佔用較多的時間)

輸出的結果就是Unity的terrian

材質渲染:

(這部分我踩了好多坑,有Substance Designer的,有Houdini Engine的,仍然沒得到滿意的效果...希望能有個大佬和我討論下)

我們在Houdini中給地形分層,做出不同的材質效果。同樣複製我們之前的get_terrian_layout節點,創建出不同的mask來分層:

這裡就不展開來講了,按照項目的需求調整maskbyfeature參數即可(那個VEX節點mask = 1選中全部創了一個base mask),而每個copylayer節點都標註了一個層級,最終的layer信息:

這裡官方教程創建了base,cliff和grass三個層級

為了避免mask之間的遮擋,我們使用blast節點清除不必要的mask,除了height mask是必須要保留,其他都可以清除掉

只保留了base,cliff,grass和必要的height

之後我們使用attribute create節點設置材質傳入的參數,因為我們這裡創建了三個層級,節點我們也同樣使用三個

參數的命名和類型需要嚴格按照Houdini Heightfields to Unity Terrain中的標準

每個節點的Group屬性需要區分開,以對不同的層級著色,例如grass的節點需要這麼寫

之後我們便可以Shift+C一站式把剛才做的創建為HDA了

參數為unity_hf_tile_size的value和unity_hf_texture_diffuse的string

在Unity中更新我們的top hda,可以看到多了texturing屬性,Path就是我們貼圖的相對路徑

關於這個路徑...實在是挺坑的,我這裡解決方案就是把貼圖放在和Scenes同一級的Resources文件夾下,然後把這個文件夾下的參數作為相對路徑傳入,注意圖片文件的後綴名也要去掉。例如這樣:

這個真的超級難用...

我這裡直接從訂閱的Substance Source里下載了三張地形的basecolor貼圖來用,之後就可以在PDG Link中Cook結果了:

不知道能不能GPU加速這個erode過程
分層不規範,材質兩行淚

地形分塊:

為了減少我們每次渲染的區域,我們給地形分塊,同樣可以在PDG中做到

在SOP下建立Split節點,創建為HDA:

tilesplit節點的Tile count和number作為參數

在Top節點下新建hdaprocessor,把上面創建的HDA傳入

在split的HDA Parameter里修改Tile Number的reference:

同時Work Items的Iteration屬性也要改,來生成a x a大小的地形

Cook Node可以看到此時的task graph多了很多task

可以看到最終產生了16個(4 x 4)分塊

在Unity採取跟之前同樣的做法,最終得到的結果為:

總結

本次地形工具中的PDG中用了4個HDA Processor,一定程度上已經可以看出PDG流程相比傳統單獨HDA做法的方便之處

跟著官網的教程製作的同時發現了很多可以深入挖掘的點,例如Erode部分的演算法,Texture部分的mask布置,地形筆刷工具的改進等等,Houdini的Heightfield工具十分齊全,感覺一定程度上已經可以代替WorldMachine高度圖導出,再結合強大的PDG流程,可以快捷的控制各個部分的效果。

雖然Houdini很牛逼,但是還要吐槽一下Houdini Engine for Unity的反人類,簡陋的UI、無法撤回的筆刷、詭異的貼圖引用路徑、莫名其妙的HDA丟失......有需求的話,感覺還是自己寫一整套方法和引擎去交互吧。


推薦閱讀:
相关文章