【Unity】無限地形搭建基礎

步驟建立GameObject(命名Mesh Genrate網格生成器),爲其添加兩個組件Mesh Filter和Mesh Renderer.,建立腳本Mesh Genrate。算法

【1】解析頂點和三角面原理,繪製mesh數組

【2】繪製mesh網格平面,增長隨機高度dom

【3】基於柏林噪音生成灰度圖編輯器

【1】解析頂點和三角面原理,繪製meshide

(Unity三角形繪製渲染,正反都是順時針方向:012;132)函數

繪製mesh的頂點和三角形。佈局

using System.Collections; using System.Collections.Generic; using UnityEngine; [RequireComponent(typeof(MeshFilter))] //RequireComponent:須要的組件將會自動被添加到game object(遊戲物體),有效的避免組裝錯誤,避免GetComponent的空引用錯誤。
public class MeshGerrate : MonoBehaviour { private Vector3[] vertices;//記錄頂點座標信息/座標值的矢量數組。

    private int[] triangLes;//記錄頂點數值的數組。

    private Mesh mesh; void Start() { mesh = new Mesh();//建立一個空的網格。 
        GetComponent<MeshFilter>().mesh = mesh; //將包含mesh的信息賦值給組件
 CreatShape(); //該方法表示:mesh網格須要須要存儲哪些頂點和三角形信息
        UpdateMesh();//加載網格
 mesh.RecalculateNormals();//從新計算法線的方向

}
void CreatShape() { vertices = new[] { new Vector3(0,0,0), new Vector3(0,0,1), new Vector3(1,0,0), new Vector3(1,0,1), //XZ平面的三角形(正面/背面) }; triangLes = new[] { 0, 1, 2, 1, 3, 2 };//順時針三個點的位置數值,與vertices綁定,一一對應三個頂點 } void UpdateMesh() { mesh.Clear();//清空全部頂點數據和全部三角形索引/每次繪製前把以前的信息清理一下,避免形成干擾。 mesh.vertices = vertices;//將頂點座標信息賦給網格 //vertices:返回一個頂點位置的數組值,或者爲一組新的頂點位置數組賦值。 mesh.triangles = triangLes;//將頂點數值賦給網格 //triangles:在網格里,一個包含全部三角形的數組。 } }

 【2】繪製mesh網格平面,增長隨機高度ui

using System.Collections; using System.Collections.Generic; using UnityEditor; using UnityEngine; [RequireComponent(typeof(MeshFilter))] //RequireComponent:須要的組件將會自動被添加到game object(遊戲物體),有效的避免組裝錯誤,避免GetComponent的空引用錯誤。
public class MeshGerrate : MonoBehaviour { private Vector3[] vertices;//記錄頂點座標信息/座標值的矢量數組。

    private int[] triangLes;//記錄頂點數值的數組。

    private Mesh mesh; public int xSize = 20; public int zSize = 20; void Start() { mesh = new Mesh();//建立一個空的網格。 
        GetComponent<MeshFilter>().mesh = mesh; //將包含mesh的信息賦值給組件
 CreatShape(); //StartCoroutine(CreatShape()); //該方法表示:mesh網格須要須要存儲哪些頂點和三角形信息 //UpdateMesh();//加載網格
 } void CreatShape() //IEnumerator CreatShape()觀察繪製狀況能夠開一個攜程,配合WaitForSeconds來看一步步繪製結果
 { int n = 0; vertices = new Vector3[(xSize + 1) * (zSize + 1)]; for (int z = 0; z <= zSize; z++) { for (int i = 0; i <= xSize; i++) { float y = Mathf.PerlinNoise(i*0.3f, z*0.2f) * 2f;//柏林噪音
                vertices[n] = new Vector3(i, y, z); n++; } } triangLes =new int[xSize*zSize*2*3]; int ver = 0; int count = 0; for (int z = 0; z < zSize; z++) { for (int i = 0; i < xSize; i++) { triangLes[count + 0] = ver + 0; triangLes[count + 1] = ver + xSize + 1; triangLes[count + 2] = ver + 1; triangLes[count + 3] = ver + xSize + 1; triangLes[count + 4] = ver + xSize + 2; triangLes[count + 5] = ver + 1; count += 6; ver++; //yield return new WaitForSeconds(0.1f);
 } ver++;//直接跳過最後一行最後一個頂點,不然最後一個頂點會連線第二行第一個點,形成黑邊。
 } } void Update() { UpdateMesh();//加載網格
 } void UpdateMesh() { mesh.Clear();//清空全部頂點數據和全部三角形索引/每次繪製前把以前的信息清理一下,避免形成干擾。
        mesh.vertices = vertices;//將頂點座標信息賦給網格 //vertices:返回一個頂點位置的數組值,或者爲一組新的頂點位置數組賦值。 
        mesh.triangles = triangLes;//將頂點數值賦給網格 //triangles:在網格里,一個包含全部三角形的數組。 
 mesh.RecalculateNormals(); } private void OnDrawGizmos() {//編輯器函數,自動調用。 //繪製可被點選的gizmos,執行這個函數。這容許你在場景中快速選擇重要的物體。
     if (vertices == null) return; for (int i = 0; i < vertices.Length; i++) { Gizmos.DrawSphere(vertices[i], 0.1f);//使用center和radius參數,繪製一個實心球體。
 } } }

【3】基於柏林噪音生成灰度圖spa

octave倍頻疊加code

using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.XR.WSA.WebCam; public class MapGenrator : MonoBehaviour { public int widthX; public int heightY; public float scale; public int octave; [Range(0,1)]//設定範圍
    public float persistance; public float lacunrity; public int seed; public Vector2 offset; public void MapGenrate() { float[,] noiseMap = PerlinNosie.GenrateNoiseMap(widthX, heightY, scale,seed,offset, persistance,lacunrity,octave); MapDisplay display = FindObjectOfType<MapDisplay>(); //FindObjectOfType:按類型查找遊戲對象
 display.DrawNoiseMap(noiseMap); } private void OnValidate()//啓動的時候執行兩次,Stop的時候執行一次,組件數值改變的時候執行一次
 { if (widthX<1) { widthX = 1; } if (heightY<1) { heightY = 1; } if (lacunrity<1) { lacunrity = 1; } if (octave < 0) { octave = 0; } } }
using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using Random = System.Random; public static class PerlinNosie //: MonoBehaviour不須要掛在物體上,因此不繼承MonoBehaviour
{ public static float[,] GenrateNoiseMap(int mapWidth, int mapHeight, float scale,int seed,Vector2 offset, float persistance, float lacunarity, int octave) //建立柏林噪聲
 { float[,] perlinNoise = new float[mapWidth, mapHeight]; if (scale <= 0) { scale = 0.0001f; } Random prng = new Random(seed);//隨機種子,每一個種子表明一個固定的數據,讀取。
        Vector2[] sctaveOffSet = new Vector2[octave]; for (int i = 0; i < octave; i++) { float offsetX = prng.Next(-10000,10000)+offset.x;//隨機數+偏移量
            float offsetY = prng.Next(-10000, 10000)+offset.y; sctaveOffSet[i]=new Vector2(offsetX,offsetY); } float minNoiseHeight = float.MaxValue; float maxNoiseHeight = float.MinValue;//這裏大小輸入時相反的,方便對比時接入值。

        float halfWidth = mapWidth / 2; float halfHeight = mapHeight / 2; for (int z = 0; z < mapHeight; z++) { for (int i = 0; i < mapWidth; i++) { float height = 0; float amplitude = 1f; float frequence = 1f; for (int j = 0; j < octave; j++) { float sampleX = (i+halfWidth) / scale * frequence+sctaveOffSet[j].x;//scale越大,地圖比例縮小(包含的越多)
                    float sampleY = (z+halfHeight) / scale * frequence+ sctaveOffSet[j].y; float perlinValue = Mathf.PerlinNoise(sampleX, sampleY) * 2 - 1;//*2-1:生成正負值,對應地圖水平線上下的點。 //Mathf.PerlinNoise:值介於0.0和1.0之間,XY表明樣本點的座標值。
                    height += perlinValue * amplitude;//柏林值乘以振幅,在三次倍頻疊加。
                    amplitude *= persistance;//振幅改變
                    frequence *= lacunarity;//頻率改變
 } if (height > maxNoiseHeight) { maxNoiseHeight = height;//存儲大小值
                }else  if (height < minNoiseHeight) { minNoiseHeight = height; } perlinNoise[i, z] = height; } } for (int z = 0; z < mapHeight; z++) { for (int i = 0; i < mapWidth; i++) { perlinNoise[i, z] = Mathf.InverseLerp(minNoiseHeight, maxNoiseHeight, perlinNoise[i, z]); //按照A-B之間的比例值計算,將數組取值從新歸到0-1之間。
 } } return perlinNoise; } }
using System.Collections; using System.Collections.Generic; using UnityEngine; public class MapDisplay : MonoBehaviour { public Renderer mapPerlinTexture; public void DrawNoiseMap(float[,] noiseMap)//將柏林經過色彩在紋理上表現出來
 { int widthX = noiseMap.GetLength(0); int heightY = noiseMap.GetLength(1); Texture2D textures = new Texture2D(widthX, heightY); Color[] color_Map=new Color[widthX * heightY]; for (int y = 0; y < heightY; y++) { for (int x = 0; x < widthX; x++) { color_Map[widthX * y + x] = Color.Lerp(Color.black, Color.white, noiseMap[x, y]);//經過float在顏色a和b之間插值,返回不一樣的元素。
 } } textures.SetPixels(color_Map);//設置一塊像素的顏色 
        textures.Apply();//實際應用前面的SetPixel和Setpixels的更改 
 mapPerlinTexture.sharedMaterial.mainTexture = textures;//將改變全部物體使用這個材質的外觀,而且也改變儲存在工程裏的材質設置。
        mapPerlinTexture.transform.localScale=new Vector3(widthX,1,heightY); //相對於父級物體變換的縮放。Y不變,XZ作變化。 //前面只富裕了材質的外觀,但沒賦予對應的大小。
 } }
using System.Collections; using System.Collections.Generic; using UnityEditor; using UnityEngine; [CustomEditor(typeof(MapGenrator))] //描述了用於編輯器實時運行類型的一個編輯器類。

public class MapGenerateEditor : Editor { public override void OnInspectorGUI()//在Unity組件面板裏添加一個按鈕來操控柏林噪聲的生成
 { MapGenrator mapgen = (MapGenrator)target;//受檢查的對象。
 DrawDefaultInspector(); //繪製內置檢視面板。

        if (GUILayout.Button("Generate"))//EditorGUI的自動佈局版本。
 { mapgen.MapGenrate(); } } }

 

結果:

相關文章
相關標籤/搜索