Unity优化篇之DrawCall
当然可以!以下是完整、详尽、可发布的博客文章,专注讲解 Unity 的静态合批与动态合批机制,并详细列出它们对 Shader 的要求和所有限制条件。文章结构清晰、技术深度足够,适合发布在 CSDN、掘金、知乎等技术平台。
urp默认隐藏动态合批,需要再这边开启动态合批的选项
🎯 Unity 静态合批 & 动态合批完全解析:原理、限制与实战优化
Unity 渲染优化的第一课,必须懂的就是 Draw Call 合批机制。本文聚焦 Unity 中的 静态合批(Static Batching) 和 动态合批(Dynamic Batching),从底层原理到 Shader 限制、失败原因、调试方法,带你一文吃透。
🧱 什么是 Draw Call 与合批?
在 Unity 中,每渲染一个物体,CPU 就会向 GPU 发送一个 Draw Call(绘制调用)。Draw Call 多意味着 CPU 压力大,可能引起帧率下降,特别是在移动端和 WebGL 平台。
Unity 为了优化性能,会尝试自动将多个渲染调用合并为一次 Draw Call,这就是“合批(Batching)”。
🟩 一、静态合批(Static Batching)
✅ 原理
静态合批是 Unity 在构建时将多个静态物体的网格数据打包成一个或多个大网格,运行时作为一个整体进行渲染,显著减少 Draw Call。
✅ 启用方式
- 选中 GameObject
- 在 Inspector 中勾选
Static
(或勾选 Static →Batching Static
) - Unity 构建时会对这些对象进行合并
✅ 条件汇总
条件 | 是否必需 | 说明 |
---|---|---|
勾选 Static 标志 | ✅ | 必须设置为 Static |
使用相同材质实例 | ✅ | 材质必须引用同一个 Material 对象 |
使用 MeshRenderer | ✅ | 不支持 SkinnedMeshRenderer |
Shader 必须兼容 | ✅ | 见下文 Shader 限制 |
不使用 MaterialPropertyBlock | ✅ | 会创建独立材质实例,破坏合批 |
⚠️ Shader 限制(静态合批)
静态合批的核心规则是:所有被合批的物体不再是“独立对象”,而是被合并成一个大网格。
所以 Shader 不允许访问对象独有的属性。
❌ 以下 Shader 写法会导致合批失败:
// 错误示例:访问对象唯一矩阵
float3 worldPos = mul(_Object2World, v.vertex).xyz;
✅ 推荐用法:
// 推荐写法:使用 Unity 内置宏
float4 clipPos = UnityObjectToClipPos(v.vertex);
❌ 禁用功能列表(会导致分批):
Shader 特性 | 说明 |
---|---|
_Object2World , _World2Object | 对象被合并后,不存在单独变换矩阵 |
GrabPass / 多 Pass Shader | 每个 Pass 是独立 Draw Call |
Shader Keyword 不一致 | _EMISSION , _NORMALMAP 等开关变化会拆分 Shader 变体 |
使用 MaterialPropertyBlock 修改参数 | 会使每个物体拥有独立材质实例,合批失败 |
💡 适用场景
- 城市建筑、地形、房屋、墙体等不会移动/旋转/缩放的对象
- 静态 UI 元素(如背景装饰)配合 SpriteAtlas 合批
🟨 二、动态合批(Dynamic Batching)
✅ 原理
动态合批是在运行时由 Unity 动态将多个小型对象的顶点数据合并成一个临时网格,从而减少 Draw Call。
Unity 每帧会重新组合这些物体的网格,虽然提升了绘制效率,但也会带来一定的 CPU 合批开销。
✅ 启用方式
Project Settings > Player > Other Settings
- ✅ 勾选
Dynamic Batching
(⚠️ 在 URP 中需在 URP Asset 勾选)
✅ 条件汇总
条件 | 是否必需 | 说明 |
---|---|---|
使用相同材质实例 | ✅ | 必须是同一个 Material 对象 |
每个 Mesh 顶点数 ≤ 300 | ✅ | 官方限制,超过即失败 |
使用 MeshRenderer | ✅ | 不支持 SkinnedMeshRenderer |
未启用 GPU Instancing | ✅ | Instancing 和动态合批互斥 |
Shader 结构必须简单 | ✅ | 顶点函数不能太复杂,不能用动画偏移 |
缩放需一致或接近 | ⚠️ | 非 uniform scale 可能破坏合批(如 X:2 Y:1 Z:1) |
⚠️ Shader 限制(动态合批)
与静态合批相比,动态合批对 Shader 要求更苛刻,因为它需要 CPU 快速合并多个对象的数据。
❌ 以下 Shader 特性将阻止动态合批:
特性 | 说明 |
---|---|
顶点函数复杂 | 含有顶点动画、扭曲、动态偏移等逻辑 |
非常量矩阵 | 顶点变换使用不确定变量会中断合批 |
使用不同 Shader Keyword | 会产生不同 Shader 变体 |
材质不同 | 即使 Shader 相同,材质参数不同也会失败 |
GrabPass、多 Pass Shader | 强制产生多个 Draw Call,无法合批 |
🧪 示例场景
- 掉落的金币、弹药、碎片等小物体
- 小型动态粒子替代物(如火花、树叶)
❌ 合批失败的常见原因汇总
原因 | 静态合批 | 动态合批 | 说明 |
---|---|---|---|
材质不同 | ❌ | ❌ | 不同材质一定不能合批 |
Shader Keyword 不一致 | ❌ | ❌ | 比如一个开启 _EMISSION ,另一个关闭 |
使用 MaterialPropertyBlock 设置属性 | ❌ | ❌ | 会实例化材质,打断合批 |
Shader 使用对象独立数据(如 _Object2World) | ❌ | ✅ | 静态合批合并后没有对象矩阵 |
使用复杂顶点动画 | ✅ | ❌ | 动态合批的顶点函数必须简单 |
Mesh 顶点数 > 300 | ✅ | ❌ | 动态合批失败,静态合批不限 |
使用 SkinnedMeshRenderer | ❌ | ❌ | 这类 Renderer 本身无法合批 |
非等比缩放(如 X=1.5 Y=1 Z=0.8) | ✅ | ⚠️ | 有概率影响动态合批稳定性 |
🛠️ 如何验证合批是否成功?
🔧 使用 Frame Debugger(首选)
-
打开路径:
Window > Analysis > Frame Debugger
-
点击左上角
Enable
-
在 Draw Call 列表中查找是否有:
Batched: Static
Batched: Dynamic
-
点击每个 Batch 可查看合批的对象和材质
🔧 使用 Profiler
-
打开:
Window > Analysis > Profiler
-
查看 Rendering 模块中的:
- Draw Calls(总绘制次数)
- Batches(实际提交的批次数)
✅ 实战优化建议
优化点 | 原因 |
---|---|
大量静止物体 → 使用静态合批 | 提升性能、减少运行时消耗 |
小物体顶点数 ≤ 300 → 可用动态合批 | 控制模型复杂度 |
统一使用共享材质 | 避免因材质不同导致分批 |
避免频繁使用 MaterialPropertyBlock | 会实例化材质、拆批 |
使用 UnityObjectToClipPos 替代 _Object2World | 保证静态合批兼容 |
用 Frame Debugger 验证结果 | 直观查看合批是否成功 |
📌 总结对比表:静态合批 vs 动态合批
项目 | 静态合批 | 动态合批 |
---|---|---|
触发方式 | 构建时 | 运行时 |
是否勾选 Static | ✅ 必须 | ❌ 不需要 |
Mesh 顶点限制 | ❌ 无限制 | ✅ ≤ 300 |
运行时性能开销 | 极低 | 较高(每帧打包) |
适用对象 | 静止对象 | 小动态物体 |
材质要求 | 同材质实例 | 同材质实例 |
Shader 要求 | 不能访问对象唯一数据 | 必须简单、轻量 |
📣 结语
Unity 提供的静态合批和动态合批,是开发者提升渲染性能最基本、也最有效的优化手段之一。理解它们的原理、限制与触发机制,可以帮助你从源头降低 Draw Call 数量,让你的游戏在中低端设备上依旧运行流畅。
开发不是一味堆特效,而是用合适的方式,做足够的表现。
相关文章:

