当前位置: 首页 > news >正文

Unity 网格模型及优化

一个模型中可以包含很多网格,一个模型可以由多个网格组成。在Unity3D中一个网格可以由多个子网格(Sub-Mesh)组成。

在渲染引擎的时候,每个子网格都要匹配一个材质球来做渲染,实际上一个子网格本身就是一个个普通的模型,它由很多个三角形构成,也需要材质球支持达成渲染。

为什么要有子网格?

美术人员在制作3D模型时,为什么不打网格编成一个,而要制作成多个子网格?

  1. 模型中的一部分网格用一种材质球来表现效果,另一部分用另一种。因为一个网格只能对应一个材质球所以要拆开。
  2. 模型中的莫部分贴图在众多模型中共同时使用的频率比较高,为了不重复制作以减少重复劳动,原本可以作为一个整体的模型会将公共材质部分单独拆分出来让一部分模型使用同一个材质球。
  3. 制作动画时,由于动画过于复杂,如果使用同一个模型去表现,则骨骼的数量就会成倍的增加,为了更好的表现动画,也为了能降低骨骼的使用数量,要拆分出来一部分模型,让它们单独成为模型动画的一部分。

从以上看多个子网格比单个网格要灵活的多,但它也有缺点,由于每个子网格都有材质球,导致子网格越多,drawcall 也越多。

子网格功能虽然强大,但也需要注意性能开销。 

动态合并3D模型

我们知道每个网格模型都需要有一个材质球支持,导致每个模型都会产生一个drawcall,过多的drawcall,CPU会忙于发送状态数据给GPU,GPU大多数时间处于等待状态,这将导致画面帧率下降及强烈的画面卡顿。

实际项目中通常会遇到这样的问题:场景中会有很多物体,人物、建筑、路标、景观、树木、石头、碎块、花草等等,有的物体可能不只有一个材质球,相同物体共用一个,当然不同的物体也可能使用相同的材质球,这些物体如果不做任何优化处理,就会产生很多drawcall。

合并3D模型的主要目的就是减少drawcall,通过减少材质球的提交次数来完成优化,简单的说就是大拥有相同材质球的模型合并成一个模型和一个材质球,从而减少向GPU提交的drawcall数量,让GPU并行处理数据时更快更顺畅。

在Unity中分为动态合批和静态合批两种,使用它们的前提条件是模型物体必须具有相同的材质球,除了这个必要条件外还有其他条件。

动态批处理

开启动态批处理时,Unity会将场景中的某些物体自动批处理成为同一个drawcall,需要满足:

  1. 顶点数目要少于900个顶点网格。如果你的着色器使用顶点坐标、法线和单独的UV,那么顶点个数就要在300以内,如果着色器使用顶点坐标、法线、UV0、UV1和切线,则顶点要在180个内的网格。
  2. 两个物体的缩放单位要相同,比如A(1,1,1) B(1,1,2)就没法合批了
  3. 使用相同材质球
  4. 多管线(Pipeline)着色器会中断动态合批,支持多个灯光的前置渲染,它们增加了多个渲染通道,因此无法批处理。旧系统中的延迟渲染路径(灯光前置通道)关闭了动态批处理,因为它需要绘制物体两次。多有多个Pass的着色器增加了渲染管道,不会被动态批处理。

从上面看动态批处理的条件非常苛刻,真实的项目里很多模型时不符合动态批处理要求的。另外动态批处理要消耗CPU将所有物体的顶点转换到世界空间,合并网格也会带来开销。一味的减小drawcall并不是万能的,开销取决于很多因素,drawcall的开销主要是由图形API的调用造成的,如果节省的开销小于准备工作的开销,就得不偿失。例如,一个主机设备或流行的API(Apple Metal这样的),drawcall的开销通常很低,那么对于它来说动态批处理就没有什么优势了。

静态批处理

静态批处理允许引擎离线的情况下进行模型合并的批处理,减少drawcall。无论模型有多大,只要使用同一个材质球都会被静态批处理优化。它通常比动态批处理更有用(因为不需要实时转换顶点来消耗CPU),缺点是消耗了更多的内存。

Unity中需要对物体设置静态标记,也就是不能移动,缩放,旋转的物体。

如果一些物体之前共用一个模型,那么unity会复制这些物体的模型用来合并,所以使内存增大。个人觉得使用内存换CPU是值得的,然而如果用100GB的内存换千分之一的CPU效率那就不值得了。

静态批处理的具体流程是,将所有静态标记的物体放入世界空间->通过材质球分类标准将它们分别合并->构建成一个大的顶点集合和索引缓存。从而减少drawcall。

