本页内容

光照贴图与全局光照

简介

注意:截至 Qt 6.4版本 ,光照贴图烘焙仍处于早期技术预览阶段。未来版本中,其功能、质量和 API 可能会发生变化。

烘焙光照贴图可预先生成来自DirectionalLight 、PointLight 和SpotLight 等光源的直接光照,包括光源投射的阴影。在运行时,系统不再需要在片段着色器中执行相应的计算,也不再需要实时生成可能耗费资源的阴影贴图(尤其是涉及阴影的情况),而是直接采样预生成的图像贴图。

每个Model 都会生成一张光照贴图。即使某个Model 包含多个子网格,并因此关联了多种材质,整个模型也会仅生成一张光照贴图。

光照图通过光线追踪技术生成,该技术本质上能提供正确的遮挡效果(“光线不会穿墙而过”),并且其生成的阴影可能比实时照明和阴影映射技术更为逼真。

更重要的是,光照贴图还允许烘焙间接照明,从而为全局照明提供了解决方案。这会将场景中其他表面反射的光线纳入考量。

下面是一个简单的示例。该场景包含四个矩形(Rectangle)和一个球体(Sphere)模型,以及一个朝下指向的“光照映射器”(DirectionalLight )和一个“光照映射器”(PointLight )。这些矩形模型分别旋转了0度和90度,这突显了实时光照计算的局限性,因为它们全都与“光照映射器”(DirectionalLight )的方向平行或垂直。

在第二张图片中,场景是在为所有五个模型烘焙好光照贴图后,启用光照贴图渲染的。两盏灯均设置为完全烘焙,这意味着直接和间接照明均已烘焙完成。 间接照明使用了256个samples 和最多3个bounces 。生成的光照贴图随后经过了降噪处理。这使得图像看起来更加逼真。

实时照明

包含球体、矩形和两盏灯的简单场景

完全烘焙的灯光

同一场景,两盏灯均设置为完全烘焙状态

下文代码片段展示了如何实现光照贴图效果。区别在于usedInBakedLighting 、bakeMode 和bakedLightmap 这三个属性。在此示例中,已通过texelsPerUnit 属性缩小了光照贴图尺寸,以节省磁盘空间并缩短应用程序加载时间。

DirectionalLight {
    bakeMode: Light.BakeModeAll

    eulerRotation.x: -90
    brightness: 0.5
    castsShadow: true
    shadowFactor: 75
}
PointLight {
    bakeMode: Light.BakeModeAll

    y: 200
    z: 100
    color: "#d9c62b"
    castsShadow: true
    shadowFactor: 75
}
Model {
    usedInBakedLighting: true
    bakedLightmap: BakedLightmap {
        enabled: true
        key: "sphere1"
    }

    source: "#Sphere"
    materials: PrincipledMaterial { }
    y: 100
}
Model {
    usedInBakedLighting: true
    bakedLightmap: BakedLightmap {
        enabled: true
        key: "rect1"
    }

    source: "#Rectangle"
    materials: PrincipledMaterial { }
    eulerRotation.x: -90
    scale: Qt.vector3d(10, 10, 10)
}

// ... three additional Rectangle models, with rotations 0, 90, and -90

上述示例使用了完全烘焙的光源。 还可以将光源配置为仅对间接照明使用烘焙光照,同时实时进行直接光照和阴影映射。在下面的场景中,有 5 个点光源,在第二张截图中,它们均被设置为“BakeModeIndirect ”。虽然直接光照和阴影看起来完全相同,但由于添加了一定程度的全局照明,第二张图像的效果明显更好。

实时照明

包含Sponza和Suzanne模型以及5盏点光源的场景

添加了烘焙的间接光照

同一场景,采用烘焙的间接光,但实时渲染为直接光

使用光照贴图时的关键注意事项

