国产精品天干天干,亚洲毛片在线,日韩gay小鲜肉啪啪18禁,女同Gay自慰喷水

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

HexMap學(xué)習(xí)筆記(七)——道路

2019-04-11 13:42 作者:皮皮關(guān)做游戲  | 我要投稿

作者 : 沈琰

前言

由于不涉及對已有地形的改變,這篇教程的難度是低于上一篇的,入過完全弄懂上一篇的教程讀起來就會很容易。另外最后道路的著色器效果很贊,值得仔細(xì)研究一下思路

此教程是HexMap系列的第七篇,在上篇中添加了河流的編輯功能,這一次添加道路。

文明的第一個(gè)標(biāo)志

1 單元格里的道路

與河流一樣,道路是穿過單元格邊緣的中間來連接不同單元格,最大的不同點(diǎn)是道路沒有流動的河水規(guī)定方向,所以道路是雙向的。一個(gè)看得過去的道路網(wǎng)絡(luò)肯定會有十字路口,所以我們還定義單元格內(nèi)穿過的道路可以超過兩條。

在六個(gè)方向上都允許有道路穿過,這意味著單元格可以包含零到六條道路,這產(chǎn)生了十四種可能的道路結(jié)構(gòu),遠(yuǎn)超河流的五種。為使其更容易實(shí)現(xiàn),我們需要一個(gè)可以表示所有結(jié)構(gòu)類型的通用方法。

十四種可能的道路結(jié)構(gòu)


1.1 記錄道路結(jié)構(gòu)

最直接的方法是每個(gè)單元格都用一個(gè)布爾類型的數(shù)組保存其道路結(jié)構(gòu),添加一個(gè)私有的數(shù)組字段并將其序列化,這樣就能在檢視面板上看到值,在預(yù)制體中預(yù)設(shè)這個(gè)數(shù)組的大小為6.

1.4 刪除無效道路

現(xiàn)在可以確保只在條件允許時(shí)添加道路,在來考慮稍后道路失效時(shí)候的刪除問題,例如當(dāng)添加河流時(shí)??梢越购恿髟诘缆飞希恿鞑粫坏缆纷钃?,讓其把路沖開。

只要將河流方向上的道路設(shè)置為false就行了,不用管是不是存在道路,修改道路狀態(tài)始終會刷新受影響的單元格,所以現(xiàn)在不用特地在SetOutgoingRiver中去調(diào)用RefreshSelfOnly方法了。

另一個(gè)會使道路無效的操作是單元格高度的改變,這種情況下需要檢測所有方向上的道路,如果高度差距過大,現(xiàn)存的道路就要刪除。

2 編輯道路

編輯道路的邏輯實(shí)在是很像編輯河流,所以HexMapEditor中需要另一個(gè)toggle組,加上隨之一起的方法來設(shè)置道路編輯的狀態(tài)。

現(xiàn)在EditCell方法同樣支持添加和刪除道路,這意味著檢測到鼠標(biāo)拖拽時(shí)有兩種可能的操作,稍稍修改一下代碼,這樣在有效拖拽時(shí)兩個(gè)toggle的狀態(tài)都會被檢測到。

你可以通過賦值河流的UI面板并修改其調(diào)用的方法來快速添加一個(gè)編輯道路的面板,不過這樣UI看起來就太長了,所以修改了一下顏色編輯面板的樣子使其更緊湊一些,好與河流面板想吻合。

添加道路編輯之后的UI

因?yàn)楝F(xiàn)在顏色編輯面板使兩行三列,多出了一個(gè)顏色的位置,就添加一個(gè)橘黃色的地形顏色。

地形的五種顏色

現(xiàn)在就可以編輯道路了,盡管看不見,但可以在檢視面板上驗(yàn)證其是否生效。

檢查單元格的道路狀態(tài)

3 道路的三角剖分

要讓道路可視化就需要將其三角化,這與河流mesh類似,除了地形上不會生成一條通道之外。

第一步,在新建一個(gè)標(biāo)準(zhǔn)著色器,使用UV坐標(biāo)為道路表面著色。

創(chuàng)建道路的材質(zhì)球并應(yīng)用這個(gè)著色器。

道路材質(zhì)球

然后為地圖塊的預(yù)制體添加另一個(gè)掛載有HexMesh的子物體,只在腳本上勾選uses UV coordinates并關(guān)閉陰影投射,比較快的辦法是復(fù)制河流的預(yù)制體修改名字和材質(zhì)球。

道路子物體

在這之后添加一個(gè)HexMesh類型的公共字段roads到HexGridChunk里,并包含到Triangulate方法里,在腳本的檢視面板上創(chuàng)建其關(guān)聯(lián)。

