当前位置: 首页 > 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网上超市的设计与实现录像...

别再让一条宽带拖慢整个公司!手把手教你用H3C防火墙配置双WAN口负载均衡(附HCL模拟器配置)

中小企业网络优化实战&#xff1a;H3C防火墙双WAN负载均衡配置指南 当视频会议频繁卡顿、文件传输速度像蜗牛爬行时&#xff0c;单条宽带已成为制约企业效率的瓶颈。对于50-200人规模的中小企业&#xff0c;双WAN负载均衡技术能以极低成本实现带宽翻倍&#xff0c;本文将用一台…...

YOLO26优化:TIP2026 FourierSR | FourierSR引入YOLO C3k2:解决感受野局限,实现高效全局特征交互

💡💡💡现有 YOLO C3k2 模块主要基于卷积与跨阶段部分连接,虽能平衡计算与精度,但仍存在以下问题: 感受野受限:堆叠的小核卷积(如 33)感受野有限,难以捕获全局上下文,对尺度变化大或远距离依赖的目标(如小目标、遮挡目标)特征提取能力不足。 特征混合效率低:通…...

不用真飞机!用BetaFlight遥控器玩转PX4无人机仿真:QGC配置与手动飞行入门

用BetaFlight遥控器解锁PX4仿真飞行&#xff1a;从硬件配置到手动操控全指南 当大多数PX4开发者还在用键盘和鼠标操作仿真无人机时&#xff0c;一群来自穿越机社区的玩家已经找到了更硬核的玩法——用真实的BetaFlight遥控器直接控制Gazebo里的虚拟飞行器。这种将硬件与仿真环境…...

《利红AI企业级应用新标准等级体系》正式发布

各相关单位及合作伙伴&#xff1a; 为助力企业推动人工智能技术在实体经济中的科学落地&#xff0c;经公司研究决定&#xff0c;现正式发布《利红AI企业级应用新标准等级体系》&#xff08;以下简称"本标准"&#xff09;。现将有关事项公告如下&#xff1a; 一、新…...

量子同态加密:理论与实践的突破

1. 量子同态加密&#xff1a;理论与实践的桥梁量子同态加密&#xff08;Quantum Homomorphic Encryption, QHE&#xff09;是密码学领域的一项突破性技术&#xff0c;它允许在加密的量子数据上直接执行任意量子计算&#xff0c;而无需事先解密。这项技术对于构建真正隐私保护的…...

仅限内部团队使用的Perplexity行业扫描协议(附可复用Prompt模板库+信源可信度评分表v2.3)

更多请点击&#xff1a; https://codechina.net 第一章&#xff1a;Perplexity行业扫描协议的定位与适用边界 Perplexity行业扫描协议&#xff08;Perplexity Industry Scanning Protocol&#xff0c;简称PISP&#xff09;并非通用型AI评估框架&#xff0c;而是一套面向垂直领…...

深度拆解Pulse算法三大剪枝策略:如何让你的路径搜索快10倍?

深度拆解Pulse算法三大剪枝策略&#xff1a;如何让你的路径搜索快10倍&#xff1f; 在解决复杂的组合优化问题时&#xff0c;如车辆路径规划&#xff08;VRP&#xff09;或旅行商问题&#xff08;TSP&#xff09;&#xff0c;算法的效率往往决定了实际应用的可行性。Pulse算法作…...

从PyCharm到ArcGIS工具箱:把你的Python地理处理脚本‘打包’成专业工具的保姆级指南

从PyCharm到ArcGIS工具箱&#xff1a;Python地理处理脚本的专业化封装实战 当你在PyCharm中完成了一个完美运行的地理处理脚本&#xff0c;接下来最自然的想法就是让它能被更多非技术同事直接使用。本文将带你跨越开发环境与生产环境的鸿沟&#xff0c;将一个孤立的Python脚本转…...

三分钟带你读懂C++中的排序方式

在 C 中&#xff0c;有多种方式可以用于排序&#xff0c;每种方法都有其适用场景。以下是几种常见的排序方式&#xff1a;1. 使用标准库中的 sort 函数C STL&#xff08;标准模板库&#xff09;提供了 <algorithm> 头文件中的 sort 函数&#xff0c;这是最常用的排序方法…...

PostgreSQL 13.8 子查询优化实战:手把手教你读懂 `pull_up_sublinks` 源码

PostgreSQL 13.8 子查询优化实战&#xff1a;手把手教你读懂 pull_up_sublinks 源码 数据库查询优化器是数据库系统的核心组件之一&#xff0c;它负责将用户提交的SQL语句转换为高效的执行计划。在PostgreSQL中&#xff0c;子查询优化是查询优化的重要环节&#xff0c;而pull_u…...