u3d網格編程-繪製多面片長方體

寫在前面:

unity3d中可以使用Mesh類,實現動態生成網格體,指定uv、法線等操作。本文將繪製一個指定長寬高的長方體,並在其內部劃分指定距離的網格,多餘的部分的頂底和uv也做了適當的使用。適合正在學習網格編程的同僚參考,下面是實現後的效果圖:

\


本文目錄按當時學習並製作的過程來劃分如下:

一、用腳本實現一個簡單的cube繪製

二、爲cube指定法線和uv等

三、用腳本繪製一個Plane

四、繪製六個面的網格體

五、指定各個頂點的uv

六、尺寸縮減處理

一、用腳本實現一個簡單的cube繪製

using UnityEngine;
using System.Collections;

[RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))]
public class Test3D : MonoBehaviour
{
    // 注意:該類繼承EditorWindow,只能包含靜態成員
    static Mesh mesh;            // 網格
    static Vector3[] Vs;         // 模型頂點座標數組
    static Vector2[] UVs;        // UV貼圖座標
    static Vector3[] normals;    // 法線
    static Vector4[] tangents;   // 切線
    static int[] Ts;             // 三角形的點序列

    // 添加菜單項,並放置最頂端
    void Start()
    {
        // 可自定義修改頂點和麪
        SetVsAndTs();
        // 設置新頂點
        SetNewVs();
        // 生成網格生成需要的數據
        CreateOther();
        // 調用創建對象函數
        CreateObjectByMesh();
    }
    //設置頂點和三角面
    static void SetVsAndTs()
    {
        Vs = new Vector3[]
        {
            new Vector3(-0.5f, -0.5f, -0.5f),
            new Vector3(0.5f, -0.5f, -0.5f),
            new Vector3(0.5f, 0.5f, -0.5f),
            new Vector3(-0.5f,0.5f, -0.5f),
            new Vector3(-0.5f,0.5f, 0.5f),
            new Vector3(0.5f, 0.5f, 0.5f),
            new Vector3(0.5f, -0.5f, 0.5f),
            new Vector3(-0.5f, -0.5f, 0.5f)
        };


        Ts = new int[]
        {
            0,2,1,
            0,3,2,
            3,4,2,
            4,5,2,
            4,7,5,
            7,6,5,
            7,0,1,
            6,7,1,
            4,3,0,
            4,0,7,
            2,5,6,
            2,6,1
        };
    }
    //生成網格的核心代碼
    static void SetNewVs()
    {
        //根據面的順序,重新創建新的頂點數組,用於計算頂點法線
        Vector3[] newVs = new Vector3[Ts.Length];
        for (int i = 0; i < newVs.Length; i++)
        {
            newVs[i] = Vs[Ts[i]];
        }
        Vs = newVs;
    }
    
    // 創建對象函數(這個功能提出來,方便以後擴展)
    void CreateObjectByMesh()
    {
        mesh = new Mesh();                      // 創建網格
        mesh.vertices = Vs;                     // 網格的頂點
        mesh.triangles = Ts;                    // 網格的三角形
        mesh.uv = UVs;                          // 網格的UV座標
        mesh.normals = normals;                 // 網格的法線
        mesh.tangents = tangents;               // 網格的切線
        gameObject.GetComponent<MeshFilter>().mesh = mesh; // 添加網格
    }
}
在MeshRenderer中使用了帶如下圖片的材質球:

在沒有劃分uv之前,將創建出這樣一個Cube:



二、爲cube指定法線和uv等

//創建uv等
    static void CreateOther()
    {
        UVs = new Vector2[Vs.Length];
        normals = new Vector3[Vs.Length];
        tangents = new Vector4[Vs.Length];

        // 根據新的點,設置三角面的頂點ID並計算點法線
        for (int i = 0; i < Ts.Length - 2; i += 3)
        {
            Vector3 normal = Vector3.Normalize(Vector3.Cross(Vs[i + 1] - Vs[i], Vs[i + 2] - Vs[i]));  // 計算點的法線
            for (int j = 0; j < 3; j++)
            {
                Ts[i + j] = i + j;        // 重新設置面的頂點ID
                normals[i + j] = normal;  // 點的法線賦值
            }
        }

        // 設置每個點的切線和UV
        for (int i = 0; i < Vs.Length; i++)
        {
            tangents[i] = new Vector4(-1, 0, 0, -1);    // 切線
            if (normals[i] == Vector3.back || normals[i] == Vector3.forward)
            {
                UVs[i] = new Vector2((Vs[i].x + 0.5f) * 0.928f , (Vs[i].y + 0.5f) * 0.42f + 0.292f);     // UV座標
            }
            else if(normals[i] == Vector3.up)
            {
                UVs[i] = new Vector2((Vs[i].x + 0.5f) * 0.928f, (Vs[i].z + 0.5f) * 0.292f + 0.708f);     // UV座標
            }
            else if (normals[i] == Vector3.down)
            {
                UVs[i] = new Vector2((Vs[i].x + 0.5f) * 0.928f, (Vs[i].z + 0.5f) * 0.292f);     // UV座標
            }
            else if (normals[i] == Vector3.left || normals[i] == Vector3.right)
            {
                UVs[i] = new Vector2((Vs[i].z + 0.5f) * 0.072f + 0.928f, (Vs[i].y + 0.5f) * 0.42f + 0.292f);     // UV座標
            }
        }

    }
