Unity Mesh(五) Mesh 立方體Cube貼圖以及六個面分別貼不同的圖片

在前面的篇章中已經有了怎麼Mesh畫一個立方體,當時的立方體是按照逆時針的畫的,其它大都都是按照順時針畫的,當時一開始畫立方體順時針沒畫出來,有些面看不到就調換了下順序,沒特別注意方向問題,然而這一篇貼圖是會暴露出這個問題,下面我們細細說來:


先展示兩張最終結果:




一.Cube順逆時針畫的差異

我們用同樣的方法畫兩個除了時針方向不一樣,其它都一樣的立方體。

腳本如下:

using UnityEngine;
using System.Collections;

public enum Direction
{
    ClockWise,
    Anti_ClockWise
}

[RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))]
public class TestCubeDirection : MonoBehaviour
{

    public Material mat;

    public Direction direction;

    // Use this for initialization
    void Start()
    {
        switch (direction)
        {
            case Direction.ClockWise:
                DrawClockWiseCube();
                break;
            case Direction.Anti_ClockWise:
                DrawAnti_ClockWiseCube();
                break;
        }
    }

    /// <summary>
    /// 按順時針畫立方體
    /// </summary>
    void DrawClockWiseCube()
    {
        gameObject.GetComponent<MeshRenderer>().material = mat;

        Mesh mesh = GetComponent<MeshFilter>().mesh;
        mesh.Clear();

        //設置頂點
        mesh.vertices = new Vector3[]
        {   new Vector3(0, 0, 0),
            new Vector3(1, 0, 0),
            new Vector3(1, 1, 0),
            new Vector3(0, 1, 0),
            new Vector3(0, 1, 1),
            new Vector3(1, 1, 1),
            new Vector3(1, 0, 1),
            new Vector3(0, 0, 1),
        };

        //順時針設置三角形的方向
        mesh.triangles = new int[]
       {
            3, 0, 1,
            3,1,2,
            2,4,3,
            2,5,4,
            7,4,5,
            7,5,6,
            0,7,6,
            0,6,1,
            3,4,7,
            3,7,0,
            1,6,5,
            1,5,2

       };

    }

    /// <summary>
    /// 按逆時針畫立方體
    /// </summary>
    void DrawAnti_ClockWiseCube()
    {
        gameObject.GetComponent<MeshRenderer>().material = mat;

        Mesh mesh = GetComponent<MeshFilter>().mesh;
        mesh.Clear();

        //設置頂點
        mesh.vertices = new Vector3[]
        {   new Vector3(0, 0, 0),
            new Vector3(1, 0, 0),
            new Vector3(1, 1, 0),
            new Vector3(0, 1, 0),
            new Vector3(0, 1, 1),
            new Vector3(1, 1, 1),
            new Vector3(1, 0, 1),
            new Vector3(0, 0, 1),
        };

        //逆時針設置
        mesh.triangles = new int[]
        {
            3,1,0,
            3,2,1,
            2,3,4,
            2,4,5,
            7,5,4,
            7,6,5,
            0,6,7,
            0,1,6,
            3,7,4,
            3,0,7,
            1,5,6,
            1,2,5
        };
    }

}

結果如圖所示:


順時針方向的看不到看它那個方向的面,而逆時針的不會,都能看到,所以這裏遺留一個問題在這裏,後面還會提到。

遺留問題:順時針,立方體不能看到朝向自己的面?


二、給立方體Cube貼圖


一開始想的時候是一點思路一樣,根據API上面的意思,貼圖的數組大小和頂點數的大小是一致的,但是8個頂點是決定不了6個面的,想了很久想不明白後,樓主動手做了個
立方體,給它貼圖:



這樣一弄就一目瞭然了,我們把每個頂點拆成三個,每個面一個這樣我們構造了24個頂點,然後8個面24個點貼圖就順理成章了。

首先,我們用Unity自帶的Cube貼了圖作爲參考:



可以看到自帶的一個面貼一張圖,貼的很整齊,那下面我們看看自己動手怎麼做

爲了不浪費那個cube,我做了這樣的操作,這樣寫起來方便點:



既然變成了24個頂點,更新後的頂點順序如下,根據面數來寫:

