01 Voxel GI:原理与管线
01 Voxel GI:原理与管线
本文只建立 Voxel GI 的管线视图:场景数据怎样进入体素场,辐射结果怎样被屏幕查询,以及 Render Graph 怎样表达这些阶段的依赖。体素坐标、三角形写入、Cone 采样和滤波细节留给后续文章。

一、全局光照
全局光照关心的是光在场景中的整体传播:直接光从光源到达表面,间接光经过一次或多次表面反射后继续影响其他表面。实时方案需要一份可更新的场景表示,用有限预算近似这个传播过程。
1.1 直接光与间接光
在本项目的数据流中,体素化先写入 Albedo、Normal、Opacity 与 Emissive;Lighting 再根据方向光阴影和这些属性生成辐射结果;屏幕阶段从辐射体积查询当前像素的间接光。这里最重要的是阶段边界:材质属性是输入,Radiance 是光照阶段的输出,屏幕纹理是最终合成前的查询结果。
二、实时 GI 方案
不同实时 GI 方案的差异主要在于场景表示与查询方式。下面的比较只用于定位本系列的体素方案,不表示项目同时实现了所有方案。
| 方案 | 场景表示 | 主要取舍 |
|---|---|---|
| 烘焙光照 / Lightmap | 纹理 | 静态场景查询便宜,但运行时动态更新受限 |
| Light Probe / 体积探针 | 探针与插值 | 动态物体接入简单,但空间细节有限 |
| 屏幕空间 GI | 屏幕深度/颜色 | 运行时轻量,但屏幕外信息缺失 |
| 硬件光线追踪 | 加速结构 | 路径表达直接,但硬件与采样预算要求高 |
| Voxel GI / VCT | 三维体素纹理 | 可查询 Bounds 内的屏幕外场景,但体素数量随三个维度增长 |
Voxel GI 选择规则三维网格作为场景缓存。Screen Trace 以相机 Depth/Normals 找到屏幕表面,再查询这份缓存;它是屏幕端的查询阶段,不替代体素化。
三、体素场景表示
体素网格把场景属性放进规则三维坐标中,使 Compute Shader 能并行构建,使光照阶段能用 3D Texture 查询。项目用独立的 Voxelization Bounds 指定网格覆盖范围,Volume 的影响区域只决定相机何时启用 GI。
3.1 范围与统一采样单位
网格范围会被规范化为世界空间轴对齐立方体,最长轴决定边长,voxelResolution 决定统一体素尺寸。这个坐标约定同时被体素写入、光照查询和屏幕位置转换使用;具体的矩阵与边界规则见下一篇。
3.2 Voxel Cone Tracing 的位置
Cone Tracing 是从表面查询辐射体积的一种方式:有限数量的宽锥体覆盖法线半球,远处查询更粗的空间层级。本文只需要知道它位于“体素 Radiance 生成”之后、“屏幕合成”之前,具体采样语义见第 05 篇。
四、Voxel GI 管线
一帧先由 VolumeManager.instance.stack 提供设置,并由 VoxelGIVolume.TryGetActive 选出当前 Volume 与规范化 Bounds。随后连续经过两个门:ShouldVoxelize 判断是否重建场景体素数据,ShouldRelight 判断是否需要重算光照;前者为真时会隐含后者为真。无方向光时仍可体素化和保留 Emissive,但跳过 Shadow Pass。
4.1 场景与辐射阶段
VoxelGIVolume 和相机上下文提供本帧的设置、Bounds、方向光与资源描述。ShouldVoxelize 为真时,方向光存在才登记 Shadow,随后 Compute 体素化写入 GBuffer;没有方向光则明确跳过 Shadow。为假时复用持久 GBuffer,再由 ShouldRelight 决定是否进入 Lighting;这两个门分别控制场景数据重建和光照重算,不能合并为一个“每帧更新”开关。
4.2 屏幕与合成阶段
Screen Trace 读取相机 Depth/Normals,重建世界位置并转成体素坐标;盒外或无效深度提前结束。Temporal(若条件满足)读取历史,Bilateral 按深度和法线抑制跨表面混合,最后将屏幕 GI 加回场景颜色。
五、Render Graph 调度
插件从 ScriptableRendererFeature 进入 URP,VoxelGIRenderPass.RecordRenderGraph 是总调度入口。Render Graph 的职责是记录每个阶段读写哪些资源,从而保证 Shadow、Voxelization、Lighting、Screen Trace、滤波和 Composite 的顺序;它不替换普通物体的 URP/Lit 表面渲染。这里的图是纵向执行关系,不把每个资源生命周期展开成另一张流程图。
5.1 一帧快照与阶段依赖
调度开始时,把当前相机、Volume、Bounds、方向光、Renderer 注册表和 Camera Context 组合成同一份设置快照。阶段只依赖快照和上游结果:GBuffer 依赖 Voxelization,DirectRadiance 依赖 GBuffer/Shadow,启用 SecondBounce 时 FinalRadiance 依赖 DirectRadiance,Screen Trace 读取当前可用 Radiance/Depth/Normals,Composite 依赖屏幕结果与 Scene Color Copy。
5.2 持久与瞬态资源
Camera Context 跨帧保留后续帧仍需读取的体素数据、辐射结果、方向光深度和屏幕历史;当前帧的原子累积、屏幕输出、滤波输出与颜色 Copy 则由 Render Graph 按阶段创建和复用。文章只需要记住这个所有权边界:跨帧结果是阶段输入,瞬态资源是阶段之间的依赖,不把两者混成同一类缓存。