在指定完每個頂點的uv之後,cube將變成如下形態:


三、用腳本繪製一個Plane

爲實現文本最初的目標,應該想辦法在一個面內劃分出多個面:

using UnityEngine;
using System.Collections;
using System.Runtime.InteropServices;

namespace Lin
{
    struct MeshStruct
    {
        public int[] Triangles;
        public Vector3[] Vertices;
        public Vector3[] Normals;
        public Vector4[] Tangents;
        public Vector2[] UV;
        public Color32[] Colors32;
    }

    public struct Vector2Int
    {
        public int x;
        public int y;
        public Vector2Int(int x, int y)
        {
            this.x = x;
            this.y = y;
        }
        public Vector2Int(Vector2 value)
        {
            x = (int)value.x;
            y = (int)value.y;
        }
        public static implicit operator Vector2Int(Vector2 value)
        {
            return new Vector2Int((int)value.x, (int)value.y);
        }
        public override string ToString()
        {
            return "{" + x + ", " + y + "}";
        }
    }

    public class CreateMesh : MonoBehaviour
    {
        public int _quality = 20;
        // 面片最大大小  
        public Vector2 _size = new Vector2(1000, 1000);

        // 表格個數  
        private Vector2Int _grid = new Vector2Int();
        // 單元格大小  
        private float _nodeSize = 0f;

        private Mesh _mesh;
        // 網格結構體  
        private MeshStruct _meshStruct;
        private MeshFilter _meshFilter;

        void Start()
        {
            _mesh = new Mesh();
            _mesh.name = "DynamicWaterMesh";
            _meshFilter = gameObject.GetComponent<MeshFilter>();
            _meshFilter.mesh = _mesh;
        }

        public void Update()
        {
            _quality = Mathf.Clamp(_quality, 4, 256);
            // 根據質量計算單元格大小  
            _nodeSize = Mathf.Max(_size.x, _size.y) / _quality;
            // 根據【單元格大小】計算【格子個數】  
            _grid.x = Mathf.RoundToInt(_size.x / _nodeSize) + 1;
            _grid.y = Mathf.RoundToInt(_size.y / _nodeSize) + 1;

            _mesh.MarkDynamic();
            AllocateMeshArrays();
            CreateMeshGrid();
            AssignMesh();
            _meshFilter.mesh = _mesh;
        }


        private void AllocateMeshArrays()
        {
            int numVertices = _grid.x * _grid.y;
            _meshStruct.Vertices = new Vector3[numVertices];
            _meshStruct.Normals = new Vector3[numVertices];
            _meshStruct.Tangents = new Vector4[numVertices];
            _meshStruct.Colors32 = new Color32[numVertices];
            _meshStruct.UV = new Vector2[numVertices];
            _meshStruct.Triangles = new int[((_grid.x - 1) * (_grid.y - 1)) * 2 * 3];
        }