3.1 單元格之間的道路

第一步先考慮單元格之間的路段。就像河流一樣,道路覆蓋的范圍是連接部分中間的兩個(gè)四邊形,這里將使用道路的四邊形將其完全覆蓋,所以可以使用相同的六個(gè)頂點(diǎn)。在HexGridChunk中添加一個(gè)TriangulateRoadSegment方法。

TrangulateEdgeStrip即是調(diào)用此方法的位置,并且只有在確實(shí)存在道路時(shí)才需要這么去做,添加一個(gè)布爾類型的參數(shù)去傳遞這個(gè)信息。

這樣當(dāng)然會出現(xiàn)編譯錯(cuò)誤,因?yàn)檎{(diào)用這個(gè)方法的位置缺少參數(shù)?,F(xiàn)在可以在沒個(gè)調(diào)用方法的位置都補(bǔ)上一個(gè)false,或者也能聲明這個(gè)參數(shù)的默認(rèn)值是false,這樣一來這個(gè)參數(shù)就變成了可選的并解決了編譯錯(cuò)誤的問題。

如果這里需要就簡單的通過六個(gè)中間頂點(diǎn)調(diào)用TriangulateRoadSegment來三角化路段。

這里只負(fù)責(zé)平坦連接處部分,要在階梯連接處三角化道路,還需要在TriangulateEdgeTerraces里添加傳遞信息的參數(shù),并傳遞到TriangulateEdgeStrip中。

TriangulateEdgeTerraces方法是在TriangulateConnection里調(diào)用,這里是能夠確認(rèn)當(dāng)前方向上是否有道路穿過的地方,無論是對于三角化邊界和階梯連接處都一樣。

單元格之間的路段

3.2 渲染到頂部

當(dāng)編輯道路時(shí),你會看到路段在單元格之間突然出現(xiàn),靠近路段中間的位置是紫色,到邊上變化為藍(lán)色。目前看起來好像符合預(yù)期,然而四處移動相機(jī)時(shí)就會發(fā)現(xiàn),路段有可能出現(xiàn)閃爍,甚至有些時(shí)候還會完全消失。這是因?yàn)榈缆返娜切尉_的覆蓋在地形三角上,渲染至頂部的三角形是隨機(jī)的,要修復(fù)這個(gè)問題需要分為兩步。

首先,我們想讓道路三角形總在地形三角形之后繪制,通過繪制常規(guī)集合圖形之后再渲染來實(shí)現(xiàn),方法是把道路放在靠后的渲染隊(duì)列中。

第二步,我們希望即使是坐標(biāo)相同,道路三角形也繪制在地形的頂部。這要通過添加一個(gè)深度測試偏移量實(shí)現(xiàn),使得GPU將道路三角形視為比實(shí)際距離更接近相機(jī)。


3.3 穿過單元格的道路

當(dāng)三角化河流時(shí),每個(gè)單元格最多只需要處理兩個(gè)河流的方向,于是我們能為五種可能的方案創(chuàng)建符合其規(guī)則的三角化方法。

然而道路有十四種可能的方案,因此我們不會用不同的方法來應(yīng)對每個(gè)方案,相反將會以完全相同的方式處理每個(gè)方向,而不去考慮特定的道路結(jié)構(gòu)。

當(dāng)有道路穿過單元格時(shí),直接讓其筆直達(dá)到單元格的中心并不超過這個(gè)方向的三角形區(qū)域。將從邊緣到中心畫一條路,然后用兩個(gè)三角形來覆蓋到中心的剩余部分。

道路的三角化部分

先只考慮沒有河流在內(nèi)的單元格,這種情況下Triangulate就簡單的構(gòu)建三角扇。把這些代碼移動到它自己的方法中,然后在道路確實(shí)存在時(shí)在TriangualteRoad中添加調(diào)用。道路左右的中間位置頂點(diǎn)可以通過插值計(jì)算單元格的中心點(diǎn)和兩個(gè)角頂點(diǎn)得到。

道路穿過的樣子


3.4 道路邊緣

現(xiàn)在可以看到道路了,但是其向著單元格中心的方向是逐漸變細(xì)的。由于沒有檢測現(xiàn)在是十四種道路結(jié)構(gòu)中的哪一種,所以沒辦法移動單元格的中心讓它更好看一些,現(xiàn)在能做的就是添加額外的道路邊緣部分到單元格的其他地方。

