Unity 场景优化策略
Unity 场景优化策略
GPU instancing
使用GPU Instancing可以将多个网格相同、材质相同、材质属性可以不同的物体合并为一个批次,从而减少Draw Calls的次数。这可以提高性能和渲染效率。
GPU instancing可用于绘制在场景中多次出现的几何体,例如树木或灌木丛。
渲染管线兼容性
| 特征 | 内置渲染管线 | 通用渲染管线 (URP) | 高清渲染管线 (HDRP) | 自定义可编程渲染管线 (SRP) |
|---|---|---|---|---|
| GPU instancing | 是的 | 是 (1) | 是 (1) | 是 (1) |
注意:
- 仅当着色器与 SRP Batcher 不兼容时。
** 设置GPU instancing**
设置很简单只需一步
在默认的材质球下找到Enable GPU Instancing,勾选就可以。

对比效果
没有勾选时:Batches是230左右,Saved By Batching是0

勾选后:Batches是8,Saved By Batching是222左右

使用下文的shader给材质添加随机色后:Batches是4,Saved By Batching是63(这里没有添加阴影Batch会少)

补充:
MaterialPropertyBlock
批处理一般作用与相同的材质。当需要对shader相同材质属性不同的模型批处理时可以用MaterialPropertyBlock。
MaterialPropertyBlock除了在 Renderer.SetPropertyBlock 被使用,还可以在 Graphics.DrawMesh使用。
void Start(){MaterialPropertyBlock material = new MaterialPropertyBlock();material.SetColor("_Color", new Color(Random.Range(0f, 1f), Random.Range(0f, 1f), Random.Range(0f, 1f)));GetComponent<MeshRenderer>().SetPropertyBlock(material);}
这里可以发现,虽然颜色不一样,但是材质球指向的是同一个
** 创建支持 GPU instancing的着色器**
渲染管线兼容性
| 特征 | 内置渲染管线 | 通用渲染管线 (URP) | 高清渲染管线 (HDRP) | 自定义可编程渲染管线 (SRP) |
|---|---|---|---|---|
| 自定义 GPU instancing着色器 | 是的 | 不 | 不 | 不 |
顶点和片元着色器示例
Shader "Custom/SimplestInstancedShader"
{Properties{_Color ("Color", Color) = (1, 1, 1, 1)}SubShader{Tags { "RenderType"="Opaque" }LOD 100Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag//生成实例化变体。它是可选的。#pragma multi_compile_instancing#include "UnityCG.cginc"struct appdata{float4 vertex : POSITION;//在顶点着色器输入/输出结构中定义INSTANCE_ID。UNITY_VERTEX_INPUT_INSTANCE_ID};struct v2f{float4 vertex : SV_POSITION;//使INSTANCE_ID访问片元着色器中的实例化属性。UNITY_VERTEX_INPUT_INSTANCE_ID };//声明名为 的每个实例常量缓冲区的开始UNITY_INSTANCING_BUFFER_START(Props)UNITY_DEFINE_INSTANCED_PROP(float4, _Color)//声明名为 的每个实例常量缓冲区的结尾 UNITY_INSTANCING_BUFFER_END(Props)v2f vert(appdata v){v2f o;//允许顶点着色器函数访问INSTANCE_IDUNITY_SETUP_INSTANCE_ID(v);//将INSTANCE_ID从输入结构复制到顶点着色器中的输出结构。UNITY_TRANSFER_INSTANCE_ID(v, o);o.vertex = UnityObjectToClipPos(v.vertex);return o;}fixed4 frag(v2f i) : SV_Target{//允许片元着色器函数访问INSTANCE_IDUNITY_SETUP_INSTANCE_ID(i);//访问实例化常量缓冲区中的每个实例着色器属性return UNITY_ACCESS_INSTANCED_PROP(Props, _Color);}ENDCG}}
}
静态批处理
它通过将多个静态物体合并成一个批次来减少渲染调用,从而减少CPU和GPU的负载,可以显著减少渲染过程中的Draw Call数量,从而提高性能。
静态批处理适用于那些不会在运行时改变位置、旋转或缩放的物体,例如地形、建筑物等。
渲染管线兼容性
| 特征 | 内置渲染管线 | 通用渲染管线 (URP) | 高清渲染管线 (HDRP) | 自定义可编程渲染管线 (SRP) |
|---|---|---|---|---|
| 静态批处理 | 是的 | 是的 | 是的 | 是的 |
静态批处理的设置
设置也很简单只需两步
-
在ProjectSettings→player→OtherSetting→StaticBatching,勾选
-
在默认的材质球下找到Enable GPU Instancing,勾选就可以。

静态批处理的限制
- 游戏对象处于活动状态且禁止(非禁止对象的会强制禁止)。
- 游戏对象具有MeshFilter组件,并且该组件已启用。
- MeshFilter 组件引用了Mesh
- 网格的顶点数大于 0。
- 该网格尚未与另一个网格合并。
- 游戏对象具有MeshRenderer组件,并且该组件已启用。
- 要批处理在一起的网格,使用相同的顶点属性。例如,Unity 可以对使用顶点位置、顶点法线和一个 UV 的网格进行批处理,但不能对使用顶点位置、顶点法线、UV0、UV1 和顶点切线的网格进行批处理。
效果
Batches是8,Saved By Batching是211

静态批处理的控制
使用StaticBatchingUtility类来控制静态批处理。
using UnityEngine;public class StaticBatchingController : MonoBehaviour
{void Start(){StartStaticBatch();}GameObject[] GetGameObjectsToBatch(){// 返回需要静态批处理的游戏对象数组// 例如:可以通过标签、层级或者其他方式来获取需要静态批处理的游戏对象// 这里只是一个简单示例,实际情况可能需要根据具体需求来获取游戏对象return GameObject.FindGameObjectsWithTag("StaticBatchingObject");}void StartStaticBatch(){// 获取所有需要静态批处理的游戏对象GameObject[] gameObjectsToBatch = GetGameObjectsToBatch();// 执行静态批处理StaticBatchingUtility.Combine(gameObjectsToBatch, this.gameObject);}void StopStaticBatch(){// 禁用静态批处理StaticBatchingUtility.Combine(null, this.gameObject);}
}
动态批处理
通过将运行时动态地将多个静态或动态的游戏对象合并成一个批次,减少渲染调用的数量,提高帧率和性能。
渲染管线兼容性
| 特征 | 内置渲染管线 | 通用渲染管线 (URP) | 高清渲染管线 (HDRP) | 自定义可编程渲染管线 (SRP) |
|---|---|---|---|---|
| 动态批处理 | 是的 | 是的 | 不 | 是的 |
静态批处理的设置
设置也很简单只需一步
在ProjectSettings→player→OtherSetting→DynamicBatching,勾选
动态批处理的限制
- Unity 无法对包含超过 225 个顶点的网格应用动态批处理。这是因为网格的动态批处理每个顶点都有开销。
使用顶点位置、顶点法线和单个 UV,则 Unity 最多可以批处理 225 个顶点。但是,如果着色器使用顶点位置、顶点法线、UV0、UV1 和顶点正切,则 Unity 只能批处理 180 个顶点。 - 如果对象使用不同的材质实例,则 Unity 无法将它们批处理在一起,即使它们本质是使用一个shader。唯一的例外是阴影投射器渲染。
- 带有光照贴图的游戏对象具有额外的渲染器参数。这意味着,如果要对光照映射的游戏对象进行批处理,它们必须指向相同的光照贴图位置。
- Unity 无法将动态批处理完全应用于使用多个pass的shader对象。
- 几乎所有 Unity 着色器都支持多个灯光前向渲染为了实现这一点,他们为每个光源处理一个额外的渲染通道。Unity 仅对第一个渲染通道进行批处理。它无法对额外的每像素光源的绘制调用进行批处理。
效果
Batches是8,Saved By Batching是220左右

手动合并网格
手动将多个网格合并为一个网格,在网格靠得很近且彼此不相对移动的情况下,可以很好地替代,静态批处理和动态批处理。
警告:Unity 无法单独剔除您组合的网格。这意味着,如果组合网格的一部分出现在屏幕上,Unity 会绘制整个组合网格。如果网格是静态的,并且希望 Unity 单独剔除它们,使用静态批处理。
合并网格的设置方法
- 在创作网格时在资源生成工具中。即模型制作阶段将其合并到一起,同时这样处理相同的模型会照成模型体量的变大。
- 在 Unity 中使用 Mesh.CombineMeshes
CombineMeshes的用法
//强制添加组件
[RequireComponent(typeof(MeshFilter))]
[RequireComponent(typeof(MeshRenderer))]
public class ExampleClass : MonoBehaviour
{void Start(){MeshFilter[] meshFilters = GetComponentsInChildren<MeshFilter>();// CombineInstance 结构体 用于描述要使用 Mesh.CombineMeshes 组合的网格。CombineInstance[] combine = new CombineInstance[meshFilters.Length];int i = 0;while (i < meshFilters.Length){combine[i].mesh = meshFilters[i].sharedMesh;combine[i].transform = meshFilters[i].transform.localToWorldMatrix;meshFilters[i].gameObject.SetActive(false);i++;}Mesh mesh = new Mesh();mesh.CombineMeshes(combine);transform.GetComponent<MeshFilter>().sharedMesh = mesh;transform.gameObject.SetActive(true);}
}
| CombineInstance 字段 | 说明 |
|---|---|
| lightmapScaleOffset | 应用于网格的烘焙光照贴图UV比例和偏移量。 |
| mesh | 要组合的网格。 |
| realtimeLightmapScaleOffset | 应用于网格的实时光照贴图UV比例和偏移。 |
| subMeshIndex | 网格的子网格索引。 |
| transform | 在组合之前要变换网格的矩阵。有关示例,请参阅 Mesh.CombineMeshes。 |
效果
Batches是8,Saved By Batching是0

遮挡剔除
遮挡剔除不说了
频繁使用遮挡剔除可能会导致一些性能问题,特别是在复杂的场景中。因为每次相机移动或场景发生变化时,都需要重新计算遮挡剔除信息,这可能会消耗一定的计算资源。
LOD
Unity中使用LOD(Level of Detail)时,可以根据相机与物体的距离,自动切换不同级别的模型,以提高性能和减少渲染开销。
unityLOD设置方法
-
创建多个不同级别的模型,分别代表远、中、近距离的模型。
-
将这些模型作为同一个游戏对象的子对象,并添加LOD Group组件。
-
在LOD Group组件中设置每个级别的距离和对应的模型。
-
Unity会根据相机与物体的距离自动切换不同级别的模型。

效果
可以与静态批处理和动态批处理结合
Batches是11,Saved By Batching是310左右

层剔除 layerCullDistances
用于指定摄像机在渲染不同图层时的剔除距离。通过设置layerCullDistances,可以控制摄像机在渲染不同图层时的剔除距离,从而提高渲染性能。层剔除和lod类似,也是按距离剔除,不同的是层剔除不会替换
float[] distances = new float[32];//设定32个默认图层
distances[11] = 300;//为第11层设定距离
Camera.mian.layerCullDistances = distances;//将剔除层传递给相机
相关文章:
Unity 场景优化策略
Unity 场景优化策略 GPU instancing 使用GPU Instancing可以将多个网格相同、材质相同、材质属性可以不同的物体合并为一个批次,从而减少Draw Calls的次数。这可以提高性能和渲染效率。 GPU instancing可用于绘制在场景中多次出现的几何体,例如树木或…...
Wireshark在Windows上安装后报错怎么办?
Wireshark是一个非常好的网络抓包分析工具,有了他可以轻松解决网络问题,大家有没有使用过呢? 在生产环境使用过的朋友是否各种windows系统安装时遇到各种问题?比如说缺少某某文件,我们经常的做法是找个DLL放在System32…...
【Proteus仿真】【51单片机】水质监测报警系统设计
文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用Proteus8仿真51单片机控制器,使用按键、LED、蜂鸣器、LCD1602、PCF8591 ADC、PH传感器、浑浊度传感器、DS18B20温度传感器、继电器模块等。 主要功能: 系统运行后&…...
TensorFlow2.0教程3-CNN
` 文章目录 基础CNN网络读取数据卷积层池化层全连接层模型配置模型训练CNN变体网络简单的深度网络添加了其它功能层的深度卷积NIN网络文本卷积基础CNN网络 读取数据 import numpy as np import tensorflow as tf import tensorflow.keras as keras import tensorflow.keras.la…...
flink1.18.0 sql-client报错
报错 Flink SQL> > > select * from t1; [ERROR] Could not execute SQL statement. Reason: java.lang.ClassNotFoundException: org.apache.kafka.clients.consumer.OffsetResetStrategy 解决 注意 一定要重启flink服务 否则还会报错: Flink SQL> select *…...
基于ssm的校园快递物流管理系统(java+jsp+ssm+javabean+mysql+tomcat)
博主24h在线,想要源码文档部署视频直接私聊,9.9拿走! 基于javawebmysql的ssm校园快递物流管理系统(javajspssmjavabeanmysqltomcat) 运行环境: Java≥8、MySQL≥5.7、Tomcat≥8 开发工具: eclipse/idea/myeclipse/s…...
C++:this指针和构造与析构的运用
目录 一,this指针 二,构造函数 三,析构函数 四,析构与构造的调用 一,this指针 首先,我们先观察以下类: #include <iostream> using namespace std; class Date { public: void In…...
通用工作站设计方案 :807-ORI-S3R500 -多路PCIe3.0的单CPU通用工作站
ORI-S3R500 -多路PCIe3.0的单CPU通用工作站 (研华工业计算机IPC-610,IPC940 升级款) 一、机箱功能和技术指标: 系统 系统型号 ORI-SR500 主板支持 EEB(12*13)/CEB(12*10.5)/ATX(12*9.6)/Mi cro ATX 前置硬盘 最大支持2个3.5寸1个2.5寸SATA …...
机器学习写代码时遇到的问题(23.11.9)
AttributeError: module ‘backend_interagg‘ has no attribute ‘FigureCanvas‘ 导包的时候改一下 import matplotlib matplotlib.use(TkAgg) import matplotlib.pyplot as plt UserWarning: Glyph 27425 (\N{CJK UNIFIED IDEOGRAPH-6B21}) missing from current font. …...
C#学习系列之事件
C#学习系列之事件 前言事件发布者和订阅者事件触发和注册事件声明事件订阅事件触发使用 总结 前言 基础学习。 事件 发布者和订阅者 发布者:通知某件事情发生的。 订阅者:对某件事情关注的。 事件触发和注册 触发:事件发生就通知所有关…...
list部分接口模拟实现(c++)
List list简介list基本框架list构造函数list_node结构体的默认构造list类的默认构造 push_back()iteartor迭代器迭代器里面的其他接口const迭代器通过模板参数实现复用operator->() insert()erase()clear()析构函数迭代器区间构造拷贝构造operator() list简介 - list可以在…...
数据结构(C语言) 实验-栈与字符串
删除子串 字符串采用带头结点的链表存储,设计算法函数void delstring(linkstring s, int i,int len) 在字符串s中删除从第i个位置开始,长度为len的子串。 void delstring(linkstring s, int i, int len) {linkstring p,q,r;int cnt 1;p s->next;wh…...
xLua Lua访问C#注意事项(七)
调用成员方法 注意:调用成员方法,第一个参数需要传该对象,建议用冒号语法 loacl camera CS.UnityEngine.GameObject.Find("Main Camera") --冒号语法 camera:GetComponent("Camera") --点语法 camera.GetComponent(camera,"…...
vue3+antv2.x的画布
报错信息: TypeError: Cannot destructure property component of registry_1.shapeMaps[node.shape] as it is undefined. at VueShapeView.renderVueComponent (http://192.168.10.35:9029/node_modules/.vite/deps/antv_x6-vue-shape.js?v49fbfab0:5569:19…...
Docker部署ubuntu1804镜像详细步骤
Docker部署ubuntu1804镜像详细步骤 ubuntu镜像库地址:https://hub.docker.com/_/ubuntu/tags?page1&ordering-name 拉取镜像(默认为最新版本): docker pull ubuntu或,拉取指定版本镜像: docker pull…...
mac 卸载第三方输入法
输入法设置里的移除,并不是真的卸载,点击还是能添加回来 在活动监视器里强制退出此输入法在访达界面使用快捷键 ShiftcommandG在弹出的对话框内输入以下路径(/资源库/Input Methods),再点击下面的前往找到你要卸载的输…...
可观察性在软件测试中的重要性
当今应用生态系统的需求和加速的数字化转型使可观察性成为人们关注的焦点。可观察性提供了对应用程序行为和技术生态系统的深入可见性,并支持更快、更明智的决策。由于缺乏可观察性,软件开发团队倾向于对生产系统行为、潜在性能瓶颈或未来故障场景做出假…...
Delphi TCP服务端监听端口获取客户端RFID网络读卡器上传的刷卡数据
本示例使用设备介绍:液显WIFI无线网络HTTP协议RFID云读卡器可编程实时可控开关TTS语-淘宝网 (taobao.com) unit Unit1;interfaceusesWindows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,Dialogs, ComCtrls, ScktComp, StdCtrls, ScktCom…...
javaSE学习笔记(一)概述、语法
目录 前言 一、概述 1.java语言发展史 2.Java语言版本 3.Java语言平台 4.Java语言特点 5.Java语言跨平台原理-可移植性 6.JRE和JDK的概述 7.JDK的下载和安装 7.1安装的细节 7.2可能出现的问题 7.3验证安装是否成功 8.JDK安装路径下的目录解释 9.path环境变量的作…...
接口开发之使用C#插件Quartz.Net定时执行CMD任务工具
C#制作定时任务工具执行CMD命令 概要准备知识点实现原理thinkphp配置winform执行CMD命令读取ini配置文件定时任务Quartz.Net 完整代码Job.csIniFunc.csForm1.csconfig.ini简易定时任务工具雏形 概要 很多时候写接口上线后还会遇到很多修改,类似JAVA,C#,delphi制作的…...
树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法
树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作,无需更改相机配置。但是,一…...
python/java环境配置
环境变量放一起 python: 1.首先下载Python Python下载地址:Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个,然后自定义,全选 可以把前4个选上 3.环境配置 1)搜高级系统设置 2…...
Objective-C常用命名规范总结
【OC】常用命名规范总结 文章目录 【OC】常用命名规范总结1.类名(Class Name)2.协议名(Protocol Name)3.方法名(Method Name)4.属性名(Property Name)5.局部变量/实例变量(Local / Instance Variables&…...
django filter 统计数量 按属性去重
在Django中,如果你想要根据某个属性对查询集进行去重并统计数量,你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求: 方法1:使用annotate()和Count 假设你有一个模型Item,并且你想…...
最新SpringBoot+SpringCloud+Nacos微服务框架分享
文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的,根据Excel列的需求预估的工时直接打骨折,不要问我为什么,主要…...
SpringCloudGateway 自定义局部过滤器
场景: 将所有请求转化为同一路径请求(方便穿网配置)在请求头内标识原来路径,然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...
Swagger和OpenApi的前世今生
Swagger与OpenAPI的关系演进是API标准化进程中的重要篇章,二者共同塑造了现代RESTful API的开发范式。 本期就扒一扒其技术演进的关键节点与核心逻辑: 🔄 一、起源与初创期:Swagger的诞生(2010-2014) 核心…...
BLEU评分:机器翻译质量评估的黄金标准
BLEU评分:机器翻译质量评估的黄金标准 1. 引言 在自然语言处理(NLP)领域,衡量一个机器翻译模型的性能至关重要。BLEU (Bilingual Evaluation Understudy) 作为一种自动化评估指标,自2002年由IBM的Kishore Papineni等人提出以来,…...
AI语音助手的Python实现
引言 语音助手(如小爱同学、Siri)通过语音识别、自然语言处理(NLP)和语音合成技术,为用户提供直观、高效的交互体验。随着人工智能的普及,Python开发者可以利用开源库和AI模型,快速构建自定义语音助手。本文由浅入深,详细介绍如何使用Python开发AI语音助手,涵盖基础功…...
CSS3相关知识点
CSS3相关知识点 CSS3私有前缀私有前缀私有前缀存在的意义常见浏览器的私有前缀 CSS3基本语法CSS3 新增长度单位CSS3 新增颜色设置方式CSS3 新增选择器CSS3 新增盒模型相关属性box-sizing 怪异盒模型resize调整盒子大小box-shadow 盒子阴影opacity 不透明度 CSS3 新增背景属性ba…...