//設置頂點
        mesh.vertices = new Vector3[]
        {
            //front
            new Vector3(0, 0, 0),
            new Vector3(0, 0, 1),
            new Vector3(1, 0, 1),
            new Vector3(1, 0, 0),

            //top
            new Vector3(0, 0, 1),
            new Vector3(0, 1, 1),
            new Vector3(1, 1, 1),
            new Vector3(1, 0, 1),

            //back
            new Vector3(0, 1, 1),
            new Vector3(0, 1, 0),
            new Vector3(1, 1, 0),
            new Vector3(1, 1, 1),

            //bottom
            new Vector3(0, 1, 0),
            new Vector3(0, 0, 0),
            new Vector3(1, 0, 0),
            new Vector3(1, 1, 0),

            //left
            new Vector3(0, 1, 0),
            new Vector3(0, 1, 1),
            new Vector3(0, 0, 1),
            new Vector3(0, 0, 0),

            //right
            new Vector3(1, 0, 0),
            new Vector3(1, 0, 1),
            new Vector3(1, 1, 1),
            new Vector3(1, 1, 0),
        };

頂點順序
順時針的如下:
 mesh.triangles = new int[]
       {
              0,1,2,
              0,2,3,
              4,5,6,
              4,6,7,
              8,9,10,
              8,10,11,
              12,13,14,
              12,14,15,
              16,17,18,
              16,18,19,
              20,21,22,
              20,22,23

       };

逆時針的如下:

mesh.triangles = new int[]
       {
              0,2,1,
              0,3,2,
              4,6,5,
              4,7,6,
              8,10,9,
              8,11,10,
              12,14,13,
              12,15,14,
              16,18,17,
              16,19,18,
              20,22,21,
              20,23,22
       };

按照正常的貼圖方式,給他們貼圖:

Vector2[] uvs = new Vector2[mesh.vertices.Length];
        for (int i = 0; i < uvs.Length; i += 4)
        {
            //正常貼圖
            uvs[i] = new Vector2(0, 0);
            uvs[i + 1] = new Vector2(0, 1);
            uvs[i + 2] = new Vector2(1, 1);
            uvs[i + 3] = new Vector2(1, 0);

結果對比如圖:




從圖中可以看出,順時針的貼圖貼的是對的,但是朝向的方向看不到,逆時針的全都能看到,但是貼圖方向錯了。

樓主上網上查找了資料,有一篇說是跟法線有關,鏈接如下:

於是樓主給每個面都設置了法線方向:

Vector3[] normals = new Vector3[mesh.vertices.Length];
        for (int i = 0; i < normals.Length; i++)
        {
            if (i < 4)
                normals[i] = Vector3.forward;
            if (i >= 4 && i < 8)
                normals[i] = Vector3.up;
            if (i >= 8 && i < 12)
                normals[i] = Vector3.back;
            if (i >= 12 && i < 16)
                normals[i] = Vector3.down;
            if (i >= 16 && i < 20)
                normals[i] = Vector3.left;
            if (i >= 20 && i < 24)
                normals[i] = Vector3.right;
        }
        mesh.normals = normals;

結果如圖:


除了亮度有變化,其它沒啥變化,樓主想了很久想不通先放下不想了,有大神會的希望告知,萬分感謝!

但是還是有其它辦法的,於是樓主在逆時針的貼圖上動了點變化:

 Vector2[] uvs = new Vector2[mesh.vertices.Length];
        for (int i = 0; i < uvs.Length; i += 4)
        {
            //uvs[i] = new Vector2(0, 0);
            //uvs[i + 1] = new Vector2(0, 1);
            //uvs[i + 2] = new Vector2(1, 1);
            //uvs[i + 3] = new Vector2(1, 0);
            uvs[i] = new Vector2(1, 0);
            uvs[i + 1] = new Vector2(1, 1);
            uvs[i + 2] = new Vector2(0, 1);
            uvs[i + 3] = new Vector2(0, 0);
        }
        mesh.uv = uvs;

結果如圖:



現在看來逆時針的貼圖做完改動後可以跟Unity自帶的是一樣的效果,所以此路不同換條路走還是可以的,當然前面那條路要是通了就更好哈!


三、給立方體Cube每個面貼不同的圖片



樓主從網上找了張圖片:


我們給立方體六個面貼不同的圖:

這個只需要給貼圖的uv做些改變,這裏我們直接集合了一個方法;

Vector2[] sixTexForCube(Vector3[] verticles)
    {
        Vector2[] uv = new Vector2[verticles.Length];

        float t = 1 / 3f;

        //front
        uv[0] = new Vector2(t, 0);
        uv[1] = new Vector2(t, t);
        uv[2] = new Vector2(0, t);
        uv[3] = new Vector2(0, 0);

        //top
        uv[4] = new Vector2(2 * t, 0);
        uv[5] = new Vector2(2 * t, t);
        uv[6] = new Vector2(t, t);
        uv[7] = new Vector2(t, 0);

        //back
        uv[8] = new Vector2(1, 0);
        uv[9] = new Vector2(1, t);
        uv[10] = new Vector2(2 * t, t);
        uv[11] = new Vector2(2 * t, 0);

        //Bottom
        uv[12] = new Vector2(t, t);
        uv[13] = new Vector2(t, 2 * t);
        uv[14] = new Vector2(0, 2 * t);
        uv[15] = new Vector2(0, t);

        //left
        uv[16] = new Vector2(2 * t, t);
        uv[17] = new Vector2(2 * t, 2 * t);
        uv[18] = new Vector2(t, 2 * t);
        uv[19] = new Vector2(t, t);

        //right
        uv[20] = new Vector2(1, t);
        uv[21] = new Vector2(1, 2 * t);
        uv[22] = new Vector2(2 * t, 2 * t);
        uv[23] = new Vector2(2 * t, t);

        return uv;
    }

最終結果如圖:



四、總結和完整代碼


哈哈,雖然有一個遺留問題,但是最終的目的達到了,下面貼出這個的完整代碼:

using UnityEngine;
using System.Collections;

[RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))]
public class Test3D : MonoBehaviour
{

