HexMap學習筆記(八)——水體

遊資網發表於2019-05-20
HexMap學習筆記(八)——水體


前言

這篇教程的難度還要大於第六篇,同時也是目前為止篇幅最長的。難度主要體現在shader上,像魔術一般沒用幾行程式碼就實現了一個不錯的水面效果。同時對河流與水體的效果混合做了相當細緻的拆分,這可能需要一定的數學功底和對shader足夠熟悉才能完全理解。

本期原文地址:HexMap 8

此教程為HexMap系列的第八篇,之前已經完成了編輯河流的功能,現在繼續新增編輯完全被水淹沒,處於水下的單元格的功能。

HexMap學習筆記(八)——水體
水位的變化

1水位的高度

最直接的在地圖中加入水體的方法是定義一個統一的水位高度,所有單元格自身的高度一旦低於水位高度那麼它就是處於水下的單元格。但是如果能定義不同的水位高度會更靈活一些(注:比如一張地圖中既能表現山頂的湖泊,又能表現大陸外的海面效果),所以這裡還是讓水的高度可變,這就需要每個單元格來記錄自己的水位高度。

HexMap學習筆記(八)——水體

如果要這麼做,就需要強制使一些其他地形特性不能出現在水下。但在這個時間點先暫時不考慮這個問題,就好似水下的道路也是合理的,它代表這個單元格不久前才沉沒到水下。

1.1水下的單元格

現在定義了水位高度,那麼最重要的資訊就是這個單元格是否在水下。當一個單元格的海拔高度低於其水位高度時,那麼這個單元格就是被淹沒的。新增一個屬性儲存這個資訊。

HexMap學習筆記(八)——水體

這麼寫就意味著當單元格的海拔高度與水位高度相等時,單元格的實際高度是在水面之上的。所以實際的水位高度會低於單元格的高度,就像河水的水面一樣。所以我們對這兩者使用相同的高度偏移量,修改HexMetrics.riverSurfaceElevationOffset的變數名讓其更通用一些。

HexMap學習筆記(八)——水體

修改HexCell.RiverSurfaceY這個屬性,讓其使用新的名字,併為水下的單元格新增類似的屬性。

HexMap學習筆記(八)——水體

1.2水體編輯

對水位高度的編輯方法與編輯單元格的高度差不多,所以在HexMapEditor中也要記錄當前的水位高度,並應用在單元格上。

HexMap學習筆記(八)——水體

新建方法並與UI相連。

HexMap學習筆記(八)——水體

並將其放入EditCell方法。

HexMap學習筆記(八)——水體

把編輯水位高度的UI新增到UI上,複製高度編輯的滑動條並修改名字,當然也別忘了修改正確的關聯方法。

HexMap學習筆記(八)——水體
控制水位的滑動條

2水面的三角剖分

我們需要一個新的mesh負責水面的三角化,並使用新的材質球。第一步,通過複製River的著色器建立一個新的名為Water的著色器,並修改一下讓其只應用顏色屬性。

HexMap學習筆記(八)——水體

複製河流的材質球來建立一個新材質球,更換上面的著色器。原本的噪聲紋理可以留著,一會就會用到它。

HexMap學習筆記(八)——水體
水體材質

通過複製預製體的Rivers子物件為其新增一個新的子物件Water,它應該使用鋼線新建的Water材質球且不需要勾選使用UV座標。像往常一樣,新建預製體的例項並更改,應用更改後刪除例項。(注:unity2018版本已經可以直接編輯預製體了)

HexMap學習筆記(八)——水體

HexMap學習筆記(八)——水體

下一步,在HexGridChunk中新增對water功能的支援。

HexMap學習筆記(八)——水體

並確保關聯的是正確的子物件預製體。

HexMap學習筆記(八)——水體
水體物件關聯

2.1水面三角形

由於水體相當於是形成了單元格的第二層mesh,就讓我們在每個方向上給其自己的三角化方法,只需要在單元格實際處於水下時呼叫它。