        private void CreateMeshGrid()
        {
            float uvStepXInit = 1f / (_size.x / _nodeSize);
            float uvStepYInit = 1f / (_size.y / _nodeSize);
            Color32 colorOne = new Color32(255, 255, 255, 255);
            Vector3 up = Vector3.up;
            bool setTangents = true;

            Vector4 tangent = new Vector4(1f, 0f, 0f, 1f);

            int k = 0;

            for (int j = 0; j < _grid.y; j++)
            {
                for (int i = 0; i < _grid.x; i++)
                {
                    int index = j * _grid.x + i;

                    // Set vertices  
                    _meshStruct.Vertices[index].x = i * _nodeSize;
                    _meshStruct.Vertices[index].y = 0f;
                    _meshStruct.Vertices[index].z = j * _nodeSize;

                    // Set triangles  
                    if (j < _grid.y - 1 && i < _grid.x - 1)
                    {
                        _meshStruct.Triangles[k + 0] = (j * _grid.x) + i;
                        _meshStruct.Triangles[k + 1] = ((j + 1) * _grid.x) + i;
                        _meshStruct.Triangles[k + 2] = (j * _grid.x) + i + 1;

                        _meshStruct.Triangles[k + 3] = ((j + 1) * _grid.x) + i;
                        _meshStruct.Triangles[k + 4] = ((j + 1) * _grid.x) + i + 1;
                        _meshStruct.Triangles[k + 5] = (j * _grid.x) + i + 1;

                        k += 6;
                    }

                    // Set UV  
                    float uvStepX = uvStepXInit;
                    float uvStepY = uvStepYInit;

                    _meshStruct.UV[index].x = i * uvStepX;
                    _meshStruct.UV[index].y = j * uvStepY;

                    // Set colors  
                    _meshStruct.Colors32[index] = colorOne;

                    // Set normals  
                    _meshStruct.Normals[index] = up;

                    if (setTangents)
                    {
                        // set tangents  
                        _meshStruct.Tangents[index] = tangent;
                    }

                    // fix stretching  
                    float delta;

                    if (_meshStruct.Vertices[index].x > _size.x)
                    {
                        delta = (_size.x - _meshStruct.Vertices[index].x) / _nodeSize;
                        _meshStruct.UV[index].x -= uvStepX * delta;

                        _meshStruct.Vertices[index].x = _size.x;
                    }

                    if (_meshStruct.Vertices[index].z > _size.y)
                    {
                        delta = (_size.y - _meshStruct.Vertices[index].z) / _nodeSize;
                        _meshStruct.UV[index].y -= uvStepY * delta;

                        _meshStruct.Vertices[index].z = _size.y;
                    }

                    if (_size.x - _meshStruct.Vertices[index].x < _nodeSize)
                    {
                        delta = (_size.x - _meshStruct.Vertices[index].x) / _nodeSize;
                        _meshStruct.UV[index].x += uvStepX * delta;

                        _meshStruct.Vertices[index].x = _size.x;
                    }

                    if (_size.y - _meshStruct.Vertices[index].z < _nodeSize)
                    {
                        delta = (_size.y - _meshStruct.Vertices[index].z) / _nodeSize;
                        _meshStruct.UV[index].y += uvStepY * delta;

                        _meshStruct.Vertices[index].z = _size.y;
                    }
                }
            }
        }

        private void AssignMesh()
        {
            _mesh.vertices = _meshStruct.Vertices;
            _mesh.normals = _meshStruct.Normals;
            _mesh.tangents = _meshStruct.Tangents;

            _mesh.uv = _meshStruct.UV;
            _mesh.colors32 = _meshStruct.Colors32;
            _mesh.triangles = _meshStruct.Triangles;

            _mesh.RecalculateBounds();

            // Freeing the memory  
            _meshStruct.Tangents = null;
            _meshStruct.Triangles = null;
            _meshStruct.UV = null;
            _meshStruct.Colors32 = null;
        }
    }
}
實現效果如下:


四、繪製六個面的網格體

在繪製平面網格的基礎上,要實現六個面網格體的繪製相對也比較容易:

using UnityEngine;
using System.Collections;
using System.Runtime.InteropServices;

namespace lin2
{
    public struct BeamMesh
    {
        public Vector3[] vertices;    // 網格的頂點
        public int[] triangles;       // 網格的三角形
        public Vector2[] uvs;         // 網格的UV座標
        public Vector3[] normals;     // 網格的法線
        public Vector4[] tangents;    // 網格的切線
        public Color32[] Colors32;
        public BeamMesh(Vector3[] vertices, int[] triangles, Vector2[] uvs, Vector3[] normals, Vector4[] tangents, Color32[] Colors32)
        {
            this.vertices = vertices;
            this.triangles = triangles;
            this.uvs = uvs;
            this.normals = normals;
            this.tangents = tangents;
            this.Colors32 = Colors32;
        }
    }

    public struct Vector3Int
    {
        public int x;
        public int y;
        public int z;
        public Vector3Int(int x, int y, int z)
        {
            this.x = x;
            this.y = y;
            this.z = z;
        }
        public Vector3Int(Vector3 value)
        {
            x = (int)value.x;
            y = (int)value.y;
            z = (int)value.z;
        }
        public static implicit operator Vector3Int(Vector3 value)
        {
            return new Vector3Int((int)value.x, (int)value.y, (int)value.z);
        }
        public override string ToString()
        {
            return "{" + x + ", " + y + ", " + z + "}";
        }
    }


    public class Create3DMesh : MonoBehaviour
    {
        //public int _quality = 20;
        // 面片最大大小  
        public Vector3 _size = new Vector3(1000, 1000, 1000);
        // 單元格大小  
        public float _nodeSize = 0f;
        // 表格個數  
        private Vector3Int _grid = new Vector3Int();
        private Vector3 _stapInit = new Vector3();

        private Mesh _mesh;
        // 網格結構體  
        private BeamMesh _meshStruct;
        private MeshFilter _meshFilter;
        private int vIndex, tIndex;