    public enum Direction
    {
        ClockWise,
        Anti_ClockWise
    }

    public Material mat;

    public Direction direction;

    // Use this for initialization
    void Start()
    {
        switch (direction)
        {
            case Direction.ClockWise:
                DrawCubeWithUV_CloclWise();
                break;
            case Direction.Anti_ClockWise:
                DrawCubeWithUV_Anti_CloclWise();
                break;
        }
    }



    void DrawCubeWithUV_CloclWise()
    {
        gameObject.GetComponent<MeshRenderer>().material = mat;

        Mesh mesh = GetComponent<MeshFilter>().mesh;
        mesh.Clear();

        //設置頂點
        mesh.vertices = new Vector3[]
        {
            //front
            new Vector3(0, 0, 0),
            new Vector3(0, 0, 1),
            new Vector3(1, 0, 1),
            new Vector3(1, 0, 0),

            //top
            new Vector3(0, 0, 1),
            new Vector3(0, 1, 1),
            new Vector3(1, 1, 1),
            new Vector3(1, 0, 1),

            //back
            new Vector3(0, 1, 1),
            new Vector3(0, 1, 0),
            new Vector3(1, 1, 0),
            new Vector3(1, 1, 1),

            //bottom
            new Vector3(0, 1, 0),
            new Vector3(0, 0, 0),
            new Vector3(1, 0, 0),
            new Vector3(1, 1, 0),

            //left
            new Vector3(0, 1, 0),
            new Vector3(0, 1, 1),
            new Vector3(0, 0, 1),
            new Vector3(0, 0, 0),

            //right
            new Vector3(1, 0, 0),
            new Vector3(1, 0, 1),
            new Vector3(1, 1, 1),
            new Vector3(1, 1, 0),
        };



        //順時針看不到正面的,貼圖在裏面
        mesh.triangles = new int[]
       {
              0,1,2,
              0,2,3,
              4,5,6,
              4,6,7,
              8,9,10,
              8,10,11,
              12,13,14,
              12,14,15,
              16,17,18,
              16,18,19,
              20,21,22,
              20,22,23

       };

        Vector2[] uvs = new Vector2[mesh.vertices.Length];
        for (int i = 0; i < uvs.Length; i += 4)
        {
            //正常貼圖
            uvs[i] = new Vector2(0, 0);
            uvs[i + 1] = new Vector2(0, 1);
            uvs[i + 2] = new Vector2(1, 1);
            uvs[i + 3] = new Vector2(1, 0);

            //轉換貼圖
            //uvs[i] = new Vector2(1, 0);
            //uvs[i + 1] = new Vector2(1, 1);
            //uvs[i + 2] = new Vector2(0, 1);
            //uvs[i + 3] = new Vector2(0, 0);
        }
        mesh.uv = uvs;

        //Vector3[] normals = new Vector3[mesh.vertices.Length];
        //for (int i = 0; i < normals.Length; i++)
        //{
        //    if (i < 4)
        //        normals[i] = Vector3.forward;
        //    if (i >= 4 && i < 8)
        //        normals[i] = Vector3.up;
        //    if (i >= 8 && i < 12)
        //        normals[i] = Vector3.back;
        //    if (i >= 12 && i < 16)
        //        normals[i] = Vector3.down;
        //    if (i >= 16 && i < 20)
        //        normals[i] = Vector3.left;
        //    if (i >= 20 && i < 24)
        //        normals[i] = Vector3.right;
        //}
        //mesh.normals = normals;
    }

