最近在做项目优化,注意到动态创建Mesh时,Unity提供了一套高级方法用于快速创建模型,特此记录学习一下。
前言
关于Mesh的基本概念再次不在阐述,可以参考Unity Mesh 官方文档,介绍的很详细,其中
基础方法包括:SetVertices、SetNormals、SetUVs、SetTriangles、SetIndices、SetColors、SetTangents、SetBoneWeights
高级方法包括:SetVertexBufferParams、SetVertexBufferData、SetIndexBufferParams、SetIndexBufferData、SetSubMesh。
优势
- 使用基础方法有个限制,就是Mesh的最大顶点数量不能超过65535,而高级方法则没有这个限制。
- 高级方法跳过了一些检查,创建速度更快,尤其模型顶点数量较多的情况下,有性能提升,实测时间缩短将近1/3。
示例
基础方法
需要提前准备好模型的数据
属性名 | 含义 | 类型 |
---|---|---|
vertices | 顶点坐标 | Verctor3[] |
normals | 法线 | Verctor3[] |
triangles | 顶点索引 | int[] |
uv | 纹理坐标 | Verctor2[] |
//创建Mesh,并赋值,相当于调用SetVertices、SetNormals、SetTriangles、SetUVs
Mesh mesh = new Mesh();
mesh.vertices = myMeshes[i].vertices;
mesh.normals = myMeshes[i].normals;
mesh.triangles = myMeshes[i].triangles;
mesh.uv = myMeshes[i].uv;
//将Mesh赋值给MeshFilter组件
GameObject gameObject = new GameObject();
MeshFilter mf = gameObject.AddComponent<MeshFilter>();
mf.sharedMesh = mesh;
//给模型赋予材质
MeshRenderer mr = gameObject.AddComponent<MeshRenderer>();
mr.material = material;
高级方法(推荐)
同上,先准备好模型的基础数据
//
//顶点属性描述中,添加该模型具有哪些属性,该例中有顶点、法线、一个uv,其中
//顶点坐标 Position 用 3 个 Float32 数据表示
//法线向量 Normal 用 3 个 Float32 数据表示
//纹理坐标 TexCoord0 用 2 个 Float32 数据表示
//
VertexAttributeDescriptor[] vertexAttributes = new[]{
new VertexAttributeDescriptor(VertexAttribute.Position, VertexAttributeFormat.Float32, 3),
new VertexAttributeDescriptor(VertexAttribute.Normal, VertexAttributeFormat.Float32, 3),
new VertexAttributeDescriptor(VertexAttribute.TexCoord0, VertexAttributeFormat.Float32, 2)
};
//
// 根据顶点数量创建缓冲区
//
// 假设创建一个四方面片,则缓冲区数据如下
// 顶点 法线 uv
// -5, -5, 0, 0, 0, -1, 0, 0, //第 1 个顶点
// -5, 5, 0, 0, 0, -1, 0, 1, //第 2 个顶点
// 5, -5, 0, 0, 0, -1, 1, 0, //第 3 个顶点
// 5, 5, 0, 0, 0, -1, 1, 1 //第 4 个顶点
//
int vertexCount = myMeshes[i].vertices.Length;
int bufferLength = 3 + 3 + 2;
int vertexAttributeBufferLength = vertexCount * bufferLength;
float[] vertexAttributeBuffer = new float[vertexAttributeBufferLength];
//
// 将准备好的模型数据填充到缓冲区
//
Vector3[] vertices = myMeshes[i].vertices;
Vector3[] normals = myMeshes[i].normals;
Vector2[] uv = myMeshes[i].uv;
for (int j = 0; j < vertexCount; j++)
{
int start = j * bufferLength;
//此处 +0 ... +7 的原由。观察四方面片示例
vertexAttributeBuffer[start + 0] = vertices[j].x;
vertexAttributeBuffer[start + 1] = vertices[j].y;
vertexAttributeBuffer[start + 2] = vertices[j].z;
vertexAttributeBuffer[start + 3] = normals[j].x;
vertexAttributeBuffer[start + 4] = normals[j].y;
vertexAttributeBuffer[start + 5] = normals[j].z;
vertexAttributeBuffer[start + 6] = uv[j].x;
vertexAttributeBuffer[start + 7] = uv[j].y;
}
//将顶点缓冲区写入Mesh
Mesh mesh = new Mesh();
mesh.SetVertexBufferParams(vertexCount, vertexAttributes);
mesh.SetVertexBufferData(vertexAttributeBuffer, 0, 0, vertexAttributeBufferLength, 0);
//将顶点索引写入索引缓冲区
int[] triangles = myMeshes[i].triangles;
int indexCount = triangles.Length;
mesh.SetIndexBufferParams(indexCount, IndexFormat.UInt32);
mesh.SetIndexBufferData(triangles, 0, 0, indexCount);
//每个Mesh至少包含一个SubMesh,也可将上面的缓冲区分开赋值,分别设置到不同的SubMesh
mesh.subMeshCount = 1;
SubMeshDescriptor subMeshDescriptor = new SubMeshDescriptor(0, indexCount);
mesh.SetSubMesh(0, subMeshDescriptor);
//高级方法由于跳过Unity检查,缺失Bounds信息,当任意三角面超过相机的裁剪区域时,整个模型会被裁剪掉(消失不见)
mesh.RecalculateBounds();
//将Mesh赋值给MeshFilter组件
GameObject gameObject = new GameObject();
MeshFilter mf = gameObject.AddComponent<MeshFilter>();
mf.sharedMesh = mesh;
//给模型赋予材质
MeshRenderer mr = gameObject.AddComponent<MeshRenderer>();
mr.material = material;
注意!!!
大家可以做一下测试,使用高级方法创建出来的Mesh,在Scene窗口旋转预览相机(或调整相机的size,在Game视图观察),当模型有三角面超过可视区域后,会突然消失不见!
这是因为,使用高级方法创建出来的Mesh,由于跳过了Unity的检查,Mesh的Bounds信息缺失,这会导致一个现象,当模型的任意三角面不在相机的裁剪区域内时,模型会突然消失(被相机裁剪掉),因此需要调用RecalculateBounds方法计算一下模型的Bounds。
基础方法创建出来的Mesh,Unity默认会对其进行Bounds计算(不需要调用RecalculateBounds方法),所以不会出现上述情况。
因此可以推测,当修改了Mesh的顶点位置后,都需要调用一下RecalculateBounds方法,重新计算Bounds。
备注
此处为了展示高级方法的用法,因此未直接创建完整缓冲区数据,多执行一次数据的组装(即vertexAttributeBuffer数组)。实际应用时,会直接将缓冲区数据准备好(而不是分开存储vertices、normals、uv、triangles),直接调用SetXXXBufferParams、SetXXXBufferData。文章来源:https://www.toymoban.com/news/detail-843793.html
参考:其他博主的文章Unity3D学习笔记4——创建Mesh高级接口文章来源地址https://www.toymoban.com/news/detail-843793.html
到了这里,关于Unity 动态创建Mesh 基础方法与高级方法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!