MAKE · WRITE · SHARE

Unity-APV体积探针

APV(Adaptive Probe Volumes,自适应探针体积,常简称”体积探针”)是 Unity 6 正式化的烘焙 GI 方案,URP 和 HDRP 都支持,这篇以 URP 为主。它是 Unity 放弃 Enlighten 之后选定的”烘焙 + 探针”路线的终点形态:把 lightmap 和 Light Probe 两套东西收敛成一套——按场景几何密度自动放置探针,烘焙成球谐系数存进 3D 纹理,动态、静态物体统一采样,还支持大世界的按块流送。

这篇先讲怎么用,再拆内部原理(为什么它叫”自适应”、数据存成什么样、烘焙做了什么),最后简短对比 UE4 的 Volumetric Lightmap。它接在 Base-渲染方案演进总览 之后——APV 就是那条”烘焙漫反射 IBL”主线的终点。

1. APV 是什么:定位

一句话:APV 是”自动放置的烘焙体积探针”

对比旧方案,它的三个核心不同:

Light Probe Groups APV
探针位置 美术手动摆 按几何密度自动生成,无需手摆
密度 均匀 / 手动 多级自适应:复杂区域密、空旷区域疏
采样对象 动态物体(静态走 lightmap) 动态 + 静态统一,逐像素采样
存储 内存里的探针数组 3D 纹理图集 + 按块流送
大世界 不适合 面向开放世界设计

逐像素采样是关键差异:旧方案按 GameObject 取探针插值,相邻物体之间会接光不一致、出现色块;APV 逐像素插值,物体间过渡更平滑。

2. 怎么用(URP 流程)

2.1 开启(在 URP Asset 里,不是 HDRP 的 Frame Settings)

  1. Project Settings > Quality > Rendering,双击激活的 URP Asset 在 Inspector 里打开。
  2. Lighting > Light Probe Lighting > Light Probe System:设为 Adaptive Probe Volumes
  3. 同一面板可勾 Enable Lighting Scenarios(多套光照)和 Enable Lighting Scenario Blending(运行时混合)。
  4. 大世界流送:Lighting > Enable Disk Streaming(磁盘 → CPU),需要时再开 Enable GPU Streaming(CPU → GPU,依赖 Disk Streaming)。

URP 没有 HDRP 那套 Camera 级 Frame Settings,APV 一开就对整个管线生效,Lit 材质自动采样。

2.2 放体积

GameObject > Light > Adaptive Probe Volume,Inspector 里选 Mode

  • Global:自动扩到整个场景 / Baking Set 里所有参与烘焙的物体,最常用。
  • Scene:按单个场景的范围。
  • Local:手动拉一个盒子,只覆盖指定区域。

配合用的小体积:Probe Adjustment Volume(局部把探针标为无效)、带 Probe Volumes Options Override 的 Volume(改某区域的运行时采样方式,不影响烘焙)。

2.3 让物体参与 / 收光

  • 光源:Mode 设为 MixedBaked,才会进 APV 烘焙。
  • 静态物体:Mesh Renderer > Lighting 勾 Contribute Global Illumination
  • 收光的物体:Mesh Renderer 的 Receive Global Illumination 设为 Light Probes(动态物体本来就收探针光)。

2.4 烘焙

  1. Window > Rendering > Lighting > Scene 页签 > Mixed Lighting,勾选 Baked Global Illumination
  2. 切到 Adaptive Probe Volumes 页签:
分组 关键参数 作用
Baking Baking Mode(Single Scene / Baking Set)、Bake 开关 单场景或多场景进一个烘焙集
Probe Placement Min / Max Probe Spacing、Probe Positions、Renderer Filter 探针间距范围;Recalculate 重算探针位置;Layer Mask / Min Renderer Size 过滤参与物体
Sky Occlusion Samples、Bounces、Albedo Override、Sky Direction 天空可见性采样
Probe Invalidity Dilation(Search Radius / Validity Threshold / Iterations)、Virtual Offset 修复无效探针、漏光
Disk Usage Scenario Size、Baking Set Size 烘焙数据磁盘占用
  1. Generate Lighting(或从下拉里选 Bake Probe Volumes,只烘焙 APV 不烘焙 lightmap)。场景里一个 APV 都没有时,Unity 会提示自动建一个。

2.5 调优与调试

Window > Analysis > Rendering Debugger > Probe Volume 页签可以可视化:Probes / Bricks / Cells 的布局、Validity(哪些探针无效,比如长在几何里)、SH(逐探针看光照)、Sky Occlusion。不需要真烘焙,光看摆放就能预览自适应密度,这是调整”哪密哪疏”的主要手段。

3. 内部原理

3.1 整体架构

APV 的数据由几个组件分工:

组件 职责
ProbeReferenceVolume 单例,管理 CPU/GPU 数据、流送、绑定、生命周期
ProbeBrickPool 管理 GPU 上的 3D 纹理图集,存探针数据(L0/L1/L2/Validity)
ProbeBrickIndex 层级空间查找:世界坐标 → 定位到哪个 brick
ProbeVolumeBakingSet 烘焙集,ScriptableObject,含配置、场景列表、流送资源引用

烘焙产物落成 .apv Streaming Asset,运行时按块从磁盘读,再上传 GPU 纹理。

3.2 自适应密度:brick 与 subdivision 层级

“自适应”是 APV 名字的核心,也是它和旧探针的本质区别。

  • 整个体积被切成 3D 的 brick(砖块),每块 brick 是 4×4×4 = 64 个探针
  • brick 有多级 subdivision:Level 0 最疏,越靠近几何,subdivision 越高、探针间距越小。默认探针间距档位是 1 / 3 / 9 / 27 米(对应 Min/Max Probe Spacing 范围),烘焙时按”到几何表面的距离”自动选档。
  • 结果就是:墙角、走廊、家具堆里探针密,空旷大厅探针稀——同样的体积,数据量却被几何复杂度”调配”了。

可以针对某个 Adaptive Probe Volume 做 Subdivision Override / Override Probe Spacing,配合 Renderer Filter(Layer Mask、Min Renderer Size)决定哪些几何参与密度计算;Fill Empty Spaces 可以让空旷区域也补上(按 Max Probe Spacing)的砖块。

3.3 存储:3D 纹理图集 + chunk 流送

探针数据最终不是存在内存数组里,而是打包进 GPU 3D 纹理图集

  • ProbeBrickPool 管理几张 3D 纹理,按波段分开存(L0_L1RxL1G_L1RyValidity 等)。
  • 空间查找靠 间接索引纹理ProbeBrickIndex):运行时用世界坐标查索引纹理 → 拿到 brick 在纹理图集里的位置 → 采样。

流送是这套存储方式带出来的能力:

  • chunk(cell)= 一组 brick,是流送的最小单位,大小约等于最大的 brick。
  • 运行时相机移动时,只加载视锥范围内的 chunk:DiskStreamingRequestAsyncReadManager 从磁盘读 .apv 数据 → 进双缓冲的 CellStreamingScratchBuffer 暂存 → 由 ProbeVolumeUploadData.compute 上传到 GPU 纹理。
  • 流送要在 URP Asset 里开启(见 2.1),这就是它能支撑开放世界的原因——不需要整张地图的探针数据常驻显存。

3.4 每个探针存什么

数据 内容 用途
SH 系数 L0/L1(4 系数)或 L2(9 系数) 漫反射辐照度:运行时按法线算间接漫反射
Validity 探针有效性(长在几何内部的探针无效) 插值时当权重,避免把光照”穿过墙”传过去
Sky Occlusion 天空可见性 + 主遮蔽方向 让探针知道天光被什么挡了,支持运行时更新

注意:APV 本身存的是漫反射。镜面反射在 URP 里仍然走 Reflection Probe——APV 不替代它。

3.5 烘焙管线:五个 pass

烘焙由 ProbeGIBaking 驱动,底层用统一的光追后端(DXR / Vulkan),过程是:

  1. Subdivision & Placement:按几何距离生成层级探针位置——这就是 3.2 的自适应密度。
  2. Light Transport:光线传输,算出每个探针的 SH 系数(L0/L1/L2)。
  3. Virtual Offset:光追把”长在几何内部”的探针推到表面之外——否则这些探针会得到黑的辐照度,造成黑斑。
  4. Sky Occlusion:算每个探针的天空可见性与遮蔽方向。
  5. Dilation:把有效区域的数据向无效区域扩散填充,填补暗斑和漏光。

3.6 运行时怎么采样

逐像素进行:

1
2
3
4
5
世界坐标
→ ProbeBrickIndex 间接索引纹理(层级查找,定位 brick)
→ 3D 纹理图集采样(brick 内探针三线性插值,约周围 8 个探针)
→ Validity 作为插值权重
→ 得到 SH,按法线算漫反射辐照度

因为采样是”三线性 + validity 权重”,所以 APV 有天然的平滑过渡,也比旧探针更不容易漏光。

3.7 Lighting Scenarios(多套光照)

先要在 URP Asset 里开启 Enable Lighting Scenarios(要混合再开 Blending),面板才会出现 Scenarios 分组。APV 把烘焙数据拆成:

  • 共享数据:subdivision 和探针位置(所有光照方案共用)。
  • Scenario 数据:探针的光照值(每套光照一份)。