當(dāng)單元格內(nèi)有道路穿過,但又不是當(dāng)前三角化的方向時(shí),添加道路邊緣的三角形。這個(gè)三角形由單元格的中心點(diǎn)和左右邊緣的中間點(diǎn)構(gòu)成。在這種情況中只有中心點(diǎn)位于道路中間,其他兩個(gè)頂點(diǎn)都在道路的邊緣上。

不管是要三角化整個(gè)道路還是僅僅只是道路的邊緣,都應(yīng)該留給Triangulate方法負(fù)責(zé),所以這里得知道道路是否經(jīng)過當(dāng)前單元格邊界的方向,為此添加一個(gè)參數(shù)。

TriangulateWithoutRiver方法會在單元格內(nèi)有道路穿過時(shí)調(diào)用TriangulateRoad方法,并同時(shí)傳遞道路是否經(jīng)過當(dāng)前方向的信息。

道路的邊緣完成


3.5 道路輪廓的平滑處理

現(xiàn)在道路完工,但是單元格的中心會有凸起的感覺。當(dāng)有道路與左右邊的頂點(diǎn)相鄰時(shí),把左右頂點(diǎn)放置在單元格中心和角頂點(diǎn)的中間時(shí),看起來還行,但如果沒有,就會產(chǎn)生凸起。為解決這個(gè)問題,可以在沒有相鄰道路的情況下,把邊緣頂點(diǎn)放到更靠近單元格中心點(diǎn)的位置,具體來說就是插值的因子由二分之一改為四分之一。

創(chuàng)建一個(gè)額外方法去計(jì)算出需要使用哪個(gè)插值,可以把這兩個(gè)值放在一個(gè)Vector2中,它的X分量是左邊頂點(diǎn)的插值,Y分量是右邊頂點(diǎn)的插值。

如果道路在當(dāng)前方向上,就把邊緣頂點(diǎn)都放到二分之一的位置。

否則就根據(jù)相鄰道路來決定,對于左邊的頂點(diǎn),當(dāng)上一個(gè)方向有道路穿過時(shí)用二分之一作為插值因子,如果沒有就用四分之一。這個(gè)邏輯對右邊的頂點(diǎn)也是一樣,只不過其參照的是下一個(gè)方向上有沒道路經(jīng)過。

現(xiàn)在就能用這個(gè)新方法確定使用哪種插值,這會讓道路的輪廓顯得更平滑一些。

平滑的道路

4 道路與河流的結(jié)合

在沒有河流的情況下道路的功能已經(jīng)完成了,但一旦有節(jié)流穿過,道路就不會被三角化。

河流邊沒有道路

創(chuàng)建一個(gè)新方法TriangulateRoadAdjacentToRiver負(fù)責(zé)這種情況下道路的三角化,并添加三角化慣有的參數(shù),在TriangulateAdjacentToRiver方法一開始調(diào)用。

一開始做的與沒有河流時(shí)道路的三角化一樣,檢測道路是否穿過這個(gè)方向的單元格邊緣,提供插值系數(shù),計(jì)算中間頂點(diǎn)接著調(diào)用TriangulateRoad方法。但由于河流會擋住道路,所以要把道路移開,結(jié)果就是道路在單元格內(nèi)的中心點(diǎn)會在不同的位置,使用roadCenter變量來記住這個(gè)新位置,它一開始的時(shí)候等于單元格的中心點(diǎn)。

這會在有河流穿過的單元格中生成部分道路,河流穿過的方向會在道路上形成缺口。

道路上的缺口

4.1 河流起點(diǎn)與終點(diǎn)的道路處理

首先考慮包含河流起點(diǎn)或終點(diǎn)的道路處理,若要確保道路不會覆蓋在河流之上,我們需要把道路在單元格內(nèi)的中線點(diǎn)推移到河流的范圍之外。未測需要獲得流入或流出的河流方向,在HexCell中添加一個(gè)方便獲取的屬性。

現(xiàn)在能在HexGridChunk中使用這個(gè)屬性,在TriangulateRoadAdjacentToRiver中把道路的中心點(diǎn)推移向相反的方向,沿著這個(gè)方向移動三分之一的距離就可以了。

修正中心點(diǎn)

下一步就是填充缺口。當(dāng)與河流相鄰時(shí)我們添加額外的道路邊緣三角形來實(shí)現(xiàn)。如果在當(dāng)前方向的上一個(gè)方向上有河流穿過,那么就在道路中心,單元格的中心點(diǎn)和道路左邊中間位置的頂點(diǎn)之間添加一個(gè)三角形。如果下一個(gè)方向上有河流穿過,就在道路中心,道路右邊的中間頂點(diǎn)和單元格中心點(diǎn)之間添加一個(gè)三角形。