参与烘焙光照的光源,其bakeMode 属性应设置为Light.BakeModeIndirect 或Light.BakeModeAll 。后者表示该光源的直接和间接光照均来自光照贴图。直接光照始终包含阴影。 另一方面,如果使用光照贴图的目的是仅为特定光源向场景中添加间接照明,同时仍需实时计算直接照明(并进行阴影映射),则该光源应使用Light.BakeModeIndirect 。

注意: 一般而言,光照贴图 适用于在变换、几何体和材质方面保持静态的模型。参与烘焙照明的光源也应遵循这一原则。

例如,如果通过动画调整eulerRotation 属性来旋转Model ,那么当将光照贴图应用到该Model 时,会产生视觉上不正确的效果。该特定Model 的渲染结果将不正确,因为预生成的光照贴图仅捕获了该对象的一个旋转状态。 同样的情况也适用于另一个例子:如果模型的某个子网格的材质会根据时间(动画)或某些用户交互动态更改其baseColor 属性。 光照贴图只能捕获给定材质的一个baseColor 。光照也是如此。例如,一个随时间旋转、改变亮度、颜色等的DirectionalLight ,就不适合使用烘焙光照。

注意:另一方面, 何时使用光照贴图始终取决于设计师的选择。特别是对于BakeModeIndirect 中的光源,即使光照贴图场景中的某些对象具有动态行为,在某些场景中,渲染结果仍可能在视觉上令人满意。

光照贴图是一项复杂的引擎和工具功能。它取代并重新实现了引擎渲染管线中的多个组件。在烘焙光照贴图时,它采用了一种根本不同的渲染模型,但同时仍使用并兼容相同的场景结构、资源数据和引擎数据结构。 基于光线追踪的渲染效果通常会优于实时渲染方案,有时甚至显著优于后者,但这需要付出一定的代价,例如相关模型和光源必须保持静态,有时还会出现光照贴图特有的质量问题和渲染伪影。

实际上,选择何时使用何种照明类型将取决于设计师的艺术决策。bakeMode 的这三种设置各有其用途,对于复杂且规模较大的场景,完全可能针对不同的光源同时使用这三种设置——这取决于场景中特定区域的适用性,以及其中包含的模型、材质和动态行为的类型。 光照贴图并非一个简单的“开/关”式开关,不能适用于任何场景和应用,而是一项强大的功能,需要对特定场景的光照需求进行仔细评估,并且通常需要相应地设计场景内容和行为, 同时需要通过“测试与调整”循环,在确定最终方案及相关设置之前,探索并测试不同的光照贴图烘焙和质量设置。

注意:光照贴图 不支持双面表面。在实时照明中,当材质的“cull mode ”设置为“Material.NoCulling ”时,系统会根据片段的朝向自动反转法线。由于光照贴图烘焙不在视图空间中进行,因此光照贴图无法实现此功能。因此,对于依赖此功能的模型,请避免使用烘焙光照。

烘焙光照贴图

与烘焙光照贴图相关的属性及类型,即离线生成图像贴图的过程,这些贴图捕获直接和间接光照,并可在应用程序后续运行时被渲染器使用:

截至 Qt 6.4 版本,光照贴图烘焙过程必须手动触发。只要存在命令行参数 `--bake-lightmaps `,或者环境变量 `QT_QUICK3D_BAKE_LIGHTMAPS ` 被设置为 `1 `(或其他非零值),引擎将进入烘焙模式,并在烘焙完成后退出应用程序。 可以通过查看调试输出中的消息来跟踪烘焙过程的各个步骤。最终结果是一个二进制文件(默认位于lightmaps.bin ),该文件将写入当前工作目录,其中包含场景中所有已烘焙的光照贴图。 此外还会生成一个.raw 文件,其中包含完整的光照贴图以及去噪所需的额外数据。该文件中,每张光照贴图都通过BakedLightmap::key 生成的唯一键进行标识。