HexMap學習筆記(八)——水體

就像河流一樣,相同水位之間的單元格,其高度是保持一致的。所以我們不需要複雜的邊緣,每個方向上一個簡單的三角形就足夠了。

HexMap學習筆記(八)——水體

HexMap學習筆記(八)——水體
水體多邊形

2.2水面連線

我們可以用一個簡單的四邊形連線相鄰單元格的水面。

HexMap學習筆記(八)——水體

HexMap學習筆記(八)——水體
邊緣連線

並用簡單的三角形填充角落上的連線。

HexMap學習筆記(八)——水體

HexMap學習筆記(八)——水體
角落連線

現在水體單元格就完成了,它們在相鄰的時候就會自動連線起來。不過現在它們在更高的高度與單元格的乾燥部分留下了一個間隙,稍後來處理這個問題。

2.3統一的水位高度

在我們假設相鄰的水體單元格有相同高度時,水面的三角化是正確的,一旦違反這個假設就出錯了。

HexMap學習筆記(八)——水體
不同的水位高度

我們可以試著強制讓水位高度等級相同,例如當編輯單元格的水位時,把這個變化傳播到相鄰單元格中,使水位保持同步。然而這個過程必須持續下去直到遇到高於水位的單元格,而這些被影響的單元格就決定了水的範圍。

這個方法的危險之處就在於它很快會失控,極端情況下水面會淹沒整張地圖。當所有地圖都在同時三角化時就會由於效能峰值產生延遲。

所以我們現在先不這麼做,這可以作為編輯器的一個進階功能,而現在就需要使用者確保相鄰水位高度的統一。

3水面動畫效果

讓我們做一點像是波浪的效果來代替水面的固定顏色。就像之前在其他著色器中做的一樣,並不是要做一個多麼逼真的效果,僅僅簡單表示下這是波浪就夠了。

HexMap學習筆記(八)——水體
絕對水平的水面

做一些與河流動畫相似的事,用世界座標在噪聲紋理上取樣並與固定顏色相加,然後把時間與V座標相加產生動畫效果。

HexMap學習筆記(八)——水體

HexMap學習筆記(八)——水體
10倍速水流滾動

3.1雙向效果

現在一點也不像波浪的效果。新增第二個噪聲紋理的取樣讓其變得更復雜一些,這一次把U座標與時間相加。兩種噪聲取樣要使用噪聲紋理圖的不同通道,這樣就是兩個不同的噪聲模式。最後waves的值就是兩種取樣值之和。

HexMap學習筆記(八)——水體

對兩個取樣值的求和的結果取值範圍在0-2之間,所以我們把結果的取值範圍縮放到0-1之間。這裡可以使用smoothstep方法得到更為有趣的結果而不是僅僅將其縮放一半。這裡會把1.5-2之間的結果投影到0-1之間,所以水面的一部分沒有可見的波浪。

HexMap學習筆記(八)——水體

HexMap學習筆記(八)——水體
雙向滾動10倍速

3.2混合波

即使用了些額外方法,兩個噪聲的樣式沒有改變這一點依然明顯,如果噪聲的樣式能發生改變效果將會好得多。我們可以通過插值計算兩個不同通道的噪聲取樣來做到,但是這個插值不能平均計算,否則水面就會很明顯的的在同一時間變化樣式,所以用混合一條波來代替。

我們通過建立一條斜對角穿過水麵的正弦波來生成一條混合波,把世界座標的X和Z值相加作為sin函式的輸入並縮放這個和到合適的大小,然後加上相同的時間時間值使其動起來。

HexMap學習筆記(八)——水體

正弦波的浮動範圍在-1到1之間,但我們需要的是一個0-1之間的值,通過把waves的值平方把值限制在0-1內。為了能單獨看到結果,把輸入值從顏色為這個值。

HexMap學習筆記(八)——水體

