GPU Resident Drawer
Unity GPU Resident Drawer - GPU 常驻绘制器详解
本文基于 Unity 6.3 LTS(6000.3)URP 官方手册核对撰写(Enable the GPU Resident Drawer in URP / Make a GameObject compatible / Enable GPU occlusion culling in URP)。内容面向 URP;HDRP 亦有相关能力,但本文以 URP 官方文档为准。
引言:它是什么
GPU Resident Drawer 会自动使用 BatchRendererGroup(BRG)API,以 GPU 实例化(GPU instancing) 的方式绘制场景中的 GameObject,从而减少 Draw Call 数量、释放 CPU 处理时间。
一句话定位:
让你不写 DOTS / ECS 代码,就把传统 GameObject 工作流接入 BRG 的 GPU 驱动实例化绘制 —— 少 Draw Call、省 CPU,还可选配 GPU 遮挡剔除。
不满足条件的物体,Unity 会回退(fall back) 为不使用 GPU 实例化的普通绘制。
一、背景:传统 CPU 驱动渲染的瓶颈
传统管线里,剔除、排序合批、Draw Call 提交主要在 CPU 上完成。物体成千上万时,CPU 主线程被 Draw Call 提交和状态切换占满,成为瓶颈。Unity 已有若干缓解手段,但各有局限:
| 已有手段 | 局限 |
|---|---|
| 静态/动态合批 | 限制多;动态合批 CPU 成本高 |
| 手动 GPU Instancing | 需相同网格+材质,手工管理 |
| SRP Batcher | 减少材质属性 setup,但仍是 CPU 逐 Draw 提交 |
| DOTS / Entities Graphics | 效果好,但要求改用 ECS 架构 |
GPU Resident Drawer 的价值:在 GameObject 工作流下自动调用 BRG,把这些开销转移到 GPU 驱动的实例化路径。
二、核心概念
建立在 BatchRendererGroup(BRG)之上
GPU Resident Drawer 的底层是 Unity 的 BatchRendererGroup(BRG) —— 一套 GPU 驱动的批量绘制 API,也是 Entities Graphics(DOTS 渲染) 的底座。
关键点:GPU Resident Drawer = 引擎自动帮你调用 BRG。无需手写 BRG、也无需引入 ECS,符合条件的
MeshRenderer会被自动收集、按可实例化的方式成批绘制。
批的识别:Hybrid Batch Group
被 GPU Resident Drawer 归组的物体,在 Frame Debugger 里显示为名为 Hybrid Batch Group 的 Draw Call —— 这是判断它是否生效的直接依据。
收益来源
多个 GameObject 使用相同网格时,Unity 能把它们合并进单个 Draw Call(实例化),这正是 "Resident Drawer" 高效的前提。
三、工作原理与数据流
对比传统 CPU 驱动:CPU 从"逐物体剔除+逐 Draw 提交"变为"提交少量实例化批",其余交给 GPU。
四、要求(官方明确)
GPU Resident Drawer 只在同时满足以下条件时工作:
| 要求 | 说明 |
|---|---|
| 渲染路径 = Forward+ | 必须使用 Forward+ 渲染路径 |
| 图形 API 支持计算着色器 | 支持 Compute Shader 的 API/平台,OpenGL ES 除外 |
| 物体带 Mesh Renderer | GameObject 需有 Mesh Renderer 组件 |
否则该物体回退为不使用 GPU 实例化的普通绘制。
启用后的两点影响(官方特别指出):
- 构建时间变长:Unity 会把所有
BatchRendererGroup着色器变体编译进构建。 - 当 Forward+ 与 GPU Resident Drawer 同时启用时,默认使用 Probe Atlas Blending。
五、启用步骤(官方原文流程)
- Project Settings > Graphics,在 Shader Stripping 区把 BatchRendererGroup Variants 设为 Keep All。
- 打开当前生效的 URP Asset,确认 SRP Batcher 已启用。(若看不到该属性,点 More(⋮) 菜单 → Show All Advanced Properties。)
- 把 GPU Resident Drawer 设为 Instanced Drawing。
- 在 Renderer List 中双击渲染器打开 Universal Renderer,把 Rendering Path 设为 Forward+。
每帧创建/修改 GameObject 时,GPU Resident Drawer 会随之更新。
六、让 GameObject 兼容 GPU Resident Drawer
一个 GameObject 要被 GPU Resident Drawer 处理,需满足全部以下条件(官方清单):
- 带 Mesh Renderer 组件。
- Mesh Renderer 里的 Light Probes 不设为 Use Proxy Volume。
- 只使用静态全局光照,不使用实时 GI。
- 使用支持 DOTS Instancing 的着色器。
- 不在"一个相机渲染结束、下一个相机开始渲染之间"移动位置。
- 不使用
MaterialPropertyBlockAPI。 - 没有使用逐实例回调的脚本(例如
OnRenderObject)。
排除某个物体
给该 GameObject 添加 Disallow GPU Driven Rendering 组件即可排除:
- 选中 GameObject。
- Inspector 中 Add Component。
- 选择 Disallow GPU Driven Rendering。
勾选 Apply to Children Recursively 可连同子物体一起排除。
七、GPU 遮挡剔除(GPU Occlusion Culling)
GPU Resident Drawer 自带一套 GPU 遮挡剔除系统(同时也支持 Dynamic Occlusion)。它用 GPU 而非 CPU 剔除被其他物体挡住的对象。
官方描述的工作机制
- Unity 从场景相机视角生成深度纹理。
- GPU 用当前帧与上一帧的深度纹理做剔除,只要在其中任一帧被判定为未遮挡,该物体就会被渲染(保守策略,避免误剔)。
- 具体判定采用两点近似:
| 机制 | 说明 |
|---|---|
| 包围球近似(Bounding sphere) | 每个潜在被遮挡物体用一个包围球表示。细长物体的球近似很粗糙,因此更难被判定为遮挡(更保守) |
| 降采样深度缓冲(Downsampled depth buffer) | 用多级降采样深度做遮挡测试;依据包围球投影到屏幕的大小选择层级,保证该层像素尺寸大于投影球。球越大,用越粗的深度层测试 |
何时有效 / 何时反而变慢
- 有效:多物体共用网格;场景遮挡多(尤其被遮挡物顶点数高);被遮挡物屏幕包围半径小。
- 可能变慢:若场景遮挡不多,GPU 为设置遮挡剔除做的额外工作反而使渲染时间上升。
启用
- 先启用 GPU Resident Drawer。
- 在生效的 Universal Renderer 里启用 GPU Occlusion。
八、分析与优化
分析工具
| 工具 | 用途 |
|---|---|
| Frame Debugger | GPU Resident Drawer 的合批显示为 Hybrid Batch Group |
| Rendering Debugger | 排查问题 |
| Rendering Statistics | 看 FPS 是否上升、CPU 处理时间与 SetPass calls 是否下降 |
| Unity Profiler | 性能剖析 |
优化建议(官方)
- 最有效的场景:场景大 + 多个 GameObject 共用同一网格(便于合并进单个 Draw Call)。
- Scene 视图 / Game 视图里的提速通常不如 Play 模式或最终构建明显。
- 可能进一步提速:
- Project Settings > Player > Other Settings 关闭 Static Batching。
- Window > Rendering > Lighting 的 Lightmapping Settings 里启用 Fixed Lightmap Size、关闭 Use Mipmap Limits。
九、优势
- 减少 Draw Call、释放 CPU 时间:核心收益。
- 零 ECS 改造:GameObject 工作流直接受益。
- 自动化:引擎自动收集归组,无需手写 BRG 或手动 Instancing。
- 适合海量同网格物体:开放世界、大量重复道具/植被/建筑。
- 可选 GPU 遮挡剔除:把遮挡剔除也搬到 GPU。
十、限制与注意点
| 限制 | 说明 |
|---|---|
| 仅 Forward+ | 必须 Forward+ 渲染路径 |
| OpenGL ES 不支持 | 需支持计算着色器的 API,GLES 除外 |
| 仅 Mesh Renderer | 需带 Mesh Renderer;不满足条件的物体回退普通绘制 |
| 兼容性约束多 | 见第六章清单(不可用 MaterialPropertyBlock、不可实时 GI、着色器需支持 DOTS Instancing 等) |
| 构建时间变长 | 需编译全部 BRG 着色器变体 |
| 收益取决于场景 | 物体少/遮挡少时收益有限,遮挡剔除甚至可能变慢 |
十一、与相关技术的关系
| 技术 | 关系 |
|---|---|
| BatchRendererGroup (BRG) | 底层 API;GPU Resident Drawer 替你调用 |
| SRP Batcher | 前置依赖(启用步骤要求开启);SRP Batcher 减少材质 setup,GPU Resident 进一步做实例化 |
| Entities Graphics (DOTS) | 同样基于 BRG;GPU Resident Drawer 把类似收益带给 GameObject,无需 ECS |
| GPU Occlusion Culling | GPU Resident Drawer 自带、可开启的 GPU 遮挡剔除 |
| Nanite(虚拟几何) | 同属 GPU 驱动渲染思潮,目标不同:虚拟几何解决"单模型面数过高",GPU Resident Drawer 解决"场景物体数过多的 CPU 开销" |
十二、总结
GPU Resident Drawer 是 Unity 6 中基于 BatchRendererGroup(BRG)构建的 GPU 驱动实例化绘制特性,专为 URP Forward+ 渲染路径设计。它让开发者无需编写 DOTS/ECS 代码即可将传统 GameObject 工作流接入 GPU 实例化管线,从而显著减少 Draw Call 数量、释放 CPU 处理时间。
该特性的核心价值在于自动化:引擎自动收集符合条件的 MeshRenderer 组件,按网格和材质归组,以 Hybrid Batch Group 的形式在 GPU 上执行实例化绘制。当物体不满足条件时,Unity 会回退为普通绘制。在兼容性方面,物体需使用支持 DOTS Instancing 的着色器、不使用 MaterialPropertyBlock、不使用实时 GI,且 Light Probes 不能设为 Use Proxy Volume。
GPU Resident Drawer 还自带 GPU 遮挡剔除系统,通过包围球近似和降采样深度缓冲实现保守的遮挡判定,进一步将剔除工作从 CPU 转移到 GPU。不过,该特性同样存在若干限制:仅支持 Forward+ 路径,不兼容 OpenGL ES,构建时间会因 BRG 着色器变体编译而延长,且性能收益高度依赖场景中同网格物体的数量。
总体而言,GPU Resident Drawer 适用于拥有大量重复网格物体的场景(如开放世界中的植被、建筑、道具),在保留 GameObject 工作流的前提下提供了接近 ECS 渲染的 CPU 性能收益。
附:核心概念速查
| 概念 | 说明 |
|---|---|
| GPU Resident Drawer | 自动用 BRG 做 GPU 实例化绘制的 URP 特性(设为 Instanced Drawing 启用) |
| BatchRendererGroup (BRG) | 底层 GPU 驱动批量绘制 API |
| Hybrid Batch Group | Frame Debugger 中该特性合批的名称 |
| BatchRendererGroup Variants | Graphics 的 Shader Stripping 设置,需设为 Keep All |
| GPU Occlusion | Universal Renderer 上的开关,启用 GPU 遮挡剔除 |
| Disallow GPU Driven Rendering | 加到物体上以将其排除的组件 |
| Probe Atlas Blending | Forward+ 与 GPU Resident Drawer 同开时默认使用 |
