当前位置: 首页 > news >正文

SRP渲染合批

SRP Batcher 可编程渲染线合并器,
在传统的Built-in管线中,游戏卡顿往往不是因为模型面数太高,而是因为DrawCall过多,或者更准确的说是SetPassCall渲染状态切换过多。
传统渲染流程:CPU要绘制一个物体时,它需要向GPU发送指令,SetPassCall:把物体的材质,贴图,Shader参数上传到GPU,然后调用DrawCall告诉GPU把这个物体的网格画出来,
如果场景里有100个物体,
1.如果他们使用的是同一个材质,并且材质上的所有参数都一样,如果开了动态合批或静态合批,就会把这些同参数同材质的物体的mesh合并到一个大的mesh,在静态合批里勾选static勾选框,这样cpu就会把这些材质贴图,mesh的顶点一起发给gpu,执行一次setpasscall,然后调用一次drawcall就可以将这些mesh一次性的画出来,如果是动态合批,就要求这个mesh是不能有位移的,并且不能进行更换材质操作,并且顶点如果超限之后也不能进行将多个mesh合并到一个大的mesh,
2.如果这些物体使用的是同一个材质,不同的材质参数,参数变了,至少会多一次 Draw Call;是否多一次 SetPass 要看 shader pass 有没有变、Unity 能不能复用同一次 pass 设置。

  1. 同一个 Material 资源 + MaterialPropertyBlock(推荐)

renderer.sharedMaterial = sharedMat; // 同一个 Material
renderer.SetPropertyBlock(mpb); // 每个物体不同参数.

传统 SRP 渲染(无 SRP Batcher)
每画一个物体,CPU 大致要做:

绑定 Shader Pass
→ 上传/绑定 Material 全部属性(纹理、颜色、向量…)
→ 上传 Object 数据(矩阵、Lightmap 等)
→ Draw
换下一个物体(哪怕 shader 相同、只是 _Color 不同)时,往往又要 重新走一遍 Material 绑定流程,CPU 开销大。

SRP Batcher 换了一种完全不同的思路。它发现:在现代图形 API 中,切换材质参数其实很快,真正慢的是切换 Shader 本身(即切换底层的渲染管线状态 PSOs)。

只要物体的 Shader 相同,即使材质球不同,它们底层的渲染内核也是一样的。因此,SRP Batcher 在 GPU 显存里开辟了两块连续的专属缓冲区(Constant Buffers,常量缓冲区):

全局每对象缓冲区(UnityPerDraw CBUFFER): 存放每个物体独特的数据,比如物体的世界坐标(Transform)、矩阵信息等。

全局每材质缓冲区(UnityPerMaterial CBUFFER): 存放材质球的专属属性,比如颜色、贴图的缩放(Tiling/Offset)等。

第一步:数据预载(极快)
CPU 不再像以前那样“画一个物体传一次数据”,而是把场景里所有物体的坐标数据和材质数据,一次性、批量地写进 GPU 的这两个 CBUFFER 显存缓冲区中。

第二步:命令流(Command Loop)
当数据都在显存里对齐后,CPU 只需要发送一个极快的、包含大量 Draw 调用的指令流。GPU 自己通过更改“指针偏移量”,就能直接去缓冲区里抓取第 1 个物体的坐标和材质进行绘制,画完立刻抓取第 2 个,中途不需要 CPU 重新介入发送 SetPass Call。

绘制时流程变成:

① 遇到新 Shader Variant → 绑定一次 Shader Pass(一次「重」切换)
② 画物体 A → 只更新 PerDraw buffer + 指向 Material 的 CBUFFER → Draw
③ 画物体 B(同 Shader Variant,不同 Material)→ 只换 Material CBUFFER 指针 + 更新 PerDraw → Draw
④ 画物体 C(同 Material)→ 只更新 PerDraw → Draw