HexMap學習筆記(八)——水體
混合波浪

為了讓波的效果不那麼明顯,為所有的值新增一些噪聲擾動。

HexMap學習筆記(八)——水體

HexMap學習筆記(八)——水體
混合波浪噪聲擾動

最後,對於我們的兩個噪聲取樣,使用混合波在兩個通道之間進行插值。使用噪聲紋理的四個不同的通道,最大限度地增加噪聲的樣式。

HexMap學習筆記(八)——水體

HexMap學習筆記(八)——水體
2倍速混合波浪效果

4沿岸水域

中間的開放水域已經完成,接下來就是填補沿岸水域的缺口。由於濱水區域需要與陸地的輪廓相吻合,所以這部分的三角剖分需要一個額外的方法。所以把TriangulateWater分成兩個方法,一個用於中間的開放水域,一個用於沿岸水域。如果當前方向的相鄰單元格存在且不處於水下,那就需要處理沿岸水域了。

HexMap學習筆記(八)——水體

HexMap學習筆記(八)——水體
沿岸水域不再三角化了

由於沿岸陸地的頂點是被擾動過的,所以當前方向沿岸的水域的三角形頂點也需要微擾。所以加上一組邊緣連線頂點把原本的單個三角形分割為多個三角扇。

HexMap學習筆記(八)——水體

HexMap學習筆記(八)——水體
由三角扇組成的沿岸水域與陸地的連線部分

下一步是邊緣連線帶的三角剖分,這裡就不需要對當前方向進行判斷了,因為只會對沿岸連線帶三角化時才會呼叫TriangulateWaterShore,也就是說方向已在呼叫之前就做過判斷了。

HexMap學習筆記(八)——水體

HexMap學習筆記(八)——水體
沿岸水域邊緣連線

同樣的,每次還要新增角落上的三角形。

HexMap學習筆記(八)——水體

HexMap學習筆記(八)——水體
沿岸水域的角落連線

現在沿岸水域就完成了,它的一部分總是埋在地形mesh之下,所以不會有間隙。

4.1沿岸水域的UV

其實可以到此為止了,但是如果沿岸的水域如果能有額外的視覺效果會顯得更有意思一些。比如離岸邊越近就越明顯的泡沫效果。要實現這個功能,那著色器就得知道沿海水域的位置離岸邊有多遠,可以通過UV座標提供這些資訊。

開放水域中並沒有使用UV座標,並且它也不需要泡沫的效果,只有沿岸的水域需要,所以這兩種水體的mesh的需求是非常不同的。給予每種型別它自己的mesh是很有必要的,所以在HexGridChunk中新增另一個mesh物件。

HexMap學習筆記(八)——水體

TriangulateWaterShore裡會使用這個新的mesh。

HexMap學習筆記(八)——水體

複製水體的物件,在預製體中建立關聯並勾選use UV coordinate,同樣為其複製水體的材質球和著色器。

HexMap學習筆記(八)——水體
沿岸水域的物件和UV

修改沿岸水體的著色器,令其顯示UV座標。

HexMap學習筆記(八)——水體

由於UV座標還沒有設定,現在顯示的是固定顏色,現在比較容易辨識沿岸水域確實是用了單獨的mesh和材質球。

HexMap學習筆記(八)——水體
沿岸水域的mesh與水體本身分開

把離岸邊的距離資訊放到V座標裡,設定0為考經水域這一邊,而1為靠近陸地這一邊。由於不需要再表示其他的什麼資訊,所有的U座標可以直接設定為0。

HexMap學習筆記(八)——水體

HexMap學習筆記(八)——水體
不正確的過渡

上邊的程式碼在邊緣連線的位置沒問題,但是在角落三角形的V座標有問題。如果下一個方向上的相鄰單元格位於水下,現在的寫法就是正確的,如果不在水下,那麼三角形的第三個頂點就在陸地的下面。

