【URP】[合批优化]-搞定Unity:DrawCall和SetPassCalls

【从UnityURP开始探索游戏渲染】专栏-直达

渲染指令渲染状态设置的介绍,可以先看这里:【渲染流水线】[应用阶段]-[渲染命令队列]以UnityURP为例-CSDN博客

(⚠️注:大家最注意的看指令DrawCall的数量,其实对于切换渲染状态的SetPassCalls也是非常耗时的,可以类比为多线程中不断切换线程导致的大量开销。所以除了要优化DrawCall的数量,还要注意SetPassCalls不要过多,不能只对DrawCall优化忽视了SetPassCalls,达到平衡才能有效提升性能。)

渲染优化能大幅提升渲染效率,有效提升帧率。本文的渲染优化主要通过在渲染命令队列中的指令状态切换的优化,即提升渲染管线效率的合批操作,来大幅提升帧率。

本文先快速介绍了各种合批,对不同合批优化点和适用场景做出介绍。综合不同合批的适用场景,给出实现与优化建议策略。最后通过实例介绍带着手动计算优化效果,直观了解并将优化能力带到实际项目中。

URP中主要四种合批技术优化渲染指令(DrawCall)和渲染状态设置(SetPassCalls)。
SRPBatcher、静态合批、动态合批、GPU Instancing 这几种方式分别优化的目标、使用场景、使用限制等都不同。下面介绍每种方式,以在不同情况下使用不同技术优化合批。

目录

‌1. SRP Batcher‌

‌优化目标‌:‌优化原理‌:‌限制‌:‌实现‌:‌适用场景‌:

‌2. 静态合批(Static Batching)‌

‌优化目标‌:‌优化原理‌:‌限制‌:实现‌:‌适用场景‌:

‌3. 动态合批(Dynamic Batching)‌

‌优化目标‌:‌优化原理‌:‌限制‌:‌实现‌:适用场景‌:

‌4. GPU Instancing‌

‌优化目标‌:优化原理‌:‌限制‌:‌实现‌:适用场景‌:

‌合批优先级与选择建议‌

注意MaterialPropertyBlock修改材质

核心原理与影响‌破坏SRP Batcher合批‌与GPU Instancing的兼容性‌‌SetPass calls上升场景‌优化建议

GPU Instancing创建1000个物体的SetPass Calls开销计算

核心结论‌‌GPU Instancing 合批有效‌:‌SetPass calls 数量公式‌:

‌分场景计算‌‌理想情况(现代平台)‌‌保守情况(中端移动设备)‌‌极限情况(低端设备)‌

‌技术原理验证‌

‌额外影响因素‌

‌性能优化建议‌‌查询平台上限‌:‌主动控制批次分割‌:‌优先级规则‌:


‌1. SRP Batcher‌

优化目标‌:

降低CPU与GPU间的通信开销,通过减少 ‌SetPass calls‌(而非直接减少DrawCall)提升动态物体的渲染效率。

优化原理‌:

  • 将材质属性持久化到GPU常量缓冲区(UBO),仅当Shader变体变化时触发完整SetPass call。
  • 相同Shader变体的材质共享渲染状态,动态数据(如模型矩阵)单独批量更新。

限制‌:

  • 需Shader兼容SRP Batcher(使用cbuffer封装材质属性)。
  • 不支持MaterialPropertyBlock和粒子系统。

实现‌:

  • 在URP中默认启用,Shader需声明cbuffer unitypermaterial

适用场景‌:

动态物体(如角色、特效)且材质属性频繁变化。

‌2. 静态合批(Static Batching)‌

优化目标‌:

  • 合并静态物体网格,减少DrawCall数量。

优化原理‌:

  • 离线或运行时合并标记为Static的网格为单一网格,通过索引偏移绘制可见部分。

限制‌:

  • 物体必须为静态(不可变换)。
  • 单批次顶点数限制(通常64k顶点),内存开销大。

实现‌:

  • 勾选物体Inspector中的Static选项,或调用StaticBatchingUtility.Combine

适用场景‌:

  • 大量静态重复物体(如建筑、地形)。

‌3. 动态合批(Dynamic Batching)‌

优化目标‌:

运行时合并小型动态物体网格,减少DrawCall。

优化原理‌:

  • 每帧合并顶点数少于900的网格,使用同一材质实例渲染。

限制‌:

  • 顶点数严格受限(含法线/UV时仅300顶点)。
  • 不支持多Pass Shader和延迟渲染。

实现‌:

  • URP中默认启用,需满足顶点数和材质一致性。

适用场景‌:

少量低模动态物体(如UI元素、小道具)。

‌4. GPU Instancing‌

优化目标‌:

通过单次DrawCall渲染相同网格的多个实例。

优化原理‌:

  • 将实例属性(位置、颜色等)打包至GPU缓冲区,按索引批量绘制。

限制‌:

  • 需相同网格和材质(参数可不同)。
  • 部分低端设备不支持。

实现‌:

  • 启用材质Enable GPU Instancing,或通过MaterialPropertyBlock设置属性。

适用场景‌:

高频重复物体(如植被、子弹)。

‌合批优先级与选择建议‌

技术优先级推荐场景
SRP Batcher最高动态物体且材质多变
GPU Instancing重复动态物体(草、树)
静态合批大量静态物体
动态合批少量低模动态物体

注意‌:SRP Batcher与GPU Instancing可同时启用,但前者优先级更高

注意MaterialPropertyBlock修改材质