打断 SRP batch 的条件:换了 Shader Variant(不同 shader、不同 pass、不同 keyword 组合)
不打断的条件:同一 Shader Variant 下,换 Material、换物体参数 —— 只更新 CBUFFER,不必完整重绑 Material
所以:

100 个物体、100 个不同 Material、但同一个 URP Lit Shader → 可能仍是 1 个 SetPass + 100 个 Draw,CPU 侧比传统路径轻很多
100 个物体、10 种 Shader Variant → 大约 10 个 SRP batch(每种 variant 一段)

SRP Batcher 不合并 mesh,Draw Call 数在 Profiler 里可能看起来没少,但 SetPass Calls 和 RenderLoop 耗时 会明显下降。

SRP Batcher 依赖 固定内存布局,Shader 必须满足:

// 所有材质属性 — 必须在一个 CBUFFER 里
CBUFFER_START(UnityPerMaterial)
float4 _BaseColor;
float4 _BaseMap_ST;
// …
CBUFFER_END
// 所有引擎内置 per-object 属性 — 必须在一个 CBUFFER 里
CBUFFER_START(UnityPerDraw)
// unity_ObjectToWorld 等由引擎注入
CBUFFER_END

Pass 之间 CBUFFER 声明 不一致

遍历待渲染物体

├─ Shader Variant 变了? ──→ 新 SRP Batch,重新 SetPass

├─ Material 变了? ──→ 切换 GPU 上已缓存的 Material CBUFFER(轻量)

└─ Object 变了? ──→ 更新 UnityPerDraw 大 Buffer 中对应槽位(轻量)

└── Draw Mesh

减少 Shader Variant 数量(少 keyword、少 pass)→ 一个 SRP batch 里能塞更多 draw
同功能尽量共用一个 Shader,用不同 Material 区分参数
自定义 Shader 严格遵循 CBUFFER 规范
不要用 MPB(在 URP/HDRP 下)
用 Frame Debugger / Profiler 看 SRP Batch 和 SetPass Calls,不要只看 Batches 数量

SRP Batcher 通常会比内置管线的传统渲染路径多占一些 GPU 内存,但这是用 显存换 CPU 的权衡,而且和 Static Batching 那种「暴涨式」占内存不是一回事。

SRP Batcher 的核心设计是:把数据长期放在 GPU 上,少做每帧重复上传。

三个内存块

1.Material CBUFFER(UnityPerMaterial)
每个兼容 SRP Batcher 的 Material 在 GPU 上有一份持久常量缓冲
通常 几 KB / Material,和 shader 属性数量有关

2.Per-Object 大 Buffer(UnityPerDraw)
存矩阵、Lightmap、SH 等 per-renderer 数据
随 可见 Renderer 数量 增长,仍是常量缓冲量级

3.纹理 / Mesh
贴图、模型本身
不变(SRP Batcher 不复制 mesh)
实际影响大不大?
对大多数项目:SRP Batcher 带来的显存增量相对纹理、Mesh、Render Target 可以忽略。

真正要留意的场景:

Unique Material 极多(几千种各不相同的材质)→ Material CBUFFER 数量线性增加
同屏 Renderer 极多 → Per-Object 大 Buffer 变大
极低端机、显存非常紧 → 需要实测,但瓶颈更常见的是贴图/分辨率,而不是 SRP Batcher 本身
运行时频繁改 Material 属性 → CBUFFER 要重传,CPU 优势下降,显存占用仍在

一帧里 CPU 和 GPU 各做什么
以「100 艘船、同 URP Lit Shader、100 个不同 Material」为例:

首帧 / Material 第一次出现
CPU:
① Mesh、Texture 已在 VRAM(加载阶段完成)
② 为新 Material 创建并上传 UnityPerMaterial CBUFFER → 留在 GPU
③ 绑定 Shader Variant(一次 SetPass / SRP Batch 开始)
④ 写 UnityPerDraw 里物体 A 的 slot(矩阵等)
⑤ Draw:告诉 GPU 用哪个 VBO、哪张 Texture、哪个 Material CBUFFER、哪个 Draw slot
后续每帧(Material 参数没变)
CPU:
① Mesh / Texture / Material CBUFFER → 不动(已在 VRAM)
② 只更新 UnityPerDraw 大 Buffer 里各物体的 transform 等
③ 对每个物体发 Draw:换 Material CBUFFER 指针 + 换 PerDraw slot + 同一 VBO/Texture 绑定
GPU:
按 Draw 命令从 VRAM 取顶点、贴图、常量 → 跑 Vertex/Fragment Shader → 输出像素
你说的「告诉 GPU 去内存里取东西组装」——对 GPU 侧就是这样;但 CPU 每帧不是重新上传 mesh/贴图/Material,而是 更新 PerDraw + 发绑定与 Draw 命令。

和内置管线对比(帮助记忆)

内置管线(无 SRP Batcher):
每 Draw 可能整套重绑 Material 属性(CPU 重)
Mesh/Texture 同样常驻 GPU,也不是每帧传整块
SRP Batcher:
Material 属性已在 GPU(UnityPerMaterial)
每 Draw 主要换 PerDraw slot + 轻量绑定
Mesh/Texture 机制不变

http://www.gsyq.cn/news/1625817.html

相关文章:

  • 多层实木浴室柜哪个公司好
  • 实测:统一调度 Claude Code 与 Codex
  • 视频对比分析工具:技术决策者的效率提升利器
  • 科研文献引用率高的经典离子载体哪家好?
  • 新版水晶DIY小程序开发,解锁专属治愈浪漫
  • ChatGPT API接入不是“填个Key就完事”:从合规性、计费模型到GDPR数据流的6层校验体系
  • Ahrefs高质量外链与垃圾外链分辨标准:Spam值超30%直接拒绝
  • 华为光猫配置解密实战:从加密原理到获取超管权限的完整指南
  • 五、关于zephyr上使用spi通信时(如使用dma+回调)需要的配置
  • 3步搭建智能家居系统:Home Assistant操作系统完整指南
  • 生产级机器学习服务:稳定性治理与可观测性实战
  • 怎样高效获取网络媒体资源:开源工具的智能跨平台解决方案
  • 网易云音乐API:5分钟搭建个人音乐服务的终极解决方案
  • 科研配图零门槛!okbiye 双分区 AI 绘图一站式搞定全学科论文可视化
  • 告别科研作图内卷!一站式 okbiye AI 科研绘图,贴合期刊标准高效出学术图
  • git合并代码记录
  • 民宿领域搜索与个性化推荐算法体系深度对比:召回、排序与冷启动技术解析
  • 深度解析Obsidian Jupyter插件:在笔记中无缝执行Python代码的3种实战方法
  • 写论文要切 5 个平台?虎贲 AI 从选题到答辩全搞定,实证图表自动生成
  • 如何在通达信中实现自动化缠论分析:ChanlunX技术实现深度解析
  • 无电源排序的双向电平转换:ASC0101S推挽24Mbps模式下的工程实践与系统集成
  • ChatGPT批量处理任务必须掌握的6个底层参数:max_tokens、temperature、seed、response_format…工程师都在忽略的精度控制键
  • 安川弧焊电源节气原理分享
  • 企业级开源CMDB系统架构解析:构建智能IT资产管理的5大核心设计原则
  • 科研制图告别复杂软件!okbiye AI 绘图分档功能一站式解决全学科出图难题
  • 多维聚合数据操作:切片、钻取与立方体构建实战
  • 装备制造行业PLM软件系统最新厂商盘点,助力行业数字化转型
  • 我用 Codex 重写了同事维护三年的代码,他没说谢谢——而是找了领导
  • 父系边界即文明边界
  • GetQzonehistory:5分钟快速找回QQ空间全部历史说说完整指南