        void Start()
        {
            _mesh = new Mesh();
            _mesh.name = "DynamicWaterMesh";
            _meshFilter = gameObject.GetComponent<MeshFilter>();
            _meshFilter.mesh = _mesh;

            // 根據【單元格大小】計算【格子個數】  
            _grid.x = Mathf.RoundToInt(_size.x / _nodeSize) + 1;
            _grid.y = Mathf.RoundToInt(_size.y / _nodeSize) + 1;
            _grid.z = Mathf.RoundToInt(_size.z / _nodeSize) + 1;
            //單元格子所佔比例
            _stapInit.x = _nodeSize / _size.x;
            _stapInit.y = _nodeSize / _size.y;
            _stapInit.z = _nodeSize / _size.z;

            _mesh.MarkDynamic();
            AllocateMeshArrays();
            CreateMeshGrid();
            AssignMesh();
            _meshFilter.mesh = _mesh;
        }


        private void AllocateMeshArrays()
        {
            int numVertices = 2 * (
                 _grid.x * _grid.z +  //上下
                 _grid.y * _grid.z +  //左右
                 _grid.x * _grid.y);  // 前後
            int NumTriangle = 2 * 2 * 3 * (
                (_grid.x - 1) * (_grid.z - 1) +        //上下
                 (_grid.y - 1) * (_grid.z - 1) +       //左右
                  (_grid.x - 1) * (_grid.y - 1));      // 前後
            _meshStruct.vertices = new Vector3[numVertices];
            _meshStruct.normals = new Vector3[numVertices];
            _meshStruct.tangents = new Vector4[numVertices];
            _meshStruct.Colors32 = new Color32[numVertices];
            _meshStruct.uvs = new Vector2[numVertices];
            _meshStruct.triangles = new int[NumTriangle];
        }

        private void CreateMeshGrid()
        {
            CreateMeshPlane(_grid.x,_grid.z,//上
                (i, j)=>  { return i * _nodeSize - _size.x * 0.5f; },
                (i, j) => { return _size.y * 0.5f; },
                (i, j) => { return j * _nodeSize - _size.z * 0.5f; },
                _stapInit.x,_stapInit.z,new Rect(0,0.71f,0.928f,0.29f),Vector3.up);
            CreateMeshPlane(_grid.x, _grid.z,//下
                (i, j) => { return i * _nodeSize - _size.x * 0.5f; },
                (i, j) => { return -_size.y * 0.5f; },
                (i, j) => { return -j * _nodeSize + _size.z * 0.5f; },
                _stapInit.x, _stapInit.z, new Rect(0,0,0.928f,0.29f), Vector3.down);
            CreateMeshPlane(_grid.z, _grid.y,//左
               (i, j) => { return -_size.x * 0.5f; },
               (i, j) => { return j * _nodeSize - _size.y * 0.5f; },
               (i, j) => { return -i * _nodeSize + _size.z * 0.5f; },
               _stapInit.z, _stapInit.y, new Rect(0.928f,0.29f,0.072f,0.42f), Vector3.left);
            CreateMeshPlane(_grid.z, _grid.y,//右
              (i, j) => { return _size.x * 0.5f; },
              (i, j) => { return j * _nodeSize - _size.y * 0.5f; },
              (i, j) => { return i * _nodeSize - _size.z * 0.5f; },
              _stapInit.z, _stapInit.y, new Rect(0.928f, 0.29f, 0.072f, 0.42f), Vector3.right);
            CreateMeshPlane(_grid.x, _grid.y,//前
               (i, j) => { return i * _nodeSize - _size.x * 0.5f; },
               (i, j) => { return j * _nodeSize - _size.y * 0.5f; },
               (i, j) => { return -_size.z * 0.5f; },
               _stapInit.x, _stapInit.y, new Rect(0f,0.29f, 0.928f,0.42f), Vector3.back);
            CreateMeshPlane(_grid.x, _grid.y,//後
              (i, j) => { return -i * _nodeSize + _size.x * 0.5f; },
              (i, j) => { return j * _nodeSize - _size.y * 0.5f; },
              (i, j) => { return _size.z * 0.5f; },
              _stapInit.x, _stapInit.y, new Rect(0f, 0.29f, 0.928f, 0.42f), Vector3.forward);
        }