白天/夜晚多套 scenario 可以在运行时切换甚至混合。前提是烘焙时选 Don't Recalculate(探针位置必须保持稳定),否则场景间无法共享/混合。一个注意点:scenario 只影响烘焙间接漫反射,不影响 baked Reflection Probe——光照变化大时,镜面要配 Realtime Reflection Probe。

4. 常见坑

  1. 漏光 / 暗斑:先看 Rendering Debugger 的 Validity,再调 Dilation(Search Radius、Validity Threshold、Iterations)和 Virtual Offset(Geometry Bias、Ray Origin Bias)。
  2. 探针不能手动摆:位置完全自动生成,只能靠 Subdivision Override、Renderer Filter 和体积来调——这是设计如此,不是 bug。
  3. 加性场景加载下 APV 不自动注册:社区常见问题,运行时需要手动 ProbeReferenceVolume.instance.SetActiveBakingSet(...) 并指定 lightingScenario
  4. 流送没生效:先确认 URP Asset 里开了 Disk Streaming(见 2.1);GPU Streaming 依赖 Disk Streaming,别只开后者。
  5. 间距权衡:Min Probe Spacing 太小 → 内存爆;Max 太大 → 光照变化快的地方(阴影边界、门窗附近)糊。先小范围烘焙看摆放再定。
  6. Light Probe Group 不能转 APV:老项目迁移只能重新放置。

5. 与 UE4 Volumetric Lightmap 的区别

UE 的 Volumetric Lightmap(VLM)是 UE4 时代取代 Indirect Lighting Cache 的方案,给动态物体和体积雾补间接光。它和 APV 是同一个思路(烘焙体积探针 + 间接索引 + 3D 纹理存储),但工程取舍不同:

维度 Unity APV UE4/5 Volumetric Lightmap
定位 Unity 6 烘焙 GI 终点,统一 lightmap + Light Probes 补动态物体的间接光,静态仍走 lightmap
密度结构 多级 subdivision 层级,按几何距离自动选(默认 1/3/9/27m) 粗格 + detail cell:靠近静态几何的 brick 内细分更密的 cell
存储 3D 纹理图集(多张 array),chunk 级流送 单个体积纹理 + 间接索引,数据全量驻留
烘焙 GPU 光追(DXR/Vulkan),五段管线,支持迭代 / scenario Lightmass(CPU/分布式),Importance Volume 控制范围
探针数据 SH L2(9 系数)+ Validity + Sky Occlusion SH(9 系数)+ SkyBentNormal + DirectionalLightShadowing
镜面 走 URP / HDRP 的 Reflection Probe 走 Reflection Capture
流送 按 chunk 视锥加载,面向开放世界 流送弱:level streaming 要求所有 level 一起 build
内存 按需流送,可控 官方例子:Paragon 从 5MB 涨到 30MB;空区域不可回收

几个值得注意的差异点:

  • “自适应”的实现方式不同。APV 用真正的多级 subdivision(每个层级独立选择间距,1/3/9/27m 档位),VLM 是”粗格 + 几何附近细分 detail cell”,密度档位靠 Detail Cell SizeMaximum Brick Memory 上限约束。VLM 的密度控制更粗。
  • 存储与流送是最大分野。VLM 官方明确是”单个体积纹理”,空空间不能回收、多个重叠体积不能混合,内存压力大;APV 从设计上就是”图集 + chunk 流送”,是奔着开放世界去的。
  • 镜面一致:两者探针里存的都是漫反射 SH,镜面都靠反射捕获/探针——这点上两个引擎没有分岔。

一句话总结:VLM 是”烘焙体积探针”这个想法的第一代工程化,APV 是同一想法的”流送化、层级化”终版。在各自引擎里,UE 的 VLM 生态位后来被 Lumen 抢走(静态场景仍可用),Unity 则没有引擎级实时 GI,APV 就是烘焙路线的收敛终点——这也正是 Base-渲染方案演进总览 里说的”两条引擎路线分歧”。

6. 总结

APV 的知识链可以压缩为:

1
2
3
4
5
自动放置(几何密度 → 多级 subdivision)
→ 烘焙(光追 5 pass:placement → 传输 → virtual offset → sky occlusion → dilation)
→ 存储(SH L0/L1/L2 + Validity,打包进 3D 纹理图集)
→ 流送(chunk 按视锥加载)
→ 运行时(间接索引纹理 → 8 探针插值 → 漫反射辐照度)

它解决的问题:不用手摆探针、逐像素采样过渡平滑、支持开放世界、能多套光照切换。代价:探针不能手调、镜面要另配反射探针、漏光需要 dilation/virtual offset 修补。理解了”brick 层级 + 图集 + 流送 + SH”这套结构,再回头看任何体积探针方案(包括 UE 的 VLM),都能立刻定位它属于哪条线。


参考资料