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