从技术上来说,静态批处理并没有节省3D API drawcall的数量,但它能减少因3D API之间的状态改变导致的消耗。大多数平台上,批处理限制在64000个顶点和64000个索引内(OpenGLES上为48000个,MacOS上为32000个),所以如果批处理过多,需要取消一些静态标记。

自己编写合并3D模型程序

Unity3D中:

  • Mesh类有一个CombineMeshes的接口,提供了合并入口。
  • MeshFilter类,是承载数据类。
  • MeshRenderer类,是绘制网格的类

在使用之前我们还需要了解

MeshFilter和MeshRenderer中的mesh与shareMesh、material及shareMaterial的区别

mesh和material都是实例型的变量,对mesh和material执行任何操作都是额外复制一份后重新赋值,即使只是get操作,同样也会执行复制操作。而就是说,对mesh和material进行操作后,就会变成另一个实例。sharedMesh和shareMaterial与前面的两个变量不同,它们是共享型的。多个模型可以共同指定一个sharedMesh和sharedMaterial,当年修改了shareMesh或sharedMaterial里面的参数,指向同一个sharedMaterial和sharedMesh的多个模型就会同时改变效果。

materials和sharedMaterialsd的区别

materials是实例型,sharedMaterials是共享型,两个都是数组。material和sharedMaterial只针对主网格。而就是说material等于materials[0],sharedMaterial等于sharedMaterial[0]。

网格、MeshFilter、MeshRenderer的关系

网格时数据资源,它可以有自己的资源文件,通常时.FBX文件。网格里存储了顶点、UV、顶点颜色、三角形、切线、法线、骨骼、骨骼权重等提供渲染所必要的数据。

MeshFilter是一个承载网格数据的类,网格被实例化后存储在MeshFilter类中。MeshFilter包含两种类型,即实例型(mesh)和共享型变量(sharedMesh)。

MeshRenderer具有渲染功能,它会提取MeshFilter中的网格数据,结合自身的materials或sharedMaterials进行渲染。

Mesh.CombineInstance合并数据实例类

合并时需要为每个将要合并的网格创建一个CombineInstance实例,并往里放入mesh、subMesh的索引,lightmap的缩放和偏移,realtimeLightmap的缩放和偏移,以及世界坐标矩阵。它承载了所有需要需要合并的数据。        

现在我们掌握了关于合并网格的理论知识我们来实现以下,这里我从Unity 商店下载了一个模型,我将角色手中的 剑和盾牌进行了合并,并生成了一个新的GameObject 效果如下:

using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;public class CombineTest : MonoBehaviour
{public List<MeshFilter> combineMeshFilers = new List<MeshFilter>();// Start is called before the first frame updatevoid Start(){CreateCombineModel();}private void CreateCombineModel(){// 提取网格所需的资源List<Material> materials = new List<Material>();CombineInstance[] combines = new CombineInstance[combineMeshFilers.Count];for (int i = 0; i < combineMeshFilers.Count; i++){CombineInstance tmpInstance = new CombineInstance();MeshFilter tmpFilter = combineMeshFilers[i];tmpInstance.mesh = tmpFilter.sharedMesh;tmpInstance.transform = tmpFilter.transform.localToWorldMatrix;combines[i] = tmpInstance;MeshRenderer renderer = tmpFilter.transform.GetComponent<MeshRenderer>();for (int j = 0; j < renderer.sharedMaterials.Length; j++){if (!materials.Contains(renderer.sharedMaterials[j]))materials.Add(renderer.sharedMaterials[j]);}}// 将所有网格合并成一个新的网格Mesh mesh = new Mesh();MeshFilter combineFilter = transform.AddComponent<MeshFilter>();MeshRenderer combineRenderer = transform.AddComponent<MeshRenderer>();mesh.CombineMeshes(combines);combineFilter.mesh = mesh;combineRenderer.materials = materials.ToArray();}
}

相关文章:

Unity 网格模型及优化

一个模型中可以包含很多网格&#xff0c;一个模型可以由多个网格组成。在Unity3D中一个网格可以由多个子网格&#xff08;Sub-Mesh)组成。 在渲染引擎的时候&#xff0c;每个子网格都要匹配一个材质球来做渲染&#xff0c;实际上一个子网格本身就是一个个普通的模型&#xff0…...

离线 快速搭建 docker docker-compose k8s 环境

所需资源 sealos_5.0.1_linux_arm64.tar.gzkubernetes.tar等docker-compose-linux-aarch64 离线安装sealos&#xff0c;用于安装k8sdocker 首先安装sealos工具 tar zxvf sealos_5.0.1_linux_arm64.tar.gz sealos && chmod x sealos && mv sealos /usr/bin*…...

Excel根据条件动态索引单元格范围