准备带光照贴图的场景主要包括以下步骤:

  • 确定哪些模型应使用光照贴图,以及哪些模型应为光照贴图提供数据。属于光照贴图场景的模型应将Model::usedInBakedLighting 设置为true。 需要生成光照贴图的模型(即为其烘焙光照贴图的模型)还应将 `Model::bakedLightmap ` 设置为一个已启用的 `BakedLightmap ` 对象,该对象提供一个唯一键,用于持久标识特定的 `Model` 对象实例(这是因为 Qt XML 需要一个键来识别持久化磁盘存储中的模型数据)。 只有几何体、变换和材质均为静态的模型,才能在运行时进行光照贴图时保证结果正确。通常情况下,任何会导致世界变换随时间变化的因素(例如动态改变或动画化的位置、旋转或缩放),都会使该模型无法参与光照贴图。 不过,艺术需求可以覆盖这一限制,特别是对于仅参与烘焙间接光照但自身不进行光照贴图的模型。对于此类模型,动态变换在视觉上通常是可以接受的,但这始终取决于具体的模型和场景。
  • 确定哪些光源应参与计算以及参与程度。Light::bakeMode 提供三个选项:
    • Light.BakeModeDisabled(默认值),这会使该光源在所有光照贴图处理中被完全忽略。
    • Light.BakeModeIndirect 通常是“稳妥”的选择,如果唯一目标是在场景中实现一定程度的全局照明(间接光照),同时不以其他方式影响该光源的渲染结果。 在此模式下,渲染器将继续使用标准的实时技术,针对该光源执行所有照明计算,包括漫反射、镜面反射、天空/环境光贡献以及阴影映射。 但是,该光源将使用预烘焙数据对间接照明产生贡献,这可能会导致照亮那些原本不会被标准实时照明计算所涉及的表面。
    • Light.BakeModeAll 是一个选项,通常仅适用于特定光源,具体取决于设计师对给定场景的评估。在此模式下,该光源的所有贡献(包括阴影)都会被烘焙。 截至 Qt 6.4 版本,镜面反射光尚不作为烘焙光照的一部分受到支持,因此此类光源将不包含镜面反射成分。 另一方面,它们将生成基于光线追踪的烘焙阴影,并具有正确的遮挡效果(例如,光线不会“穿墙而过”),因为在此模式下,该光源产生的所有直接光照贡献都在光照贴图烘焙时通过光线追踪生成,而不是在运行时计算。 此外,间接光照也会被烘焙,这与 BakeModeIndirect 模式相同。
  • 在烘焙模式下运行场景(应用程序),确保光照贴图成功生成。 从 Qt 6.4 开始,应用程序应采用这样的结构:首先显示的是已生成光照贴图的场景,或者可以通过 Qt QML Viewer(如qml 工具)加载该场景。烘焙完成后(其进度可通过控制台/调试输出进行跟踪),应用程序将退出。
  • 正常运行场景(应用程序),以查看加载光照贴图后的效果。随后即可开始调整:
    • 对于某些模型,将texelsPerUnit 参数从默认值调低至更小的数值是合理的。这尤其适用于内置基元以及几何结构足够简单的对象。此举可生成更小的光照贴图并缩短烘焙时间。首次烘焙时,默认值通常已足够,后续可根据需要进行调整。
    • Lightmapper 对象提供了许多具有合理默认值的设置,但其中部分设置可能需要调整,以符合设计师的预期。 例如,samples 和bounces 的调整会影响间接光照的质量,而indirectLightFactor 则可增强间接光照的贡献度。若出现图像瑕疵(特别是在阴影周围),可通过bias 进行微调。
    • 对生成的光照贴图进行降噪至关重要。间接光照是通过路径追踪计算得出的,根据所使用的samples 数量不同,生成的图像会带有不同程度的噪点。 增加采样数可减少噪点,但会延长生成光照贴图所需的时间。无论采样数多少,对生成的光照贴图(以二进制文件形式存储的 32 位 RGBA 浮点图像)运行去噪处理通常都是明智之举。

