如何使用LPPV在大型开放世界中补光
解读
国内一线厂面试问“LPPV”并不是想听概念背诵,而是考察候选人能否在开放世界海量动态光源与移动端带宽/发热之间做权衡。LPPV(Light Probe Proxy Volume)本质是把“光照探针”从“点”扩展成“体”,让GPU Instance/植被/飘带这类无法烘焙的物体也能拿到局部光照信号,同时避免实时光。答题时要围绕“为什么用→怎么用→怎么省→怎么防错”四步展开,并给出Unity版本差异(2021 LTS之后支持Streaming,2019 LTS需要手动Slice),否则会被追问“你项目到底跑过没”。
知识点
- LPPV数据格式:3D纹理,每个体素存SH L2系数(RGB各9维),带宽≈144 byte/voxel。
- Proxy Volume划分策略:**世界分块(World Subdivision)与对象跟随(Object Anchor)**两种模式;开放世界必须选World,否则边界探针无法跨块复用。
- 更新频率:TimeSlicing分帧刷新,每帧最多更新MaxAtlasCells(默认64)个体素,防止卡顿。
- 内存预算公式:
Memory(MB) = (WorldSize.x/CellSize) × (WorldSize.y/CellSize) × (WorldSize.z/CellSize) × 144 / 1024 / 1024
移动端建议≤8 MB,对应256×16×256世界、CellSize 4 m。 - Shader采样:
UnitySampleBakedProbe(float3 worldPos, float3 normal, LPPV lodVolume),注意worldPos需减去VolumeOrigin,否则采样错位。 - 兼容性与坑:
- SRP Batching会打断LPPV常量缓冲,需要在Shader里手动
UNITY_INSTANCING_BUFFER_START(Probes)。 - WebGL1不支持3D纹理,需回退到2D Atlas,性能掉30%。
- Vulkan+Adreno 5xx驱动对3D纹理更新有bug,必须开Force OpenGL ES3。
- SRP Batching会打断LPPV常量缓冲,需要在Shader里手动
答案
“我们在25 km²的开放世界里用LPPV解决昼夜循环下植被与岩石的局部补光问题,核心分四步:
- 离线预烘焙:把世界按256×4×256 m切块,每块内用GPU Progressive Lightmapper烘焙一套L1 Probe,再离线升阶到SH L2,存进Streaming AssetBundle;运行时按需异步加载,内存峰值压到7.2 MB。
- 运行时更新:只更新玩家周围3×3块,用Job System+Burst每帧更新最多64个体素,耗时<1.2 ms(小米10测试)。
- 着色器端:植被Shader里用
UnitySampleBakedProbe取LPPV,再与主方向光做NdotL混合,强度用Per-Instance的AO Fade控制,避免过亮。 - 边界处理:块与块之间用Trilinear+Normal Bias 0.05做混合,玩家跨块时Volume Origin做0.5 s插值,肉眼无跳变。
最终同屏5 k颗SpeedTree在Adreno 650上GPU成本仅0.8 ms,相比全实时光节省4.3 ms,发热降3 ℃,包体只增加2.1 MB。”
拓展思考
如果面试官继续追问“LPPV与Screen Space GI怎么选”,可以答:
“LPPV适合低频、大范围的物体,SSGI适合高频、相机周边;我们实际混合使用:玩家半径50 m内用SSGI(Unity 2022 SSAO+Screen Space Ray Trace)补高频AO,50 m外靠LPPV;两者在50 m处用Depth Fade混合,既省带宽又保细节。
若项目要跑Quest2这类Tile Memory极小的设备,可把LPPV体素降到SH L1,内存减半,再用ALU在Shader里把L1还原成L2,误差肉眼不可见,GPU耗时再降0.3 ms。”