Unity优化篇之DrawCall
当然可以!以下是完整、详尽、可发布的博客文章,专注讲解 Unity 的静态合批与动态合批机制,并详细列出它们对 Shader 的要求和所有限制条件。文章结构清晰、技术深度足够,适合发布在 CSDN、掘金、知乎等技术平台。 urp默认隐藏动态…...

SpringCloud学习笔记-2
说明:来源于网络,如有侵权请联系我删除 1.提问:如果注册中心宕机,远程调用还能成功吗 答:当微服务发起请求时,会向注册中心请求所有的微服务地址,然后在向指定的微服务地址发起请求。在设计实…...
C++.OpenGL (9/64)复习(Review)
复习(Review) 核心概念快速回顾 #mermaid-svg-MMSQf7gXQlHqiqfM {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-MMSQf7gXQlHqiqfM .error-icon{fill:#552222;}#mermaid-svg-MMSQf7gXQlHqiqfM .error-text{fill:#…...
Spring Boot-面试题(52)
摘要: 1、通俗易懂,适合小白 2、仅做面试复习用,部分来源网络,博文免费,知识无价,侵权请联系! 1. 什么是 Spring Boot 框架? Spring Boot 是基于 Spring 框架的快速开发框架&#…...

从混乱到秩序:探索管理系统如何彻底改变工作流程
内容摘要 在许多企业与组织中,工作流程混乱是阻碍发展的“绊脚石”。员工们常常被繁琐的步骤、模糊的职责和沟通不畅等问题搞得焦头烂额,工作效率低下,错误频发。而与之形成鲜明对比的是,一些引入了先进管理系统的团队࿰…...