不管在處理何種河流結(jié)構(gòu)都要進(jìn)行這樣的處理,所以把這段代碼放在方法的末尾。

不使用else么?
這樣就不適用所有情況了,河流有可能同時(shí)流經(jīng)這兩個(gè)方向。
道路完成

4.2 筆直河流的道路處理

單元格內(nèi)有筆直河流穿過情況下道路的處理帶來了額外的挑戰(zhàn),因?yàn)閱卧竦闹行狞c(diǎn)事實(shí)上被分為了兩個(gè)。我們已經(jīng)添加了額外的三角形來填補(bǔ)沿河的空隙,但我們還得斷開河流兩邊的道路。

道路覆蓋在筆直河流之上

如果單元格內(nèi)不是河流的起點(diǎn)或終點(diǎn),那么再檢測一下河流流入和流出方向是否相反,如果是,那毫無疑問就是筆直的河流。

為了確定河流相對于當(dāng)前方向的位置,我們必須檢查相鄰的方向,河流方向不是在左邊就是在右邊。如同我們在方法末尾做的那樣,把這些檢測緩存到布爾值中,這也使代碼更容易閱讀。

我們需要把道路的中心點(diǎn)往遠(yuǎn)離河流方向的角上推移,如果這條河流經(jīng)過前一個(gè)方向,那這個(gè)角就是固定里六邊形的第二方向上的角,否則就是第一個(gè)角。

移動道路使其在于河流方向相鄰的位置結(jié)束,需要移動道路的中心點(diǎn)到朝向這個(gè)角的方向的一半的位置,然后還有把單元格的中心向這個(gè)方向移動四分之一的距離。

分開的道路

現(xiàn)在單元格內(nèi)的道路網(wǎng)已經(jīng)分開,當(dāng)河流兩邊都有路的時(shí)候看起來沒問題,但當(dāng)一邊沒有時(shí),會在這邊留下一點(diǎn)孤零零的小尾巴,這部分沒什么用也不美觀,所以把這部分去掉。

檢查一下當(dāng)前方向是否有道路穿過,如果沒有,檢測一下河流同邊的其他方向,如果兩者都沒有道路穿過,就在三角化之前跳出方法。

修剪后的道路
為什么不搭一座橋?
現(xiàn)在先把注意力集中在道路上,橋和其他的建筑結(jié)構(gòu)放在未來的教程中。

4.3 鋸齒急彎河流的道路處理

下一步是包含鋸齒急彎河流單元格的道路處理,這種形狀的河流不會分割路網(wǎng),所以我們只需要移動道路的中心點(diǎn)就行了。

最簡單的檢測是否是急彎的方法是比較單元格內(nèi)河流流出和流出的方向,如果他們相鄰,那這就是急彎了。這有兩種可能的情況,取決于河流的流向。

我們可以使用河流流入方向的角作為移動道路中心點(diǎn)的方向,具體是哪個(gè)取決于河流的流向,把道路中心點(diǎn)往這個(gè)方向上移動0.2的距離。

道路從鋸齒急彎上移開

4.4 彎曲河流內(nèi)側(cè)的道路處理

最后的河流形狀是平滑的曲線,與筆直河流相同,這是可以分離道路的類型。但在這種情況下曲線內(nèi)的一邊處理起來會有一些不同,先處理這部分。

如果當(dāng)前處理方向的兩個(gè)相鄰方向都有河流穿過,那就是在彎曲河流的內(nèi)側(cè)。

我們需要把道路中心點(diǎn)向當(dāng)前方向的邊緣位置拉,使道路縮短一截,0.7的距離就差不多了。單元格的中心點(diǎn)位置也要移動,它的值是0.5。

被縮短的道路

與筆直河流那做的處理一樣,把單獨(dú)剩下的一點(diǎn)尾巴去掉。這里只需要檢測當(dāng)前的方向。

4.5 彎曲河流外側(cè)的道路處理

在檢測了之前所有情況之后,唯一剩下的可能就是在彎曲河流的外測。外側(cè)的位置有單個(gè)單元格的部分,需要找到其中間的方向。一但找到就以此方向?yàn)閰⒄瞻训缆分行狞c(diǎn)移動0.25的距離。

在外側(cè)修正道路位置

最后一步是修剪這邊道路的多余部分,最簡單的方法是相對中間方向檢測其包括相鄰方向在內(nèi)的三個(gè)方向,如果這三個(gè)方向上均沒有道路,就跳出。

道路在修剪前后的對比

5 道路的外表

