随机世界的生成
內(nèi)容來(lái)源:http://accidentalnoise.sourceforge.net/minecraftworlds.html
?更多搜索? unity?Perlin
其他文字 為Unity3D游戲生成2D和3D多邊形隨機(jī)地圖:?http://www.manew.com/thread-40880-1-1.html
3D立方體世界級(jí)別生成
部分由于游戲的受歡迎程度的Minecraft出現(xiàn)在世界游戲設(shè)置做出立方體,3D地形充滿了有趣的東西,如洞穴,出挑,等等所構(gòu)成的想法引起大家的興趣死灰復(fù)燃最近。這樣的世界是ANL風(fēng)格產(chǎn)生的噪聲的理想應(yīng)用。這個(gè)例子是基于我之前討論這種技術(shù)的努力的討論。(這篇鏈接文章后來(lái)被收錄在2011年4月的“?游戲開發(fā)者雜志”雜志中。)自編寫以來(lái),圖書館的結(jié)構(gòu)發(fā)生了一些變化。
在(鏈接到我的世界帖子)中,我討論了使用3D噪聲函數(shù)來(lái)實(shí)現(xiàn)Minecraft風(fēng)格的地形。從那時(shí)起,圖書館已經(jīng)發(fā)展了一點(diǎn),所以我將重新審視這些帖子并再次討論它。由于我不得不回答很多關(guān)于這個(gè)系統(tǒng)的問(wèn)題,所以我將嘗試更清楚地了解所涉及的概念。為了澄清這些基本概念,我將開始創(chuàng)建一個(gè)2D地形的想法,就像你在Terraria和King Arthur's Gold等游戲中看到的那樣,然后將其擴(kuò)展到像Minecraft這樣的3D案例中。這將允許我更有效地使用圖像來(lái)演示這些概念。
該系統(tǒng)具有以下抽象目標(biāo):能夠使用特定點(diǎn)或單元的坐標(biāo)來(lái)饋送系統(tǒng),并且能夠確定該位置應(yīng)該是什么類型的塊。我們希望它是一個(gè)黑盒子;?我們給它一點(diǎn),我們得到一個(gè)塊類型。當(dāng)然,請(qǐng)注意,這僅適用于世界的初始生成。這些類型的游戲中的塊可以通過(guò)玩家動(dòng)作來(lái)改變,并且此時(shí)嘗試使用相同類型的系統(tǒng)來(lái)描述這些改變是不合適的。需要以其他方式跟蹤這些更改。這個(gè)系統(tǒng)產(chǎn)生了初始的世界,原始的,沒(méi)有人類或非人類的手。
這種技術(shù)也可能不適合某些系統(tǒng)(如草或其他生物實(shí)體)的建模,因?yàn)檫@些系統(tǒng)本身就是復(fù)雜的實(shí)體,不容易以隱式方式建模。與降雪,結(jié)冰等系統(tǒng)相同......這里介紹的技術(shù)代表了一種隱含的方法,即可以在某一點(diǎn)評(píng)估的一個(gè),并且在給定點(diǎn)的值不依賴于周圍的值。生物和其他類型的系統(tǒng)通常需要了解周圍環(huán)境以便執(zhí)行精確的模擬。一個(gè)街區(qū)接收多少陽(yáng)光?附近有水嗎?必須回答這些問(wèn)題和其他問(wèn)題,以模擬生物系統(tǒng)的增長(zhǎng)和傳播,并在較小程度上模擬其他類型的氣候相關(guān)系統(tǒng)。它也不適合用于水模擬。該系統(tǒng)沒(méi)有流動(dòng)概念,不了解流體力學(xué)或重力。水是一個(gè)復(fù)雜的主題,需要大量復(fù)雜的處理。
這并不是說(shuō)隱含方法在這些方面完全沒(méi)用;?事實(shí)并非如此。但是,在這些系統(tǒng)中,隱式方法只是眾多工具中的一種。它們可用于模擬區(qū)域,擾動(dòng)區(qū)域等,但系統(tǒng)的核心將是執(zhí)行環(huán)境分析和模擬的顯式方法,這超出了本文和此庫(kù)的范圍。
所以,我們只是模擬污垢和巖石。我們想要一個(gè)功能,告訴我們一個(gè)給定的位置應(yīng)該是污垢,沙子,空氣,金,鐵,煤等......但是,首先,我們將保持簡(jiǎn)單。我們想要一個(gè)能告訴我們給定塊是Solid還是Air的函數(shù)。這個(gè)功能應(yīng)該模擬我們周圍的地球。也就是說(shuō),天空在上方,堅(jiān)固在下面。因此,讓我們承擔(dān)將天空與地球分開的圣經(jīng)任務(wù)。為此,讓我們探索漸變功能。梯度函數(shù)在N維空間中被給予線段(即,在我們正在工作的任何坐標(biāo)空間中,無(wú)論是2D,3D還是更高),并計(jì)算沿著該段對(duì)齊的梯度場(chǎng)。輸入坐標(biāo)投影在此線上,并根據(jù)它們相對(duì)于定義線段的端點(diǎn)所在線的位置計(jì)算其梯度值。投影到段之間某處的點(diǎn)被賦予范圍為(-1,1)的值。所以這給了我們一個(gè)很好的起點(diǎn)。我們可以設(shè)置沿Y軸對(duì)齊的漸變函數(shù)。在范圍的頂部,我們將漸變場(chǎng)映射到-1(打開),在底部我們將它映射到1(實(shí)心)。
terraintree = {{name =“ground_gradient”,type =“gradient”,x1 = 0,x2 = 0,y1 = 0,y2 = 1} }(關(guān)于符號(hào)的快速說(shuō)明。示例代碼以Lua聲明表的形式編寫。有關(guān)格式的更多信息,請(qǐng)參閱Lua集成部分。基本上,格式旨在由特殊類解析,讀取聲明并將它們轉(zhuǎn)換為噪聲模塊實(shí)例的實(shí)際樹。我更喜歡這種格式而不是更加冗長(zhǎng)的逐步C ++格式,因?yàn)樗?jiǎn)潔,更清晰。我認(rèn)為,源代碼更具人性化并且比C ++代碼更簡(jiǎn)潔。在大多數(shù)情況下,聲明應(yīng)該易于閱讀和理解。模塊被命名,源在適當(dāng)?shù)臅r(shí)候通過(guò)名稱或值指定。用于解析表聲明的Lua代碼包括在內(nèi)在源代碼分發(fā)中,如果要直接使用這些聲明。)
對(duì)于2D情況,梯度函數(shù)接受(x1,x2,y1,y2)形式的線段,擴(kuò)展到3D情況的(x1,x2,y1,y2,z1,z2)。由(x1,y1)形成的點(diǎn)描繪了線段的起點(diǎn),其被映射到0.由(x2,y2)形成的點(diǎn)是映射到1的線段的末端。所以這里我們映射線段(0,1) - >(0,0)到梯度。這將梯度設(shè)置在函數(shù)的Y = 1和Y = 0區(qū)域之間。所以這個(gè)樂(lè)隊(duì)形成了世界的Y范圍。我們映射的任何一個(gè)世界都將在這個(gè)范圍內(nèi)。我們可以映射X中的任何區(qū)域(實(shí)際上是無(wú)窮大,但受到雙精度的限制),但有趣的東西,即地面,將位于波段內(nèi)。現(xiàn)在,這種行為可以調(diào)整,但就目前而言,我們有足夠的靈活性。請(qǐng)記住,任何高于或低于此范圍的值都可能是無(wú)趣的,因?yàn)樯厦娴哪切┛赡苋慷际情_放的,而下面的那些可能都是可靠的。(正如你將在短時(shí)間內(nèi)看到的那樣,這個(gè)陳述實(shí)際上可能證明是錯(cuò)誤的。盡管如此,更多關(guān)于此。)對(duì)于本系列中的大多數(shù)圖像,我將映射由框(0,1)定義的方形區(qū)域。 - >(1,0)在2D空間中。那時(shí),我們的世界看起來(lái)像這樣:1) - >(1,0)在2D空間中。那時(shí),我們的世界看起來(lái)像這樣:1) - >(1,0)在2D空間中。那時(shí),我們的世界看起來(lái)像這樣:
?
看起來(lái)不是很多,而且它肯定不回答“給定點(diǎn)是固定還是開放?”的問(wèn)題。為了回答這個(gè)問(wèn)題,我們必須應(yīng)用所謂的步驟函數(shù)。我們希望在一側(cè)的所有位置都是開放的,而另一側(cè)的所有位置都是實(shí)心的,而不是平滑的梯度。在ANL中,我們可以使用Select函數(shù)完成此操作。Select函數(shù)接受兩個(gè)輸入函數(shù)或值(在這種情況下它們等同于Solid和Open),并根據(jù)控制函數(shù)的值(在本例中為Gradient函數(shù))在它們之間進(jìn)行選擇。Select模塊有兩個(gè)附加參數(shù),即閾值和衰減,它們會(huì)影響此過(guò)程。對(duì)于這一步,不需要衰減,因此我們將其設(shè)置為0.?然而,閾值參數(shù)決定了Solid和Ground之間的分界線的繪制位置。漸變函數(shù)中大于此值的任何位置都將為“實(shí)心”,并且任何小于閾值的位置都將打開。由于漸變映射我們?cè)?和1之間的范圍,因此放置閾值的邏輯位置為0.5。這將空間分成兩半。我們將表示1的值為solid,而將0的值表示為open。所以我們將設(shè)置地平面功能如下:
terraintree = {{name =“ground_gradient”,type =“gradient”,x1 = 0,x2 = 0,y1 = 0,y2 = 1},{name =“ground_select”,type =“select”,low = 0,high = 1,threshold = 0.5,control =“ground_gradient”} }像以前一樣映射函數(shù)的相同區(qū)域,我們得到這樣的結(jié)果:
?
它確實(shí)回答了“給定點(diǎn)是固定還是開放?”的問(wèn)題。您可以在2D空間中使用任何可能的坐標(biāo)調(diào)用該函數(shù),結(jié)果將為1或0,具體取決于該點(diǎn)相對(duì)于地面的位置。然而,這不是一個(gè)非常有趣的功能。只是一條扁平線,延伸到無(wú)限遠(yuǎn)。為了使它活躍起來(lái),我們將談?wù)撘环N通常被稱為“湍流”的技術(shù)。
對(duì)于將值添加到函數(shù)的輸入坐標(biāo)的概念,湍流是一個(gè)奇特的詞。想象一下,你用坐標(biāo)(0,1)調(diào)用地面函數(shù)。它位于地平面之上,因?yàn)樵赮 = 1時(shí),梯度值為0,小于閾值0.5。所以這一點(diǎn)將被計(jì)算為Open。但是,如果在調(diào)用地面函數(shù)之前,該點(diǎn)已經(jīng)以某種方式被轉(zhuǎn)換了呢?如果我們從該點(diǎn)的Y坐標(biāo)中減去一個(gè)隨機(jī)值,該怎么辦?說(shuō),3?我們減去3,得到坐標(biāo)(0,-2)。現(xiàn)在,如果我們用這個(gè)點(diǎn)調(diào)用地面函數(shù),那么該點(diǎn)被評(píng)估為實(shí)體,因?yàn)閅 = -2位于梯度段的末尾之外,該梯度段映射到1.所以突然之間,而不是打開,點(diǎn)(0,1)會(huì)突然變得堅(jiān)固。你會(huì)在空中漂浮一塊堅(jiān)固的巖石。通過(guò)在調(diào)用ground_select函數(shù)之前在輸入點(diǎn)的Y坐標(biāo)中添加或減去隨機(jī)數(shù),可以對(duì)函數(shù)中的任何點(diǎn)執(zhí)行相同操作。這是ground_select函數(shù)的圖像,展示了這一點(diǎn)。在調(diào)用ground_select函數(shù)之前,每個(gè)坐標(biāo)位置都有一個(gè)在(-0.25,0.25)范圍內(nèi)添加到Y(jié)坐標(biāo)的值。
?
這比扁平線更有趣,但它看起來(lái)并不像地面。這是因?yàn)槊總€(gè)點(diǎn)都被一個(gè)完全隨機(jī)的值擾亂,導(dǎo)致混亂的混亂模式。但是,如果我們使用連續(xù)隨機(jī)函數(shù),例如ANL的?分形函數(shù),而不是混亂的混亂模式,我們將獲得更多控制的東西。所以,讓我們繼續(xù)前進(jìn),將分形線連接到地面,看看我們得到了什么。
terraintree = {{name =“ground_gradient”,type =“gradient”,x1 = 0,x2 = 0,y1 = 0,y2 = 1},{name =“ground_shape_fractal”,type =“fractal”,fractaltype = anl.FBM,basistype = anl.GRADIENT,interptype = anl.QUINTIC,octaves = 6,frequency = 2},{name =“ground_scale”,type =“scaleoffset”,scale = 0.5,offset = 0,source =“ground_shape_fractal”},{name =“ground_perturb”,type =“translatedomain”,source =“ground_gradient”,ty =“ground_scale”},{name =“ground_select”,type =“select”,low = 0,high = 1,threshold = 0.5,control =“ground_perturb”} }這里有幾點(diǎn)需要注意。首先,我們?cè)O(shè)置一個(gè)Fractal模塊,并使用ScaleOffset模塊對(duì)其進(jìn)行鏈接。ScaleOffset模塊將分形的輸出縮放到更易管理的級(jí)別。一些地形可能是多山的,需要更大的規(guī)模,而其他地形更平坦,規(guī)模更小。我們稍后會(huì)詳細(xì)討論不同的地形類型,但現(xiàn)在這將用于演示目的。如果我們現(xiàn)在輸出函數(shù),我們會(huì)得到這樣的結(jié)果:
?
現(xiàn)在這比純隨機(jī)噪音更有趣,不是嗎?至少,即使某些景觀有點(diǎn)奇怪,它也像地面一樣,那些浮島絕對(duì)是奇怪的。這是因?yàn)檩敵鰣D中的每個(gè)點(diǎn)隨機(jī)偏移了一個(gè)不同的值,由分形確定。為了便于說(shuō)明,這里是分形的輸出實(shí)際上是失真的:
?
上面圖像為黑色的任何地方代表-0.25,白色的任何地方代表0.25。因此,無(wú)論分形是最暗的黑色,地面函數(shù)中的對(duì)應(yīng)點(diǎn)都會(huì)向下“扭曲”0.25。(0.25表示屏幕的1/4。)由于一點(diǎn)可能會(huì)稍微扭曲,而空間上方的另一點(diǎn)可能會(huì)更加扭曲,這會(huì)導(dǎo)致懸垂和浮島的可能性。自然界中的懸垂自然發(fā)生。浮島當(dāng)然不會(huì)。(除了阿凡達(dá),就是。科學(xué)!)如果你的游戲想擁有這樣奇特的幻想景觀,那么這很棒,但如果你想要一個(gè)更逼真的模型,那么我們需要馴服提供失真的分形函數(shù)一點(diǎn)點(diǎn)。幸運(yùn)的是,ScaleDomain?功能提供了這樣的手段。
我們想要做的是強(qiáng)制該函數(shù)更像高度圖函數(shù)。想象一下2D高度圖,其中地圖中的每個(gè)點(diǎn)表示網(wǎng)格點(diǎn)的網(wǎng)格點(diǎn)中的上升或下降的高度或低度。地圖中的白色值表示高山,黑色值表示低山谷。我們想要一個(gè)類似的行為,但為了做到這一點(diǎn),我們必須基本上消除其中一個(gè)維度。在高度圖的情況下,我們正在從2D高度圖創(chuàng)建3D地形。同樣,在我們的2D地形的情況下,我們需要有一維高度圖。通過(guò)強(qiáng)制分形中具有相同Y坐標(biāo)的所有點(diǎn)來(lái)評(píng)估相同的值,然后我們將使用相同的X偏移具有相同量的所有點(diǎn),從而確保不會(huì)出現(xiàn)浮島。我們可以使用ScaleDomain來(lái)設(shè)置的scaleY因子為0。因此,被稱為ground_shape_fractal功能之前,我們稱之為ground_scale_y按比例繪制在y 0.坐標(biāo)這確保了Y的值具有分形的輸出沒(méi)有影響,從而有效地將其變成一維噪聲函數(shù)。為此,我們進(jìn)行以下更改:
terraintree = {{name =“ground_gradient”,type =“gradient”,x1 = 0,x2 = 0,y1 = 0,y2 = 1},{name =“ground_shape_fractal”,type =“fractal”,fractaltype = anl.FBM,basistype = anl.GRADIENT,interptype = anl.QUINTIC,octaves = 6,frequency = 2},{name =“ground_scale”,type =“scaleoffset”,scale = 0.5,offset = 0,source =“ground_shape_fractal”},{name =“ground_scale_y”,type =“scaledomain”,source =“ground_scale”,scaley = 0},{name =“ground_perturb”,type =“translatedomain”,source =“ground_gradient”,ty =“ground_scale_y”},{name =“ground_select”,type =“select”,low = 0,high = 1,threshold = 0.5,control =“ground_perturb”} }我們將ScaleDomain函數(shù)鏈接到ground_scale,然后將ground_perturb的源更正為ScaleDomain函數(shù)。這將改變從上面的圖像擾亂地面的分形,而不是:
現(xiàn)在,如果我們查看輸出,我們可以看到結(jié)果:
?
好多了。浮島完全被消除,地形更像是連綿起伏的山脈和丘陵。然而,這種不幸的副作用是懸崖和懸崖的丟失。現(xiàn)在所有的地面都是連續(xù)的,滾動(dòng)的。如果我們?cè)敢?#xff0c;我們可以通過(guò)多種方式糾正這種情況。
第一種方法是使用另一個(gè)TranslateDomain函數(shù)和另一個(gè)Fractal。如果我們?cè)赬方向上施加少量的分形湍流,我們可以稍微擾亂山脈的邊緣和表面,足以形成一些懸崖和懸垂。讓我們看看它在行動(dòng)中。
terraintree = {{name =“ground_gradient”,type =“gradient”,x1 = 0,x2 = 0,y1 = 0,y2 = 1},{name =“ground_shape_fractal”,type =“fractal”,fractaltype = anl.FBM,basistype = anl.GRADIENT,interptype = anl.QUINTIC,octaves = 6,frequency = 2},{name =“ground_scale”,type =“scaleoffset”,scale = 0.5,offset = 0,source =“ground_shape_fractal”},{name =“ground_scale_y”,type =“scaledomain”,source =“ground_scale”,scaley = 0},{name =“ground_perturb”,type =“translatedomain”,source =“ground_gradient”,ty =“ground_scale_y”},{name =“ground_overhang_fractal”,type =“fractal”,fractaltype = anl.FBM,basistype = anl.GRADIENT,interptype = anl.QUINTIC,octaves = 6,frequency = 2},{name =“ground_overhang_scale”,type =“scaleoffset”,source =“ground_overhang_fractal”,scale = 0.2,offset = 0},{name =“ground_overhang_perturb”,type =“translatedomain”,source =“ground_perturb”,tx =“ground_overhang_scale”},{name =“ground_select”,type =“select”,low = 0,high = 1,threshold = 0.5,control =“ground_overhang_perturb”} }結(jié)果是:
?
第二種方式就是設(shè)定的scaleY的參數(shù)ground_scale_y到的東西比0離開Y標(biāo)尺的功能有點(diǎn)讓一些變化大,雖然較高的設(shè)置規(guī)模,更多的地形會(huì)來(lái)類似于早期的,未擴(kuò)展的版本。
這些結(jié)果肯定比滾山更有趣。然而,盡管它很有趣,它仍然會(huì)變得非常無(wú)聊,探索一個(gè)無(wú)盡的英里和相同的一般模式的地形。更重要的是,這樣的地形將是非常不現(xiàn)實(shí)的。自然界有很多變化來(lái)保持事物的趣味性。因此,讓我們看看我們可以做些什么來(lái)讓世界變得更加多樣化。
查看前面的示例代碼,我們可以看到那里的模式。我們有漸變功能,在應(yīng)用步進(jìn)功能和地面給定堅(jiān)固之前,由功能操縱以給出地面形狀。因此,為了增加不同的地形而開始使事物變得復(fù)雜的自然地方是給出地形的部分。我們可以像我們喜歡的那樣復(fù)雜(而且我們可以負(fù)擔(dān)得起;每個(gè)分形都會(huì)增加處理開銷,所以你應(yīng)該只使用盡可能多的分?jǐn)?shù),而不是使用一個(gè)分形來(lái)擾亂Y和另一個(gè)擾亂X.需要,并盡量保守。)我們可以設(shè)置代表山脈,山麓,低地平原,荒地等的地形......并使用各種選擇的輸出函數(shù),鏈接到低頻分形,描繪每種類型的區(qū)域。那么,讓我們來(lái)看看我們?nèi)绾螌?shí)現(xiàn)各種類型的地形。
為了便于說(shuō)明,我們將設(shè)置三種類型的地形:高地(平緩起伏的山丘),山脈和低地(大多是平坦的)。我們將使用基于選擇的系統(tǒng)在它們之間切換,并將它們?nèi)科唇映蓮?fù)雜的掛毯。我們走了......
低地:
這個(gè)很容易。我們可以使用上面的設(shè)置,稍微降低山丘的振幅,甚至可以使它們比加法更具減法性,以降低平均海拔。我們可能會(huì)降低八度計(jì)數(shù)以使它們更平滑。
{name =“l(fā)owland_shape_fractal”,type =“fractal”,fractaltype = anl.FBM,basistype = anl.GRADIENT,interptype = anl.QUINTIC,octaves = 2,frequency = 1}, {name =“l(fā)owland_autocorrect”,type =“autocorrect”,source =“l(fā)owland_shape_fractal”,low = 0,high = 1}, {name =“l(fā)owland_scale”,type =“scaleoffset”,source =“l(fā)owland_autocorrect”,scale = 0.2,offset = -0.25}, {name =“l(fā)owland_y_scale”,type =“scaledomain”,source =“l(fā)owland_scale”,scaley = 0}, {name =“l(fā)owland_terrain”,type =“translatedomain”,source =“ground_gradient”,ty =“l(fā)owland_y_scale”},高原:
再次,簡(jiǎn)單。(實(shí)際上,這些都不是真的那么難。)但是,我們將使用不同的基礎(chǔ),使山丘像沙丘一樣。
{name =“highland_shape_fractal”,type =“fractal”,fractaltype = anl.RIDGEDMULTI,basistype = anl.GRADIENT,interptype = anl.QUINTIC,octaves = 2,frequency = 2}, {name =“highland_autocorrect”,type =“autocorrect”,source =“highland_shape_fractal”,low = 0,high = 1}, {name =“highland_scale”,type =“scaleoffset”,source =“highland_autocorrect”,scale = 0.45,offset = 0}, {name =“highland_y_scale”,type =“scaledomain”,source =“highland_scale”,scaley = 0}, {name =“highland_terrain”,type =“translatedomain”,source =“ground_gradient”,ty =“highland_y_scale”},山:
{name =“mountain_shape_fractal”,type =“fractal”,fractaltype = anl.BILLOW,basistype = anl.GRADIENT,interptype = anl.QUINTIC,octaves = 4,frequency = 1}, {name =“mountain_autocorrect”,type =“autocorrect”,source =“mountain_shape_fractal”,low = 0,high = 1}, {name =“mountain_scale”,type =“scaleoffset”,source =“mountain_autocorrect”,scale = 0.75,offset = 0.25}, {name =“mountain_y_scale”,type =“scaledomain”,source =“mountain_scale”,scaley = 0.1}, {name =“mountain_terrain”,type =“translatedomain”,source =“ground_gradient”,ty =“mountain_y_scale”},當(dāng)然,你可以獲得更多的創(chuàng)意,但這確立了一般模式。您可以考慮地形的特征,并構(gòu)建適合您的噪聲功能。所有這些都遵循相同的原則;?差異主要在于規(guī)模。現(xiàn)在,為了將它們組合在一起,我們將設(shè)置一些額外的分形來(lái)充當(dāng)Select的控件。然后我們將Select模塊鏈接在一起以生成整體。
{name =“terrain_type_fractal”,type =“fractal”,fractaltype = anl.FBM,basistype = anl.GRADIENT,interptype = anl.QUINTIC,octaves = 3,frequency = 0.5}, {name =“terrain_autocorrect”,type =“autocorrect”,source =“terrain_type_fractal”,low = 0,high = 1}, {name =“terrain_type_cache”,type =“cache”,source =“terrain_autocorrect”}, {name =“highland_mountain_select”,type =“select”,low =“highland_terrain”,high =“mountain_terrain”,control =“terrain_type_cache”,threshold = 0.55,falloff = 0.15}, {name =“highland_lowland_select”,type =“select”,low =“l(fā)owland_terrain”,high =“highland_mountain_select”,control =“terrain_type_cache”,threshold = 0.25,falloff = 0.15},所以我們?cè)谶@里為低地,高地和山脈建立了三種主要類型。我們使用一個(gè)分形來(lái)在所有三個(gè)之間進(jìn)行選擇,以便從低地 - >高地 - >山脈中自然發(fā)展。然后我們使用另一個(gè)分形隨機(jī)將荒地插入地圖。最終的模塊鏈?zhǔn)?#xff1a;
terraintree = {{name =“l(fā)owland_shape_fractal”,type =“fractal”,fractaltype = anl.FBM,basistype = anl.GRADIENT,interptype = anl.QUINTIC,octaves = 2,frequency = 1},{name =“l(fā)owland_autocorrect”,type =“autocorrect”,source =“l(fā)owland_shape_fractal”,low = 0,high = 1},{name =“l(fā)owland_scale”,type =“scaleoffset”,source =“l(fā)owland_autocorrect”,scale = 0.2,offset = -0.25},{name =“l(fā)owland_y_scale”,type =“scaledomain”,source =“l(fā)owland_scale”,scaley = 0},{name =“l(fā)owland_terrain”,type =“translatedomain”,source =“ground_gradient”,ty =“l(fā)owland_y_scale”},{name =“ground_gradient”,type =“gradient”,x1 = 0,x2 = 0,y1 = 0,y2 = 1},{name =“highland_shape_fractal”,type =“fractal”,fractaltype = anl.RIDGEDMULTI,basistype = anl.GRADIENT,interptype = anl.QUINTIC,octaves = 2,frequency = 2},{name =“highland_autocorrect”,type =“autocorrect”,source =“highland_shape_fractal”,low = 0,high = 1},{name =“highland_scale”,type =“scaleoffset”,source =“highland_autocorrect”,scale = 0.45,offset = 0},{name =“highland_y_scale”,type =“scaledomain”,source =“highland_scale”,scaley = 0},{name =“highland_terrain”,type =“translatedomain”,source =“ground_gradient”,ty =“highland_y_scale”},{name =“mountain_shape_fractal”,type =“fractal”,fractaltype = anl.BILLOW,basistype = anl.GRADIENT,interptype = anl.QUINTIC,octaves = 4,frequency = 1},{name =“mountain_autocorrect”,type =“autocorrect”,source =“mountain_shape_fractal”,low = 0,high = 1},{name =“mountain_scale”,type =“scaleoffset”,source =“mountain_autocorrect”,scale = 0.75,offset = 0.25},{name =“mountain_y_scale”,type =“scaledomain”,source =“mountain_scale”,scaley = 0.1},{name =“mountain_terrain”,type =“translatedomain”,source =“ground_gradient”,ty =“mountain_y_scale”},{name =“terrain_type_fractal”,type =“fractal”,fractaltype = anl.FBM,basistype = anl.GRADIENT,interptype = anl.QUINTIC,octaves = 3,frequency = 0.5},{name =“terrain_autocorrect”,type =“autocorrect”,source =“terrain_type_fractal”,low = 0,high = 1},{name =“terrain_type_cache”,type =“cache”,source =“terrain_autocorrect”},{name =“highland_mountain_select”,type =“select”,low =“highland_terrain”,high =“mountain_terrain”,control =“terrain_type_cache”,threshold = 0.55,falloff = 0.15},{name =“highland_lowland_select”,type =“select”,low =“l(fā)owland_terrain”,high =“highland_mountain_select”,control =“terrain_type_cache”,threshold = 0.25,falloff = 0.15},{name =“ground_select”,type =“select”,low = 0,high = 1,threshold = 0.5,control =“highland_lowland_select”} }以下是這將產(chǎn)生的各種地形的隨機(jī)全景照片:
你可以看到那里有一個(gè)非常好的變化。有些地方有高聳的鋸齒狀山脈,而其他地方有平緩的公寓。現(xiàn)在,我們想要添加洞穴,以探索地下的奇跡。
對(duì)于洞穴,我使用了一個(gè)針對(duì)ground_select的乘法系統(tǒng)。也就是說(shuō),我想出了一個(gè)輸出1或0的函數(shù),并將它與ground_select的輸出相乘。這具有設(shè)置為在洞穴函數(shù)中打開函數(shù)中0的任何位置的效果。所以我想要一個(gè)洞穴出現(xiàn)的地方必須在洞穴功能中返回0,我希望它不是我設(shè)置為1的洞穴。至于洞穴的形狀,我喜歡將洞穴系統(tǒng)基于1個(gè)八度音程山脊多重分形。
{name =“cave_shape”,type =“fractal”,fractaltype = anl.RIDGEDMULTI,basistype = anl.GRADIENT,interptype = anl.QUINTIC,octaves = 1,frequency = 2},這導(dǎo)致類似于:
如果將Select函數(shù)應(yīng)用為階梯函數(shù),就像我們對(duì)地面漸變一樣,使閾值的低邊選擇為1(無(wú)洞穴),高邊選擇為0(洞穴),然后結(jié)果看起來(lái)像這樣:
{name =“cave_shape”,type =“fractal”,fractaltype = anl.RIDGEDMULTI,basistype = anl.GRADIENT,interptype = anl.QUINTIC,octaves = 1,frequency = 2}, {name =“cave_select”,type =“select”,low = 1,high = 0,control =“cave_shape”,threshold = 0.8,falloff = 0},結(jié)果:
當(dāng)然,這看起來(lái)相當(dāng)平滑,所以讓我們添加一些分形噪聲來(lái)擾亂域。
{name =“cave_shape”,type =“fractal”,fractaltype = anl.RIDGEDMULTI,basistype = anl.GRADIENT,interptype = anl.QUINTIC,octaves = 1,frequency = 2}, {name =“cave_select”,type =“select”,low = 1,high = 0,control =“cave_shape”,threshold = 0.8,falloff = 0}, {name =“cave_perturb_fractal”,type =“fractal”,fractaltype = anl.FBM,basistype = anl.GRADIENT,interptype = anl.QUINTIC,octaves = 6,frequency = 3}, {name =“cave_perturb_scale”,type =“scaleoffset”,source =“cave_perturb_fractal”,scale = 0.25,offset = 0}, {name =“cave_perturb”,type =“translatedomain”,source =“cave_select”,tx =“cave_perturb_scale”},結(jié)果:
這樣可以使洞穴稍微變暗,并使它們不那么平滑。讓我們看看如果我們現(xiàn)在將洞穴應(yīng)用于地形可能會(huì)是什么樣子:
通過(guò)與該值打門限在cave_select,我們可以使洞穴薄或厚。但我們真正應(yīng)該做的一件事就是盡量做到這一點(diǎn),以便洞穴不會(huì)從地表地形挖出如此巨大的,不敬虔的塊狀物。要做到這一點(diǎn),我們可以回到highland_lowland_select函數(shù),你會(huì)記得,這是用于擾亂地面漸變的最終地形函數(shù)。這里有用的功能是它仍然是一個(gè)梯度,隨著函數(shù)深入地球而增加。我們可以使用這個(gè)梯度來(lái)減弱洞穴功能,以便在您深入地球時(shí)洞穴變得更大。幸運(yùn)的是,這種衰減可以簡(jiǎn)單地通過(guò)乘以輸出來(lái)實(shí)現(xiàn)highland_lowland_select函數(shù)使用cave_shape的輸出,然后將結(jié)果傳遞給cave函數(shù)鏈的其余部分。現(xiàn)在,我們要做的一個(gè)重要改變是增加了一個(gè)Cache功能。緩存函數(shù)將存儲(chǔ)給定輸入坐標(biāo)的函數(shù)結(jié)果,如果使用相同的坐標(biāo)再次調(diào)用該函數(shù),它將返回緩存的副本,而不是重新計(jì)算結(jié)果。這對(duì)于這樣的情況很有用,其中一個(gè)復(fù)雜函數(shù)(highland_lowland_select)將在模塊鏈中被多次調(diào)用。如果沒(méi)有緩存,每次調(diào)用復(fù)雜函數(shù)的整個(gè)鏈時(shí)都會(huì)重新計(jì)算。要引入緩存,我們首先進(jìn)行以??下更改:
{name =“highland_lowland_select”,type =“select”,low =“l(fā)owland_terrain”,high =“highland_mountain_select”,control =“terrain_type_cache”,threshold = 0.25,falloff = 0.15}, {name =“highland_lowland_select_cache”,type =“cache”,source =“highland_lowland_select”}, {name =“ground_select”,type =“select”,low = 0,high = 1,threshold = 0.5,control =“highland_lowland_select_cache”},這會(huì)附加Cache,然后重定向ground_select的輸入來(lái)自緩存,而不是直接來(lái)自函數(shù)。然后我們可以修改洞穴代碼來(lái)添加衰減:
{name =“cave_shape”,type =“fractal”,fractaltype = anl.RIDGEDMULTI,basistype = anl.GRADIENT,interptype = anl.QUINTIC,octaves = 1,frequency = 4}, {name =“cave_attenuate_bias”,type =“bias”,source =“highland_lowland_select_cache”,bias = 0.45}, {name =“cave_shape_attenuate”,type =“combiner”,operation = anl.MULT,source_0 =“cave_shape”,source_1 =“cave_attenuate_bias”}, {name =“cave_perturb_fractal”,type =“fractal”,fractaltype = anl.FBM,basistype = anl.GRADIENT,interptype = anl.QUINTIC,octaves = 6,frequency = 3}, {name =“cave_perturb_scale”,type =“scaleoffset”,source =“cave_perturb_fractal”,scale = 0.5,offset = 0}, {name =“cave_perturb”,type =“translatedomain”,source =“cave_shape_attenuate”,tx =“cave_perturb_scale”}, {name =“cave_select”,type =“select”,low = 1,high = 0,control =“cave_perturb”,threshold = 0.48,falloff = 0},我們首先添加了Bias功能。這是為了方便起見(jiàn),允許我們調(diào)整梯度衰減函數(shù)的范圍。然后我們添加了cave_shape_attenuate函數(shù),它是anl :: MULT類型的Combiner。這會(huì)將漸變乘以cave_shape。然后將結(jié)果傳遞給cave_perturb函數(shù)。結(jié)果看起來(lái)像這樣:
你可以看到洞穴在朝向地面的區(qū)域變得更薄。(忽略頂部的東西,它只是漸變的一個(gè)神器,對(duì)最終的洞穴沒(méi)有影響。如果它成為一個(gè)問(wèn)題 - 比方說(shuō),如果你把這個(gè)函數(shù)用于別的東西,那么漸變可以在被使用之前被鉗制到(0,1)。)有點(diǎn)難以看出它是如何與地形相關(guān)的,所以讓我們繼續(xù)把所有東西合成在一起,看看我們得到了什么。到目前為止,這是我們的整個(gè)功能鏈。
terraintree = {{name =“ground_gradient”,type =“gradient”,x1 = 0,x2 = 0,y1 = 0,y2 = 1},{name =“l(fā)owland_shape_fractal”,type =“fractal”,fractaltype = anl.BILLOW,basistype = anl.GRADIENT,interptype = anl.QUINTIC,octaves = 2,frequency = 0.25},{name =“l(fā)owland_autocorrect”,type =“autocorrect”,source =“l(fā)owland_shape_fractal”,low = 0,high = 1},{name =“l(fā)owland_scale”,type =“scaleoffset”,source =“l(fā)owland_autocorrect”,scale = 0.125,offset = -0.45},{name =“l(fā)owland_y_scale”,type =“scaledomain”,source =“l(fā)owland_scale”,scaley = 0},{name =“l(fā)owland_terrain”,type =“translatedomain”,source =“ground_gradient”,ty =“l(fā)owland_y_scale”},{name =“highland_shape_fractal”,type =“fractal”,fractaltype = anl.FBM,basistype = anl.GRADIENT,interptype = anl.QUINTIC,octaves = 4,frequency = 2},{name =“highland_autocorrect”,type =“autocorrect”,source =“highland_shape_fractal”,low = -1,high = 1},{name =“highland_scale”,type =“scaleoffset”,source =“highland_autocorrect”,scale = 0.25,offset = 0},{name =“highland_y_scale”,type =“scaledomain”,source =“highland_scale”,scaley = 0},{name =“highland_terrain”,type =“translatedomain”,source =“ground_gradient”,ty =“highland_y_scale”},{name =“mountain_shape_fractal”,type =“fractal”,fractaltype = anl.RIDGEDMULTI,basistype = anl.GRADIENT,interptype = anl.QUINTIC,octaves = 8,frequency = 1},{name =“mountain_autocorrect”,type =“autocorrect”,source =“mountain_shape_fractal”,low = -1,high = 1},{name =“mountain_scale”,type =“scaleoffset”,source =“mountain_autocorrect”,scale = 0.45,offset = 0.15},{name =“mountain_y_scale”,type =“scaledomain”,source =“mountain_scale”,scaley = 0.25},{name =“mountain_terrain”,type =“translatedomain”,source =“ground_gradient”,ty =“mountain_y_scale”},{name =“terrain_type_fractal”,type =“fractal”,fractaltype = anl.FBM,basistype = anl.GRADIENT,interptype = anl.QUINTIC,octaves = 3,frequency = 0.125},{name =“terrain_autocorrect”,type =“autocorrect”,source =“terrain_type_fractal”,low = 0,high = 1},{name =“terrain_type_y_scale”,type =“scaledomain”,source =“terrain_autocorrect”,scaley = 0},{name =“terrain_type_cache”,type =“cache”,source =“terrain_type_y_scale”},{name =“highland_mountain_select”,type =“select”,low =“highland_terrain”,high =“mountain_terrain”,control =“terrain_type_cache”,threshold = 0.55,falloff = 0.2},{name =“highland_lowland_select”,type =“select”,low =“l(fā)owland_terrain”,high =“highland_mountain_select”,control =“terrain_type_cache”,threshold = 0.25,falloff = 0.15},{name =“highland_lowland_select_cache”,type =“cache”,source =“highland_lowland_select”},{name =“ground_select”,type =“select”,low = 0,high = 1,threshold = 0.5,control =“highland_lowland_select_cache”},{name =“cave_shape”,type =“fractal”,fractaltype = anl.RIDGEDMULTI,basistype = anl.GRADIENT,interptype = anl.QUINTIC,octaves = 1,frequency = 4},{name =“cave_attenuate_bias”,type =“bias”,source =“highland_lowland_select_cache”,bias = 0.45},{name =“cave_shape_attenuate”,type =“combiner”,operation = anl.MULT,source_0 =“cave_shape”,source_1 =“cave_attenuate_bias”},{name =“cave_perturb_fractal”,type =“fractal”,fractaltype = anl.FBM,basistype = anl.GRADIENT,interptype = anl.QUINTIC,octaves = 6,frequency = 3},{name =“cave_perturb_scale”,type =“scaleoffset”,source =“cave_perturb_fractal”,scale = 0.5,offset = 0},{name =“cave_perturb”,type =“translatedomain”,source =“cave_shape_attenuate”,tx =“cave_perturb_scale”},{name =“cave_select”,type =“select”,low = 1,high = 0,control =“cave_perturb”,threshold = 0.48,falloff = 0},{name =“ground_cave_multiply”,type =“combiner”,operation = anl.MULT,source_0 =“cave_select”,source_1 =“ground_select”} }以下是此功能的隨機(jī)位置選擇:
現(xiàn)在看起來(lái)很不錯(cuò)。洞穴都是地下深處相當(dāng)大的洞穴,但在地表,它們往往會(huì)衰減到小隧道。這有助于營(yíng)造神秘氣息。當(dāng)您外出探索這片土地時(shí),您會(huì)遇到一個(gè)小洞穴入口。它去哪兒了?它有多深?沒(méi)有辦法說(shuō),但隨著你的探索,它開始擴(kuò)大到廣闊的洞穴,充滿了黑暗和危險(xiǎn)。當(dāng)然還有戰(zhàn)利品。永遠(yuǎn)是戰(zhàn)利品。
您可以通過(guò)多種方式調(diào)整此方法以獲得不同的結(jié)果。您可以修改閾值設(shè)置cave_select和設(shè)置cave_attenuate_bias,或更改cave_attenuate_bias到不同的功能來(lái)重映射漸變的范圍,以更好地滿足您的需求。您可以添加另一個(gè)在Y軸上擾亂洞穴系統(tǒng)的分形,以消除X方向上偶然出現(xiàn)的非自然光滑隧道(僅在X中擾亂洞穴形狀)。您可以添加另一個(gè)分形作為另一個(gè)衰減源,設(shè)置為cave_shape_attenuate的第三個(gè)源在區(qū)域基礎(chǔ)上縮放衰減,使得洞穴在某些區(qū)域(例如,可能是山脈)更密集地出現(xiàn),而在其他區(qū)域則更不密集或根本不出現(xiàn)。該區(qū)域選擇器將從terrain_type_fractal函數(shù)派生,以了解山區(qū)的位置。這一切只是考慮你想要什么,了解各種功能對(duì)輸出的影響,并嘗試各種參數(shù),直到你得到你喜歡的東西。這不是一門完美的科學(xué),通常有很多方法可以達(dá)到任何特定的效果。
缺點(diǎn)
這種地形生成方法存在缺陷。產(chǎn)生噪音可能相當(dāng)慢。重要的是減少分形的數(shù)量,你使用的分形的八度計(jì)數(shù),以及盡可能減少其他慢速操作。盡可能嘗試重新使用分形,并緩存每個(gè)被調(diào)用多次的函數(shù)。在這個(gè)例子中,我非常自由地使用分形,為三種地形類型中的每一種提供單獨(dú)的分形。通過(guò)使用ScaleOffset重新映射范圍并將它們?nèi)炕趩蝹€(gè)分形,我本可以節(jié)省大量處理時(shí)間。在2D中它并不是那么糟糕,但是當(dāng)你開始進(jìn)入3D并嘗試映射大量數(shù)據(jù)時(shí),時(shí)間真的會(huì)增加。
擴(kuò)展到3D
現(xiàn)在,如果你制作像Terraria或King Arthur's Gold這樣的游戲,這一切都很棒,但如果你想制作像Minecraft或Infiniminer這樣的游戲呢?代替?我們要對(duì)功能鏈做出哪些改變?答案是“不多”。上面的功能鏈幾乎可以直接用于3D地形。您所要做的就是使用生成器的3D變體映射3D體積,并將Y軸映射到體積的垂直軸,而不是2D區(qū)域。但是,需要進(jìn)行一項(xiàng)更改,即洞穴的工作方式。你看,Ridged Multifractal適用于2D洞穴系統(tǒng),但在3D中它雕刻了一系列彎曲的殼而不是隧道,效果不對(duì)。所以在3D中,有必要設(shè)置2個(gè)洞穴形狀分形,包括1個(gè)八度嶺脊多重分形噪聲但具有不同的種子,將它們選擇為1或0,并將它們相乘。這樣,無(wú)論分形交叉哪里變成洞穴,
terraintree3d = {{name =“ground_gradient”,type =“gradient”,x1 = 0,x2 = 0,y1 = 0,y2 = 1},{name =“l(fā)owland_shape_fractal”,type =“fractal”,fractaltype = anl.BILLOW,basistype = anl.GRADIENT,interptype = anl.QUINTIC,octaves = 2,frequency = 0.25},{name =“l(fā)owland_autocorrect”,type =“autocorrect”,source =“l(fā)owland_shape_fractal”,low = 0,high = 1},{name =“l(fā)owland_scale”,type =“scaleoffset”,source =“l(fā)owland_autocorrect”,scale = 0.125,offset = -0.45},{name =“l(fā)owland_y_scale”,type =“scaledomain”,source =“l(fā)owland_scale”,scaley = 0},{name =“l(fā)owland_terrain”,type =“translatedomain”,source =“ground_gradient”,ty =“l(fā)owland_y_scale”},{name =“highland_shape_fractal”,type =“fractal”,fractaltype = anl.FBM,basistype = anl.GRADIENT,interptype = anl.QUINTIC,octaves = 4,frequency = 2},{name =“highland_autocorrect”,type =“autocorrect”,source =“highland_shape_fractal”,low = -1,high = 1},{name =“highland_scale”,type =“scaleoffset”,source =“highland_autocorrect”,scale = 0.25,offset = 0},{name =“highland_y_scale”,type =“scaledomain”,source =“highland_scale”,scaley = 0},{name =“highland_terrain”,type =“translatedomain”,source =“ground_gradient”,ty =“highland_y_scale”},{name =“mountain_shape_fractal”,type =“fractal”,fractaltype = anl.RIDGEDMULTI,basistype = anl.GRADIENT,interptype = anl.QUINTIC,octaves = 8,frequency = 1},{name =“mountain_autocorrect”,type =“autocorrect”,source =“mountain_shape_fractal”,low = -1,high = 1},{name =“mountain_scale”,type =“scaleoffset”,source =“mountain_autocorrect”,scale = 0.45,offset = 0.15},{name =“mountain_y_scale”,type =“scaledomain”,source =“mountain_scale”,scaley = 0.25},{name =“mountain_terrain”,type =“translatedomain”,source =“ground_gradient”,ty =“mountain_y_scale”},{name =“terrain_type_fractal”,type =“fractal”,fractaltype = anl.FBM,basistype = anl.GRADIENT,interptype = anl.QUINTIC,octaves = 3,frequency = 0.125},{name =“terrain_autocorrect”,type =“autocorrect”,source =“terrain_type_fractal”,low = 0,high = 1},{name =“terrain_type_y_scale”,type =“scaledomain”,source =“terrain_autocorrect”,scaley = 0},{name =“terrain_type_cache”,type =“cache”,source =“terrain_type_y_scale”},{name =“highland_mountain_select”,type =“select”,low =“highland_terrain”,high =“mountain_terrain”,control =“terrain_type_cache”,threshold = 0.55,falloff = 0.2},{name =“highland_lowland_select”,type =“select”,low =“l(fā)owland_terrain”,high =“highland_mountain_select”,control =“terrain_type_cache”,threshold = 0.25,falloff = 0.15},{name =“highland_lowland_select_cache”,type =“cache”,source =“highland_lowland_select”},{name =“ground_select”,type =“select”,low = 0,high = 1,threshold = 0.5,control =“highland_lowland_select_cache”},{name =“cave_attenuate_bias”,type =“bias”,source =“highland_lowland_select_cache”,bias = 0.45},{name =“cave_shape1”,type =“fractal”,fractaltype = anl.RIDGEDMULTI,basistype = anl.GRADIENT,interptype = anl.QUINTIC,octaves = 1,frequency = 4},{name =“cave_shape2”,type =“fractal”,fractaltype = anl.RIDGEDMULTI,basistype = anl.GRADIENT,interptype = anl.QUINTIC,octaves = 1,frequency = 4},{name =“cave_shape_attenuate”,type =“combiner”,operation = anl.MULT,source_0 =“cave_shape1”,source_1 =“cave_attenuate_bias”,source_2 =“cave_shape2”}, {name =“cave_perturb_fractal”,type =“fractal”,fractaltype = anl.FBM,basistype = anl.GRADIENT,interptype = anl.QUINTIC,octaves = 6,frequency = 3},{name =“cave_perturb_scale”,type =“scaleoffset”,source =“cave_perturb_fractal”,scale = 0.5,offset = 0},{name =“cave_perturb”,type =“translatedomain”,source =“cave_shape_attenuate”,tx =“cave_perturb_scale”},{name =“cave_select”,type =“select”,low = 1,high = 0,control =“cave_perturb”,threshold = 0.48,falloff = 0},{name =“ground_cave_multiply”,type =“combiner”,operation = anl.MULT,source_0 =“cave_select”,source_1 =“ground_select”} }一些結(jié)果:
現(xiàn)在,它看起來(lái)像一些參數(shù)需要一些調(diào)整。也許減少衰減,或加厚洞穴,減少地形分形中的八度音階數(shù),使地形更平滑等等......再次,這完全取決于你想要達(dá)到的目的。
轉(zhuǎn)載于:https://www.cnblogs.com/sanyejun/p/9300799.html
總結(jié)
- 上一篇: XP WiN7远程桌面3389多用户登陆
- 下一篇: 门户通专访SEO专家王通:攻破网站优化难