当前位置:   article > 正文

Unity 动态创建Mesh 基础方法与高级方法_unity 动态生成mesh

unity 动态生成mesh

最近在做项目优化,注意到动态创建Mesh时,Unity提供了一套高级方法用于快速创建模型,特此记录学习一下。

前言

关于Mesh的基本概念再次不在阐述,可以参考Unity Mesh 官方文档,介绍的很详细,其中

基础方法包括:SetVertices、SetNormals、SetUVs、SetTriangles、SetIndices、SetColors、SetTangents、SetBoneWeights
高级方法包括:SetVertexBufferParams、SetVertexBufferData、SetIndexBufferParams、SetIndexBufferData、SetSubMesh。

优势

  1. 使用基础方法有个限制,就是Mesh的最大顶点数量不能超过65535,而高级方法则没有这个限制
  2. 高级方法跳过了一些检查,创建速度更快,尤其模型顶点数量较多的情况下,有性能提升,实测时间缩短将近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;

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

高级方法(推荐)

同上,先准备好模型的基础数据


	//
	//顶点属性描述中,添加该模型具有哪些属性,该例中有顶点、法线、一个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;

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79

注意!!!

      由于使用高级方法创建出来的Mesh,跳过了Unity的检查,Mesh的Bounds信息缺失,这会导致一个现象,当模型的任意三角面不在相机的裁剪区域内时,模型会突然消失(被相机裁剪掉),因此需要调用RecalculateBounds方法计算一下模型的Bounds。

      基础方法创建出来的Mesh,Unity默认会对其进行Bounds计算,即使不调用RecalculateBounds方法,也不会出现上述情况。

      只要修改了Mesh的顶点位置后,都需要调用一下RecalculateBounds方法重新计算Bounds,否则包括物理检测、视窗裁剪这些设计到Bounds得计算,都将出错。

备注

此处为了展示高级方法的用法,因此未直接创建完整缓冲区数据,多执行一次数据的组装(即vertexAttributeBuffer数组)。实际应用时,会直接将缓冲区数据准备好(而不是分开存储vertices、normals、uv、triangles),直接调用SetXXXBufferParams、SetXXXBufferData。

参考:其他博主的文章Unity3D学习笔记4——创建Mesh高级接口

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/633280
推荐阅读
相关标签
  

闽ICP备14008679号