「Custom SRP」:全局光照与环境
系列第 6 篇。Note 4 与 Note 5 处理的是直接光照与遮挡——这是光从光源直接到达表面的部分。本篇关注间接光照:光在场景中反弹后到达表面的能量、来自天空的环境光、来自周围表面的反射。这部分能量在真实世界中往往占比 50% 以上,是 PBR 视觉真实感的关键来源。Custom SRP 在这一块走”接入 Unity 烘焙 GI 生态”的路线——不重造 GI 求解器,而是负责把 Lightmap、Light Probe、Reflection Probe 的烘焙结果正确地送到 Shader。
TL;DR
- 三件套结构:静态对象用 Lightmap(单位面积辐射能量)、动态对象用 Light Probe(球谐函数表达任意方向的入射光)、镜面反射统一用 Reflection Probe(预过滤 cubemap)。各司其职、按对象类型分发。
- 球谐函数(SH)是 GI 的核心数学工具:用 9 个系数(L0+L1)就能编码整个球面的低频光照分布,每像素只需 9 次乘加即可重建任意方向的辐射度——这是为什么 Light Probe 几乎免费。
- Reflection Probe 的 Mip 映射对应粗糙度:高 Mip 是预先模糊过的版本,粗糙表面采样高 Mip 自然得到柔和反射。这是 IBL(Image-Based Lighting)的标准实现模式。
- Box Projection 是视差校正:默认 Cubemap 假设 Probe 在无穷远,近距离反射会出现”贴图飘移”。Box Projection 把反射光线从 Probe 中心校正到表面位置,让室内场景的镜面反射看起来贴合墙面。
- Meta Pass 是间接光的源头:场景中表面”反弹什么颜色的光”完全由 Meta Pass 输出的 Albedo 决定。烘焙器需要这个 Pass 才能正确求解全局光照。
1. GI 系统全景
1.1 三类对象 × 三类数据源
GI 的接入逻辑可以总结为对象类型与数据源的映射表:
| 对象类型 | Diffuse 间接光 | Specular 间接光(环境反射) |
|---|---|---|
| 静态对象(Static, Lightmap Static) | Lightmap | Reflection Probe |
| 动态对象(移动、Skinned Mesh) | Light Probe (SH) | Reflection Probe |
| 大型动态对象(粒子、超大动态网格) | LPPV (Light Probe Proxy Volume) | Reflection Probe |
镜面反射对所有对象都用 Reflection Probe——这是因为 Lightmap 与 Light Probe 都不能编码视角依赖的反射,必须依赖 Cubemap。
1.2 GI 数据流
flowchart TD
A[场景烘焙阶段·Editor] --> B[Meta Pass 输出 Albedo / Emission]
B --> C[Progressive Lightmapper 求解]
C --> D[Lightmap Texture
静态对象 UV2]
C --> E[Light Probe SH 系数
球面采样点]
C --> F[ShadowMask Texture
遮挡数据]
G[Reflection Probe 烘焙] --> H[Cubemap with Mips
预过滤粗糙度]
D --> I[运行时·Shader]
E --> I
F --> I
H --> I
I --> J[GI struct
diffuse · specular · shadowMask]
J --> K[IndirectBRDF
Note 3 §3.3]
style A fill:#fff3e0,stroke:#f57c00
style I fill:#e3f2fd,stroke:#1976d2,stroke-width:2px
style K fill:#e8f5e9,stroke:#388e3c,stroke-width:2px
整个流程横跨 编辑器烘焙阶段 与 运行时着色阶段:编辑器把 GI 求解结果固化到资源(Lightmap 贴图、Probe 系数、ShadowMask),运行时由 Shader 按对象类型采样这些预烘焙数据。
Custom SRP 的工作集中在两端的最末环节:编辑器侧 提供正确的 Meta Pass 让烘焙器读取材质属性;运行时侧 在 Lit Shader 中正确采样并融合到 BRDF。中间的求解过程(Progressive Lightmapper、Bakery、Enlighten)由 Unity 引擎或第三方插件负责,与 SRP 解耦。
1.3 GI struct 抽象
类似于 Note 3 中 Surface / Light / BRDF 的统一抽象,GI 有自己的中间结构:
1 | |
GetGI(lightmapUV, surfaceWS, brdf) 是一个统一入口,根据是否定义 LIGHTMAP_ON 关键字分支到 Lightmap 或 SH 路径。Specular 部分用同一份 Reflection Probe 采样逻辑,对所有对象通用。
2. Lightmap:静态对象的烘焙漫反射
2.1 Lightmap UV 的传递
每个标记为 Lightmap Static 的 Mesh 需要一套独立的 UV 通道(典型是 UV2,对应 TEXCOORD1)。烘焙器在这个 UV 空间中为每个 texel 求解到达该位置的总漫反射能量。
引擎通过 unity_LightmapST 把每对象在全局 Lightmap Atlas 中的 offset/scale 传递给 Shader。这个变量是 UnityPerDraw CBUFFER 的固定字段(Note 2 §4.1 已强调),由引擎根据 PerObjectData.Lightmaps 自动填充:
1 | |
GI_ATTRIBUTE_DATA / GI_VARYINGS_DATA / TRANSFER_GI_DATA 是 Catlike 实现的宏抽象——只在 LIGHTMAP_ON 关键字定义时展开实际代码,否则展开为空。这避免了为非 lightmap 对象传递无用 UV 通道的开销。
2.2 Lightmap 采样
运行时采样直接从 unity_Lightmap 读取:
1 | |
SampleSingleLightmap 是 RP Core Library 提供的标准函数,处理 HDR 编码、压缩格式解码、texelSize 等细节。UNITY_LIGHTMAP_FULL_HDR 决定 Lightmap 是否使用 RGB16F(高质量)或 RGBM 编码(兼容性高,但精度有限)。
2.3 Directional Lightmap
普通 Lightmap 只存储漫反射光照强度,不知道光来自哪个方向——这意味着 Normal Map 在 Lightmap-only 对象上无效(漫反射不响应法线扰动)。
Directional Lightmap 用第二张贴图(unity_LightmapInd)存储每 texel 的主导光方向。Shader 端把方向信息与表面法线点积,让 Normal Map 重新生效:
1 | |
实践中 Catlike 的 Custom SRP 对 Directional Lightmap 的处理简化为标准 Lightmap 采样(不解码方向数据)——这是工程取舍:完整 Directional Lightmap 解码每像素需要额外采样 + 复杂方向计算,但视觉收益在大多数静态场景中并不显著(因为大场景 Lightmap 分辨率本身就低)。
2.4 GPU Instancing 与 Lightmap
Lightmap 的 unity_LightmapST 在 UnityPerDraw CBUFFER 中是 per-object 数据。这意味着即使两个对象使用同一张 Lightmap Atlas,只要它们在 Atlas 中的位置(offset/scale)不同,就不能合并为同一 instance batch。
这是个隐性的性能陷阱:场景中 100 个相同 Mesh 的静态柱子,本来期望走 GPU Instancing,但因为 Lightmap UV offset 各不相同——每个柱子单独 batch。规避方法有限:
- 静态对象用 SRP Batcher 而非 Instancing:SRP Batcher 不要求 instance buffer 一致,per-object 数据通过
UnityPerDraw的 offset 切换即可。这是 SRP Batcher 在静态场景中的天然优势 - 真的需要 Instancing 时:把多个相同 Mesh 合并到一张 Atlas 子区域,让它们共享相同的
unity_LightmapST——但这需要美术工具配合
3. Light Probe:动态对象的球谐光照
3.1 球谐函数的数学基础
球谐函数(Spherical Harmonics, SH) 是定义在球面上的一组正交基函数,类似 Fourier 级数对周期函数的展开。任意球面函数
其中
实时渲染使用 二阶 SH(L0 + L1),共 4 个系数(每个 RGB 通道),存储成本 12 个浮点数。这足以表达低频光照分布——粗略的”前后亮度”、”左右亮度”、”上下亮度”——而高频细节(强方向光、锐利阴影)会被平均掉,这正是 GI 漫反射所需要的特性。
Custom SRP 沿用 Unity 内置约定使用 L1+L2(共 9 系数),对应 unity_SHAr/g/b、unity_SHBr/g/b、unity_SHC 7 个 vec4 变量(注意 Unity 把 RGB 三个通道的 SH 拆开存储以便 GPU 并行处理)。
3.2 SH 解码
给定表面法线
1 | |
SampleSH9 是 RP Core Library 函数,展开为约 30 行 ALU——按 SH 基函数权重对系数做加权求和。整个 SH 解码每像素 ~30 ALU、零纹理采样——这就是 SH 几乎免费的根本原因。
max(0.0, ...) 是必要的——SH 的低频近似可能在某些方向上产生负值,这在物理上无意义,截断到 0 是工程惯例。
💡 球谐振铃(SH Ringing)的数学本质:这种产生负值的现象在信号处理中有正式名称——SH Ringing,是球面上的吉布斯现象(Gibbs Phenomenon)。当使用低阶(L1/L2)连续函数去拟合高频高对比度光照(比如一个极亮的聚光灯直射白墙、强烈逆光环境)时,截断的低阶 SH 必然在原信号陡变区域的反向产生过冲——亮的一面更亮、背光面跌入负值。这是 Fourier 截断级数对方波拟合时同样会出现的振荡现象,球面版本由 Ramamoorthi 与 Hanrahan 在 2001 年首次形式化。截断到 0 是实时渲染中最廉价的工程 Hack——HDRP 等高端管线会引入 SH 窗化(windowing)函数(Hanning / Lanczos)在烘焙阶段对系数做加权衰减,主动牺牲部分锐度换取负值消除,但这会让所有 SH 都变得更柔和,是质量层面的取舍。Custom SRP 选择最廉价的截断方案——这是教学路线的合理决策,但读者应该知道这是个 trade-off 而不是”理所当然”的代码。
max(0.0, ...) 这条小小的 saturate,背后承载的是这一整段球谐数学的物理边界。
3.3 Light Probe 数据来源
每个动态对象在每帧渲染前,引擎会:
- 找到对象世界位置周围的 4 个最近 Light Probe
- 用四面体重心坐标插值 4 个 Probe 的 SH 系数
- 把插值结果写入对象的
UnityPerDrawCBUFFER(unity_SHAr/g/b 等字段)
这个流程通过 PerObjectData.LightProbe 在 RendererListDesc 中声明启用。引擎自动处理插值,Shader 端只需采样系数。
实践要点:
- Light Probe 网格密度决定动态对象 GI 质量:稀疏网格在过渡区会产生明显的光照跳变(角色从一个 Probe 走到另一个 Probe 时颜色突变)
- Probe 应该放在角色路径上:而不是均匀网格——空中的 Probe 浪费烘焙时间
- 室内/室外过渡处加密:光照变化最剧烈的位置需要更密的 Probe 分布
3.4 Light Probe Proxy Volume(LPPV)
单个对象只采样最近的 4 个 Probe——对小对象足够,但对大型动态对象(粒子系统、超大可移动物体、可破坏建筑),不同部位应该接收不同光照。LPPV 通过在对象包围盒内插值生成一个体积纹理,每个像素根据世界位置采样对应位置的 SH。
1 | |
unity_ProbeVolumeParams.x 是开关——引擎根据对象是否启用 LPPV 自动设置。LPPV 需要在 RendererListDesc 中声明 PerObjectData.LightProbeProxyVolume 标志位。
📱 LPPV 在移动端的隐形带宽杀手:LPPV 的核心数据载体是 3D 纹理(Texture3D),依赖硬件的三线性插值在体素之间平滑过渡。这在桌面端 GPU 上几乎免费——但在移动端 TBR 架构下,3D 纹理是显存带宽的灾难。原因是 3D 纹理的内存布局是按 Z-order 或线性切片存储,邻近 voxel 的内存局部性(Memory Locality)极差——shader 在三线性插值时每像素需要读取 8 个相邻 voxel,这 8 个 voxel 在物理内存上分散在多张缓存行中,极易引发多次 Cache Miss,每次 miss 都是一次主存往返。在移动端这意味着:原本期望几个像素的低频光照查询变成几十次显存访问,整个 PostFX 和着色阶段的带宽预算被一个大型 LPPV 物体吃光。实测某些 Mali GPU 上,开启 LPPV 的大动态对象会让该 frame 的整体带宽消耗翻倍。移动端项目应对大型动态对象,通常宁愿将其拆分为多个子 Mesh 走传统 Light Probe,也要极其谨慎地开启 LPPV——把 LPPV 视为高端平台特性,与 SSR、Compute Shader 同等谨慎对待。
4. Reflection Probe:环境镜面反射
4.1 IBL 采样原理
镜面反射需要知道”从某个方向看过来是什么颜色”——这正是 Cubemap 的功能。Reflection Probe 在每个采样点烘焙一个 Cubemap,Shader 运行时根据反射光线方向采样这个 Cubemap:
其中
但完美镜面反射只有在 roughness = 0 时正确——粗糙表面应该模糊采样。
4.2 Mip Chain 编码粗糙度
预过滤 Cubemap:烘焙阶段给同一 Cubemap 生成多级 Mip,每一级用越来越大的卷积核模糊。Mip 0 是清晰的、Mip N 是几乎全部模糊为环境平均色的。
Shader 运行时根据材质 roughness 计算应该采样哪一级 Mip:
1 | |
PerceptualRoughnessToMipmapLevel 把 perceptualRoughness(
非线性映射让中等粗糙度(perceptualRoughness ≈ 0.5)对应到合理的 Mip,避免 0/1 极端外的视觉突变。
DecodeHDREnvironment 处理 HDR 编码:Cubemap 通常用 RGBM 编码(M 通道存储指数)以低开销存储 HDR 数据,运行时解码为线性 RGB。
4.3 Box Projection:视差校正
默认 Cubemap 假设 Probe 位于无穷远——意味着无论表面在哪里,反射方向都从原点采样。这在室外开放场景没问题(天空盒的几何确实远),但在室内场景会立刻露馅:
- 房间四面墙的 Probe 烘焙在房间中心
- 一面有镜子的墙边,反射应该显示对面墙面(贴在镜子上)
- 但默认采样总是从 Probe 中心(房间中心)出发,反射出来的位置是错的——视觉上像”反射图像在玻璃后面浮动”
Box Projection 通过 Probe 的包围盒(BoxProjection AABB)校正反射方向:
1 | |
cubemapPosition.w 是开关——unity_SpecCube0_BoxMin/BoxMax 配合,引擎根据 Probe 配置自动填充。开启 Box Projection 的 Probe 在 Inspector 中标记 “Box Projection”。
工程实践:室内场景全部使用 Box Projection;室外开放场景关闭以节省每像素几次 ALU。
⚠️ Box Projection 的几何前提:Box Projection 的整个数学推导严格假设房间是一个 AABB(轴对齐包围盒)——即六个面分别垂直于 X/Y/Z 三个世界轴。这条假设需要在与美术沟通规范时作为硬性约束传达,否则会出现以下问题:(1) 圆柱形大厅、穹顶建筑(教堂、剧院、体育馆内部):圆形墙面无法用一个 AABB 描述,反射会在曲面与盒边界的不匹配处产生严重撕裂,反射图像在墙面上”跳跃”;(2) 倾斜走廊或非正交墙面的复古建筑:墙面与 Box 法线不平行,反射的 mapping 错位,越靠近墙面错位越明显;(3) 多层穿插的复杂空间:用一个 AABB 包不住整个空间,必须强制切分为多个 Probe,过渡区出现明显的 Probe 边界瑕疵。遇到这些场景时只有两条出路:回退到无穷远 Cubemap(牺牲视差校正质量但避免撕裂),或引入屏幕空间反射 SSR(每像素几十次光线步进,移动端通常无法承担)。给美术的实操规范:室内场景几何尽量做成 AABB 友好(直角房间为主);曲面区域规划为”非反射焦点”(避免镜面材质放置在那里);如果艺术上必须有曲面+镜面(教堂铜镜),单独标注为高端平台特性,移动端使用降级方案(无视差 + 模糊度提升)。这种”防患于未然”的几何规范沟通,能避免项目后期发现”反射就是不对”时被迫返工美术或上 SSR。
4.4 Reflection Probe Blending
物体在两个 Probe 影响范围交叠区时,需要在两个 Probe 之间插值。Unity 支持最多两层 Probe(unity_SpecCube0 + unity_SpecCube1),通过 unity_SpecCube0_BoxMin.w 字段(或类似机制)传递混合权重:
1 | |
完整版 Probe Blending 会在 unity_SpecCube0 与 unity_SpecCube1 之间按权重 lerp。Custom SRP 简化实现只采样 SpecCube0——这是教学路线的取舍。完整 Blending 主要在 HDRP 等高端管线中使用。
4.5 PerObjectData 声明
要让引擎为每个对象正确填充 Reflection Probe 数据,必须在 RendererListDesc 中声明:
1 | |
漏掉某项 → 对应 Shader 变量保持默认值(通常是 0 或单位矩阵)→ 渲染结果错误但 Shader 编译不会报错——这是最难诊断的一类 bug。RendererListDesc 的 rendererConfiguration 字段是 GI 接入的”开关总闸”。
5. Ambient 环境光
Ambient 是最简单的间接光层级——给所有动态对象一个统一的”基础亮度”,避免阴影区完全死黑。Unity Lighting 设置中的三种模式:
| 模式 | 数据形式 | 视觉特点 |
|---|---|---|
| Skybox | 来自 Skybox 的 SH 采样 | 自动匹配天空颜色,最物理 |
| Gradient | 三个手动颜色(天 / 地平线 / 地) | 美术可调,适合写实风格 |
| Color | 单一颜色 | 最廉价,扁平美术风格 |
Ambient 的实现统一通过 SH——三种模式都生成一组等效的 SH 系数(对 Skybox 模式是真正的球面采样、对 Gradient 是手动配置的等效 SH),然后通过 unity_SHAr/g/b 等变量传给 Shader。这意味着 Ambient 与 Light Probe 共享同一个 SH 解码路径——Shader 端不需要区分两者。
Skybox 模式是最自然的选择:当美术调整 Skybox 后,Ambient 自动跟随,无需手动调整。Lighting 设置中的 “Auto Generate” 启用时引擎会持续跟踪 Skybox 变化。
Glossy Environment Reflection(Skybox 作为低分辨率 Cubemap 给所有对象用作 Reflection Probe fallback)也属于这一类——当对象不在任何 Reflection Probe 范围内时,引擎自动使用 Skybox 卷积版本作为 unity_SpecCube0。
6. Meta Pass:GI 烘焙的源头
6.1 Meta Pass 的角色
GI 烘焙器需要知道”场景中每个表面把什么颜色的光反弹出去”——这个数据由 Meta Pass 提供。烘焙器在运行 Progressive Lightmapper 时,对每个 Lightmap texel 执行类似 path tracing 的过程,每次光线击中表面时调用该表面 Shader 的 Meta Pass,读取该位置的反射率(Albedo)与自发光(Emission)。
HLSL
1 | |
unity_MetaFragmentControl.x/y 是烘焙器的二选一信号——同一个 Meta Pass 被调用两次,一次用于 Albedo 输出、一次用于 Emission。Catlike 实现把镜面反射在高粗糙度时按比例加到 Albedo 中,让磨砂金属表面也能正确参与 GI 反弹。
UnityMetaVertexPosition 是关键——它把 vertex 从世界空间投影到 Lightmap UV 空间,让 Meta Pass 渲染到 Lightmap 而不是相机视图。这个函数处理了 Mesh 的 lightmap UV 与 dynamic lightmap UV 的复杂映射逻辑。
6.2 不写 Meta Pass 的后果
如果 Shader 没有 Meta Pass:
- Lightmap 烘焙结果偏黑:烘焙器找不到合法的 Albedo 输出,默认用纯黑——意味着该材质表面”不反射光”,整个场景的间接光照会显著偏暗
- Emission 不参与 GI:自发光物体(霓虹灯、火焰)应该照亮周围,但只有静态烘焙的发光物才会贡献 GI——如果 Meta Pass 缺失,发光物变成视觉上的发光物但物理上的纯黑物
- GI 仅来源于天空盒:Ambient + Skybox Reflection 仍然有效,但场景内表面之间的反弹完全消失
实践原则:任何有静态对象的项目,所有 Lit Shader 必须写 Meta Pass——这是 GI 接入的硬性要求。
6.3 Cull Off 与单面写入
Meta Pass 通常配置 Cull Off——因为 Lightmap 渲染需要从所有方向接收信息,背面剔除会丢失某些表面贡献。但这意味着双面 Mesh(草、织物)的两面会写入同一 Lightmap texel——美术需要在 UV 布局上避免重叠。
7. LOD 与 GI 的协同
7.1 Cross-fade 对 GI 的影响
Note 2 §5.2 介绍了 LOD Cross-fade Dithering——通过 dither alpha 让 LOD 切换平滑。这个机制对 GI 数据的影响值得单独说明:
- Lightmap UV:每个 LOD 级别有自己的 lightmap UV,烘焙时各自独立。Cross-fade 期间两个 LOD 的 Lightmap 不会冲突
- Light Probe SH 系数:所有 LOD 共享同一对象的 SH 数据,无需特殊处理
- Reflection Probe 配置:同上
- Per-object data 一致性:
unity_ProbeOcclusion等 per-object 字段对一个对象的所有 LOD 是一致的——LOD 只是几何细节级别,不改变其在世界中的位置/光照属性
7.2 LOD Group 与 Static 标记的微妙关系
Lightmap Static 标记与 LOD Group 的组合需要谨慎:
- LOD0 标记 Static、LOD1+ 不标记:常见但有暗坑——LOD0 走 Lightmap、LOD1+ 走 Light Probe,过渡时光照风格切换可能出现可见差异
- 所有 LOD 都 Static:所有级别都进入 Lightmap 烘焙,但只有 LOD0 通常被烘焙器选中(基于屏幕尺寸优先级)。Lightmap UV 必须为每个 LOD 单独设置
- 所有 LOD 都不 Static:全部走 Light Probe,行为一致——这是动态对象的标准做法
工程推荐:远距离不变的大型场景元素(地形、建筑外墙)所有 LOD 都标 Static 并设 lightmap UV;动态/可破坏对象(角色、敌人、可拾取物)一律不标 Static。
8. TA Takeaway
8.1 GI 数据成本图谱
GI 在每像素的总成本:
1 | |
GI 是 PBR Lit Shader 中性价比最高的视觉投资——用约 15% 的 fragment 成本提供约 50% 的视觉真实感来源。在性能预算紧张的项目中,可以裁剪直接光质量(PCF、cascade),但应该尽可能保留 GI 完整性。
8.2 烘焙时间是项目效率的隐形杀手
Lightmap 烘焙在大场景中可能耗时数小时。核心影响因素:
- Lightmap 分辨率:512²、1024²、2048²,分辨率每翻倍烘焙时间约 3-4 倍
- Lightmap 数量:场景被切分为多张 Atlas,每张独立烘焙
- Indirect Samples:决定 GI 求解的精度,提高样本数线性增加时间
- 场景几何复杂度:Meta Pass 调用次数 = 顶点数 × 烘焙采样数
实践建议:
- 项目早期定下 lightmap 分辨率上限(典型 256-512 texels/m),后期不要轻易上调
- 场景调整频繁时降低 Indirect Samples(开发期用低质量、发布前才用高质量)
- 烘焙阶段使用 GPU Lightmapper(CUDA / Metal)比 CPU 快 5-10×
- 启用 Lightmap Mode = Distance Shadowmask(Note 5 §6.3),保留实时阴影质量同时节省烘焙时间
8.3 Probe 布置的工程艺术
Light Probe 布置不是”摆得越多越好”——而是让 Probe 落在光照变化最剧烈的位置:
- 室内/室外过渡:门口、窗边、洞口的两侧各放一个,否则角色穿越时光照会突变
- 不同材质区域分界:水边、火光附近、彩色玻璃下方,Probe 应该贴近边界两侧
- 避免无意义的密集:纯白墙体内部不需要密 Probe——光照梯度极小
- 垂直分布:在多层建筑中,每层楼至少一组 Probe(人眼对垂直光照变化敏感)
Reflection Probe 布置原则更直接:
- 每个独立空间一个:每个房间、每片户外区域单独一个
- 位置在视觉中心:人眼最常关注的视点附近,而不是几何中心
- Resolution 与房间大小匹配:小房间 64²、大房间 128²、户外 256²
8.4 PerObjectData 声明的工程纪律
GI 接入的最常见 bug 类型不是 Shader 错误,而是 PerObjectData 漏声明——Shader 编译通过、运行无报错、画面看起来”差点意思”但说不清差在哪。建立两条工程纪律:
- 新项目模板预设全部 GI 相关 flag:把 ReflectionProbes / Lightmaps / LightProbe / OcclusionProbe / LightProbeProxyVolume / OcclusionProbeProxyVolume / ShadowMask 全部默认开启。性能担心是次要的——引擎只对实际需要的对象填充数据,未使用的标志几乎零成本
- Shader 端 fallback 防御:所有 GI 采样在
LIGHTMAP_ON等关键字未定义时给出合理默认值(漫反射用 SH、镜面用 Reflection Probe),避免单一路径失效导致整片黑色
8.5 实践原则
- 静态场景必写 Meta Pass:缺失会导致整体偏暗、Emission 失效
- 室内场景启用 Box Projection:消除”反射图像漂浮”现象
- 大动态对象启用 LPPV:避免单 Probe 对大型粒子系统的光照失真
- Lightmap Mode 用 Distance Shadowmask:质量与烘焙时间最佳平衡
- Auto Generate Lighting 在大项目中关闭:防止 Editor 频繁烘焙拖慢工作流;改为手动触发
- GI 调试用 Scene View 模式:Baked Lightmap / Indirect / Light Probes 等可视化是诊断 GI 问题的首选工具
关键 API 速查
1 | |
HLSL
1 | |