假如我是一个老板&#xff0c;下面有数不胜数的员工&#xff0c;我要检查他们每周的工作产出&#xff0c;列一个排行榜&#xff0c;提高员工积极性&#xff0c;毕竟多劳多得嘛。 每天去手动统计&#xff0c;未免显得不太聪明&#xff0c;我们可以利用公式来解决这个问题。 我们…...

【计算机网络五】HTTP协议!网站运行的奥秘!

目录 HTTP协议 1.HTTP是什么&#xff1f; 2.Fiddler抓包查看HTTP协议格式 3.HTTP请求 4.HTTP响应 HTTP协议 1.HTTP是什么&#xff1f; HTTP ( 全称为 " 超文本传输协议 ") 诞生与 1991 年 . 目前已经发展为最主流使用的一种应用层协议 . HTTP 的前几个版本…...

开源模型应用落地-qwen模型小试-Qwen2.5-7B-Instruct-tool usage入门-Qwen-Agent深入学习(四)

一、前言 Qwen-Agent 是一个利用开源语言模型Qwen的工具使用、规划和记忆功能的框架。其模块化设计允许开发人员创建具有特定功能的定制代理,为各种应用程序提供了坚实的基础。同时,开发者可以利用 Qwen-Agent 的原子组件构建智能代理,以理解和响应用户查询。 本篇将换一种方…...

stream学习

Stream流 定义 Steam流&#xff0c;用于操作集合或者数组中的数据&#xff0c;大量结合了Lamda表达式的语法风格&#xff0c;代码简洁。 重点&#xff1a; 流只能收集一次 ​ 获取Stream流 Stream流要与数据源建立连接。 1.list ​ 直接调用steam()即可 // list List<Stri…...

【数据结构】实验二 单链表的基本操作

一、实验目的 掌握线性表的链式存储结构的表示和实现方法。 掌握链表基本操作的算法实现&#xff0c;以及对相应算法的性能分析。 二、实验内容 1&#xff09;根据输入的一系列整数&#xff0c;以0标志结束&#xff0c;用头插法建立单链表&#xff0c;并输出单链表中各元素…...

SQL 分组查询中的非聚合列要求及实例解析

在 SQL 查询中&#xff0c;当我们对数据进行分组时&#xff0c;通常会用到 GROUP BY 子句。SQL 标准要求&#xff1a;所有非聚合列&#xff08;即没有使用聚合函数的列&#xff09;都必须出现在 GROUP BY 子句中&#xff0c;或者是聚合函数的结果。这篇文章通过一个实例来说明这…...

Unity中实现战斗帧同步的高级技术

一、帧同步的基本原理 帧同步&#xff08;Frame Synchronization&#xff09;在网络游戏中指的是在每一帧上保证所有玩家所看到的游戏状态一致&#xff0c;而不是每个玩家单独计算自己的状态。实现帧同步通常需要每个客户端仅发送用户输入到服务器&#xff0c;并由服务器进行全…...

Qt 正则表达式提取文件中的 USB 设备 ID

Qt 正则表达式提取文件中的 USB 设备 ID flyfish 文档内容 Bus: 001 Device: 001 Description: 1d6b:0002 Linux Foundation 2.0 root hub Bus: 002 Device: 003 Description: 0e0f:0002 , Inc. USB Hub Bus: 002 Device: 002 Description: 0e0f:0003 , Inc. Mouse Bus: 002…...

使用 Python 和 OpenCV 实现摄像头人脸检测并截图

概述 在现代应用中&#xff0c;人脸检测是一项非常重要的技术&#xff0c;广泛应用于安全监控、身份验证等领域。本文将详细介绍如何使用 Python 和 OpenCV 库实现摄像头人脸检测并截图&#xff0c;并通过具体的代码示例来展示整个过程。 环境准备 在开始编写代码之前&#…...

【二叉搜素树】——LeetCode二叉树问题集锦:6个实用题目和解题思路

文章目录 计算布尔二叉树的值求根节点到叶节点的数字之和二叉树剪枝验证二叉搜索树二叉搜索树中第K小的元素二叉树的所有路径 计算布尔二叉树的值 解题思路&#xff1a; 这是一个二叉树的布尔评估问题。树的每个节点包含一个值&#xff0c;其中叶子节点值为 0 或 1&#xff0…...

【计算机视觉】FusionGAN

1. FusionGAN论文阅读 abreheret/FusionGAN: Pytorch implementation of "Generating a Fusion Image: One’s Identity and Another’s Shape" 1.1. WHY 在现实世界中,将对象或人物转换为期望的形状是一种常用技术,但现有的图像翻译方法在处理身份和形状时存在…...

