Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qtquick3d-lightmap.qdoc
Go to the documentation of this file.
1// Copyright (C) 2022 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
3
4/*!
5
6\title Lightmaps and Global Illumination
7\page quick3d-lightmap
8
9\section1 Introduction
10
11Global illumination (GI) is the indirect light that reaches a surface after
12bouncing off other surfaces in a scene. Simulating GI produces effects such
13as color bleeding between nearby surfaces and softer ambient shading.
14
15\section1 Approaches to Global Illumination
16
17Qt Quick 3D offers two approaches to global illumination (GI):
18
19\list
20\li \b{Screen-Space Global Illumination (SSGI):} A dynamic
21indirect lighting method that uses screen-space buffers to approximate global
22illumination. You can enable SSGI through
23the \l{QtQuick3D.Helpers::ExtendedSceneEnvironment} type by setting the
24\l{QtQuick3D.Helpers::ExtendedSceneEnvironment::}{ssgiEnabled} property to
25\c true. SSGI is suitable for animated content where lights and geometry
26change at runtime, though screen-space approximations reduce accuracy.
27
28\li \b{Baked lightmaps:} A lighting method that uses raytraced lighting
29baked into textures and sampled at runtime. Baked lightmaps provide
30global illumination at lower runtime cost, which benefits static
31models, materials, and lights.
32\endlist
33
34For a side-by-side visual and behavioral comparison of the two
35techniques, see \l{Qt Quick 3D - SSGI Lightmap Example}.
36
37\section1 Baked Lightmaps
38
39Baked lightmaps allow pre-generating the \b{direct lighting} from lights such
40as \l DirectionalLight, \l PointLight, and \l SpotLight, including the shadows
41cast by the lights. At run time, instead of performing the appropriate
42calculations in the fragment shader, and, in case of shadows, generating the
43potentially costly shadow maps in real time, the pre-generated image map is
44sampled instead.
45
46A lightmap is generated per \l{Model}. Even if a \l{Model} has multiple submeshes, and
47is therefore associated with multiple materials, there will be one single
48lightmap image generated for the entire model.
49
50Lightmaps are generated using raytracing, which by nature provides proper
51occlusion ("light does not travel through walls"), and possibly more realistic
52shadows than the real-time techniques for lighting and shadow mapping.
53
54More importantly, lightmaps also allow baking \b{indirect lighting}, providing
55a solution for global illumination. This takes light rays reflected from other
56surfaces in the scene into account.
57
58Below is a simple example. The scene contains four Rectangle and a Sphere
59model, with a \l{DirectionalLight} pointing downwards and a PointLight. The rectangle
60models are rotated 0 and 90 degrees, which exaggerates the limitations of the
61real-time lighting calculations because they are all either parallel or
62perpendicular to the \l{DirectionalLight}'s direction.
63
64On the second image, the scene is rendered with lightmapping enabled, after having
65lightmaps baked for all five models. Both lights are set to fully baked,
66meaning both direct and indirect illumination is baked. Indirect lighting uses
67256 \l{Lightmapper::}{samples} and a maximum of 3 \l{Lightmapper::}{bounces}.
68The resulting lightmaps were then denoised. This gives a significantly more
69realistic image.
70
71\b{Real-time lighting}
72
73\image lightmap_simple_none.jpg "Simple scene with sphere, rectangles, and two lights"
74
75\b{Fully baked lighting}
76
77\image lightmap_simple_all.jpg "The same scene with both lights set to fully baked"
78
79Below is a snippet that shows how the lightmapped results were achieved. The
80difference lies in the \l{Model::usedInBakedLighting}{usedInBakedLighting},
81\l{Light::bakeMode}{bakeMode}, and \l{Model::bakedLightmap}{bakedLightmap}
82properties. For this example, the lightmap size has been reduced using the
83\l{Lightmapper::texelsPerUnit}{texelsPerUnit} property, to save
84disk space and reduce application load times.
85
86\qml
87DirectionalLight {
88 bakeMode: Light.BakeModeAll
89
90 eulerRotation.x: -90
91 brightness: 0.5
92 castsShadow: true
93 shadowFactor: 75
94}
95PointLight {
96 bakeMode: Light.BakeModeAll
97
98 y: 200
99 z: 100
100 color: "#d9c62b"
101 castsShadow: true
102 shadowFactor: 75
103}
104Model {
105 usedInBakedLighting: true
106 bakedLightmap: BakedLightmap {
107 enabled: true
108 key: "sphere1"
109 }
110
111 source: "#Sphere"
112 materials: PrincipledMaterial { }
113 y: 100
114}
115Model {
116 usedInBakedLighting: true
117 bakedLightmap: BakedLightmap {
118 enabled: true
119 key: "rect1"
120 }
121
122 source: "#Rectangle"
123 materials: PrincipledMaterial { }
124 eulerRotation.x: -90
125 scale: Qt.vector3d(10, 10, 10)
126}
127
128// ... three additional Rectangle models, with rotations 0, 90, and -90
129
130\endqml
131
132The above example used fully baked lights. A light can also be configured to
133only use baked lighting for indirect illumination, while performing direct
134lighting and shadow mapping in real time. In the below scene there are 5 point
135lights, all of which are set to \l{Light::bakeMode}{BakeModeIndirect} for the
136second screenshot. While the direct lighting and shadows look identical, the
137second image looks significantly better due to a degree of global illumination
138added.
139
140\b{Real-time lighting}
141
142\image lightmap_sponza_none.jpg "Scene with Sponza and Suzanne models and 5 point lights"
143
144\b{With baked indirect lighting added}
145
146\image lightmap_sponza_indirect.jpg "Same scene with baked indirect but real-time direct lighting"
147
148\section2 Important considerations when working with lightmaps
149
150Lights contributing to baked lighting have their \l{Light::bakeMode}{bakeMode}
151property set to either \l{Light::bakeMode}{Light.BakeModeIndirect} or \l{Light::bakeMode}{Light.BakeModeAll}. The latter indicates
152that both the direct and indirect contribution for that particular light is
153coming from the lightmap. The direct contribution always includes shadows as
154well. On the other hand, if the intention with the lightmap is only to add
155indirect illumination to the scene for a particular light, while still having
156direct lighting calculated (and perform shadow mapping) in real time, then the
157light should use \l{Light::bakeMode}{Light.BakeModeIndirect} instead.
158
159\note Lightmaps are, generally speaking, suitable for models that are static
160when it comes to transform, geometry, and materials. The same applies to the
161lights participating in the baked lighting.
162
163For example, a scene that rotates a \l{Model} by animating the
164\l{Node::eulerRotation}{eulerRotation} property will give visually incorrect
165results when applying a lightmap to that \l{Model}. The rendering results for that
166particular \l{Model} will be incorrect, as the pre-generated lightmap only captures
167one single rotation state for the object. The same would be true, taking
168another example, if the material for one of the model's submeshes dynamically
169changes its \l{PrincipledMaterial::baseColor}{baseColor} property based on time
170(animation) or some user interaction. The lightmap can only capture one given
171material \l{PrincipledMaterial::baseColor}{baseColor}. The same is true for
172lights. For example, a \l DirectionalLight that rotates, changes its
173brightness, color, etc. over time is not suitable for baked lighting.
174
175\note On the other hand, it is always a designer choice when to use
176lightmapping. Especially with \l{Light::bakeMode}{BakeModeIndirect} lights, it
177is likely that there will be scenes where the results are still visually
178satisfying, even though some of the objects in the lightmapped scene employ
179dynamic behavior.
180
181Lightmapping is a complex engine and tooling feature. It replaces and
182reimplements several pieces of the engine's rendering pipeline. It works with a
183fundamentally different rendering model when baking lightmaps, while still
184consuming and interoperating with the same scene structure, asset data, and
185engine data structures. The raytracing-based results will often outclass the
186real-time alternatives, sometimes significantly, which comes at the expense of
187limitations, such as the mandatory static-ness of the models and lights
188involved, and, sometimes, quality and rendering artifact issues that are
189specific to lightmapping.
190
191In practice it will be an artistic choice by the designers what type of
192lighting to use, and when. All three \l{Light::bakeMode}{bakeMode} settings
193have their uses, and complex, larger scenes may very well utilize all three for
194different lights, depending on what is deemed suitable for a given section of
195the scene, and what sort of models, materials, and dynamic behavior are
196present. Lightmapping is not a simple on/off type of toggle switch that can be
197enabled for any scene and application, but a powerful feature that assumes
198careful evaluation of the lighting needs of a given scene, and often requires
199the scene contents and behavior to be designed accordingly, combined with a
200test-and-tune loop where different lightmap baking and quality settings are
201explored and tested before deciding on the final approach and the related
202settings.
203
204\note Lightmaps do not support two-sided surfaces. With real time lighting a
205material with a \l{Material::cullMode}{cull mode} of \c
206Material.NoCulling automatically inverts the normal as appropriate based on the
207facing of the fragment. This is not an option for lightmaps since lightmap
208baking does not operate in view space. Therefore, avoid baked lighting for
209models that would rely on this.
210
211\section1 Baking Lightmaps
212
213Properties and types relevant for baking lightmaps, meaning the offline process
214of generating the image maps that capture direct and indirect lighting and can
215be used by the renderer in subsequent runs of the application:
216
217\list
218\li \l Model::usedInBakedLighting
219\li \l Model::lightmapBaseResolution,
220\li \l Light::bakeMode,
221\li \l Lightmapper and \l SceneEnvironment::lightmapper
222\li \l BakedLightmap and \l Model::bakedLightmap
223\endlist
224
225As of Qt 6.4, the lightmap baking process has to be triggered manually.
226Whenever the command line argument \c{--bake-lightmaps} is present, or the
227environment variable \c{QT_QUICK3D_BAKE_LIGHTMAPS} is set to \c 1 (or another
228non-zero value), the engine will work in baking mode and exit the application
229once baking has completed. The steps of the baking process can be followed by
230checking the messages printed on the debug output. The result is a binary file
231(\c{lightmaps.bin} by default) written to the current working directory
232containing all the baked lightmaps in the scene. There will also be a \c{.raw}
233file created that contains the whole lightmap and some extra data that is needed
234for denoising. Each lightmap is uniquely identified in the file by the unique
235key from \l{BakedLightmap::key}.
236
237Preparing a lightmapped scene takes the following main steps:
238
239\list
240
241\li Identify which models should use a lightmap, and which models should
242contribute to the lightmap. Models that are part of the lightmapped scene
243should set \l Model::usedInBakedLighting to true. Models that are lightmapped
244(i.e., a lightmap is to be baked for them) should in addition set \l
245Model::bakedLightmap to an enabled \l BakedLightmap object, that provides a
246unique key that will persistently identify the particular Model object
247instance (this is because Qt needs a key to identify the model data in
248persistent disk storage). Only models with static geometry, transformation, and
249materials are guaranteed to have correct results when lightmapped at run-time.
250Most commonly, anything that leads to a non-static world transform over time,
251such as a dynamically changed or animated position, rotation, or scale, will
252disqualify the model from participating. Artistic needs can override this,
253however, especially for models that only contribute to baked indirect lighting
254but are not themselves lightmapped. For these it may often be visually
255acceptable to have dynamic transforms, but this always depends on the model and
256the scene in question.
257
258\li Identify which lights should contribute, and to which degree. \l
259Light::bakeMode offers three options:
260
261 \list
262
263 \li Light.BakeModeDisabled, the default, which effectively makes the light
264 ignored for all lightmapping purposes.
265
266 \li Light.BakeModeIndirect is often the "safe" choice, if the only goal is
267 to have a level of global illumination (indirect lighting) in the scene,
268 while not affecting the rendering results for the light in other ways. In
269 this mode the renderer will continue to perform all lighting, including
270 diffuse, specular, sky/environment contributions, and shadow mapping for
271 this light using the standard real-time techniques. However, the light will
272 contribute to indirect lighting using the pre-baked data, possibly leading
273 to illuminating surfaces that are otherwise left untouched by the standard
274 real-time lighting calculations.
275
276 \li Light.BakeModeAll is an option which will likely be used for certain
277 lights only, based on the designers' evaluation for what is deemed
278 appropriate for a given scene. In this mode all contribution from the light
279 is baked, including shadows. As of Qt 6.4 specular lighting are not
280 supported as part of the baked lighting, so such lights will not have
281 specular contributions. They will, on the other hand generate raytraced,
282 baked shadows and have proper occlusion for the light (will not "pass
283 through walls", for instance) since here all the direct lighting
284 contributions resulting from the light are raytraced at lightmap baking
285 time, instead of being calculated at run time. In addition, indirect
286 lighting is baked, just as with BakeModeIndirect.
287
288 \endlist
289
290\li Running the scene (application) in baking mode, ensuring lightmaps are
291successfully generated. As of Qt 6.4, applications are expected to be
292structured in a way that the lightmapped scene is the first view shown, or that
293the scene in question can be loaded up with a QML viewer such as the \c qml
294tool. Once baking completes, the progress of which can be followed on the
295console/debug output, the application exits.
296
297\li Running the scene (application) normally, to see how it looks with the
298lightmaps loaded. The tuning can then begin:
299
300 \list
301
302 \li For some models it will make sense to reduce
303 \l{Model::texelsPerUnit}{texelsPerUnit} from the default value
304 to something smaller. This applies especially to the built-in
305 primitives and anything with simple enough geometry. This leads to smaller
306 lightmaps and faster bake times. When baking the first time, the default
307 should be sufficient, the value can be tuned afterwards.
308
309 \li The Lightmapper object exposes numerous settings that have reasonable
310 defaults, but it is not unlikely that some of these will need to be tuned
311 to match the designers' expectation. For example, \l {Lightmapper::}{samples}
312 and \l {Lightmapper::}{bounces} can be changed to affect the quality of
313 indirect lighting, while \l {Lightmapper::}{indirectLightFactor} allows
314 making the indirect contribution more prominent. If artifacts, in
315 particular around shadows, occur, \l {Lightmapper::}{bias} can be
316 fine-tuned.
317
318 \li Denoising the generate lightmaps is essential. Indirect lighting is
319 calculated using \l{https://en.wikipedia.org/wiki/Path_tracing}{path
320 tracing}, which produces noisy images depending on the number of the
321 \l {Lightmapper::}{samples} used. Increasing the sample count reduces noise,
322 but increases the time needed to generate the lightmap. Regardless of the
323 sample count, it will almost always make sense to run a denoiser on the
324 generated lightmaps, which are 32-bit RGBA floating point images stored
325 in a binary file.
326
327 \endlist
328
329\endlist
330
331As of Qt 6.5, a runtime solution is provided interactively through the DebugView.
332Under Tools there is now a button that when pressed will trigger the baking process.
333A window will pop up showing the current process. Canceling can be done by
334either hitting the cancel button or closing this window. When complete, it will
335write the lightmap binary to the current directory.
336
337\section2 Denoising
338
339Below is an example of a \l{https://en.wikipedia.org/wiki/Cornell_box}{Cornell
340box} scene, rendered first using the lightmap baked with 256
341\l {Lightmapper::}{samples} and a maximum of 3 \l {Lightmapper::}{bounces}. In
342the second example, the generated image file has been denoised, and the results
343look significantly better, with the noise mostly gone.
344
345\b{Original}
346
347\image lightmap_noise_original.jpg "Cornell box scene with one point light, fully baked lightmap"
348
349\b{Denoised}
350
351\image lightmap_noise_denoised.jpg "Cornell box scene with the lightmaps denoised"
352
353Denoising is done automatically on every baked lightmap. It is possible to do
354just denoising, if an existing baked \c{.raw} lightmap file exists in the working
355directory, by clicking the \c{Denoise} button in the DebugView. It is also possible to
356denoise by calling the application with the \c{--denoise-lightmaps} argument.
357To tweak the strength of the denoising, the \l{Lightmapper::}{denoiseSigma} property
358can be used.
359
360\section2 Lightmap UVs
361
362Lightmap UV coordinates do not use the same UV data as regular texturing. When
363rendering with lightmaps, neither the UV0 nor UV1 data is used by the renderer
364when sampling the lightmap. Instead, there is an additional, dedicated UV
365channel in the mesh, containing UV charts laid out in a manner that is suitable
366for the purposes of lightmapping. This involves avoiding overlaps and having
367padding where appropriate. For regular UV data there are no such requirements,
368and one may very well want to use the same U and V coordinates for more than
369one vertex.
370
371The process of generating a suitable UV set is called lightmap UV unwrapping. Qt
372will perform this when baking lightmaps and store the resulting mesh in the lightmaps
373file so that a compatible mesh is always loaded and used for the generated lightmap.
374This means that, if a model will always use baked lighting, then the source mesh
375file does not need to be shipped with the application.
376
377\section2 Lightmap texture size
378
379For each model, including all its submeshes, the lightmap baking process will
380determine a suitable lightmap texture size during the lightmap UV generation
381phase. This has an impact on quality, performance, and resource usage (both on
382disk and in memory).
383
384The default is often suitable and needs no adjustment, especially for models
385with medium to high complexity.
386
387For very simple models it may be desirable to manually reduce the size,
388however, because a smaller lightmap size could still provide visually good
389looking results, while reducing the asset (lightmap image) sizes saves both
390disk space and memory. To do this, set the \l{Model::texelsPerUnit}{texelsPerUnit}
391to a suitably small number. The actual lightmap width and height will then,
392depending on the size and the geometry of the model, try to approximate the
393texel density so that it matches \l{Model::texelsPerUnit}{texelsPerUnit}.
394
395When changing the value, one should always rebake the lightmaps and visually
396inspect the results in order to evaluate the effects of the changed lightmap
397size.
398
399\section1 Using Lightmaps at Run-Time
400
401Properties and types relevant when using the pre-baked lightmaps at run time:
402
403\list
404\li \l Light::bakeMode,
405\li \l BakedLightmap and \l Model::bakedLightmap
406\endlist
407
408Once the baking has successfully completed, running the application normally
409(without the command-line argument or environment variable set) will now pick
410up the generated lightmap images and render correctly, which is not possible
411until the lightmaps have been baked first. If desired, the application can
412place those in a different location, or ship them as part of the executable via
413the Qt Resource System. This is enabled by the \l{Lightmapper::}{source}
414property.
415
416Taking the example code with the sphere and four rectangles from above, the
417baking process generates a \c{lightmaps.bin} file containing all the baked
418meshes and lightmaps. The application needs to ship this file, so that it can be
419found by the engine, in the location specified by \l{Lightmapper::}{source}.
420
421\sa {Qt Quick 3D - Baked Lightmap Example}
422\sa {Qt Quick 3D - SSGI Lightmap Example}
423
424*/