HexMap學習筆記(八)——水體

HexMap學習筆記(八)——水體
正確的過渡

4.2沿岸水域的泡沫效果

現在沿岸水域的三角剖分沒問題,可以在此基礎上新增一些泡沫的效果,最簡單直接的方式是把shore的值新增到統一的顏色上。

HexMap學習筆記(八)——水體

HexMap學習筆記(八)——水體
線性的foam值

為了讓其看起來更有意思一些,把正弦波取值平方後乘入shore的值。

HexMap學習筆記(八)——水體

HexMap學習筆記(八)——水體
正弦平方值衰減的foam值

要使泡沫效果在靠近海岸時顯得更大,可以在使用shore的值之前取其平方根。

HexMap學習筆記(八)——水體

HexMap學習筆記(八)——水體
越靠近海岸foam的值越大

新增一點扭曲使其更自然一些,讓靠近岸邊的扭曲變得越來越弱,這樣就能很好的與沿岸的輪廓吻合。

HexMap學習筆記(八)——水體

HexMap學習筆記(八)——水體
擾動後的泡沫效果

當然也要讓波動與扭曲都動起來。

HexMap學習筆記(八)——水體

HexMap學習筆記(八)——水體
泡沫的動畫效果

除了正向移動的泡沫,應該還有逆向移動的泡沫。讓我們新增第二個正弦波來模擬逆向移動,讓其幅度稍弱一些並給一點時間上的偏移,最後的foam值應該是兩條正弦函式的最大值。

HexMap學習筆記(八)——水體

HexMap學習筆記(八)——水體
前進與後退的泡沫效果混合

4.3混合波浪與泡沫的效果

現在中間的開放水域到沿岸水域的過渡效果很生硬,因為這兩個效果的邏輯不一樣,要修正這一點就需要在WaterShore的著色器中也能使用waves的程式碼。

我們不用把waves部分的程式碼全複製到WaterShore中,只需要在其中加入Water.cginc的CG檔案引用,實際上就是新建一個.cginc字尾的包涵檔案,然後將waves和foam的程式碼都放到裡面當做函式使用。

著色器的包涵檔案是如何工作的?

建立自己的著色器包涵檔案的內容在Rendering 5,Multiple Lights這篇教程中有提及。

(注:Unity中沒有直接建立cginc格式檔案的選項,需要你在檔案瀏覽器中建立一個txt檔案再把字尾名改成cginc。有可能會提示檔案可能不可用,但絕對是能用的。然後將之前shader檔案中的計算程式碼移到這個cginc檔案中,像c++一樣在shader中新增標頭檔案引用就可以了)

HexMap學習筆記(八)——水體

修改Water的著色器,使其應用新的cginc檔案引用。

HexMap學習筆記(八)——水體

然後在WaterShore著色器中計算foam和waves的值,然後讓開放水域的波浪按沿岸水域的泡沫波動頻率來移動,最後的結果應該是foam和waves的最大值。

HexMap學習筆記(八)——水體

HexMap學習筆記(八)——水體
波浪與泡沫效果的混合

5更大的沿岸水域範圍

一部分的沿岸水域的mesh會隱藏在地形mesh之下,如果只有一小部分當然沒什麼問題。但不幸的是較為陡峭懸崖下的水裡,絕大部分的沿岸水域連帶泡沫效果都看不見了。

HexMap學習筆記(八)——水體
沿岸水域幾乎看不見了

這個問題可以通過增加沿岸水域的尺寸,減少中間的固定六邊形的半徑來實現。這樣HexMetrics裡就需要一個表示水體mesh內六邊形的比例因子,並新增方法去獲取水體的角頂點。

地形的比例因子是0.8,如果想要把水體邊緣連線帶的範圍擴大一倍,水體的比例因子就要設定為0.6。

HexMap學習筆記(八)——水體

使用這些新方法在HexGridChunk裡去獲取水體mesh的角頂點。

