寫在前面:
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; } }
最後說明的是,這個腳本需要使用其他腳本來調用才能生成網格。