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制作的…...
React19源码系列之 事件插件系统
事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...
【论文笔记】若干矿井粉尘检测算法概述
总的来说,传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度,通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...
学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1
每日一言 生活的美好,总是藏在那些你咬牙坚持的日子里。 硬件:OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写,"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...
2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面
代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口(适配服务端返回 Token) export const login async (code, avatar) > {const res await http…...
Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)
引言:为什么 Eureka 依然是存量系统的核心? 尽管 Nacos 等新注册中心崛起,但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制,是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...
微服务商城-商品微服务
数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...
unix/linux,sudo,其发展历程详细时间线、由来、历史背景
sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...
深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南
🚀 C extern 关键字深度解析:跨文件编程的终极指南 📅 更新时间:2025年6月5日 🏷️ 标签:C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言🔥一、extern 是什么?&…...
mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包
文章目录 现象:mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时,可能是因为以下几个原因:1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