    void DrawCubeWithUV_Anti_CloclWise()
    {
        gameObject.GetComponent<MeshRenderer>().material = mat;

        Mesh mesh = GetComponent<MeshFilter>().mesh;
        mesh.Clear();

        //設置頂點
        mesh.vertices = new Vector3[]
        {
            //front
            new Vector3(0, 0, 0),
            new Vector3(0, 0, 1),
            new Vector3(1, 0, 1),
            new Vector3(1, 0, 0),

            //top
            new Vector3(0, 0, 1),
            new Vector3(0, 1, 1),
            new Vector3(1, 1, 1),
            new Vector3(1, 0, 1),

            //back
            new Vector3(0, 1, 1),
            new Vector3(0, 1, 0),
            new Vector3(1, 1, 0),
            new Vector3(1, 1, 1),

            //bottom
            new Vector3(0, 1, 0),
            new Vector3(0, 0, 0),
            new Vector3(1, 0, 0),
            new Vector3(1, 1, 0),

            //left
            new Vector3(0, 1, 0),
            new Vector3(0, 1, 1),
            new Vector3(0, 0, 1),
            new Vector3(0, 0, 0),

            //right
            new Vector3(1, 0, 0),
            new Vector3(1, 0, 1),
            new Vector3(1, 1, 1),
            new Vector3(1, 1, 0),
        };

        //逆時針看到的很好,但是貼圖反了
        mesh.triangles = new int[]
       {
              0,2,1,
              0,3,2,
              4,6,5,
              4,7,6,
              8,10,9,
              8,11,10,
              12,14,13,
              12,15,14,
              16,18,17,
              16,19,18,
              20,22,21,
              20,23,22
       };
#if false
        //六個面貼同一張圖片
        Vector2[] uvs = new Vector2[mesh.vertices.Length];
        for (int i = 0; i < uvs.Length; i += 4)
        {
            //uvs[i] = new Vector2(0, 0);
            //uvs[i + 1] = new Vector2(0, 1);
            //uvs[i + 2] = new Vector2(1, 1);
            //uvs[i + 3] = new Vector2(1, 0);
            uvs[i] = new Vector2(1, 0);
            uvs[i + 1] = new Vector2(1, 1);
            uvs[i + 2] = new Vector2(0, 1);
            uvs[i + 3] = new Vector2(0, 0);
        }
        mesh.uv = uvs;
#else
        //六個面貼不同的圖片
        Vector2[] uvs = sixTexForCube(mesh.vertices);
        mesh.uv = uvs;
#endif
        //法線
        //Vector3[] normals = new Vector3[mesh.vertices.Length];
        //for (int i = 0; i < normals.Length; i++)
        //{
        //    if (i < 4)
        //        normals[i] = Vector3.forward;
        //    if (i >= 4 && i < 8)
        //        normals[i] = Vector3.up;
        //    if (i >= 8 && i < 12)
        //        normals[i] = Vector3.back;
        //    if (i >= 12 && i < 16)
        //        normals[i] = Vector3.down;
        //    if (i >= 16 && i < 20)
        //        normals[i] = Vector3.left;
        //    if (i >= 20 && i < 24)
        //        normals[i] = Vector3.right;
        //}
        //mesh.normals = normals;
    }

    Vector2[] sixTexForCube(Vector3[] verticles)
    {
        Vector2[] uv = new Vector2[verticles.Length];

        float t = 1 / 3f;

        //front
        uv[0] = new Vector2(t, 0);
        uv[1] = new Vector2(t, t);
        uv[2] = new Vector2(0, t);
        uv[3] = new Vector2(0, 0);

        //top
        uv[4] = new Vector2(2 * t, 0);
        uv[5] = new Vector2(2 * t, t);
        uv[6] = new Vector2(t, t);
        uv[7] = new Vector2(t, 0);

        //back
        uv[8] = new Vector2(1, 0);
        uv[9] = new Vector2(1, t);
        uv[10] = new Vector2(2 * t, t);
        uv[11] = new Vector2(2 * t, 0);

        //Bottom
        uv[12] = new Vector2(t, t);
        uv[13] = new Vector2(t, 2 * t);
        uv[14] = new Vector2(0, 2 * t);
        uv[15] = new Vector2(0, t);

        //left
        uv[16] = new Vector2(2 * t, t);
        uv[17] = new Vector2(2 * t, 2 * t);
        uv[18] = new Vector2(t, 2 * t);
        uv[19] = new Vector2(t, t);

        //right
        uv[20] = new Vector2(1, t);
        uv[21] = new Vector2(1, 2 * t);
        uv[22] = new Vector2(2 * t, 2 * t);
        uv[23] = new Vector2(2 * t, t);

        return uv;
    }
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章