1.传统渲染模式(非 SRP Batcher)的处理方式 2.SRP Batcher 的处理方式 3.如何开启SRP Batcher 4.SRP Batcher的使用限制 1.传统渲染模式(非 SRP Batcher)的处理方式 在传统模式下, "材质参数是否不同" 是判断"是否需要切换渲染状态" 的核心依据, 哪怕只是同一个Shader的不同材质实例( 参数不同) , CPU都会做大量重复的状态切换工作: 核心逻辑 a. 渲染状态的判定标准: 传统模式中, "材质实例" 是渲染状态的核心标识 —— 每个不同的材质实例( 哪怕仅参数不同) , 都会被 视为"不同的渲染状态" b. 具体处理流程( 以3 个物体为例: Shader相同, 材质A/ 材质B/ 材质C, 参数分别为颜色红/ 绿/ 蓝) - CPU处理物体1 : 设置材质A的所有参数( 纹理、颜色红、Shader 变体等) → 提交Draw Call → 绘制物体1 - CPU处理物体2 : 先清空/ 切换材质A的状态 → 设置材质B的所有参数( 纹理、颜色绿、Shader 变体等) → 提交Draw Call → 绘制物体2 - CPU处理物体3 : 再清空/ 切换材质B的状态 → 设置材质C的所有参数( 纹理、颜色蓝、Shader变体等) → 提交Draw Call → 绘制物体3 c. 最终结果 产生3 次Draw Call ( 物体数= Draw Call 数) 核心开销: CPU反复切换材质状态( 每次切换都要向GPU重新传递所有材质参数) , 这是最大的性能损耗点 补充: 传统动态批处理的例外 只有当物体满足"顶点数 < 900 + 使用完全相同的材质实例(参数无差异)" 时, 传统动态批处理才会合并Draw Call; 但只要 材质参数不同, 哪怕Shader一样, 动态批处理也失效, 仍会逐个提交Draw Call2.SRP Batcher 的处理方式 SRP Batcher的核心优势就体现在"区分参数类型" —— 哪怕材质参数不同, 只要这些差异属于"Per-Object(每个物体)数据" , 就能大幅减少状态切换 第一步: 先判断"参数差异的类型" SRP Batcher会把材质参数分为两类, 这是处理的关键
第二步: 具体处理流程( 同上面3 个物体的例子: Shader相同, 仅颜色参数不同) a. 预处理阶段 CPU提前将该Shader对应的Per- Material公共数据( 比如纹理、高光强度) 打包, 一次性上传到GPU的常量缓冲区并缓存 —— 这 一步只做1 次 b. 绘制阶段- CPU为这3 个物体仅设置1 次Shader/ Per- Material 公共状态( 无需反复切换) - 仅为每个物体更新Per- Object数据( 颜色红/ 绿/ 蓝、各自的世界矩阵) , 这些数据会被批量组织成连续内存块上传- 最终批量提交这3 个物体的绘制指令( 仅1 次核心的状态设置, 后续仅更新可变参数) c. 最终结果 产生1 次"有效状态切换" + 3 次轻量级的Draw Call ( 仅更新 Per- Object 数据) 核心开销: 几乎消除了"Shader / 材质公共状态" 的切换成本, 仅保留少量Per- Object 数据的更新开销( 远低于传统模式) 例外情况: 若参数差异是Per- Material类型 如果材质参数的差异是"Per-Material级" ( 比如一个用纹理A, 一个用纹理B) , 那么SRP Batcher会将它们分为不同的组- 用纹理A的物体归为组1 , 用纹理B的归为组2 - 组1 : 1 次状态设置+ 组内物体批量绘制- 组2 : 1 次状态设置+ 组内物体批量绘制- 相比传统模式, 仍能减少组内的状态切换开销( 比如组1 有10 个物体, 传统模式10 次切换, SRP Batcher仅1 次) 直观例子对比 假设场景中有100 个立方体, 用同一个Shader, 仅每个立方体的自发光颜色不同 a. 传统模式: 100 次Draw Call, 100 次材质状态切换, CPU开销大b. SRP Batcher: 1 次核心状态设置+ 100 次轻量级Per- Object数据更新, CPU开销仅为传统模式的1 / 10 甚至更低3.如何开启SRP Batcher 在Unity2021后, 在SRP管线( URP、HDRP) 中该功能默认开启, 不允许关闭了; 之前的版本中可以在URP Asset中的Inspector窗 口勾选开启, 观察SRP Batcher是否工作,只需要用Frame Debugger查看渲染事件是否为SRP Batch即可4.SRP Batcher的使用限制 1 ) . 对象使用的Shader必须与SRP Batcher兼容 在HDRP和URP中, 所有Lit Shader和Unlit Shader都符合这一要求( 除了它们的粒子版本) ; 若要让一个自定义Shader与SRP Batcher兼容, 它必须满足以下要求 a. Shader必须将所有引擎内置属性声明在一个名为UnityPerDraw的常量缓冲区里 b. Shader必须将所有材质属性声明在一个名为UnityPerMaterial的常量缓冲区里- 引擎内置属性是Unity引擎自动为每个渲染物体生成、管理的属性, 不是你在Shader里自定义的, 也没法在材质面板手动调 整, 这些属性的核心特点是: 每个物体独有、随物体变化( 比如物体的位置/ 旋转/ 缩放对应的矩阵) - 材质属性是你在Shader里自定义的、可以在材质面板手动调整的属性, 核心特点是: 同一材质的所有物体共用、不随物体变 化( 比如一个红色材质, 所有用它的物体都是红色) 2 ) . 对象不能使用 MaterialPropertyBlocks, MaterialPropertyBlock 是一个特殊的容器, 用来在不复制材质的情况下, 给 某个物体单独设置材质参数3 ) . 对象不能是粒子 对象需要是MeshRenderer或SkinnedMeshRenderer ( 注意: 蒙皮网格渲染器在新版本支持, 2019 之前不支持)