轉載請注明出處:http://www.cnblogs.com/shamoyuu/p/unity_minecraft_01.html
最近總有人問及我的游戲里跟《我的世界》一樣的地形是如何實現的,所以在這里開一個系列教程總結回答一下,也算是對自己的一個梳理和記錄。
一、簡單分析
對《我的世界》感興趣,且有一定Unity3D基礎的人,應該都或多或少的嘗試過自己去做一個吧。
有些人是用Unity3D自帶的cube,然后用三層for循環,把cube堆疊起來,但是會發現游戲幾乎卡爆了,根本沒辦法運行。
如果看過我以前換裝系統教程人應該都知道,這是因為每一個cube都是獨立的物體,一個chunk就是65536個方塊,不卡爆就怪了。
既然這樣,那我們把所有的cube合並成一個物體行不行?
也不行。
因為在地底90%的面都是看不到的,這些面實際上不應該存在,也都應該刪掉,否則對CPU和GPU都是極大的負擔。
基於以上的原因,直接用cube是肯定不行的,那就只能我們自己通過代碼來生成面,而且只生成我們需要的面,這樣就沒有上面的問題了。《我的世界》也是這么做的。
二、理論基礎(重點)
1、法線
法線就是垂直於面的一條線,它有方向,沒有大小。
法線的方向就是面朝外的方向。比如我們現在盯着顯示器看,從顯示器的正中心會有一條法線垂直於屏幕指向我們。
法線向外的面就是正面,相反的就是背面,一般來講,從正面看才能看到面,背面看面是看不到的。
2、三邊面和四邊面
三邊面就是三條邊組成的面,四邊面就是四條邊組成的面。
三邊面在三維空間中是不可扭曲的,而四邊面在三維空間中可以扭曲。所以Unity里只支持三邊面。其他支持四邊面的軟件例如3dmax在導出fbx的時候,會把四邊面轉換成三邊面。
3、左手坐標系和右手坐標系
我們的三維坐標系,在3dmax里是右手坐標系,而在Unity里是左手坐標系。
左手坐標系和右手坐標系的區別可以看一下這個博客 http://www.cnblogs.com/mythou/p/3327046.html

4、三邊面如何組成四邊面

先看看上面這張非常傳神的圖,左邊是Unity里的左手坐標系,右邊是我們想在這個坐標系里生成的一個面以及它的各個點坐標。
012和230這兩個三邊面就組成了一個四邊面。
如果我問,這個四邊面有幾個頂點,想必大家都會回答4個,實際上是6個,012和230這是6個頂點,不同面的頂點不公用。
要組成2個三邊面可以有很多種順序,例如012和320、012和032、023和012等等等
但是我們一般都是按照4個點的順序來畫2個三邊面組成四邊面,所以可選的只有【012和230、230和012】,以及【032和210、210和032】這兩大類
這兩類畫法有什么區別呢?細心的童鞋應該已經發現,這兩種方式前者是逆時針,后者是順時針。
這種循環的方向會導致面的法線方向不同,而這個法線方向會決定這個面的朝向。
我們要確定這個法線方向其實很簡單,上面說了,Unity里是左手坐標系,我們拿出左手,伸直,拇指與其他四個指頭垂直,然后四指彎曲,指尖朝向循環的方向,拇指就指向法線的方向。
有沒有覺得很熟悉?這和初中學過的左手螺旋定則一模一樣。

由此我們得出結論,要想生成正確的面(法線指向我們),我們只能用【032和210、210和032】
這里需要注意的一點是,我們確定4個點的循環方向,和生成三邊面時的循環方向無關,只要生成三邊面時,用到的前4個點的index順序沒錯就行了。
三、代碼實現
該有的理論知識都有了,下面我們就手動生成一個面試試看
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Chunk : MonoBehaviour { private Mesh mesh; //面需要的點 private List<Vector3> vertices = new List<Vector3>(); //生成三邊面時用到的vertices的index private List<int> triangles = new List<int>(); void Start() { mesh = new Mesh(); AddFrontFace(); //為點和index賦值 mesh.vertices = vertices.ToArray(); mesh.triangles = triangles.ToArray(); //重新計算頂點和法線 mesh.RecalculateBounds(); mesh.RecalculateNormals(); //將生成好的面賦值給組件 GetComponent<MeshFilter>().mesh = mesh; } void AddFrontFace() { //添加4個點 vertices.Add(new Vector3(0, 0, 0)); vertices.Add(new Vector3(0, 0, 1)); vertices.Add(new Vector3(0, 1, 1)); vertices.Add(new Vector3(0, 1, 0)); //第一個三角面 triangles.Add(0); triangles.Add(3); triangles.Add(2); //第二個三角面 triangles.Add(2); triangles.Add(1); triangles.Add(0); } }
然后建一個空物體,把這個腳本拖上去,再添加MeshFilter和MeshRenderer組件,然后隨便給一個Material,運行
