????????正經(jīng)人誰(shuí)寫日記啊
? ? ? ? ? ? ? ? ? ? ? ? ????????????????????????--汪涵
????????我以前也一直認(rèn)為一個(gè)正經(jīng)忙碌的人哪有時(shí)間和精力去寫日記呢?
????????但是我錯(cuò)了,正因?yàn)槊G沒(méi)有精力,才要將重要的事情記錄下來(lái).
????????我記錄的東西也都是一些比較簡(jiǎn)單的Unity使用,C#程序設(shè)計(jì)的淺顯的東西.
????????但是誰(shuí)知道呢,當(dāng)我不停地探索之后,發(fā)出來(lái)的內(nèi)容,也許對(duì)于那些剛?cè)腴T的新人來(lái)說(shuō),會(huì)是一個(gè)引導(dǎo).
關(guān)于地形(terrain)對(duì)象
????????有四個(gè)重要參數(shù),地形寬度,地形長(zhǎng)度和地形高度,以及高度圖分辨率.
????????前面三個(gè)都好理解,主要是最后一個(gè)高度圖分辨率,它是一個(gè)二維的平面圖,用灰色深度來(lái)代表地形高低起伏的一個(gè)圖.(最黑為0)
? ? ? ? 它不直觀展示出來(lái),它只在程序計(jì)算地形高度時(shí)起作用,這就比較抽象.
? ? ? ? 并且高度圖的分辨率和地形分辨率(長(zhǎng)*寬)可以不是一樣的.
? ? ? ? 更低的分辨率在生成地形高度時(shí)會(huì)變得更陡峭.(這不是創(chuàng)建陡峭地形的方法,這種只會(huì)影響玩家的游戲體驗(yàn).)
? ? ? ? 一個(gè)1024*1024的地形圖如果配上513*513的高度圖那么整個(gè)地形的起伏會(huì)非常平滑
但是一個(gè)10240*10240的地形圖,如果配上513*513的高度圖,那么整個(gè)地形的起伏會(huì)變得非常突兀.
因?yàn)槊總€(gè)高度圖的像素點(diǎn),將要承擔(dān)10倍于1024*1024地形圖的起伏.
? ?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
public class CreateTerrain : MonoBehaviour
{
public int seed;
public float terrainWidth = 1024f;//地形的寬度
public float terrainLength = 1024f;//地形的長(zhǎng)度
public int terrainHeight = 50;//地形的高度
public Texture2D[] terrainTexture;
public float perlinScale = 10.0f;
public float[] perlinThreshold = {0.25f, 0.5f, 0.75f };
private float randomOffsetX;
private float randomOffsetY;
public float centerHeight ;
public float edgeHeight ;
[Range(0, 2048)]
public float slopeRadius;
int terrainResolution;
public static float Add(float a, float b)
{
float c = a + b;
return c;
//計(jì)算高度圖分辨率
}
? ? 所以在創(chuàng)建高度圖分辨率時(shí)應(yīng)該和地形寬度和長(zhǎng)度進(jìn)行一個(gè)動(dòng)態(tài)改變.
將長(zhǎng)度和寬度相加,并且除以2,已達(dá)到清晰度和兼顧配置的需求.
void Start()
{
terrainResolution = ((int)Add(terrainWidth,terrainLength)/2);
Random.InitState(seed);
randomOffsetX = Random.Range(0f, 10000f);
randomOffsetY = Random.Range(0f, 10000f);
?????????Unity的任何游戲?qū)ο?都有2種坐標(biāo)系,一個(gè)是世界坐標(biāo)系,一個(gè)是本地坐標(biāo)系.如果是3D游戲就是三維坐標(biāo)系,如果是2D游戲就是二維坐標(biāo)系.
? ? ? ? 三維坐標(biāo)系實(shí)在是讓人頭大,它是計(jì)算機(jī)圖形學(xué)的一個(gè)基礎(chǔ)概念.在鏡頭控制系統(tǒng)中是最繞人的,在地形創(chuàng)建中只需要關(guān)注他的世界坐標(biāo)系即可.
//創(chuàng)建一個(gè)簡(jiǎn)單的平面地形,并將其移動(dòng)到(0,0,0)坐標(biāo)
Vector3 terrainPosition = new Vector3(terrainWidth,terrainHeight,terrainLength);
TerrainData terrainData = new TerrainData();
terrainData.heightmapResolution = terrainResolution;
terrainData.size = terrainPosition;
????????Vector3類型是一個(gè)三維向量結(jié)構(gòu)體,將要?jiǎng)?chuàng)建的地形的長(zhǎng)寬高賦值給它,并在后面將值賦值給創(chuàng)建出的地形對(duì)象.
? ? ? ? TerrainData是Terrain游戲?qū)ο罄锩娴臄?shù)據(jù)對(duì)象,通過(guò)terrainData對(duì)象你才能控制terrain的具體數(shù)據(jù).(長(zhǎng)寬高,位置等等.)
? ? ? ? 而且還可以在游戲中實(shí)時(shí)控制地形.
????????
GameObject terrainObject = Terrain.CreateTerrainGameObject(terrainData);//創(chuàng)建地形的方法
float terrainHalfWidth = terrainWidth * 0.5f;
float terrainHalfLength = terrainLength * 0.5f;
Vector3 terrainOffset = new Vector3(-terrainHalfWidth, terrainHeight, -terrainHalfLength);
terrainObject.transform.position += terrainOffset;
? ? ? ? 緊跟著就是創(chuàng)建地形方法.CreateTerrainGameObject();
? ? ? ? 創(chuàng)建出的只是一個(gè)地形對(duì)象,如果不給他設(shè)置任何的數(shù)值,它將是一個(gè)默認(rèn)的大小和位置.
? ? ? ? 生成地形時(shí)是從地形的左下角作為(0,0)的,所以1024*1024的地形將會(huì)在右上角處達(dá)到(1024,1024)坐標(biāo).
? ? ? ? 所以我還加了一個(gè)移動(dòng)地形對(duì)象的操作,將地形中心點(diǎn)對(duì)準(zhǔn)(0,0)
? ? ? ? 方法就是將地形大小除以2,之后對(duì)先有地形的三維坐標(biāo)進(jìn)行更改.
地形對(duì)象的坐標(biāo)系和其大小始終是一樣的,當(dāng)?shù)匦巫兇髸r(shí),他的坐標(biāo)系也會(huì)跟著變大,所以直接減去地形的長(zhǎng)寬的一半,并將新的位置賦值給地形對(duì)象的.transform.position,就可以實(shí)現(xiàn)將地形中心點(diǎn)移動(dòng)到世界坐標(biāo)系的(0,0)了.
關(guān)于地形貼圖(TerrainTexture2D)
????????地形貼圖支持多貼圖功能,因此只能使用數(shù)組形式來(lái)進(jìn)行賦值,哪怕只有一個(gè)貼圖
TerrainLayer[] terrainLayers = new TerrainLayer[terrainTexture.Length];//TerrainLayer支持多貼圖功能,因此只能使用數(shù)組形式來(lái)進(jìn)行賦值,哪怕只有一個(gè)貼圖.
for (int i = 0; i < terrainTexture.Length; i++)
{
terrainLayers[i] = new TerrainLayer();
terrainLayers[i].diffuseTexture = terrainTexture[i];
terrainLayers[i].tileSize = new Vector2(16, 16);
terrainLayers[i].tileOffset = new Vector2(0, 0);
terrainLayers[i].diffuseTexture.wrapMode = TextureWrapMode.Repeat;
terrainLayers[i].normalMapTexture = null;
terrainLayers[i].normalScale = 0.0f;
terrainLayers[i].smoothness = 0.0f;
terrainLayers[i].metallic = 0.0f;
}
? ? ? ? ? ?上面代碼接著地形創(chuàng)建.
? ? ? ? 聲明一個(gè)TerrainLayer[]類型的數(shù)組,這個(gè)數(shù)組就是貼圖圖層數(shù)組,他存儲(chǔ)了所有的預(yù)先在unity界面里導(dǎo)入的貼圖.
? ? ? ? 我這里導(dǎo)入了4張貼圖
? ? ? ? ? ? ? ? ? ? ? ? ?
????????所以會(huì)循環(huán)4次,依次新建地形貼圖圖層對(duì)象,將貼圖賦予地形散射(漫反射)?紋理.
? ? ? ? 設(shè)置貼圖大小,設(shè)置地形層的紋理平鋪偏移量,設(shè)置地形層散射紋理的包裝模式為“重復(fù)”。這意味著當(dāng)紋理在地形表面被平鋪時(shí),如果紋理范圍超過(guò)地形表面,紋理將在邊界處重復(fù),從而覆蓋整個(gè)地形表面,將地形層的法線貼圖設(shè)置為 null,
設(shè)置地形層的法線縮放值,設(shè)置地形層的光滑度,設(shè)置地形層的金屬度.
terrainData.alphamapResolution = terrainResolution;
terrainData.terrainLayers = terrainLayers;
float[,,] splatmapData = new float[terrainData.alphamapResolution, terrainData.alphamapResolution,terrainTexture.Length];
for (int i = 0; i < terrainData.alphamapResolution; i++)
{
for (int j = 0; j < terrainData.alphamapResolution; j++)
{
float perlinValue = Mathf.PerlinNoise((float)(i+randomOffsetX) / terrainData.alphamapResolution * perlinScale, (float)(j+randomOffsetY) / terrainData.alphamapResolution * perlinScale);
if (perlinValue <= perlinThreshold[0])
{
splatmapData[i, j, 0] = 1;
splatmapData[i, j, 1] = 0;
splatmapData[i, j, 2] = 0;
splatmapData[i, j, 3] = 0;
}
else if(perlinValue <= perlinThreshold[1])
{
splatmapData[i, j, 0] = 0;
splatmapData[i, j, 1] = 1;
splatmapData[i, j, 2] = 0;
splatmapData[i, j, 3] = 0;
}
else if (perlinValue <= perlinThreshold[2])
{
splatmapData[i, j, 0] = 0;
splatmapData[i, j, 1] = 0;
splatmapData[i, j, 2] = 1;
splatmapData[i, j, 3] = 0;
}
else
{
splatmapData[i, j, 0] = 0;
splatmapData[i, j, 1] = 0;
splatmapData[i, j, 2] = 0;
splatmapData[i, j, 3] = 1;
}
}
}
terrainData.SetAlphamaps(0, 0, splatmapData);
? ? ? ? ?接下來(lái)進(jìn)行貼圖混合,I,J的最大值分別取地形高度圖分辨率,perlinThreshold在前面變量聲明時(shí)已經(jīng)定義了一個(gè)固定的值,這里就是將4個(gè)貼圖按25%的比例進(jìn)行權(quán)重分配.
? ? ? ? 循環(huán)內(nèi)部利用柏林噪聲和隨機(jī)值偏移量來(lái)控制,柏林噪聲生成的數(shù)值,使用隨機(jī)值偏移量可以實(shí)現(xiàn)種子功能,在同一種子下,柏林噪聲生成的噪聲形態(tài)將會(huì)一樣.
????????
? ? ? ? 對(duì)于貼圖交界處,unity會(huì)自動(dòng)混合平滑過(guò)渡,不需要另行編寫代碼.
? ? ? ? 最后,設(shè)置阿爾法maps將這個(gè)三維數(shù)組賦值給剛剛創(chuàng)建的地形上.
關(guān)于地形高度圖(terrainHeightMap)
float[,] circleHeightMap = CreateCircleHeightMap(terrainResolution, centerHeight / terrainHeight, edgeHeight / terrainHeight, slopeRadius);
terrainData.SetHeights(0, 0, circleHeightMap);//應(yīng)用高度圖
float[,] CreateCircleHeightMap(int resolution, float centerHeight, float edgeHeight, float radius)
{
float[,] heightMap = new float[resolution, resolution];
float halfWidth = terrainWidth * 0.5f;
float halfLength = terrainLength * 0.5f;
float maxDistSqr = radius;
float transitionWidth = Mathf.Min(terrainWidth, terrainLength) * 0.2f;//計(jì)算高度過(guò)渡區(qū)的寬度.
float transitionEndSqr = maxDistSqr+transitionWidth;//計(jì)算高度過(guò)渡區(qū)結(jié)束點(diǎn).
float transitionStartSqr = maxDistSqr;
for (int i = 0; i < resolution; i++)
{
for (int j = 0; j < resolution; j++)
{
float distX = (i / (float)resolution) * terrainWidth - halfWidth;
float distY = (j / (float)resolution) * terrainLength - halfLength;
float distSqr = distX * distX+ distY * distY;
distSqr = Mathf.Sqrt(distSqr);
if (distSqr <= transitionStartSqr)
{
heightMap[i, j] = centerHeight;
}
else if (distSqr <= transitionEndSqr)
{
float t = (distSqr - transitionStartSqr) / (transitionEndSqr - transitionStartSqr);
heightMap[i, j] = Mathf.Lerp(centerHeight, edgeHeight, t);
}
else
{
heightMap[i, j] = edgeHeight;
}
}
}
return heightMap;
}
上述代碼定義了一個(gè)從地圖最中心點(diǎn)開(kāi)始,根據(jù)輸入的園的半徑來(lái)獲得一個(gè)高區(qū)平臺(tái),并且在平臺(tái)邊緣會(huì)平滑過(guò)渡到地形的低區(qū).
? ? ? ? 利用平方距離和勾股定理來(lái)確定當(dāng)前的(i,j)點(diǎn)對(duì)于中心點(diǎn)的距離,t系數(shù)是一個(gè)歸一化數(shù)值,負(fù)責(zé)平滑過(guò)渡插值,而平滑過(guò)渡的寬度區(qū)域,則是用transitionWidth的系數(shù)0.2f來(lái)決定的,越大的系數(shù)將會(huì)讓過(guò)渡區(qū)域越寬,因?yàn)槭褂玫氖钦麄€(gè)地形長(zhǎng)寬的最大值,所以基本上在0.5f時(shí)就已經(jīng)能覆蓋整個(gè)地形.
根據(jù)實(shí)際情況來(lái)設(shè)置.
? ? ? ? 下圖為平臺(tái)高度60,地區(qū)高度10,過(guò)渡區(qū)寬度系數(shù)0.2f,所生成的地形.符合預(yù)期.文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-709380.html
文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-709380.html
到了這里,關(guān)于Unity地形動(dòng)態(tài)生成的一些經(jīng)驗(yàn)記錄的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!