HexMap學習筆記(八)——水體

HexMap學習筆記(八)——水體
使用水體專用的比例

可以看到六邊形之間的距離已經翻倍,現在HexMetrics裡要定義新的獲取邊緣連線橋頂點的方法。

HexMap學習筆記(八)——水體

在HexGirdChunk裡修改並使用新方法。

HexMap學習筆記(八)——水體

HexMap學習筆記(八)——水體
水體六邊形更長的連線橋部分

5.1水體與固定六邊形邊緣之間的處理

雖然這給了泡沫效果更大的空間,但是也有更多的部分被隱藏到地形mesh之下。理想情況下我們可以在水體的一邊使用水體的邊緣連線方式,而在陸地的一邊使用固定六邊形邊緣的連線方式。

當我們從水體mesh的角頂點開始計算時,不能簡單的使用連線橋來獲取相反方向的固定內六邊形的邊緣頂點(注:水體的內六邊形比例因子是0.6,而地形是0.8,直接用水體連線角頂點計算出的邊緣頂點會比岸邊的邊緣更靠外一些)。相反可以從相鄰單元格的中心點往回算。修改TriangulateWaterShore方法使其用這種新方法。

HexMap學習筆記(八)——水體

HexMap學習筆記(八)——水體
不正確的角落連線

可以看到這起效了,除了還要考慮下一個方向的相鄰單元格是否處於水下的情況來判斷角上的三角形第三個頂點的位置。

HexMap學習筆記(八)——水體

HexMap學習筆記(八)——水體
正確的角落連線

這看起來好多了,只不過當大部分泡沫都可見的情況下泡沫會很明顯。為補償這些修改,可以把著色器中的shore值稍微調小一點。

HexMap學習筆記(八)——水體

HexMap學習筆記(八)——水體
最終的泡沫效果

6水下的河流

現在水體的效果完成了,至少是沒有河流流入的情況下完成了。由於現在水體與河流的編輯邏輯互相不關聯,所以在這種情況下河流會從水下流過。

HexMap學習筆記(八)——水體
河流流入水體中

半透明物體的渲染順序取決於他們與相機之間的距離,越是離相機近的物體越是最後渲染,確保它們最終顯示在頂部。這意味著當你移動相機時,河流與水面到相機的距離發生變化,使得有時河流顯示在水面上,有時河流顯示在水面下。讓我們從規定統一的渲染順序開始,河流應該始終是繪製在水面上的,這樣瀑布的效果才會正確的顯示出來,我們可以通過改變River著色器的佇列順序來實現這一點。

HexMap學習筆記(八)——水體

HexMap學習筆記(八)——水體
最後繪製河流

6.1隱藏處於水下的河流

雖然河床處於水下沒什麼問題,河水確實也會流向水底,但是我們不應該能在水底看到河流的效果,特別是它還沒有渲染在實際的水面上。關於這個問題可以通過只在非水下的單元格才繪製河段河段三角形來解決。

HexMap學習筆記(八)——水體

對於TriangulateConnection方法則是隻在當前和相鄰單元格都不在水下時才繪製。

HexMap學習筆記(八)——水體

HexMap學習筆記(八)——水體
不再有河流處於水下的效果了

6.2瀑布

現在水底河流的問題解決了,但是現在河流與水體之間產生了間隙。當河流所在單元格的高度與水位相同時產生的間隙較小或者直接覆蓋了。但從一個高度差異較大的單元格流向水面時就會產生較大的間隙而不是瀑布的效果,先解決這個問題。

瀑布的河段會穿過水麵,它的一部分在水面上,一部分在下。我們需要保留水面上的部分而捨棄下面的,這需要費些功夫,為此建立一個專用的方法。

這個新方法需要四個頂點,兩個河流高度的,兩個水位高度的。把它們對齊後就能看到沿著瀑布向下的河流流向,所以前兩個左右兩邊的頂點在頂部,其餘的在底部。