问:SQL优化,七条实践总结?

SQL语句优化是数据库性能调优的重要部分&#xff0c;通过合理的优化可以显著提升查询速度和系统性能。文章总结几种常见SQL语句优化方法。 1. 优化Where子句的顺序 原则&#xff1a;表之间的连接条件应写在其他Where条件之前&#xff0c;能够过滤掉最大数量记录的条件应优先写…...

unity单例模式的不同声明(待完善

总结&#xff1a; 这段代码实现了一个泛型单例模式&#xff08;Singleton Pattern&#xff09;&#xff0c;用于确保某个类&#xff08;由泛型参数 T 指定&#xff09;在整个应用程序中只有一个实例&#xff0c;并且在第一次访问时才创建该实例。该模式保证了该实例的全局唯一…...

大模型在蓝鲸运维体系应用——蓝鲸运维开发智能助手

本文来自腾讯蓝鲸智云社区用户: CanWay 背景 1、运维转型背景 蓝鲸平台从诞生之初&#xff0c;就一直在不遗余力地推动运维转型&#xff0c;让运维团队可以通过一体化PaaS平台&#xff0c;快速编写脚本&#xff0c;编排流程&#xff0c;开发运维工具&#xff0c;从被动地提供…...

vue2,vue3响应式的理解

vue2的话主要使用的是defineProperty对已有属性添加get,set,从而完成对数据的响应式控制&#xff0c;但每次需要for循环对属性进行遍历 function DefineReactive(target, key, value) {//存在多层嵌套的objectObserver(value);Object.defineReactive(target, key, {get() {retu…...

群控系统服务端开发模式-应用开发-前端退出功能

我们从未登录一直到退出&#xff0c;现在已经登录到操作&#xff0c;现在完成退出。退出有两种情况下会退出&#xff1a;第一种情况下是手动点击退出按钮&#xff0c;第二种情况下是登录过期时间到了自动退出的。 一、手动退出 因退出及个人信息页面都在公有页面&#xff0c;所…...

Web入门

Spring 官网&#xff1a;Spring | Home Spring是一个开源的Java企业级应用开发框架。Spring的主要目的是使Java EE&#xff08;Java Platform, Enterprise Edition&#xff09;开发更容易&#xff0c;并且通过提供一系列丰富的库和接口来促进良好编程实践&#xff0c;是…...

基于SpringBoot网上超市的设计与实现录像

基于SpringBoot网上超市的设计与实现录像 SpringBoot网上超市的设计与实现录像...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销&#xff0c;平衡网络负载&#xff0c;延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止

<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet&#xff1a; https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...

自然语言处理——Transformer

自然语言处理——Transformer 自注意力机制多头注意力机制Transformer 虽然循环神经网络可以对具有序列特性的数据非常有效&#xff0c;它能挖掘数据中的时序信息以及语义信息&#xff0c;但是它有一个很大的缺陷——很难并行化。 我们可以考虑用CNN来替代RNN&#xff0c;但是…...

MySQL中【正则表达式】用法

MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现&#xff08;两者等价&#xff09;&#xff0c;用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例&#xff1a; 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...

【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统

目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索&#xff08;基于物理空间 广播范围&#xff09;2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

CRMEB 中 PHP 短信扩展开发:涵盖一号通、阿里云、腾讯云、创蓝

目前已有一号通短信、阿里云短信、腾讯云短信扩展 扩展入口文件 文件目录 crmeb\services\sms\Sms.php 默认驱动类型为&#xff1a;一号通 namespace crmeb\services\sms;use crmeb\basic\BaseManager; use crmeb\services\AccessTokenServeService; use crmeb\services\sms\…...

【网络安全】开源系统getshell漏洞挖掘

审计过程&#xff1a; 在入口文件admin/index.php中&#xff1a; 用户可以通过m,c,a等参数控制加载的文件和方法&#xff0c;在app/system/entrance.php中存在重点代码&#xff1a; 当M_TYPE system并且M_MODULE include时&#xff0c;会设置常量PATH_OWN_FILE为PATH_APP.M_T…...

Axure零基础跟我学:展开与收回

亲爱的小伙伴,如有帮助请订阅专栏!跟着老师每课一练,系统学习Axure交互设计课程! Axure产品经理精品视频课https://edu.csdn.net/course/detail/40420 课程主题:Axure菜单展开与收回 课程视频:...

2025 后端自学UNIAPP【项目实战:旅游项目】7、景点详情页面【完结】

1、获取景点详情的请求【my_api.js】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口&#xff08;适配服务端返回 Token&#xff09; export const login async (code, avatar) > {const res await http(/login/getWXSessionKey, {code,avatar}); };//…...