Unity ShaderGraph Baked GI节点详解:原理、应用与性能优化
1. 项目概述为什么我们需要关注Baked GI节点在Unity的ShaderGraph世界里节点是构建视觉效果的基石。今天要拆解的这个“烘焙全局光照节点”Baked GI Node对于很多从离线渲染或传统光照贴图流程转过来的开发者来说可能既熟悉又陌生。熟悉的是“烘焙全局光照”这个概念——它意味着将复杂的光照计算如间接光、环境光遮蔽、全局反射预先计算并存储到纹理中运行时直接采样从而用极低的性能开销换取高质量的静态光照效果。陌生的是在ShaderGraph这样一个基于节点的可视化编程环境中我们如何获取并利用这些烘焙好的数据这正是Baked GI节点的核心价值所在。它不是一个执行计算的节点而是一个“数据访问门户”。当你在场景中精心布置了光照探头Light Probes为静态物体烘焙了光照贴图Lightmaps后这个节点就是着色器与这些宝贵烘焙数据之间的桥梁。它允许你在自定义着色器中针对模型表面的每一个顶点或片元精确地获取到该位置应接收到的、已烘焙好的全局光照颜色信息。无论是想为角色添加受静态环境影响的边缘光还是让动态物体与烘焙场景的光照无缝融合亦或是实现一些依赖于环境光照的特殊材质效果比如某些风格的卡通渲染或风格化渲染这个节点都是关键。简单来说如果你满足于Unity内置的标准着色器Standard Shader或URP/HDRP的Lit Shader你可能不会直接用到它。但一旦你开始用ShaderGraph定制专属的、需要与环境光照深度交互的材质Baked GI节点就从幕后走到了台前成为一个必须理解和掌握的工具。它解决的正是“自定义着色器如何享用全局光照烘焙成果”这一核心问题。2. 节点核心原理与工作流程拆解2.1 全局光照烘焙数据源解析要理解Baked GI节点必须先厘清Unity中烘焙全局光照数据的两种主要存储和采样方式光照贴图Lightmaps和光照探头Light Probes。节点的工作本质上就是对这两套系统的智能调度。光照贴图Lightmaps这是针对标记为“Static”静态的GameObject的。在烘焙过程中Unity会为这些物体的表面生成第二套UV即光照贴图UV并将计算好的光照信息主要是间接漫反射光和部分直接光烘焙到一张或一组大纹理中。在运行时着色器根据片元的光照贴图UV坐标去这张大纹理上采样就能得到该点的烘焙光照颜色。这非常高效但只适用于完全静止的物体。光照探头Light Probes场景中动态移动的物体如角色、车辆无法使用固定的光照贴图。这时就需要光照探头系统。我们在场景空间中布置一系列探针点烘焙时在每个探针位置记录下该点的光照信息以球谐函数系数形式存储。运行时对于动态物体表面的每个顶点Unity会找到包围它的最近几个探头并利用球谐函数插值计算出该顶点应接收的环境光照。这个过程是实时的但开销比采样贴图稍高。Baked GI节点的“智能”之处在于它内部根据输入信息自动判断并混合使用这两种数据源。对于有有效光照贴图坐标且物体为Static的片元它优先从光照贴图采样对于动态物体或光照贴图覆盖不到的区域如模型内部它会回退到使用光照探头数据进行球谐函数插值。2.2 节点端口与数据流详解节点提供了四个输入端口和一个输出端口每个端口都承载着特定的使命Position (Vector3, World Space)这是世界空间下的顶点或片元位置。它是光照探头采样的核心依据。光照探头网格的插值计算严重依赖于这个位置信息。如果输入的位置不准确比如还在模型空间那么从光照探头获取的光照信息将是完全错误的导致物体“漂浮”在错误的光照环境中。Normal (Vector3, World Space)世界空间下的法线向量。它同样至关重要尤其是对于光照探头数据。球谐函数编码的光照信息是带有方向性的法线决定了从哪个方向去“读取”球谐光照。例如一个朝上的面法线为(0,1,0)和一个朝下的面即使在同一位置从球谐函数中解码出的光照颜色也可能不同因为接收的天空光和地面反射光不同。Static UV (Vector2)通常连接顶点着色器阶段输出的第一套UV即UV0。这套UV用于采样静态光照贴图。只有当渲染的物体被标记为Contribute GI和Static并且场景进行了光照贴图烘焙后这个端口的输入才会生效。它对应着模型导入设置中生成的那套光照贴图UV。Dynamic UV (Vector2)通常连接顶点着色器阶段输出的第二套UV即UV1。这套UV用于采样动态光照贴图如果渲染管线支持如Enlighten或某些Progressive Lightmapper设置下的实时全局光照更新部分。在大多数只使用完全烘焙静态光照的场景中这个端口可以保持默认值或连接一个常量。Out (Vector3)输出的RGB颜色值。这就是最终采样/插值得到的烘焙全局光照颜色。通常是一个HDR颜色可能超过(1,1,1)需要后续进行适当的色调映射处理才能与直接光照等其他颜色叠加。这四个输入端口共同构成了一个完整的查询请求“在这个位置Position面向这个方向Normal如果存在静态光照贴图请用这个坐标Static UV去查如果存在动态光照贴图更新请用这个坐标Dynamic UV去查。” 节点内部逻辑处理这个请求并返回一个融合后的光照颜色。2.3 “Apply Lightmap Scaling”控件的作用这是一个容易被忽略但有时很关键的布尔切换控件。在Unity的光照贴图系统中为了优化纹理空间利用和避免边缘采样问题引擎可能会对光照贴图UV进行微小的缩放和偏移。当“Apply Lightmap Scaling”设置为True时Baked GI节点在采样光照贴图前会自动应用这些缩放和偏移变换。这确保了采样坐标与引擎内部使用的坐标一致避免出现光照贴图采样错位或边缘瑕疵。注意在绝大多数情况下尤其是在使用Unity自动生成的光照贴图UV时这个选项应该保持为True默认值。只有在你完全手动控制光照贴图UV并且确信UV坐标已经包含了所有必要的变换时才可能将其设置为False。错误地关闭此选项是导致自定义着色器光照贴图采样出现黑边或错位问题的常见原因之一。3. 核心应用场景与实战配置3.1 场景一为自定义无光照着色器添加环境光Unity的URP/HDRP内置的“无光照着色器”Unlit Shader默认是不接收任何烘焙全局光照的物体看起来会完全“漂浮”于场景光照之外。通过Baked GI节点我们可以轻松为其注入环境光感。操作步骤在ShaderGraph中新建一个Unlit Master节点作为输出。添加一个Baked GI节点。获取世界空间位置和法线。通常使用Position节点设置为World空间和Normal Vector节点设置为World空间。对于片元着色器级别的精度推荐使用Fragment Position和Fragment Normal。获取UV。使用UV节点分别选择UV0通道连接至Static UVUV1通道连接至Dynamic UV。将Baked GI节点的Out端口直接连接到Unlit Master节点的Color输入端口。可选由于烘焙光照可能是HDR值可以添加一个简单的Clamp或Reinhard Tonemapping节点防止过亮。关键点这样你的“无光照”着色器就能呈现出由光照探头和光照贴图提供的柔和环境漫反射光物体能自然地融入场景的光照氛围中而性能开销仅增加了极低成本的纹理采样或球谐函数计算。3.2 场景二实现动态物体与烘焙场景的光照融合这是Baked GI节点最经典的应用。假设你有一个烘焙了精美室内光照的静态场景现在需要放入一个动态的角色。标准流程的局限如果你使用标准的Lit着色器Unity会自动为动态物体应用光照探头。但这仅限于漫反射环境光。如果你还希望角色能接收来自烘焙场景的镜面反射环境光即反射探针效果或者你想对光照数据进行更艺术化的处理比如只使用特定颜色的间接光就需要自定义着色器。自定义融合方案创建一个基于PBR或自定义光照模型的ShaderGraph。按照上述方法配置好Baked GI节点获取到烘焙的漫反射环境光颜色我们称之为indirectDiffuse。将indirectDiffuse与你计算出的直接光照漫反射结果相加。对于镜面反射部分你通常还需要采样一个Reflection Probe或使用Scene Color节点来捕获周围环境。但Baked GI节点本身不提供镜面反射信息它专注于漫反射全局光照。通过这种方式你可以精确控制动态物体上烘焙光照的强度、颜色甚至可以将它与程序化生成的光照效果混合实现诸如“角色在黑暗中微微发光但仍能感受到远处窗口暖光影响”的复杂效果。3.3 场景三风格化渲染中的光照控制在卡通渲染Cel-Shading、水彩风格等非真实感渲染中我们常常需要对光照进行高度的风格化控制。Baked GI节点提供了稳定的、预计算的环境光基底。实战案例卡通渲染中的阴影与高光获取基础环境光使用Baked GI节点得到标准的环境光颜色。风格化处理将得到的RGB颜色转换为灰度值例如使用Dot Product与(0.299, 0.587, 0.114)点积得到一个亮度值。阶跃化Posterize使用Posterize节点对这个亮度值进行量化比如只分出3个明暗阶。重新着色根据量化后的阶数映射到不同的颜色上。例如最暗阶映射为深蓝色模拟阴影冷色调中间阶映射为物体固有色最亮阶映射为暖黄色。与直接光结合将风格化处理后的环境光与经过同样阶跃化处理的直接光照结果进行叠加通常是相加或屏幕混合。这样做的好处是你的风格化角色或物体其阴影和中间色调部分不再是单调的黑色或固有色而是带有了场景环境光的色彩倾向使得风格化作品也能拥有丰富的色彩层次和场景融入感。Baked GI节点提供的稳定、平滑的输入是进行这类艺术化再处理的理想起点。4. 跨渲染管线兼容性与疑难排查4.1 HDRP与URP下的行为差异正如官方文档警告的Baked GI节点的行为并非由ShaderGraph全局定义而是由各个渲染管线后端实现。这意味着在HDRP和URP下其内部HLSL代码可能不同。主要差异可能体现在数据源权重HDRP可能更倾向于使用光照探头数据并对其有更高质量的解码如使用更高阶的球谐函数。URP可能对光照贴图的依赖更重。HDR处理HDRP工作在更高的动态范围下Baked GI节点输出的颜色值范围可能更大更亮的HDR值。在URP中输出可能已经被限制在较低的动态范围内。功能支持某些高级烘焙功能如光照贴图方向性、光照探头代理体在一个管线中可能通过此节点暴露在另一个管线中则不可用。最佳实践核心原则永远在目标管线中进行最终测试。如果你计划让着色器跨HDRP和URP使用务必在两个管线项目下分别检查着色器的视觉效果。不要假设在一个管线中工作正常在另一个管线中也一定正常。如果发现显著差异可能需要为不同管线创建变体着色器或使用Shader Graph的Keyword和Custom Function节点来编写条件代码。4.2 常见问题与解决方案实录在实际使用中你可能会遇到以下问题。这里记录了我的排查笔记问题1节点输出一片黑色Out (0,0,0)。这是最常见的问题。请按以下清单逐步排查场景是否烘焙这是最根本的原因。在Lighting窗口Window Rendering Lighting中确保已点击“Generate Lighting”或“Bake”按钮并且烘焙成功完成。检查控制台是否有烘焙错误。物体是否标记为静态对于需要从光照贴图采样的物体必须勾选Inspector右上角的“Static”复选框至少是Contribute GI。动态物体则依赖光照探头。光照探头是否布置即使对于静态物体某些渲染设置下也可能需要光照探头来补充信息。确保场景中有覆盖所有区域的Light Probe Group并且已参与烘焙。输入数据是否正确重点检查Position和Normal是否转换到了世界空间。一个快速的调试方法是将Position直接输出为颜色观察物体是否显示为基于世界坐标的彩虹图。将Normal输出为颜色观察法线方向是否连续变化。UV通道是否正确确保Static UV连接的是模型的第一套UV通常用于纹理贴图并且该模型在导入设置中已生成光照贴图UVLightmap UVs。你可以在模型导入器的Model分页下查看和配置。问题2光照贴图边缘有接缝或错位。检查“Apply Lightmap Scaling”确保其设置为True。检查光照贴图UV生成模型的光照贴图UV可能存在重叠或拉伸。在模型导入设置中尝试提高“Pack Margin”值或使用第三方建模软件生成更干净的第二套UV。检查光照贴图分辨率过低的分辨率会导致像素化边缘。在Lighting窗口的Lightmapping Settings中适当提高“Lightmap Resolution”值。问题3动态物体上的光照不连续或跳跃。光照探头密度不足动态物体在移动时其光照是通过插值周围探头得到的。如果探头布置太稀疏当物体从一个探头组移动到另一个时光照会发生突变。增加探头密度尤其是在光照变化剧烈的区域如墙角、明暗交界处。探头位置不合理确保探头放置在开放空间不要嵌入墙体或地面内部。使用“Auto Generate”功能通常能获得一个不错的基础分布但关键区域仍需手动调整。问题4性能开销异常。Baked GI节点本身开销很低。但如果发现使用该节点的着色器明显更慢需检查是否在片元着色器中采样了高分辨率光照贴图确保光照贴图分辨率设置合理并非越高越好。是否对每个片元都执行了复杂的球谐函数计算对于动态物体考虑将Baked GI节点的计算从片元着色器移至顶点着色器然后在片元间进行插值。虽然精度略有下降但对于平滑的模型可以大幅提升性能。在ShaderGraph中这意味着将提供Position和Normal的节点设置为Vertex阶段然后通过Interpolator传递到片元阶段。5. 高级技巧与性能优化指南5.1 混合烘焙光照与实时全局光照现代渲染管线如HDRP和URP支持混合光照模式Mixed Lighting和部分实时全局光照技术如Screen Space Global Illumination。Baked GI节点主要处理完全烘焙的静态光照。如何与实时元素结合策略是分层处理使用Baked GI节点获取“静态基底”这部分是场景中永不变化的光照贡献。使用其他节点获取实时GI贡献例如HDRP中可以使用Diffusion Profile和Screen Space GI相关节点。URP中可能需要依赖后处理体积或自定义计算。动态混合根据物体的静态/动态属性、与光源的距离等因素使用Lerp节点混合烘焙光照和实时光照。例如对于静态物体权重完全偏向烘焙光照对于动态物体可以混合烘焙的环境光和实时的直接光。关键在于理解Baked GI节点只是你光照方程中的一个输入项而不是全部。你需要构建一个更大的着色器框架来统筹所有光照源。5.2 在顶点着色器与片元着色器间的权衡将Baked GI计算放在顶点阶段还是片元阶段是一个经典的性能与质量权衡。顶点着色器计算将Position和Normal在顶点着色器中输入Baked GI节点输出颜色在顶点间插值后传给片元。优点性能极佳每个模型只需对少数顶点计算球谐函数或采样光照贴图通过导数。缺点光照在三角形内部是线性插值的对于低多边形模型或需要高频光照细节如光照贴图中的小阴影的情况会出现明显的马赫带色块现象质量低下。片元着色器计算在每个像素点都执行一次完整的Baked GI采样。优点质量最高能精确呈现光照贴图的每一个细节。缺点性能开销最大尤其是对于高覆盖率的物体。我的经验法则动态、平滑曲面物体如角色、车辆优先使用顶点着色器计算。因为动态物体主要依赖光照探头球谐光照本身变化平滑顶点插值足以保证视觉质量同时能节省大量性能。静态、复杂表面物体如建筑、地形必须使用片元着色器计算。因为它们依赖高分辨率的光照贴图来表现阴影和细节顶点插值会严重损失这些信息。折中方案对于某些需要高质量但又担心性能的物体可以尝试在ShaderGraph中使用Custom Function节点手动实现一个在顶点着色器计算基础值在片元着色器进行简单修正如基于法线细节纹理的混合方案。5.3 自定义光照探针与光照贴图采样逻辑对于有极致优化或特殊风格化需求的团队可能会觉得Baked GI节点的内部黑盒逻辑不够灵活。这时可以绕过它直接访问底层数据。替代方案手动编码光照探头数据Unity的ShaderLab和HLSL提供了内置函数如ShadeSH9用于低阶球谐或SampleSH系列函数。你可以直接在Custom Function节点中调用这些函数传入世界空间法线来获取光照探头颜色。这让你可以控制使用球谐函数的阶数甚至对结果进行自定义的数学或艺术化处理。光照贴图数据通过TEXTURE2D宏和SAMPLER宏声明unity_Lightmap和unity_LightmapInd方向性光照贴图等内置纹理并使用DECODE_LIGHTMAP宏来采样和解码。这需要你手动处理光照贴图UV的缩放偏移即unity_LightmapST但给了你完全的采样控制权。警告这是一条进阶路径需要对Unity的着色器底层和CG/HLSL有较深理解。它破坏了ShaderGraph的可视化优势且代码高度依赖于Unity版本和渲染管线。除非有非常明确且强烈的需求例如实现某种论文中的特殊光照解码算法否则不建议初学者或普通项目使用。Baked GI节点提供的稳定性和跨版本兼容性在大多数情况下价值更高。通过深入理解Baked GI节点的原理、熟练掌握其应用场景、并有效规避常见的陷阱你就能在ShaderGraph中自如地驾驭烘焙全局光照这股强大的力量让自定义着色器创作既充满艺术自由又能牢牢扎根于高效、高质量的生产管线之中。