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;
    }

}

最后说明的是,这个脚本需要使用其他脚本来调用才能生成网格。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值