最新研究揭示云端大语言模型防护机制的成效与缺陷
一项全面新研究揭露了主流云端大语言模型(LLM)平台安全机制存在重大漏洞与不一致性,对当前人工智能安全基础设施现状敲响警钟。该研究评估了三大领先生成式AI平台的内容过滤和提示注入防御效果,揭示了安全措施在阻止有害内容生成与…...

HTML5+CSS3+JS小实例:具有粘性重力的磨砂玻璃导航栏
实例:具有粘性重力的磨砂玻璃导航栏 技术栈:HTML+CSS+JS 效果: 源码: 【HTML】 <!DOCTYPE html> <html lang="zh-CN"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width…...
CVAT标注服务
CVAT 是一个交互式的视频和图像标注工具,适用于计算机视觉,是一个典型的现代Web应用架构,可以实现大部分情况的标注工作,可以通过serveless CVAT-github cvat文档 下面将就其配置介绍一下几个服务: 1. 核心服务 (C…...
SpringBoot+Mybatisplus配置多数据源(超级简单!!!!)
今天分享配置多数据源的另外一种方式,SpringBoMybatisplus配置多数据源,此种方式配置相对简单,都是苞米豆封装好的,配置容易;此篇分享比较简单的方式配置数据源,多个固定的数据源,通过注解选择使…...
Git Svn
github一般需要科学上网,通过SourceTree通过URL克隆,会提示无效URL或者SLL Timeout之类,如果电脑开启了VPN,在系统设置-网络-DNS查看代理端口,如:127.0.0.1:7890 手动配置git代理 git config --global ht…...

Python爬虫伪装
一、网站防爬机制概述 在当今互联网环境中,具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类: 身份验证机制:直接将未经授权的爬虫阻挡在外反爬技术体系:通过各种技术手段增加爬虫获取数据的难度…...

Webpack的基本使用 - babel
Mode配置 Mode配置选项可以告知Webpack使用相应模式的内置优化 默认值是production(什么都不设置的情况下) 可选值有:none | development | production; 这几个选项有什么区别呢? 认识source-map 我们的代码通常运行在浏览器…...
LLaMA-Factory的5种推理方式总结
LLaMA-Factory 作为一款开源的大语言模型微调与推理框架,提供了 5 种核心推理方式,覆盖从本地调试到生产部署的全流程需求。以下是具体方式及示例: 1. 交互式命令行推理 适用场景:快速测试模型效果或进行简单对话。 示例命令&am…...

链游技术破壁:NFT资产确权与Play-to-Earn经济模型实战
链游技术破壁:NFT资产确权与Play-to-Earn经济模型实战 ——从「投机泡沫」到「可持续生态」的技术重构 一、NFT确权技术革新:从链上存证到动态赋权 跨链确权架构 全链互操作协议:采用LayerZero协议实现以太坊装备与Solana土地的跨链组合&…...

为什么HDI叠孔比错孔设计难生产
摘要:本文深入探讨了HDI(高密度互连)技术中叠孔与错孔设计在生产难度上的差异。通过对两种设计在对位精度、制程复杂性、可靠性挑战等方面进行详细分析,阐述了叠孔设计在生产过程中面临的一系列难题,旨在为HDI产品的设…...

数据分析实战2(Tableau)
1、Tableau功能 数据赋能(让业务一线也可以轻松使用最新数据) 分析师可以直接将数据看板发布到线上自动更新看板自由下载数据线上修改图表邮箱发送数据设置数据预警 数据探索(通过统计分析和数据可视化,从数据发现问题…...

游戏开发中的CI/CD优化案例:知名游戏公司Gearbox使用TeamCity简化CI/CD流程
案例背景 关于Gearbox: Gearbox 是一家美国电子游戏公司,总部位于德克萨斯州弗里斯科,靠近达拉斯。Gearbox 成立于1999年,推出过多款史上最具代表性的视频游戏,包括《半衰期》、《战火兄弟连》以及《无主之地》。 团队…...

Linux --TCP协议实现简单的网络通信(中英翻译)
一、什么是TCP协议 1.1 、TCP是传输层的协议,TCP需要连接,TCP是一种可靠性传输协议,TCP是面向字节流的传输协议; 二、TCPserver端的搭建 2.1、我们最终好实现的效果是 客户端在任何时候都能连接到服务端,然后向服务…...

LlamaIndex 工作流简介以及基础工作流
什么是工作流? 工作流是一种由事件驱动、基于步骤的应用程序执行流程控制方式。 你的应用程序被划分为多个称为“步骤(Steps)”的部分,这些步骤由“事件(Events)”触发,并且它们自身也会发出事…...

如何利用Elastic Stack(ELK)进行安全日志分析
在以下文章中,我将解释如何使用Elastic Stack(ELK)进行安全日志分析,以提高安全性和监控网络活动。ELK是一个功能强大的开源日志管理和分析平台,由Elasticsearch、Logstash和Kibana组成,适用于各种用例&…...

创客匠人:以 AI 利器赋能创始人 IP 打造,加速知识变现新路径
在知识付费与个人 IP 崛起的时代,创客匠人作为行业领先的技术服务商,正通过 AI 工具重构创始人 IP 打造与知识变现的生态。其推出的三大 AI 利器 ——AI 销售信、免训数字人、AI 智能客服,精准解决 IP 运营中的核心痛点。 以 AI 销售信为例&…...

Opencv中的copyto函数
一.OpenCV中copyto函数详解 copyto()是 OpenCV 中用于图像复制和融合的核心函数,支持灵活的数据复制和掩模(Mask)操作,其功能和使用方法如下: 1. 核心功能 基础复制:将源图像&…...
TeamCity Agent 配置完整教程(配合 Docker Compose 快速部署)
在《使用 Docker Compose 从零部署 TeamCity PostgreSQL(详细新手教程)》中,我们成功部署了 TeamCity Server 和数据库服务。但要真正运行构建任务,还需要至少一个 Build Agent(构建代理)。 本教程将继续…...

基于深度强化学习的Scrapy-Redis分布式爬虫动态调度策略研究
在大数据时代,网络数据的采集与分析变得至关重要,分布式爬虫作为高效获取海量数据的工具,被广泛应用于各类场景。然而,传统的爬虫调度策略在面对复杂多变的网络环境和动态的抓取需求时,往往存在效率低下、资源浪费等问…...

在 Ubuntu 24.04 LTS 上安装 Jenkins 并配置全局工具(Git、JDK、Maven)
在 Ubuntu 24.04 LTS 上安装 Jenkins 并配置全局工具(Git、JDK、Maven) Jenkins 是一款开源的持续集成和持续交付(CI/CD)工具,在 DevOps 实践中有着广泛的应用。本文将手把手带你在 Ubuntu 24.04 LTS 系统中完成 Jenkins 的安装,并配置所需的全局工具:Git、JDK 和 Maven…...
Tika Server:企业级文档内容解析的轻量级服务化方案
目录 Tika Server:企业级文档内容解析的轻量级服务化方案 一、什么是 Tika Server? 二、Tika Server 的功能特点 1. 多种文档格式支持 2. 提取结构化信息 3. RESTful 接口设计 三、是否开源?是否支持私有化部署? 四、部署…...
LMG1020YFFR 电子元器件详解
LMG1020YFFR 电子元器件详解 基本概述 LMG1020YFFR是德州仪器(TI)生产的一款高性能、低侧栅极驱动器,属于其GaN(氮化镓)功率器件驱动产品系列。 主要功能特性 驱动能力: 峰值输出电流:5A/-5A 可驱动GaN FETs、SiC MOSFETs和高速硅MOSFETs…...

防爆型断链保护器的应用场景有哪些?
防爆型断链保护器是一种用于防止链条断裂导致设备损坏或安全事故的装置,尤其适用于存在爆炸风险的工业环境。以下是其主要应用场景: 1.石油化工行业 在石油化工厂、炼油厂等场所,防爆型断链保护器可用于保护输送设备…...
leetcode_206 反转链表
1. 题意 原地反转链表,非常经典的一道题。 2. 解决 2.1 非递归 非递归的比较好理解;链表需要维护前驱和后继两个信息,当我们要更改后继时,先要把原来的后继先存起来。 /*** Definition for singly-linked list.* struct List…...

OPenCV CUDA模块光流------高效地执行光流估计的类BroxOpticalFlow
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 cv::cuda::BroxOpticalFlow 是 OpenCV CUDA 模块中实现Brox光流算法的类。该类用于在 GPU 上高效地计算两帧图像之间的稠密光流(Dens…...