写在前面:
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;
}
}
最后说明的是,这个脚本需要使用其他脚本来调用才能生成网格。