Unity 动态创建Mesh 基础方法与高级方法

news/发布时间2024/5/15 19:09:47

最近在做项目优化,注意到动态创建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、SetUVsMesh 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;}//将顶点缓冲区写入MeshMesh 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,也可将上面的缓冲区分开赋值,分别设置到不同的SubMeshmesh.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高级接口

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.bcls.cn/JrZG/5156.shtml

如若内容造成侵权/违法违规/事实不符,请联系编程老四网进行投诉反馈email:xxxxxxxx@qq.com,一经查实,立即删除!

相关文章

Web安全之浅见

备注&#xff1a;这是我在2017年在自己的网站上写的文章&#xff0c;今天迁移过来。 昨天去参加了公司组织的一个关于网络安全的培训&#xff0c;了解了很多关于网络安全方面的知识&#xff0c;也才意识到网络安全是一项极其重要的领域。 本篇文章主要聊聊Web安全。不过我对于网…

【云原生】Spring Cloud Gateway的底层原理与实践方法探究

&#x1f389;&#x1f389;欢迎光临&#x1f389;&#x1f389; &#x1f3c5;我是苏泽&#xff0c;一位对技术充满热情的探索者和分享者。&#x1f680;&#x1f680; &#x1f31f;特别推荐给大家我的最新专栏《Spring 狂野之旅&#xff1a;从入门到入魔》 &#x1f680; 本…

[算法沉淀记录] 排序算法 —— 堆排序

排序算法 —— 堆排序 算法基础介绍 堆排序&#xff08;Heap Sort&#xff09;是一种基于比较的排序算法&#xff0c;它利用堆这种数据结构来实现排序。堆是一种特殊的完全二叉树&#xff0c;其中每个节点的值都必须大于或等于&#xff08;最大堆&#xff09;或小于或等于&am…

Linux的进程

在Linux中&#xff0c;可以使用多种方式来结束进程。以下是8种常见的方式&#xff1a; 终端中断&#xff08;Ctrl C&#xff09;&#xff1a;在终端中运行的程序可以通过按下Ctrl C组合键来发送SIGINT信号&#xff0c;终止该进程的执行。 kill命令&#xff1a;使用kill命令可…

数字货币风暴:比特币价格突破历史新高,引发金融市场震荡

比特币价格在2023年突破了历史新高&#xff0c;达到了一个令人惊讶的水平&#xff0c;引发了金融市场的震荡和广泛的关注。这一价格的飙升引发了对数字货币的热议&#xff0c;以及对其未来发展的种种猜测。 许多人认为&#xff0c;比特币价格飙升的原因之一是对数字资产的日益…

QT C++实现点击按键弹出窗口并显示图片/视频|多窗口应用程序的设计和开发

一、介绍 首先&#xff0c;QT界面开发中主要大体分为2种多窗口的形式&#xff1a; 嵌入式&#xff1a; 新生成的窗口嵌入在主窗口内部独立窗口&#xff1a; 以弹窗形式的新窗口生成和展示 这里就讲解最简单的&#xff1a;点击案件后&#xff0c;跳出一个新窗口 二、代码实…

PHP WebSocket:技术解析与实用指南

本文旨在帮助初学者掌握在PHP中使用WebSocket的关键概念和技术。我们将深入讨论从建立连接、绑定到监听等各方面的操作&#xff0c;并提供易于理解和实践的指导。 一、socket协议的简介 WebSocket是什么&#xff0c;有什么优点 WebSocket是一个持久化的协议&#xff0c;这是…

【Java EE初阶二十三】servlet的简单理解

1. 初识servlet Servlet 是一个比较古老的编写网站的方式&#xff0c;早起Java 编写网站,主要使用 Servlet 的方式&#xff0c;后来 Java 中产生了一个Spring(一套框架)&#xff0c;Spring 又是针对 Servlet 进行了进一步封装,从而让我们编写网站变的更简单了&#xff1b;Sprin…

Android全新UI框架之常用ComposeUI组件

在Compose中&#xff0c;每个组件都是一个带有Composable注解的函数&#xff0c;被称为Composable。Compose已经预置了很多基于MD设计规范的Composable组件。 在布局方面&#xff0c;Compose提供了Column、Row、Box三种布局组件(感觉跟flutter差不多)&#xff0c;类似于传统视图…

《Docker 简易速速上手小册》第7章 高级容器管理(2024 最新版)

