如果想讓一個對象顯示3D模型呻待,需要2個組件 ,第一個是mesh filter。這個組件持有mesh的索引。第二個是mesh renderer炒辉,用來設(shè)定mesh如何渲染:用哪些材質(zhì)嬉挡,是否阻擋或者接受光線等等彤悔。多個材質(zhì)主要是用于導(dǎo)入類的模型噪服,同一個模型下有多個mesh組
創(chuàng)建一個點(diǎn)組成的網(wǎng)格
[RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))]
public class Grid : MonoBehaviour {
public int xSize, ySize;
}
創(chuàng)建一個空對象綁上腳本。MeshFilter的Mesh對象留空恨诱,寬高設(shè)為10媳瞪,5。給一個帶漫反射貼圖的默認(rèn)材質(zhì)
先來關(guān)注點(diǎn)的位置:點(diǎn)比格子數(shù)多一
private Vector3[] vertices;
private void Generate () {
vertices = new Vector3[(xSize + 1) * (ySize + 1)];
}
畫一個小黑球來標(biāo)記點(diǎn)的位置照宝,點(diǎn)的坐標(biāo)必須是世界坐標(biāo)蛇受。在編輯模式下也會跑到這個方法,所以先判斷空返回
private void OnDrawGizmos () {
if (vertices == null)
return;
Gizmos.color = Color.black;
for (int i = 0; i < vertices.Length; i++)
{
Gizmos.DrawSphere(vertices[i], 0.1f);
}
}
為了顯示出點(diǎn)的順序厕鹃。加個協(xié)程兢仰。把點(diǎn)賦給Mesh
private Mesh mesh;
private void Awake () {
StartCoroutine(Generate());
}
private IEnumerator Generate () {
WaitForSeconds wait = new WaitForSeconds(0.05f);
vertices = new Vector3[(xSize + 1) * (ySize + 1)];
for (int i = 0, y = 0; y <= ySize; y++) {
for (int x = 0; x <= xSize; x++, i++) {
vertices[i] = new Vector3(x, y);
yield return wait;
}
}
mesh.vertices = vertices;
}
順時針畫的三角形是朝前的,逆時針的三角是向后的(下面看不見的)
triangles[0] = 0;
triangles[3] = triangles[2] = 1;
triangles[4] = triangles[1] = xSize + 1;
triangles[5] = xSize + 2;
int[] triangles = new int[xSize * 6];
for (int ti = 0, vi = 0, x = 0; x < xSize; x++, ti += 6, vi++) {
triangles[ti] = vi;
triangles[ti + 3] = triangles[ti + 2] = vi + 1;
triangles[ti + 4] = triangles[ti + 1] = vi + xSize + 1;
triangles[ti + 5] = vi + xSize + 2;
yield return wait;
}
private void Awake () {
Generate();
}
private void Generate () {
GetComponent<MeshFilter>().mesh = mesh = new Mesh();
mesh.name = "Procedural Grid";
vertices = new Vector3[(xSize + 1) * (ySize + 1)];
for (int i = 0, y = 0; y <= ySize; y++) {
for (int x = 0; x <= xSize; x++, i++) {
vertices[i] = new Vector3(x, y);
}
}
mesh.vertices = vertices;
int[] triangles = new int[xSize * ySize * 6];
for (int ti = 0, vi = 0, y = 0; y < ySize; y++, vi++) {
for (int x = 0; x < xSize; x++, ti += 6, vi++) {
triangles[ti] = vi;
triangles[ti + 3] = triangles[ti + 2] = vi + 1;
triangles[ti + 4] = triangles[ti + 1] = vi + xSize + 1;
triangles[ti + 5] = vi + xSize + 2;
}
}
mesh.triangles = triangles;
}
生成額外的點(diǎn)數(shù)據(jù)
因?yàn)槿切慰偸瞧降募敛辏詰?yīng)該不需要分別提供法線信息把将,但通過這種方法,可以實(shí)現(xiàn)一些技巧∫涿現(xiàn)實(shí)中頂點(diǎn)沒有法線察蹲,三角形有。通過附加自定義法線給點(diǎn)然后在三角形之間進(jìn)行插值催训,我們可以假裝我們有一個平滑彎曲的表面而不是一堆平的三角形洽议。
每點(diǎn)定義一個法線,所以我們來填充另一個向量數(shù)組漫拭〗柿澹或者我們可以要求Mesh通過三角面自己解出法線。就這么干吧嫂侍。
private void Generate () {
…
mesh.triangles = triangles;
mesh.RecalculateNormals();
}
接下來處理UV坐標(biāo)儿捧。注意到網(wǎng)格目前已經(jīng)有了一個標(biāo)準(zhǔn)顏色,即使它已經(jīng)使用了一個帶有漫反射貼圖的材質(zhì)挑宠。因?yàn)槲覀儧]有提供UV菲盾。所以值都是0。
vertices = new Vector3[(xSize + 1) * (ySize + 1)];
Vector2[] uv = new Vector2[vertices.Length];
for (int i = 0, y = 0; y <= ySize; y++) {
for (int x = 0; x <= xSize; x++, i++) {
vertices[i] = new Vector3(x, y);
uv[i] = new Vector2((float)x / xSize, (float)y / ySize);
}
}
mesh.vertices = vertices; mesh.uv = uv;
另一種添加細(xì)節(jié)的方法是加法線貼圖各淀。這種貼圖包含了編碼成顏色的法線向量懒鉴。但光給法線貼圖沒效果,必須先給切線向量
切線的作用
法線貼圖是定義在切線空間中的碎浇。它是一個隨著物體表面起伏的3D空間临谱。這個方法允許我們將不同地方不同朝向的法線應(yīng)用到同一張貼圖中
表面向量代表了空間的上方向,但是應(yīng)該用哪種方法表示呢奴璃?它是通過切線定義的悉默。理想情況下,法線和切線的夾角是90度苟穆。它們的叉乘就是定義3D空間所需要的第三個向量抄课。實(shí)際上角度通常不是90,但結(jié)果也夠好了雳旅。
所以切線是個3D向量跟磨,但UNITY實(shí)際用了4D向量。第四個分量通常是-1或者1攒盈,用于控制切線空間的第三維的方向抵拘,要嘛朝前要嘛朝后。這個促進(jìn)了法線貼圖的鏡像型豁,通常用于3D模型中的對稱性僵蛛,比如人。Unity shader實(shí)現(xiàn)這個計(jì)算就需要我們使用-1.
由于我們用的是平面偷遗,所以所有切線簡單的指向右墩瞳。
vertices = new Vector3[(xSize + 1) * (ySize + 1)];
Vector2[] uv = new Vector2[vertices.Length];
Vector4[] tangents = new Vector4[vertices.Length];
Vector4 tangent = new Vector4(1f, 0f, 0f, -1f);
for (int i = 0, y = 0; y <= ySize; y++) {
for (int x = 0; x <= xSize; x++, i++) {
vertices[i] = new Vector3(x, y);
uv[i] = new Vector2((float)x / xSize, (float)y / ySize);
tangents[i] = tangent;
}
}
mesh.vertices = vertices;
mesh.uv = uv;
mesh.tangents = tangents;
Mesh需要點(diǎn)坐標(biāo)和三角索引,通常也要UV坐標(biāo)氏豌,最多4組喉酌,還有切線。我們也可以添加頂點(diǎn)顏色泵喘,雖然標(biāo)準(zhǔn)SHADER沒有用它泪电。我們可以自定義使用它的SHADER。