HexMap學習筆記(八)——水體

當相鄰單元格在水下且高度能形成瀑布的情況下,在TriangulateConnection中呼叫這個方法。

HexMap學習筆記(八)——水體

在當前單元格處於水下而相鄰單元格不是時,還要處理方向相反的瀑布。

HexMap學習筆記(八)——水體

這就又產生了水下河流的問題。接下來修改TriangulateWaterfallInWater方法,把底部的兩個頂點拉到水面上。但是僅修改Y座標是不夠的,這相當於把河段斜著拉到水面上,在懸崖位置上會形成裂縫。必須通過插值計算頂部和底部頂點來把底部沿著連線方向拉向頂部。

HexMap學習筆記(八)——水體

要向上移動底部頂點,將它們在水面下的距離除以懸崖到水底的高度,就得到了插值函式的值。

HexMap學習筆記(八)——水體

得到的結果就是方向相同但更短一些的瀑布。但是由於底部頂點現在的位置發生了變化,它們受到的頂點擾動與之前不同,這意味的最終結果仍然會不匹配。為解決這個問題必須在插值之前手動對頂點進行擾動,然後新增一個不應用頂點擾動的四邊形。

HexMap學習筆記(八)——水體

雖然已經有了一個新增不受頂點擾動的三角形的方法,但還沒有一個同樣的新增四邊形方法。所以在HexMesh中新增所需的AddQuadUnperturbed方法。

HexMap學習筆記(八)——水體

HexMap學習筆記(八)——水體
瀑布在水體上結束

7河口

當河流與水面高度相同時,河流的mesh會與沿岸水域的mesh相接。如果是河水流入海里的情況,那這裡就是河流與海岸邊潮汐相遇的位置,這樣的地方稱之為河口。

HexMap學習筆記(八)——水體
河流與沿岸水域相遇,不在有頂點擾動效果

河口目前有兩個問題。第一個問題,河流四邊形連線著水面邊緣的第二個和第四個頂點,跳過了第三個頂點。由於沿岸水域沒有使用這第三個頂點,最終會形成一個間隙或者直接就覆蓋了。這個問題可以通過修改河口的幾何結構來解決。

第二個問題是沿岸的泡沫效果到河水流動效果之間的過渡十分生硬,要解決這個問題,還需要另外一個材質球去混合這兩個效果。

這意味著河口需要特殊處理,所以為此建立一個專用的方法。在河流穿過當前方向時在TriangulateWaterShore裡去呼叫。

HexMap學習筆記(八)——水體

混合效果的區域不用去填充整個邊緣連線帶,使用一個梯形就足夠。所以我們可以在這裡先新增兩個沿岸區域的三角形。

HexMap學習筆記(八)——水體

HexMap學習筆記(八)——水體
梯形的空洞


7.1 UV2座標

河流的效果是使用的UV動畫,沿岸水域的泡沫效果也是使用的UV動畫。所以要混合彼此的效果,最終要設定兩組UV座標。還好Unity中的Mesh最多可以支援四組UV座標的設定,而現在只需要在HexMesh中新增第二個UV座標。

HexMap學習筆記(八)——水體

通過複製並修改之前的UV設定方法新增第二組UV的設定方法。

HexMap學習筆記(八)——水體

7.2河流著色器方法

因為兩個著色器中都要使用河流特效,所以把River著色器中的程式碼整合成一個新方法放到water的包涵檔案中,以便兩者都能呼叫到。

HexMap學習筆記(八)——水體

修改河流的著色器使其應用這個方法。

HexMap學習筆記(八)——水體

7.3單獨的河口mesh物體

在HexGridChunk中新增河口mesh的欄位。

HexMap學習筆記(八)——水體

通過複製並修改沿岸水域物件,建立河口的物件著色器和材質,並拖入地圖塊預製體中。確保其同時勾選了UV1和UV2。

HexMap學習筆記(八)——水體
河口物件

