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
11\note As of Qt 6.4, lightmap baking is in an early technical preview state.
12Changes to features, quality, and API are likely to happen in future releases.
13
14Baked lightmaps allow pre-generating the \b{direct lighting} from lights such
15as \l DirectionalLight, \l PointLight, and \l SpotLight, including the shadows
16cast by the lights. At run time, instead of performing the appropriate
17calculations in the fragment shader, and, in case of shadows, generating the
18potentially costly shadow maps in real time, the pre-generated image map is
19sampled instead.
20
21A lightmap is generated per \l{Model}. Even if a \l{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 \l{DirectionalLight} 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 \l{DirectionalLight}'s direction.
38
39On the second image, 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{Lightmapper::texelsPerUnit}{texelsPerUnit} 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 bakedLightmap: BakedLightmap {
82 enabled: true
83 key: "sphere1"
84 }
85
86 source: "#Sphere"
87 materials: PrincipledMaterial { }
88 y: 100
89}
90Model {
91 usedInBakedLighting: true
92 bakedLightmap: BakedLightmap {
93 enabled: true
94 key: "rect1"
95 }
96
97 source: "#Rectangle"
98 materials: PrincipledMaterial { }
99 eulerRotation.x: -90
100 scale: Qt.vector3d(10, 10, 10)
101}
102
103// ... three additional Rectangle models, with rotations 0, 90, and -90
104
105\endqml
106
107The above example used fully baked lights. A light can also be configured to
108only use baked lighting for indirect illumination, while performing direct
109lighting and shadow mapping in real time. In the below scene there are 5 point
110lights, all of which are set to \l{Light::bakeMode}{BakeModeIndirect} for the
111second screenshot. While the direct lighting and shadows look identical, the
112second image looks significantly better due to a degree of global illumination
113added.
114
115\b{Real-time lighting}
116
117\image lightmap_sponza_none.jpg "Scene with Sponza and Suzanne models and 5 point lights"
118
119\b{With baked indirect lighting added}
120
121\image lightmap_sponza_indirect.jpg "Same scene with baked indirect but real-time direct lighting"
122
123\section2 Important considerations when working with lightmaps
124
125Lights contributing to baked lighting have their \l{Light::bakeMode}{bakeMode}
126property set to either \l{Light::bakeMode}{Light.BakeModeIndirect} or \l{Light::bakeMode}{Light.BakeModeAll}. The latter indicates
127that both the direct and indirect contribution for that particular light is
128coming from the lightmap. The direct contribution always includes shadows as
129well. On the other hand, if the intention with the lightmap is only to add
130indirect illumination to the scene for a particular light, while still having
131direct lighting calculated (and perform shadow mapping) in real time, then the
132light should use \l{Light::bakeMode}{Light.BakeModeIndirect} instead.
133
134\note Lightmaps are, generally speaking, suitable for models that are static
135when it comes to transform, geometry, and materials. The same applies to the
136lights participating in the baked lighting.
137
138For example, a scene that rotates a \l{Model} by animating the
139\l{Node::eulerRotation}{eulerRotation} property will give visually incorrect
140results when applying a lightmap to that \l{Model}. The rendering results for that
141particular \l{Model} will be incorrect, as the pre-generated lightmap only captures
142one single rotation state for the object. The same would be true, taking
143another example, if the material for one of the model's submeshes dynamically
144changes its \l{PrincipledMaterial::baseColor}{baseColor} property based on time
145(animation) or some user interaction. The lightmap can only capture one given
146material \l{PrincipledMaterial::baseColor}{baseColor}. The same is true for
147lights. For example, a \l DirectionalLight that rotates, changes its
148brightness, color, etc. over time is not suitable for baked lighting.
149
150\note On the other hand, it is always a designer choice when to use
151lightmapping. Especially with \l{Light::bakeMode}{BakeModeIndirect} lights, it
152is likely that there will be scenes where the results are still visually
153satisfying, even though some of the objects in the lightmapped scene employ
154dynamic behavior.
155
156Lightmapping is a complex engine and tooling feature. It replaces and
157reimplements several pieces of the engine's rendering pipeline. It works with a
158fundamentally different rendering model when baking lightmaps, while still
159consuming and interoperating with the same scene structure, asset data, and
160engine data structures. The raytracing-based results will often outclass the
161real-time alternatives, sometimes significantly, which comes at the expense of
162limitations, such as the mandatory static-ness of the models and lights
163involved, and, sometimes, quality and rendering artifact issues that are
164specific to lightmapping.
165
166In practice it will be an artistic choice by the designers what type of
167lighting to use, and when. All three \l{Light::bakeMode}{bakeMode} settings
168have their uses, and complex, larger scenes may very well utilize all three for
169different lights, depending on what is deemed suitable for a given section of
170the scene, and what sort of models, materials, and dynamic behavior are
171present. Lightmapping is not a simple on/off type of toggle switch that can be
172enabled for any scene and application, but a powerful feature that assumes
173careful evaluation of the lighting needs of a given scene, and often requires
174the scene contents and behavior to be designed accordingly, combined with a
175test-and-tune loop where different lightmap baking and quality settings are
176explored and tested before deciding on the final approach and the related
177settings.
178
179\note Lightmaps do not support two-sided surfaces. With real time lighting a
180material with a \l{QQuick3DMaterial::cullMode}{cull mode} of \c
181Material.NoCulling automatically inverts the normal as appropriate based on the
182facing of the fragment. This is not an option for lightmaps since lightmap
183baking does not operate in view space. Therefore, avoid baked lighting for
184models that would rely on this.
185
186\section1 Baking Lightmaps
187
188Properties and types relevant for baking lightmaps, meaning the offline process
189of generating the image maps that capture direct and indirect lighting and can
190be used by the renderer in subsequent runs of the application:
191
192\list
193\li \l Model::usedInBakedLighting
194\li \l Model::lightmapBaseResolution,
195\li \l Light::bakeMode,
196\li \l Lightmapper and \l SceneEnvironment::lightmapper
197\li \l BakedLightmap and \l Model::bakedLightmap
198\endlist
199
200As of Qt 6.4, the lightmap baking process has to be triggered manually.
201Whenever the command line argument \c{--bake-lightmaps} is present, or the
202environment variable \c{QT_QUICK3D_BAKE_LIGHTMAPS} is set to \c 1 (or another
203non-zero value), the engine will work in baking mode and exit the application
204once baking has completed. The steps of the baking process can be followed by
205checking the messages printed on the debug output. The result is a binary file
206(\c{lightmaps.bin} by default) written to the current working directory
207containing all the baked lightmaps in the scene. There will also be a \c{.raw}
208file created that contains the whole lightmap and some extra data that is needed
209for denoising. Each lightmap is uniquely identified in the file by the unique
210key from \l{BakedLightmap::key}.
211
212Preparing a lightmapped scene takes the following main steps:
213
214\list
215
216\li Identify which models should use a lightmap, and which models should
217contribute to the lightmap. Models that are part of the lightmapped scene
218should set \l Model::usedInBakedLighting to true. Models that are lightmapped
219(i.e., a lightmap is to be baked for them) should in addition set \l
220Model::bakedLightmap to an enabled \l BakedLightmap object, that provides a
221unique key that will persistently identify the particular Model object
222instance (this is because Qt needs a key to identify the model data in
223persistent disk storage). Only models with static geometry, transformation, and
224materials are guaranteed to have correct results when lightmapped at run-time.
225Most commonly, anything that leads to a non-static world transform over time,
226such as a dynamically changed or animated position, rotation, or scale, will
227disqualify the model from participating. Artistic needs can override this,
228however, especially for models that only contribute to baked indirect lighting
229but are not themselves lightmapped. For these it may often be visually
230acceptable to have dynamic transforms, but this always depends on the model and
231the scene in question.
232
233\li Identify which lights should contribute, and to which degree. \l
234Light::bakeMode offers three options:
235
236 \list
237
238 \li Light.BakeModeDisabled, the default, which effectively makes the light
239 ignored for all lightmapping purposes.
240
241 \li Light.BakeModeIndirect is often the "safe" choice, if the only goal is
242 to have a level of global illumination (indirect lighting) in the scene,
243 while not affecting the rendering results for the light in other ways. In
244 this mode the renderer will continue to perform all lighting, including
245 diffuse, specular, sky/environment contributions, and shadow mapping for
246 this light using the standard real-time techniques. However, the light will
247 contribute to indirect lighting using the pre-baked data, possibly leading
248 to illuminating surfaces that are otherwise left untouched by the standard
249 real-time lighting calculations.
250
251 \li Light.BakeModeAll is an option which will likely be used for certain
252 lights only, based on the designers' evaluation for what is deemed
253 appropriate for a given scene. In this mode all contribution from the light
254 is baked, including shadows. As of Qt 6.4 specular lighting are not
255 supported as part of the baked lighting, so such lights will not have
256 specular contributions. They will, on the other hand generate raytraced,
257 baked shadows and have proper occlusion for the light (will not "pass
258 through walls", for instance) since here all the direct lighting
259 contributions resulting from the light are raytraced at lightmap baking
260 time, instead of being calculated at run time. In addition, indirect
261 lighting is baked, just as with BakeModeIndirect.
262
263 \endlist
264
265\li Running the scene (application) in baking mode, ensuring lightmaps are
266successfully generated. As of Qt 6.4, applications are expected to be
267structured in a way that the lightmapped scene is the first view shown, or that
268the scene in question can be loaded up with a QML viewer such as the \c qml
269tool. Once baking completes, the progress of which can be followed on the
270console/debug output, the application exits.
271
272\li Running the scene (application) normally, to see how it looks with the
273lightmaps loaded. The tuning can then begin:
274
275 \list
276
277 \li For some models it will make sense to reduce
278 \l{Model::texelsPerUnit}{texelsPerUnit} from the default value
279 to something smaller. This applies especially to the built-in
280 primitives and anything with simple enough geometry. This leads to smaller
281 lightmaps and faster bake times. When baking the first time, the default
282 should be sufficient, the value can be tuned afterwards.
283
284 \li The Lightmapper object exposes numerous settings that have reasonable
285 defaults, but it is not unlikely that some of these will need to be tuned
286 to match the designers' expectation. For example, \l {Lightmapper::}{samples}
287 and \l {Lightmapper::}{bounces} can be changed to affect the quality of
288 indirect lighting, while \l {Lightmapper::}{indirectLightFactor} allows
289 making the indirect contribution more prominent. If artifacts, in
290 particular around shadows, occur, \l {Lightmapper::}{bias} can be
291 fine-tuned.
292
293 \li Denoising the generate lightmaps is essential. Indirect lighting is
294 calculated using \l{https://en.wikipedia.org/wiki/Path_tracing}{path
295 tracing}, which produces noisy images depending on the number of the
296 \l {Lightmapper::}{samples} used. Increasing the sample count reduces noise,
297 but increases the time needed to generate the lightmap. Regardless of the
298 sample count, it will almost always make sense to run a denoiser on the
299 generated lightmaps, which are 32-bit RGBA floating point images stored
300 in a binary file.
301
302 \endlist
303
304\endlist
305
306As of Qt 6.5, a runtime solution is provided interactively through the DebugView.
307Under Tools there is now a button that when pressed will trigger the baking process.
308A window will pop up showing the current process. Canceling can be done by
309either hitting the cancel button or closing this window. When complete, it will
310write the lightmap binary to the current directory.
311
312\section2 Denoising
313
314Below is an example of a \l{https://en.wikipedia.org/wiki/Cornell_box}{Cornell
315box} scene, rendered first using the lightmap baked with 256
316\l {Lightmapper::}{samples} and a maximum of 3 \l {Lightmapper::}{bounces}. In
317the second example, the generated image file has been denoised, and the results
318look significantly better, with the noise mostly gone.
319
320\b{Original}
321
322\image lightmap_noise_original.jpg "Cornell box scene with one point light, fully baked lightmap"
323
324\b{Denoised}
325
326\image lightmap_noise_denoised.jpg "Cornell box scene with the lightmaps denoised"
327
328Denoising is done automatically on every baked lightmap. It is possible to do
329just denoising, if an existing baked \c{.raw} lightmap file exists in the working
330directory, by clicking the \c{Denoise} button in the DebugView. It is also possible to
331denoise by calling the application with the \c{--denoise-lightmaps} argument.
332To tweak the strength of the denoising, the \l{Lightmapper::}{denoiseSigma} property
333can be used.
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
347will perform this when baking lightmaps and store the resulting mesh in the lightmaps
348file so that a compatible mesh is always loaded and used for the generated lightmap.
349This means that, if a model will always use baked lighting, then the source mesh
350file does not need to be shipped with the application.
351
352\section2 Lightmap texture size
353
354For each model, including all its submeshes, the lightmap baking process will
355determine a suitable lightmap texture size during the lightmap UV generation
356phase. This has an impact on quality, performance, and resource usage (both on
357disk and in memory).
358
359The default is often suitable and needs no adjustment, especially for models
360with medium to high complexity.
361
362For very simple models it may be desirable to manually reduce the size,
363however, because a smaller lightmap size could still provide visually good
364looking results, while reducing the asset (lightmap image) sizes saves both
365disk space and memory. To do this, set the \l{Model::texelsPerUnit}{texelsPerUnit}
366to a suitably small number. The actual lightmap width and height will then,
367depending on the size and the geometry of the model, try to approximate the
368texel density so that it matches \l{Model::texelsPerUnit}{texelsPerUnit}.
369
370When changing the value, one should always rebake the lightmaps and visually
371inspect the results in order to evaluate the effects of the changed lightmap
372size.
373
374\section1 Using Lightmaps at Run-Time
375
376Properties and types relevant when using the pre-baked lightmaps at run time:
377
378\list
379\li \l Light::bakeMode,
380\li \l BakedLightmap and \l Model::bakedLightmap
381\endlist
382
383Once the baking has successfully completed, running the application normally
384(without the command-line argument or environment variable set) will now pick
385up the generated lightmap images and render correctly, which is not possible
386until the lightmaps have been baked first. If desired, the application can
387place those in a different location, or ship them as part of the executable via
388the Qt Resource System. This is enabled by the \l{Lightmapper::}{source}
389property.
390
391Taking the example code with the sphere and four rectangles from above, the
392baking process generates a \c{lightmaps.bin} file containing all the baked
393meshes and lightmaps. The application needs to ship this file, so that it can be
394found by the engine, in the location specified by \l{Lightmapper::}{source}.
395
396\sa {Qt Quick 3D - Baked Lightmap Example}
397
398*/