        /// <summary>
        /// 創建出一個面的mesh數據
        /// </summary>
        /// <param name="axisX"></param>
        /// <param name="axisY"></param>
        /// <param name="vx"></param>
        /// <param name="vy"></param>
        /// <param name="vz"></param>
        /// <param name="uvstapX"></param>
        /// <param name="uvstapY"></param>
        /// <param name="normal"></param>
        private void CreateMeshPlane(int axisX, int axisY, System.Func<int, int, float> vx, System.Func<int, int, float> vy, System.Func<int, int, float> vz, float uvstapX, float uvstapY,Rect uvRect, Vector3 normal)
        {
            int start = vIndex;
            for (int j = 0; j < axisY; j++)
            {
                for (int i = 0; i < axisX; i++)
                {
                    // Set vertices  
                    _meshStruct.vertices[vIndex].x = vx(i, j);
                    _meshStruct.vertices[vIndex].y = vy(i, j);
                    _meshStruct.vertices[vIndex].z = vz(i, j);

                    // Set triangles  
                    if (j < axisY - 1 && i < axisX - 1)
                    {
                        _meshStruct.triangles[tIndex + 0] = (j * axisX) + i + start;
                        _meshStruct.triangles[tIndex + 1] = ((j + 1) * axisX) + i + start;
                        _meshStruct.triangles[tIndex + 2] = (j * axisX) + i + 1 + start;

                        _meshStruct.triangles[tIndex + 3] = ((j + 1) * axisX) + i + start;
                        _meshStruct.triangles[tIndex + 4] = ((j + 1) * axisX) + i + 1 + start;
                        _meshStruct.triangles[tIndex + 5] = (j * axisX) + i + 1 + start;

                        tIndex += 6;
                    }
                    float uvx = uvRect.x + i * uvstapX * uvRect.width;
                    float uvy = uvRect.y + j * uvstapY * uvRect.height;
                    SetOther(uvx, uvy, normal);
                    //ClampExtrVertials();
                    vIndex++;
                }
            }
        }


        private void AssignMesh()
        {
            _mesh.vertices = _meshStruct.vertices;
            _mesh.normals = _meshStruct.normals;
            _mesh.tangents = _meshStruct.tangents;

            _mesh.uv = _meshStruct.uvs;
            _mesh.colors32 = _meshStruct.Colors32;
            _mesh.triangles = _meshStruct.triangles;

            _mesh.RecalculateBounds();

            // Freeing the memory  
            _meshStruct.tangents = null;
            _meshStruct.triangles = null;
            _meshStruct.uvs = null;
            _meshStruct.Colors32 = null;
        }
    }
}
以上利用每個點相對於總長度的比例來實現網格座標的確定,uv的設置如下:

五、指定各個頂點的uv

        private void SetOther(float uvx, float uvy, Vector3 normal)
        {
            Color32 colorOne = new Color32(255, 255, 255, 255);
            bool setTangents = true;
            Vector4 tangent = new Vector4(1f, 0f, 0f, 1f);

            // Set UV  
            _meshStruct.uvs[vIndex].x = uvx;
            _meshStruct.uvs[vIndex].y = uvy;

            // Set colors  
            _meshStruct.Colors32[vIndex] = colorOne;

            // Set normals  
            _meshStruct.normals[vIndex] = normal;

            if (setTangents)
            {
                // set tangents  
                _meshStruct.tangents[vIndex] = tangent;
            }

        }
以上腳本可以實現三個邊的公約數定義網格大小,但如果設定的格式大小不是公約數,將會產生如下的效果

六、尺寸縮減處理

由於在用戶可能會輸入不是公約數的網格大小,因此,本人的解決辦法是將格字數強制增加一列,同時在將各個頂點限制在長寬高之內,並利用最後的頂點座標來設定uv.

將網格製作製作成一個工具類,如下:

using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Events;
using System.Collections.Generic;
public struct Vector3Int
{
    public int x;
    public int y;
    public int z;
    public Vector3Int(int x, int y, int z)
    {
        this.x = x;
        this.y = y;
        this.z = z;
    }
    public Vector3Int(Vector3 value)
    {
        x = (int)value.x;
        y = (int)value.y;
        z = (int)value.z;
    }
    public static implicit operator Vector3Int(Vector3 value)
    {
        return new Vector3Int((int)value.x, (int)value.y, (int)value.z);
    }
    public override string ToString()
    {
        return "{" + x + ", " + y + ", " + z + "}";
    }
}

public static class MeshUtility
{
    static int vIndex, tIndex;

    /// <summary>
    /// 按要求創建網格體信息
    /// </summary>
    /// <param name="binfo"></param>
    /// <param name="size"></param>
    /// <returns></returns>
	public static MeshStruct CreateBeamMesh(BeamInfo binfo, bool dir = false)
    {
        //不進行分割
        if (!dir)
        {
            return GenerateSimpleBox(binfo);
        }
        else
        {
            return GenerateDirBox(binfo);
        }
    }