7.4河口的三角剖分

在河流結束位置到水體mesh之間新增一個三角形解決重疊或者是間隙的問題。由於河口的著色器是從沿岸水域複製過來的,設定其UV座標與泡沫特效吻合。

HexMap學習筆記(八)——水體

HexMap學習筆記(八)——水體
中間的三角形

在中間的三角形兩邊新增兩個四邊形,這樣就組成了一個梯形。

HexMap學習筆記(八)——水體

HexMap學習筆記(八)——水體
梯形完成

旋轉左邊的四邊形,使其對角線上的連線更短一些,這樣就得到一個對稱的幾何形狀。

HexMap學習筆記(八)——水體

HexMap學習筆記(八)——水體
旋轉四邊形,保持對稱

7.5河口的流動效果

要同時顯示河流的效果就需要用到UV2座標。中間三角形的底部頂點位於河流的正中間,所以它的U座標就應該是0.5。由於河流是朝向水體移動的,所以河口左邊的U座標應該是1,河口右邊的U座標則是0。設定第二組UV座標為0-1使其能吻合河流的流向。

HexMap學習筆記(八)——水體

三角形兩邊的四邊形都應該往這個方向匹配,對於河流寬度以外的點保持相同的U座標。

HexMap學習筆記(八)——水體

HexMap學習筆記(八)——水體
梯形的UV2

要檢查一下UV2的座標設定是否正確,用河口的著色器讓其視覺化。可以通過在input結構中新增float2 uv2_MainTex來獲取這個結構。

HexMap學習筆記(八)——水體

HexMap學習筆記(八)——水體
UV2座標的效果

看起來沒問題,就以此為基礎新增河流特效。

HexMap學習筆記(八)——水體

HexMap學習筆記(八)——水體
使用UV2去從建立河流的特效

之前定義的單元格之間河流V座標的範圍是0.8-1,所以現在河口這部分也應該沿用這個範圍而不是設定成0-1。然後由於水體的內六邊形的比例因子比陸地小,所以沿岸河流的連線部分比陸地單元格之間的連線部分要大50%,把這個算進去設定V座標的範圍就應該是0.8-1.1。

HexMap學習筆記(八)——水體

HexMap學習筆記(八)——水體

HexMap學習筆記(八)——水體
同步河流與河口的流動

7.6河流效果的修正

目前河口的河流效果依然是筆直的,但實際情況是當河流流入較大區域時應該向外擴充套件,此時流向應該是彎曲的,我們可以通過彎曲UV2的座標來模擬這個過程。

與其讓U座標的在河面寬度外的座標保持恆定,不如將其移動0.5的距離。這樣一來最左邊就變成了1.5,最右邊變成了-0.5。

同時改變底部U座標的位置放寬河道,把左邊的點由1改為0.7,右邊的點從0改為0.3。

HexMap學習筆記(八)——水體

HexMap學習筆記(八)——水體

HexMap學習筆記(八)——水體
變寬的河流

要完成這個曲線的特效,在4個同樣的點上修改V座標。由於河流的流向總時朝向河流的出口,把頂部的V座標增加到1。為了讓曲線的效果更好看一些,底部的兩個V座標增加到1.15。

HexMap學習筆記(八)——水體

HexMap學習筆記(八)——水體

HexMap學習筆記(八)——水體
曲線的河流流動

7.7混合河流與泡沫效果

最後剩下的工作是混合沿岸水域發泡沫與河流的效果,這裡會使用shore的值進行線性插值來實現。

HexMap學習筆記(八)——水體

雖然感覺理論上能生效,但可能會得到一個編譯錯誤的資訊。編譯器會告訴你_MainTexST被重新定義,這是由於Unity的表面著色器中同時使用uv_MainTex和uv2_MainTex造成的bug,得找一個變通的辦法。