文章目录 7.1 容器监控与日志7.1.1 重点基础知识7.1.2 重点案例&#xff1a;监控 Flask 应用7.1.3 拓展案例 1&#xff1a;使用 ELK Stack 收集和分析日志7.1.4 拓展案例 2&#xff1a;使用集成监控工具 7.2 性能调优与资源限制7.2.1 重点基础知识7.2.2 重点案例&#xff1a;Fl…

RapidJson开源库使用

1.下载 GitHub - Tencent/rapidjson: A fast JSON parser/generator for C with both SAX/DOM style APIA fast JSON parser/generator for C with both SAX/DOM style API - Tencent/rapidjsonhttps://github.com/Tencent/rapidjson 官方使用手册&#xff1a;RapidJSON: 首页…

自定义Chrome的浏览器开发者工具DevTools界面的字体和样式

Chrome浏览器开发者工具默认的字体太小&#xff0c;想要修改但没有相关设置。 外观——字体可以自定义字体&#xff0c;但大小不可以调整。 github上有人给出了方法 整理为中文教程&#xff1a; 1.打开浏览器开发者工具&#xff0c;点开设置——实验&#xff0c;勾上红框设…

【HTML】SVG实现炫酷的描边动画

前沿 今天闲来无事&#xff0c;看到Antfu大佬的个性签名&#xff0c;觉得还是非常炫酷的&#xff0c;于是也想要搞一个自己的个性签名用来装饰自己的门面&#xff0c;不过由于手写的签名太丑了&#xff0c;遂放弃。于是尝试理解原理&#xff0c;深入研究此等密法&#xff0c;终…

ChatGPT调教指南 | 咒语指南 | Prompts提示词教程(三)

在人工智能成为我们日常互动中无处不在的一部分的时代&#xff0c;与大型语言模型(llm)有效沟通的能力是无价的。“良好提示的26条原则”为优化与这些复杂系统的交互提供了全面的指导。本指南证明了人类和人工智能之间的微妙关系&#xff0c;强调清晰、专一和结构化的沟通方法。…

邮件系统国产化,U-Mail助推企业数字化建设

在当今数字化时代&#xff0c;企业管理和办公效率的提升已成为企业发展的关键。随着信息技术的迅速发展&#xff0c;邮件系统成为许多企业提高办公效率和管理水平的重要工具。然而&#xff0c;长期以来&#xff0c;国内企业在邮件系统方面主要依赖于国外产品&#xff0c;这不仅…

多条件查询展开收起

顶部筛选条件很多时&#xff0c;就需要对赛选条件进行分组&#xff0c;每组都要有展开收起&#xff0c;根据页面自定义&#xff0c;还需要显示收起查询中有几条查询中的内容 思路&#xff1a; 封装一个组件&#xff0c;利用插槽自定义查询条件和分组 // 子组件 <script se…

简单版 git快速上手和使用clone项目 新建/切换分支 提交修改

Git是一个广泛使用的版本控制系统&#xff0c;允许多个用户跟踪文件的更改&#xff0c;并协作开发项目。 首先确定自己电脑已经安装了git&#xff0c;具体安装步骤请查找教程&#xff0c;应该不难。 以windows电脑为例&#xff0c;安装完后在搜索栏搜索git会出现 先解释一下这…

git使用过的命令记录

目录 git add .git commit --amendgit push -f origin HEAD:mastergit checkout .git stash想把某个pr的修改应用到本地git pull 将远程仓库的最新代码更新到本地git 撤销&#xff0c;放弃本地修改参考文档 git add . 将本地修改提交到暂存区 git commit --amend 如果本地有…

【leetcode】记忆化搜索

记忆化搜索 一、斐波那契数1、题目描述2、代码3、解析 二、不同路径1、题目描述2、代码3、解析 三、最长递增子序列1、题目描述2、代码3、解析 四、猜数字大小II1、题目描述2、代码3、解析 五、矩阵中的最长递增路径1、题目描述2、代码3、解析 一、斐波那契数 1、题目描述 le…

Oracle 基础表管理(Heap-Organized Table Management)

表是数据库中负责数据存储的对象&#xff0c;在RDBMS中&#xff0c;数据以行、列的形式存储在表中。Oracle中表有很多种类型&#xff0c;最基础且应用最常用的类型就是堆表&#xff08;Heap-Organized Table&#xff09;&#xff0c;本文列举了Oracle堆表的常用管理操作。 一、…
推荐文章