    /// <summary>
    /// 按要求將網格,得到新的網格
    /// </summary>
    /// <param name="meshData"></param>
    /// <param name=""></param>
    /// <returns></returns>
    public static void CurveMeshStruct(HandleData handle, MeshStruct meshDataTemp,ref MeshStruct meshData)
    {
        for (int i = 0; i < meshData.vertices.Length; i++)
        {
            Vector3 item = meshData.vertices[i];
            //區域內部
            if (item.x > handle.LeftCenterPoint.x && item.x < handle.RightCenterPoint.x)
            {
                Vector3 newCenterPos = BezierUtility.CalculateBezierPoint((item.x - handle.LeftCenterPoint.x) / (handle.RightCenterPoint.x - handle.LeftCenterPoint.x), handle.LeftCenterPoint, handle.HandPoint1, handle.HandPoint2, handle.RightCenterPoint);
                meshData.vertices[i].y = meshDataTemp.vertices[i].y + newCenterPos.y;
            }
        }
    }
    /// <summary>
    /// 設置分割後的網格體
    /// </summary>
    /// <param name="binfo"></param>
    static MeshStruct GenerateDirBox(BeamInfo binfo)
    {
        Vector3Int _grid = new Vector3Int();
        // 根據【單元格大小】計算【格子個數】  
        _grid.x = Mathf.CeilToInt((float)binfo.length / binfo.gridSize) + 1;
        _grid.y = Mathf.CeilToInt((float)binfo.height / binfo.gridSize) + 1;
        _grid.z = Mathf.CeilToInt((float)binfo.wigth / binfo.gridSize) + 1;
        MeshStruct _meshStruct = AllocateMeshArrays(_grid);
        CreateMeshGrid(_grid, binfo, ref _meshStruct);
        return _meshStruct;
    }

    static MeshStruct AllocateMeshArrays(Vector3Int _grid)
    {
        int numVertices = 2 * (
             _grid.x * _grid.z +  //上下
             _grid.y * _grid.z +  //左右
             _grid.x * _grid.y);  // 前後
        int NumTriangle = 2 * 2 * 3 * (
            (_grid.x - 1) * (_grid.z - 1) +        //上下
             (_grid.y - 1) * (_grid.z - 1) +       //左右
              (_grid.x - 1) * (_grid.y - 1));      // 前後
        MeshStruct _meshStruct = new MeshStruct();
        _meshStruct.vertices = new Vector3[numVertices];
        _meshStruct.normals = new Vector3[numVertices];
        _meshStruct.tangents = new Vector4[numVertices];
        _meshStruct.Colors32 = new Color32[numVertices];
        _meshStruct.uvs = new Vector2[numVertices];
        _meshStruct.triangles = new int[NumTriangle];
        return _meshStruct;
    }

    static void CreateMeshGrid(Vector3Int _grid, BeamInfo binfo, ref MeshStruct _meshStruct)
    {
        vIndex = tIndex = 0;
        float xMin = -binfo.length * 0.5f;
        float xMax = binfo.length * 0.5f;
        float yMin = -binfo.height * 0.5f;
        float yMax = binfo.height * 0.5f;
        float zMin = -binfo.wigth * 0.5f;
        float zMax = binfo.wigth * 0.5f;
        CreateMeshPlane(_grid.x, _grid.z,//上
            (i, j) => { return Mathf.Clamp(i * binfo.gridSize + xMin, xMin, xMax); },
            (i, j) => { return yMax; },
            (i, j) => { return Mathf.Clamp(-j * binfo.gridSize + zMax, zMin, zMax); },
            /*new Rect(0, 0.7083f, 0.9278f, 0.2917f)*/
            (x, y, z) => { return 0 + ((x + xMax) / binfo.length) * 0.9278f; },
            (x, y, z) => { return 0.7083f + ((z + zMax) / binfo.wigth) * 0.2917f; },
            Vector3.up, ref _meshStruct, true);
        CreateMeshPlane(_grid.x, _grid.z,//下
            (i, j) => { return Mathf.Clamp(i * binfo.gridSize + xMin, xMin, xMax); },
            (i, j) => { return yMin; },
            (i, j) => { return Mathf.Clamp(-j * binfo.gridSize + zMax, zMin, zMax); },
            //new Rect(0, 0, 0.9278f, 0.2917f),
            (x, y, z) => { return 0 + ((x + xMax) / binfo.length) * 0.9278f; },
            (x, y, z) => { return 0 + ((z + zMax) / binfo.wigth) * 0.2917f; },
            Vector3.down, ref _meshStruct);
        CreateMeshPlane(_grid.z, _grid.y,//左
           (i, j) => { return xMin; },
           (i, j) => { return Mathf.Clamp(j * binfo.gridSize + yMin, yMin, yMax); },
           (i, j) => { return Mathf.Clamp(-i * binfo.gridSize + zMax, zMin, zMax); },
            //new Rect(0.9278f, 0.2917f, 0.0722f, 0.4167f), 
            (x, y, z) => { return 0.9278f + ((z + zMax) / binfo.wigth) * 0.0722f; },
            (x, y, z) => { return 0.2917f + ((y + yMax) / binfo.height) * 0.4167f; },
           Vector3.left, ref _meshStruct);
        CreateMeshPlane(_grid.z, _grid.y,//右
          (i, j) => { return xMax; },
          (i, j) => { return Mathf.Clamp(j * binfo.gridSize + yMin, yMin, yMax); },
          (i, j) => { return Mathf.Clamp(-i * binfo.gridSize + zMax, zMin, zMax); },
           //new Rect(0.9278f, 0.2917f, 0.0722f, 0.4167f),
           (x, y, z) => { return 0.9278f + ((z + zMax) / binfo.wigth) * 0.0722f; },
            (x, y, z) => { return 0.2917f + ((y + yMax) / binfo.height) * 0.4167f; },
          Vector3.right, ref _meshStruct, true);
        CreateMeshPlane(_grid.x, _grid.y,//前
           (i, j) => { return Mathf.Clamp(i * binfo.gridSize + xMin, xMin, xMax); },
           (i, j) => { return Mathf.Clamp(j * binfo.gridSize + yMin, yMin, yMax); },
           (i, j) => { return zMin; },
            //new Rect(0f, 0.2917f, 0.9278f, 0.4167f),
            (x, y, z) => { return 0 + ((x + xMax) / binfo.length) * 0.9278f; },
            (x, y, z) => { return 0.2917f + ((y + yMax) / binfo.height) * 0.4167f; },
           Vector3.back, ref _meshStruct);
        CreateMeshPlane(_grid.x, _grid.y,//後
          (i, j) => { return Mathf.Clamp(i * binfo.gridSize + xMin, xMin, xMax); },
          (i, j) => { return Mathf.Clamp(j * binfo.gridSize + yMin, yMin, yMax); },
          (i, j) => { return zMax; },
          //new Rect(0f, 0.2917f, 0.9278f, 0.4167f),
          (x, y, z) => { return 0 + ((x + xMax) / binfo.length) * 0.9278f; },
            (x, y, z) => { return 0.2917f + ((y + yMax) / binfo.height) * 0.4167f; },
          Vector3.forward, ref _meshStruct, true);
    }