在Unity URP中直接使用MaterialPropertyBlock修改材质属性‌可能导致SetPass calls显著上升‌,具体取决于以下机制和限制:

核心原理与影响

破坏SRP Batcher合批

MaterialPropertyBlock绕过材质属性的常量缓冲区(UBO)管理,直接通过独立路径设置属性值。这会强制Unity跳过SRP Batcher的优化流程,导致相同Shader变体的物体无法合批,每个渲染器触发独立的SetPass call。

与GPU Instancing的兼容性

  • ✅ ‌支持GPU Instancing合批‌:若材质启用GPU Instancing,即使使用MaterialPropertyBlock修改属性(如位置、颜色),同一网格的多个实例仍可被合批(单次DrawCall)。
  • ❌ ‌破坏SRP Batcher‌:如前所述,SRP Batcher要求属性通过cbuffer统一管理,而MaterialPropertyBlock破坏了此机制。

SetPass calls上升场景

当以下条件同时满足时,SetPass calls会显著增加:

  • 物体使用相同材质但通过MaterialPropertyBlock设置不同属性;
  • 未启用GPU Instancing(或物体不满足Instancing条件);
  • SRP Batcher因属性修改方式失效。

优化建议

场景推荐方案理由
高频修改属性且需合批启用GPU InstancingMaterialPropertyBlock可保持Instancing合批能力
依赖SRP Batcher的动态物体避免使用MaterialPropertyBlock改用结构化缓冲区(如ComputeBuffer)或合并材质属性到Shader变体
少量物体个性化可接受SetPass calls上升性能损耗可控,优于创建独立材质实例
  • 是否导致SetPass calls上升取决于合批技术组合‌:
    • 若仅依赖‌SRP Batcher‌,使用MaterialPropertyBlock会强制合批失效,引发SetPass calls飙升。
    • 若启用‌GPU Instancing‌,则可通过Instancing合批抑制SetPass calls增长。
    • 因此,在URP中需根据项目使用的合批策略权衡MaterialPropertyBlock的使用,优先搭配GPU Instancing以维持性能

GPU Instancing创建1000个物体的SetPass Calls开销计算

  • Q:使用GPU Instancing创建1000个物体,每个物体都用MaterialPropertyBlock修改同一个材质的颜色。那么绘制这1000个物体会需要多少个setpass calls?

  • A:SetPass calls 的数量取决于渲染批次的分割情况‌,具体规则如下:

    核心结论‌

    GPU Instancing 合批有效‌:

    使用 MaterialPropertyBlock 修改颜色 ‌不会破坏 GPU Instancing 的合批机制‌,只要所有物体满足:

    • 相同网格(Mesh)
    • 相同材质(Material)
    • 启用 GPU Instancing

    SetPass calls 数量公式‌:

    SetPass calls = ceil(1000 / 每批次最大实例数)
    
    • 每批次最大实例数‌ 由目标平台决定(通过 SystemInfo.maximumDrawMeshInstanceCount 查询)

    ‌分场景计算‌

    ‌理想情况(现代平台)‌

    • 最大实例数‌:1024(PC/主机/移动高端设备)
    • SetPass calls‌:ceil(1000 / 1024) = 1仅需 1 次 SetPass call

    ‌保守情况(中端移动设备)‌

    • 最大实例数‌:500(如 Adreno 600 系列)
    • SetPass calls‌:ceil(1000 / 500) = 2需要 2 次 SetPass calls

    ‌极限情况(低端设备)‌

    • 最大实例数‌:256(部分 OpenGL ES 3.0 设备)
    • SetPass calls‌:ceil(1000 / 256) = 4需要 4 次 SetPass calls

    ‌技术原理验证‌

    机制是否影响 SetPass calls原因
    GPU Instancing✅ 合批有效颜色数据通过逐实例缓冲区传递,单次 DrawCall 支持多实例
    MaterialPropertyBlock❌ 不破坏 Instancing属性修改在 GPU Instancing 流程中被正确处理
    SRP Batcher❌ 被绕过MaterialPropertyBlock 强制跳过 SRP Batcher,但 Instancing 仍生效

    ‌额外影响因素‌

    • 视锥体裁剪
      • 仅 ‌可见‌ 的实例会被提交渲染(不可见实例不增加 SetPass calls)
    • LOD 分组
      • 不同 LOD 级别的实例会被拆分成独立批次
    • 阴影绘制
      • 若物体投射阴影,阴影通道会触发额外 SetPass calls(与主通道独立)

    ‌性能优化建议‌

    查询平台上限‌:

    csharp
    int maxInstances = SystemInfo.maximumDrawMeshInstanceCount;// 运行时动态判断
    

    主动控制批次分割‌:

    csharp
    // 手动分割实例数组,确保每批 <= maxInstances
    Graphics.DrawMeshInstanced(mesh, submeshIndex, material, matrices, countPerBatch);
    

    优先级规则‌:

    • 优先保证 ‌GPU Instancing 合批‌(比 SRP Batcher 更适合动态修改属性)
    • 避免在 MaterialPropertyBlock 中修改非 Instancing 支持的属性(如纹理)

    📌 ‌最终结论‌:在 2025 年的主流设备上(如支持 Vulkan/Metal 的移动设备或 PC),‌SetPass calls 通常为 1 次‌,低端设备最多不超过 4 次。


【从UnityURP开始探索游戏渲染】专栏-直达
(欢迎点赞留言探讨,更多人加入进来能更加完善这个探索的过程,🙏)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

淡海水

感谢支持 共同进步 好运++

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值