到目前為止都使用UV坐標(biāo)為道路著色,由于只是改變了U坐標(biāo),我們實(shí)際看到的是道路中間到邊緣之間的過渡。

道路顯示的UV坐標(biāo)

現(xiàn)在已經(jīng)能確保道路的三角剖分的正確性,就可以開始改變道路的顏色,使其表現(xiàn)得更像道路,如同對河流所做的一樣。這將是一個(gè)簡單的可視化改動,沒什么特變的。

首先從使用純色開始,使用材質(zhì)球的顏色將其涂為紅色。

似乎沒有效果,這是因?yàn)橹魇遣煌该鞯摹,F(xiàn)在需要把a(bǔ)lpha值進(jìn)行混合,具體來說就是需要一個(gè)混合貼花的表面著色器??梢酝ㄟ^在#pragma suface指令中添加decal:blend來獲得預(yù)想的著色器。

透明度混合的道路

結(jié)果產(chǎn)生了從中間到邊緣的線性混合,效果似乎不是太好。為了讓其看起來更像一條路,需要在路中間保留一個(gè)固定的顏色區(qū)域,然后再快速過渡到一個(gè)不透明的區(qū)域。這里可以使用smoothstep函數(shù),把從0到1之間的線性變化變?yōu)閟形的曲線。

線性變化與平滑曲線

smoothstep函數(shù)有一個(gè)最大和最小參數(shù),可以在任意范圍內(nèi)擬合曲線,超出這個(gè)范圍的輸入被固定住,因此曲線會變得平滑。這里使用0.4作為曲線的起點(diǎn),0.7作為曲線的終點(diǎn),這表示U坐標(biāo)從0到0.4之間是完全透明的,從0.1到1之間是完全不透明的,轉(zhuǎn)換發(fā)生在0.4到0.7之間。

從透明到不透明之間的快速變化

5.1 道路外表噪聲化

由于道路的頂點(diǎn)也會受到噪聲擾動,所以道路的寬度會發(fā)生變化。因此道路邊緣過渡部分的寬度也會發(fā)生變化,有時(shí)模糊有時(shí)清晰,這樣很像是土路或者沙路帶來的感覺。

讓我們更進(jìn)一步,在道路的邊緣添加一些噪聲效果,這將是道路的形狀開起來更粗糙一些,不會顯得那么棱角分明,這可以通過對噪聲紋理采樣做到。使用世界坐標(biāo)的XZ對噪聲紋理進(jìn)行采樣,就像在擾動單元格頂點(diǎn)時(shí)候一樣。

要訪問表面著色器中的世界坐標(biāo),需要在輸入結(jié)構(gòu)中添加float3 worldPos。

現(xiàn)在可以在surf中使用這個(gè)坐標(biāo)來對主紋理圖進(jìn)行采樣,一定要縮小坐標(biāo)的比例,不然紋理會在小范圍平鋪顯示。

通過將U坐標(biāo)與噪聲紋理的X值相乘來對過渡值進(jìn)行擾動,但由于噪聲紋理的平均值是0.5,這將會覆蓋大部分的道路。為防止這種情況發(fā)生,在相乘之前先加上0.5。

道路邊緣的擾動

最后也對道路的顏色進(jìn)行擾動,這配和凌亂的道路邊緣給其一些臟亂的效果。

將顏色乘上紋理圖的另一個(gè)通道,比如noise.y。所以顏色的平均值只有最大值的一半,這擾動的幅度有些大,所以縮小一點(diǎn)噪聲采樣的取值并加上一個(gè)常量,所以總值還是可以達(dá)到1。

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

下一篇教程是:https://catlikecoding.com/unity/tutorials/hex-map/part-8/


有線下學(xué)習(xí)游戲開發(fā)打算的童鞋,歡迎訪問:http://levelpp.com/?

另有專業(yè)開發(fā)交(gao)流(ji)群等待大家強(qiáng)勢插入:869551769

HexMap學(xué)習(xí)筆記(七)——道路的評論 (共 條)

分享到微博請遵守國家法律
广宗县| 沁阳市| 舞阳县| 八宿县| 建水县| 香格里拉县| 巢湖市| 黑龙江省| 瓦房店市| 垣曲县| 南陵县| 根河市| 邢台县| 新野县| 梁河县| 新郑市| 彰武县| 临泽县| 湖南省| 边坝县| 新丰县| 贡嘎县| 凤翔县| 济阳县| 蚌埠市| 义马市| 体育| 兴安县| 涟水县| 兴宁市| 缙云县| 虹口区| 开原市| 忻城县| 永嘉县| 宁安市| 德令哈市| 惠水县| 五华县| 商洛市| 灵宝市|