    /// <summary>
    /// 創建出一個面的mesh數據
    /// </summary>
    /// <param name="axisX"></param>
    /// <param name="axisY"></param>
    /// <param name="vx"></param>
    /// <param name="vy"></param>
    /// <param name="vz"></param>
    /// <param name="uvstapX"></param>
    /// <param name="uvstapY"></param>
    /// <param name="normal"></param>
    static void CreateMeshPlane(int axisX, int axisY,
        System.Func<int, int, float> vx,
        System.Func<int, int, float> vy,
        System.Func<int, int, float> vz,
        System.Func<float, float, float, float> vuvx,
        System.Func<float, float, float, float> vuvy,
        Vector3 normal, ref MeshStruct _meshStruct, bool revers = false)
    {
        int start = vIndex;
        for (int j = 0; j < axisY; j++)
        {
            for (int i = 0; i < axisX; i++)
            {
                // Set vertices  
                _meshStruct.vertices[vIndex].x = vx(i, j);
                _meshStruct.vertices[vIndex].y = vy(i, j);
                _meshStruct.vertices[vIndex].z = vz(i, j);

                // Set triangles  
                if (j < axisY - 1 && i < axisX - 1)
                {
                    _meshStruct.triangles[tIndex + 0] = revers ? (j * axisX) + i + 1 + start : (j * axisX) + i + start;
                    _meshStruct.triangles[tIndex + 1] = ((j + 1) * axisX) + i + start;
                    _meshStruct.triangles[tIndex + 2] = revers ? (j * axisX) + i + start : (j * axisX) + i + 1 + start;

                    _meshStruct.triangles[tIndex + 3] = revers ? (j * axisX) + i + 1 + start : ((j + 1) * axisX) + i + start;
                    _meshStruct.triangles[tIndex + 4] = ((j + 1) * axisX) + i + 1 + start;
                    _meshStruct.triangles[tIndex + 5] = revers ? ((j + 1) * axisX) + i + start : (j * axisX) + i + 1 + start;

                    tIndex += 6;
                }
                float uvx = vuvx(_meshStruct.vertices[vIndex].x, _meshStruct.vertices[vIndex].y, _meshStruct.vertices[vIndex].z);//uvRect.x + i * uvstapX * uvRect.width;
                float uvy = vuvy(_meshStruct.vertices[vIndex].x, _meshStruct.vertices[vIndex].y, _meshStruct.vertices[vIndex].z);//uvRect.y + j * uvstapY * uvRect.height;
                SetOther(uvx, uvy, normal, ref _meshStruct);
                vIndex++;
            }
        }
    }

