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;

高级方法(推荐)

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


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

参考:其他博主的文章Unity3D学习笔记4——创建Mesh高级接口文章来源地址https://www.toymoban.com/news/detail-843793.html

到了这里,关于Unity 动态创建Mesh 基础方法与高级方法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • UNITY 基础之 实现动态加载网络端、PC端和 ANDROID 端指定路径下的图片的简单方法

    Unity中的一些基础知识点,便于后期查看学习。 本节介绍,如何动态加载网络上,电脑上或者Android手机上指定路径的图片的简单方式,方法不唯一,仅供参考。 1、UnityWebRequest 发起网络请求,DownloadHandlerTexture 作为发起下载图片,解析得到图片 2、下载地址不仅支持网络路径

    2024年02月09日
    浏览(15)
  • Unity动态创建材质球

    目录 一、获取贴图 1:从Assets文件中获取 2:从本地文件中获取 二、创建材质球 三、替换材质 总结 前言 我们在做一些AR类似与涂涂乐的功能时,经常会用到给模型替换材质球的功能。当我们的用户创建好贴图时就需要动态将新的贴图转换成材质贴在模型上。他的原理其实很

    2024年02月05日
    浏览(18)
  • 【Unity入门】22.动态创建实例

        大家好,我是Lampard~~     欢迎来到Unity入门系列博客,所学知识来自B站阿发老师~感谢    (1)Instantiate克隆创建对象     昨天我们学习了预制体这个概念,在编辑器中使用预制体创建游戏对象,并学习如何修改预制体等。 今天主要来学习,如何在脚本中利用预制体创

    2024年02月05日
    浏览(16)
  • Unity Audio -- (2)创建动态音效

            本节的目标是添加脚步声到角色身上,当角色走路时,触发动画事件并播放声音。         脚步声是我们在真实世界中常常被我们所忽视的声音,但脚步声能够传达出许多环境信息。你现在可以花一小段时间绕着你周围的环境走一走并仔细听听脚步声。如果可能

    2024年02月08日
    浏览(31)
  • 10. unity预制体、动态创建实体案例

    1. 预制体 预制体 Prefab 就是事先制作好的物体,可以提高开发效率。 1.1 预制体的制作 第一步 :在界面编辑器中先创建一个三维模型,比如创建一个正方体,命名为“骰子”,然后给它添加一个材质,再挂载一个旋转的脚本,如图所示: 第二步 :经过上述步骤制作好模型后

    2024年02月05日
    浏览(23)
  • Unity的Resources类:从基础到高级的全面指南

    Unity中的Resources类为开发者提供了一个方便的方式来加载和管理运行时资源。尽管它的使用简单直观,但为了充分发挥其潜力和避免常见的陷阱,还是需要对其有一些深入了解。 Resources类是Unity中的一个静态类,它提供了方法来加载存储在特定“Resources”文件夹内的资源。这

    2024年02月07日
    浏览(18)
  • Unity网格篇Mesh(一)

    创建网格坐标 使用携程计算他们位置 利用三角形确定一个面 自动生成法线 添加纹理坐标和切线 这篇教程中我们将利用顶点和三角面创建一个网格。 原英文篇 如果你想要在Unity显示一些东西,你需要一个网格。他可以是一个3D模型从另一个程序倒入的(3dmax,maya)。它也可

    2024年02月03日
    浏览(25)
  • Unity网格篇Mesh(二)

    本文接上一遍Unity网格篇Mesh(二) 我们的网格目前处于一种特殊的情况下。因为我们到目前为止还没有给他们法线向量,默认的法线向量是(0,0,1)(垂直于屏幕向里),而我们需要的正好相反。 法线工作原理是什么呢? 法线是垂直于面的向量。我们通常使用单位长度的法向量

    2024年01月17日
    浏览(24)
  • 留个档,Unity Navigation. 动态创建NavMesh,动态Bake NavMesh, 动态烘培NavMesh

    运行时,动态创建NavMesh,动态Bake NavMesh, 动态烘培NavMesh 根据unity官方的demo,解析一下,发现动态创建NavMesh导航并不难. 其实只需要 网格信息,还有 需要创建的范围即可。 可以认为是固定公式了 简化写法如下,是不是需要缓存某些信息,就看具体逻辑实现了 程序学无止尽。

    2024年02月13日
    浏览(14)
  • Unity C#编程基于《C#高级编程第12版》——C#基础

    类 : 编程中的一种 抽象 的数据类型(用于表现存储数据的类型)。用于描述一组具有相同属性和行为的对象(例如:狗、猫、鸡羊可看作是一个对象,狗的属性可以是名字、花色、体重,行为可以有吃东西,跑步)。 通过类可以方便的实例化出相同类型的对象(前面举例

    2024年01月23日
    浏览(26)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包