从 Qt 6.5 开始,通过“DebugView ”提供了交互式的运行时解决方案。在“Tools”下现在有一个按钮,点击后将触发烘焙过程。此时会弹出一个窗口,显示当前的处理进度。 若要取消操作,可点击“取消”按钮或关闭该窗口。处理完成后,系统会将光照贴图二进制文件写入当前目录。

降噪

下文是一个康奈尔方盒场景的示例:第一个渲染结果使用了通过 256 个samples 以及最多 3 个bounces 烘焙的光照贴图;第二个示例中,生成的图像文件经过了降噪处理,效果显著改善,噪点基本消失。

原始图像

康奈尔盒子场景,带一个点光源,光照贴图已完全烘焙

去噪后

经过降噪处理的光照贴图的康奈尔盒子场景

每个烘焙好的光照贴图都会自动进行去噪处理。如果工作目录中存在已烘焙的.raw 光照贴图文件,只需在DebugView 中点击Denoise 按钮,即可仅执行去噪操作。此外,还可以通过在调用应用程序时添加--denoise-lightmaps 参数来实现去噪。若需调整去噪强度,可使用denoiseSigma 属性。

光照贴图 UV

光照贴图的 UV 坐标不使用与常规贴图相同的 UV 数据。在使用光照贴图渲染时,渲染器在采样光照贴图时既不使用 UV0 数据,也不使用 UV1 数据。取而代之的是,网格中存在一个额外的专用 UV 通道,其中包含以适合光照贴图目的的方式布局的 UV 图表。 这涉及避免重叠并在适当位置添加填充。对于常规 UV 数据,则没有此类要求,而且人们很可能希望为多个顶点使用相同的 U 和 V 坐标。

生成合适 UV 集的过程称为光照贴图 UV 展开。 Qt 会在烘焙光照贴图时执行此操作,并将生成的网格存储在光照贴图文件中,以确保始终加载兼容的网格并将其用于生成的光照贴图。这意味着,如果模型始终使用烘焙光照,则无需将源网格文件随应用程序一起发布。

光照贴图纹理大小

对于每个模型(包括其所有子网格),光照贴图烘焙过程将在光照贴图 UV 生成阶段确定合适的光照贴图纹理大小。这会影响质量、性能以及资源使用情况(包括磁盘和内存)。

默认设置通常已足够,无需调整,特别是对于中等至高复杂度的模型。

不过,对于非常简单的模型,可能需要手动缩小尺寸,因为较小的光照贴图尺寸仍能提供视觉上良好的效果,同时缩小资源(光照贴图图像)的大小既能节省磁盘空间,又能节省内存。要做到这一点,请将“texelsPerUnit ”设置为一个适当的小数值。 然后,根据模型的大小和几何形状,光照贴图的实际宽度和高度将尝试近似纹素密度,使其与texelsPerUnit 相匹配。

更改该值后,应始终重新烘焙光照贴图,并通过目视检查结果来评估光照贴图尺寸变更带来的影响。

运行时使用光照贴图

在运行时使用预烘焙光照贴图时相关的属性与类型:

烘焙成功完成后,正常运行应用程序(未设置命令行参数或环境变量)将自动加载生成的光照贴图图像并正确渲染,而在光照贴图完成烘焙之前,这是无法实现的。 如果需要,应用程序可以将这些文件放置在其他位置,或者通过 Qt 资源系统将其作为可执行文件的一部分打包。这可以通过source 属性来启用。

以上面包含一个球体和四个矩形的示例代码为例,烘焙过程会生成一个名为 `lightmaps.bin ` 的文件,其中包含所有已烘焙的网格和光照贴图。应用程序需要将该文件放置在由 `source` 指定的位置,以便引擎能够找到它。

另请参阅 Qt Quick 3D - 烘焙光照贴图示例和Qt Quick 3D - SSGI 光照贴图示例。

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.