    static void SetOther(float uvx, float uvy, Vector3 normal, ref MeshStruct _meshStruct)
    {
        Color32 colorOne = new Color32(255, 255, 255, 255);
        bool setTangents = true;
        Vector4 tangent = new Vector4(1f, 0f, 0f, 1f);
        // Set UV  
        _meshStruct.uvs[vIndex].x = uvx;
        _meshStruct.uvs[vIndex].y = uvy;

        // Set colors  
        _meshStruct.Colors32[vIndex] = colorOne;

        // Set normals  
        _meshStruct.normals[vIndex] = normal;

        if (setTangents)
        {
            // set tangents  
            _meshStruct.tangents[vIndex] = tangent;
        }

    }
    /// <summary>
    /// 默認網格體繪製
    /// </summary>
    /// <param name="binfo"></param>
    static MeshStruct GenerateSimpleBox(BeamInfo binfo)
    {
        Color32 colorOne = new Color32(255, 255, 255, 255);

        Vector3[] Vs = new Vector3[]
       {
            new Vector3(-0.5f * binfo.length, -0.5f * binfo.height, -0.5f * binfo.wigth),
            new Vector3(0.5f * binfo.length,  -0.5f* binfo.height, -0.5f* binfo.wigth),
            new Vector3(0.5f  * binfo.length,  0.5f* binfo.height, -0.5f* binfo.wigth),
            new Vector3(-0.5f * binfo.length,  0.5f* binfo.height, -0.5f * binfo.wigth),
            new Vector3(-0.5f * binfo.length,  0.5f* binfo.height, 0.5f* binfo.wigth),
            new Vector3(0.5f  * binfo.length,  0.5f* binfo.height, 0.5f* binfo.wigth),
            new Vector3(0.5f  * binfo.length, -0.5f* binfo.height, 0.5f * binfo.wigth),
            new Vector3(-0.5f * binfo.length, -0.5f * binfo.height, 0.5f* binfo.wigth)
       };
        int[] Ts = new int[]
   {
            0,2,1,
            0,3,2,
            3,4,2,
            4,5,2,
            4,7,5,
            7,6,5,
            7,0,1,
            6,7,1,
            4,3,0,
            4,0,7,
            2,5,6,
            2,6,1
   };

        //根據面的順序,重新創建新的頂點數組,用於計算頂點法線
        Vector3[] newVs = new Vector3[Ts.Length];
        for (int i = 0; i < newVs.Length; i++)
        {
            newVs[i] = Vs[Ts[i]];
        }
        Vs = newVs;
        Vector2[] UVs = new Vector2[Vs.Length];
        Vector3[] normals = new Vector3[Vs.Length];
        Vector4[] tangents = new Vector4[Vs.Length];
        Color32[] colors = new Color32[Vs.Length];
        // 根據新的點,設置三角面的頂點ID並計算點法線
        for (int i = 0; i < Ts.Length - 2; i += 3)
        {
            Vector3 normal = Vector3.Normalize(Vector3.Cross(Vs[i + 1] - Vs[i], Vs[i + 2] - Vs[i]));  // 計算點的法線
            for (int j = 0; j < 3; j++)
            {
                Ts[i + j] = i + j;        // 重新設置面的頂點ID
                normals[i + j] = normal;  // 點的法線賦值
                colors[i + j] = colorOne;
            }
        }

        // 設置每個點的切線和UV
        for (int i = 0; i < Vs.Length; i++)
        {
            tangents[i] = new Vector4(-1, 0, 0, -1);    // 切線
            if (normals[i] == Vector3.back || normals[i] == Vector3.forward)
            {
                UVs[i] = new Vector2((Vs[i].x + 0.5f * binfo.length) * 0.928f / binfo.length, (Vs[i].y + 0.5f * binfo.height) * 0.42f / binfo.height + 0.292f);     // UV座標
            }
            else if (normals[i] == Vector3.up)
            {
                UVs[i] = new Vector2((Vs[i].x + 0.5f * binfo.length) * 0.928f / binfo.length, (Vs[i].z + 0.5f * binfo.wigth) * 0.292f / binfo.wigth + 0.708f);     // UV座標
            }
            else if (normals[i] == Vector3.down)
            {
                UVs[i] = new Vector2((Vs[i].x + 0.5f * binfo.length) * 0.928f / binfo.length, (Vs[i].z + 0.5f * binfo.wigth) / binfo.wigth * 0.292f);     // UV座標
            }
            else if (normals[i] == Vector3.left || normals[i] == Vector3.right)
            {
                UVs[i] = new Vector2((Vs[i].z + 0.5f * binfo.wigth) * 0.072f / binfo.wigth + 0.928f, (Vs[i].y + 0.5f * binfo.height) * 0.42f / binfo.height + 0.292f);     // UV座標
            }
        }
        MeshStruct bMesh = new MeshStruct(Vs, Ts, UVs, normals, tangents, colors);
        return bMesh;
    }

}

最後說明的是,這個腳本需要使用其他腳本來調用才能生成網格。




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