這裡會手動出傳遞第二個UV座標的資訊來代替使用uv2MainTex。把uv2_MainTex重新命名為riverUV,然後在著色器中新增一個頂點函式,它將座標賦值個著色器。

HexMap學習筆記(八)——水體

HexMap學習筆記(八)——水體
基於沿岸水域的效果插值

插值混合起效了,除了頂部左右的頂點之外。河流效果在這些位置不應該存在,所以這裡不能使用shore的值,而必須使用在這兩個頂點UV為0的值。還好還有第一組UV座標能用,把值儲存在這裡。

HexMap學習筆記(八)——水體

HexMap學習筆記(八)——水體
正確的混合

現在的河口效果包含了延展變寬的河流,岸邊的水和泡沫效果。雖然不是精確與瀑布效果匹配,但這種效果與瀑布結合在一起看也還不錯。

HexMap學習筆記(八)——水體
河口的流動

8從水體向外流動的河流

儘管現在河流可以流入水體之中,但並不支援從水體中向外流動。但是現實世界中的湖泊有河流向外流出是很常見的,所以我們補充這部分。

在我們的地圖中河流從水體向外流動其實是流向了更高的高度,我們之前定義了這種情況下河流是無效的,因此要建立一個特殊方法,當水位高度與目標單元格高度相同時,允許河流這麼流動。在HexCell中新增一個私有方法,該方法使用新的方式檢測河流是否有效。

HexMap學習筆記(八)——水體

使用這個新方法來檢測是否允許設定流出河流。

HexMap學習筆記(八)——水體

還需要檢測河流在改變單元格高度或者水位高度時的有效性,建立一個處理此問題的私有方法。

HexMap學習筆記(八)——水體

在高度和水位的屬性裡都使用這個新方法。

HexMap學習筆記(八)——水體

HexMap學習筆記(八)——水體
河流同時從湖水中流入和流出

8.1水域之間的逆流

我們之前建立了HexGirdChunk.TriangulateEstuary方法是假設河流總是流入方向,因此河水總是流向同一個方向。當我們處理流出方向的河流時就需要倒轉水流方向。這就需要TriangtlateEstuary方法知道河水的流向,所以給其一個布林型別的引數定義是否在處理傳入方向的河流。

HexMap學習筆記(八)——水體

當在TriangulateWaterShore中呼叫這個方法時傳遞資訊。(注:這裡會有一個小問題,當前是流出河流且流出河流的方向與流入河流的初始方向相同時,這裡會跳過流出河流的檢測,使得河口與河流流向相反,需要與上一個cell.hasIncomingRiver的判定)

HexMap學習筆記(八)——水體

現在通過改變UV2的座標來逆轉河流的流向,在處理流出方向的河流時映象U座標,-0.5變成1.5,0變成1,1變成0,1.5變成-0.5。

V座標可能就不那麼直觀了,可以回顧一下之前是如何處理逆向河流的V座標。這裡的0.8應該變成0,1應該變成-0.2,以此類推1.1變成-0.3,1.15變成-0.35。

由於每種情況下的UV2座標差異較大,所以為此使用單獨的程式碼賦值。

HexMap學習筆記(八)——水體

HexMap學習筆記(八)——水體
正確的河流效果

OK,這篇文章就到這裡。

本期工程地址:https://github.com/tank1018702/Hex-Map-Learning/tree/water

有想系統學習遊戲開發的童鞋,歡迎訪問http://levelpp.com/。

下一篇教程為Terrain Features.

系列文章
HexMap學習筆記(一)——建立六邊形網格
HexMap學習筆記(二)——單元格顏色混合
HexMap學習筆記(三)——海拔高度與階梯連線

HexMap學習筆記(四)——不規則化
HexMap學習筆記(五)——更大的地圖
HexMap學習筆記(六)——河流
HexMap學習筆記(七)——道路

HexMap學習筆記(八)——水體

作者:沈琰編譯
專欄地址:https://zhuanlan.zhihu.com/p/59705625


相關文章