Lightmaps und globale Beleuchtung

Einführung

Mit gebackenen Lightmaps kann die direkte Beleuchtung von Lichtern wie DirectionalLight, PointLight und SpotLight einschließlich der von den Lichtern geworfenen Schatten vorgeneriert werden. Anstatt zur Laufzeit die entsprechenden Berechnungen im Fragment-Shader durchzuführen und im Falle von Schatten die potentiell kostspieligen Shadow-Maps in Echtzeit zu generieren, wird stattdessen die vorgenerierte Image-Map abgetastet.

Hinweis: Ab Qt 6.4 befindet sich das Lightmap-Baking in einem frühen technischen Vorschaustadium. Änderungen an den Funktionen, der Qualität und der API werden wahrscheinlich in zukünftigen Versionen erfolgen.

Eine Lightmap wird pro Modell erzeugt. Selbst wenn ein Modell mehrere Submeshes hat und daher mit mehreren Materialien verbunden ist, wird ein einziges Lightmap-Bild für das gesamte Modell erzeugt.

Lightmaps werden mit Raytracing generiert, das von Natur aus eine korrekte Okklusion ("Licht geht nicht durch Wände") und möglicherweise realistischere Schatten als die Echtzeittechniken für Beleuchtung und Schattenmapping bietet.

Noch wichtiger ist, dass Lightmaps auch das Backen von indirekter Beleuchtung ermöglichen und eine Lösung für globale Beleuchtung bieten. Dabei werden Lichtstrahlen, die von anderen Oberflächen in der Szene reflektiert werden, berücksichtigt.

Nachfolgend ein einfaches Beispiel. Die Szene enthält vier Rechteck- und ein Kugelmodell mit einem nach unten gerichteten DirectionLight und einer PointLight. Die Rechteckmodelle sind um 0 und 90 Grad gedreht, was die Grenzen der Echtzeit-Beleuchtungsberechnungen verdeutlicht, da sie alle entweder parallel oder senkrecht zur Richtung der DirectionalLight verlaufen.

Rechts wird die Szene mit aktiviertem Lightmapping gerendert, nachdem die Lightmaps für alle fünf Modelle gebacken wurden. Beide Lichter sind auf vollständig gebacken eingestellt, was bedeutet, dass sowohl die direkte als auch die indirekte Beleuchtung gebacken ist. Für die indirekte Beleuchtung werden 256 samples und maximal 3 bounces verwendet. Die resultierenden Lightmaps wurden dann entrauscht. Das Ergebnis ist ein wesentlich realistischeres Bild.

Beleuchtung in Echtzeit

"Simple scene with sphere, rectangles, and two lights"

Vollständig gebackene Beleuchtung

"The same scene with both lights set to fully baked"

Der folgende Ausschnitt zeigt, wie die Lightmapping-Ergebnisse erzielt wurden. Der Unterschied liegt in den Eigenschaften usedInBakedLighting, bakeMode und bakedLightmap. In diesem Beispiel wurde die Größe der Lichtkarte mit der Eigenschaft lightmapBaseResolution reduziert, um Speicherplatz zu sparen und die Ladezeiten der Anwendung zu verringern.

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
    lightmapBaseResolution: 256
    bakedLightmap: BakedLightmap {
        enabled: true
        key: "sphere1"
    }

    source: "#Sphere"
    materials: PrincipledMaterial { }
    y: 100
}
Model {
    usedInBakedLighting: true
    lightmapBaseResolution: 256
    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

Im obigen Beispiel wurden vollständig gebackene Lichter verwendet. Ein Licht kann auch so konfiguriert werden, dass nur die gebackene Beleuchtung für die indirekte Beleuchtung verwendet wird, während die direkte Beleuchtung und die Schattenzuordnung in Echtzeit erfolgen. In der folgenden Szene gibt es 5 Punktlichter, die für den rechten Screenshot alle auf BakeModeIndirect eingestellt sind. Während die direkte Beleuchtung und die Schatten identisch aussehen, sieht das rechte Bild aufgrund einer gewissen globalen Beleuchtung deutlich besser aus.

Beleuchtung in Echtzeit

"Scene with Sponza and Suzanne models and 5 point lights"

Mit gebackener indirekter Beleuchtung

"Same scene with baked indirect but real-time direct lighting"

Wichtige Überlegungen bei der Arbeit mit Lichtkarten

Bei Lichtern, die zur gebackenen Beleuchtung beitragen, ist die Eigenschaft bakeMode entweder auf BakeModeIndirect oder BakeModeAll eingestellt. Letzteres bedeutet, dass sowohl der direkte als auch der indirekte Beitrag für dieses bestimmte Licht von der Lichtkarte stammt. Der direkte Beitrag umfasst immer auch Schatten. Wenn man hingegen mit der Lightmap nur die indirekte Beleuchtung für ein bestimmtes Licht in die Szene einbringen will, während die direkte Beleuchtung in Echtzeit berechnet wird (und Schattenmapping durchgeführt wird), dann sollte das Licht stattdessen BakeModeIndirect verwenden.

Hinweis: Lightmaps sind im Allgemeinen für Modelle geeignet, die in Bezug auf Transformation, Geometrie und Materialien statisch sind. Das Gleiche gilt für die Lichter, die an der gebackenen Beleuchtung beteiligt sind.

Eine Szene, die zum Beispiel ein Modell durch Animieren der Eigenschaft eulerRotation dreht, wird visuell falsche Ergebnisse liefern, wenn eine Lightmap auf dieses Modell angewendet wird. Die Rendering-Ergebnisse für dieses bestimmte Modell werden falsch sein, da die vorgenerierte Lightmap nur einen einzigen Rotationszustand für das Objekt erfasst. Dasselbe gilt, um ein anderes Beispiel zu nennen, wenn das Material für eine der Untermaschen des Modells seine baseColor Eigenschaft dynamisch in Abhängigkeit von der Zeit (Animation) oder einer Benutzerinteraktion ändert. Die Lichtkarte kann nur ein bestimmtes Material baseColor erfassen. Das Gleiche gilt für Lichter. Zum Beispiel ist eine DirectionalLight, die sich dreht, ihre Helligkeit, Farbe usw. mit der Zeit ändert, nicht für gebackene Beleuchtung geeignet.

Hinweis: Andererseits ist es immer eine Entscheidung des Designers, wann er Lightmapping verwenden möchte. Besonders bei BakeModeIndirect Lichtern ist es wahrscheinlich, dass es Szenen gibt, bei denen die Ergebnisse immer noch visuell zufriedenstellend sind, auch wenn einige der Objekte in der Lightmapping-Szene ein dynamisches Verhalten aufweisen.

Lightmapping ist ein komplexes Engine- und Tooling-Feature. Es ersetzt und implementiert mehrere Teile der Rendering-Pipeline der Engine neu. Beim Backen von Lightmaps wird mit einem grundlegend anderen Rendering-Modell gearbeitet, wobei jedoch dieselbe Szenenstruktur, dieselben Asset-Daten und dieselben Datenstrukturen der Engine verwendet werden und mit ihnen interagieren. Die auf Raytracing basierenden Ergebnisse sind den Echtzeit-Alternativen oft überlegen, manchmal sogar deutlich, was auf Kosten von Einschränkungen geht, wie z. B. der obligatorischen Statik der beteiligten Modelle und Lichter und manchmal Qualitäts- und Rendering-Artefakt-Problemen, die spezifisch für Lightmapping sind.

In der Praxis wird es eine künstlerische Entscheidung der Designer sein, welche Art von Beleuchtung sie wann verwenden. Alle drei Einstellungen von bakeMode haben ihre Berechtigung, und in komplexen, größeren Szenen kann es durchaus vorkommen, dass alle drei für verschiedene Beleuchtungen verwendet werden, je nachdem, was für einen bestimmten Abschnitt der Szene als geeignet erachtet wird und welche Art von Modellen, Materialien und dynamischem Verhalten vorhanden ist. Lightmapping ist kein einfacher Ein/Aus-Schalter, der für jede Szene und Anwendung aktiviert werden kann, sondern eine leistungsstarke Funktion, die eine sorgfältige Bewertung der Beleuchtungsanforderungen einer bestimmten Szene voraussetzt und oft erfordert, dass der Inhalt und das Verhalten der Szene entsprechend gestaltet werden, kombiniert mit einer Test- und Abstimmungsschleife, in der verschiedene Lightmap-Backing- und Qualitätseinstellungen erforscht und getestet werden, bevor man sich für den endgültigen Ansatz und die entsprechenden Einstellungen entscheidet.

Hinweis: Lightmaps unterstützen keine zweiseitigen Oberflächen. Bei Echtzeit-Beleuchtung kehrt ein Material mit einer cull mode von Material.NoCulling die Normalen automatisch um, je nach der Ausrichtung des Fragments. Dies ist bei Lightmaps nicht möglich, da das Backen von Lightmaps nicht im View Space funktioniert. Vermeiden Sie daher gebackene Beleuchtung für Modelle, die darauf angewiesen sind.

Backen von Lightmaps

Eigenschaften und Typen, die für das Baking von Lightmaps relevant sind, d. h. den Offline-Prozess der Erzeugung von Image Maps, die direkte und indirekte Beleuchtung erfassen und vom Renderer in nachfolgenden Durchläufen der Anwendung verwendet werden können:

Ab Qt 6.4 muss der Lightmap-Backvorgang manuell ausgelöst werden. Immer wenn das Kommandozeilenargument --bake-lightmaps vorhanden ist oder die Umgebungsvariable QT_QUICK3D_BAKE_LIGHTMAPS auf 1 (oder einen anderen Wert ungleich Null) gesetzt ist, arbeitet die Engine im Backmodus und beendet die Anwendung, sobald das Backen abgeschlossen ist. Die Schritte des Backvorgangs können anhand der in der Debug-Ausgabe ausgegebenen Meldungen verfolgt werden. Das Ergebnis ist ein Satz von .exr Dateien, die in das aktuelle Verzeichnis geschrieben werden, wobei die Dateinamen jeweils ein qlm_ Präfix haben, gefolgt von dem eindeutigen Schlüssel von BakedLightmap::key.

Die Vorbereitung einer Lightmapped-Szene umfasst die folgenden Hauptschritte:

  • Identifizieren Sie, welche Modelle eine Lightmap verwenden sollen und welche Modelle zur Lightmap beitragen sollen. Modelle, die Teil der Lightmap-Szene sind, sollten Model::usedInBakedLighting auf true setzen. Modelle, die lightmapped sind (d.h. für die eine Lightmap gebacken werden soll), sollten zusätzlich Model::bakedLightmap auf ein aktiviertes BakedLightmap Objekt setzen, das einen eindeutigen Schlüssel liefert, der die bestimmte Model-Objektinstanz dauerhaft identifiziert. (Das liegt daran, dass Qt einen Schlüssel benötigt, um die Modelldaten im persistenten Plattenspeicher zu identifizieren) Nur Modelle mit statischer Geometrie, Transformation und Materialien haben garantiert korrekte Ergebnisse, wenn zur Laufzeit ein Lightmap erstellt wird. In der Regel wird alles, was zu einer nicht statischen Welttransformation über die Zeit führt, wie z.B. eine dynamisch veränderte oder animierte Position, Rotation oder Skalierung, das Modell von der Teilnahme ausschließen. Künstlerische Anforderungen können dies jedoch außer Kraft setzen, insbesondere bei Modellen, die nur zur gebackenen indirekten Beleuchtung beitragen, aber selbst nicht beleuchtet sind. Für diese kann es oft visuell akzeptabel sein, dynamische Transformationen zu haben, aber das hängt immer von dem Modell und der betreffenden Szene ab.
  • Legen Sie fest, welche Lichter in welchem Ausmaß beitragen sollen. Light::bakeMode bietet drei Optionen:
    • Light.BakeModeDisabled, die Standardeinstellung, bei der das Licht für alle Lightmapping-Zwecke effektiv ignoriert wird.
    • Light.BakeModeIndirect ist oft die "sichere" Wahl, wenn das einzige Ziel darin besteht, ein gewisses Maß an globaler Beleuchtung (indirekte Beleuchtung) in der Szene zu haben, ohne die Rendering-Ergebnisse für das Licht auf andere Weise zu beeinflussen. In diesem Modus führt der Renderer weiterhin alle Beleuchtungen, einschließlich diffuser, spiegelnder, Himmels-/Umgebungsbeiträge und Schattenzuordnung für dieses Licht unter Verwendung der Standard-Echtzeittechniken aus. Das Licht trägt jedoch zur indirekten Beleuchtung bei, indem es die vorgebackenen Daten verwendet, was dazu führen kann, dass Oberflächen beleuchtet werden, die ansonsten von den Standard-Echtzeitbeleuchtungsberechnungen unberührt bleiben.
    • Light.BakeModeAll ist eine Option, die wahrscheinlich nur für bestimmte Lichter verwendet wird, basierend auf der Einschätzung der Designer, was für eine bestimmte Szene als angemessen erachtet wird. In diesem Modus wird der gesamte Beitrag des Lichts gebacken, einschließlich der Schatten. Seit Qt 6.4 werden spiegelnde Lichter nicht mehr als Teil der gebackenen Beleuchtung unterstützt, so dass solche Lichter keine spiegelnden Beiträge haben. Auf der anderen Seite erzeugen sie raytraced, gebackene Schatten und haben eine korrekte Okklusion für das Licht (gehen z.B. nicht durch Wände), da hier alle direkten Beleuchtungsbeiträge, die aus dem Licht resultieren, zum Zeitpunkt des Backens der Lightmap raytraced werden, anstatt zur Laufzeit berechnet zu werden. Außerdem wird die indirekte Beleuchtung gebacken, genau wie bei BakeModeIndirect.
  • Ausführen der Szene (Anwendung) im Backmodus, um sicherzustellen, dass Lightmaps erfolgreich erzeugt werden. Ab Qt 6.4 wird erwartet, dass Anwendungen so strukturiert sind, dass die Lightmap-Szene die erste Ansicht ist, die angezeigt wird, oder dass die betreffende Szene mit einem QML-Viewer wie dem qml Tool geladen werden kann. Nach Abschluss des Backvorgangs, dessen Fortschritt in der Konsole/Debug-Ausgabe verfolgt werden kann, wird die Anwendung beendet.
  • Die Szene (Anwendung) wird normal ausgeführt, um zu sehen, wie sie mit den geladenen Lightmaps aussieht. Dann kann das Tuning beginnen:
    • Für einige Modelle wird es sinnvoll sein, lightmapBaseResolution von den standardmäßigen 1024 auf etwas Kleineres zu reduzieren. Dies gilt besonders für die eingebauten Primitive und alles mit einfacher Geometrie. Dies führt zu kleineren Lightmaps und schnelleren Bake-Zeiten. Beim ersten Backen sollte der Standardwert ausreichend sein, danach kann der Wert angepasst werden.
    • Das Lightmapper-Objekt bietet zahlreiche Einstellungen mit vernünftigen Standardwerten, aber es ist nicht unwahrscheinlich, dass einige davon angepasst werden müssen, damit sie den Erwartungen der Designer entsprechen. Zum Beispiel können samples und bounces geändert werden, um die Qualität der indirekten Beleuchtung zu beeinflussen, während indirectLightFactor es ermöglicht, den indirekten Beitrag stärker hervorzuheben. Wenn Artefakte, insbesondere im Schattenbereich, auftreten, kann bias feiner abgestimmt werden.
    • Die Entrauschung der erzeugten Lichtkarten ist unerlässlich. Die indirekte Beleuchtung wird mit Hilfe der Pfadverfolgung berechnet, die je nach Anzahl der verwendeten samples verrauschte Bilder erzeugt. Eine Erhöhung der Stichprobenzahl verringert das Rauschen, erhöht aber die für die Erstellung der Lichtkarte benötigte Zeit. Unabhängig von der Anzahl der Samples ist es fast immer sinnvoll, einen Denoiser auf die erzeugten Lightmaps anzuwenden, die als 32-Bit-RGBA-Fließkommabilder in .exr-Dateien gespeichert werden.

Seit Qt 6.5 wird eine Laufzeitlösung interaktiv über DebugView bereitgestellt. Unter Tools gibt es nun eine Schaltfläche, die bei Betätigung den Backprozess auslöst. Es öffnet sich ein Fenster, das den aktuellen Prozess anzeigt. Der Vorgang kann entweder durch Drücken der Schaltfläche Abbrechen oder durch Schließen des Fensters abgebrochen werden. Wenn der Vorgang abgeschlossen ist, wird versucht, die vorhandenen .exr-Dateien zu überschreiben, falls dies mit dem loadPrefix möglich ist, andernfalls werden sie in das aktuelle Verzeichnis geschrieben. Im Moment ist die Entrauschung noch ein manueller Prozess, auch wenn die Runtime-Lösung verwendet wird.

Rauschunterdrückung

Unten sehen Sie ein Beispiel für eine Cornell-Box-Szene, die zunächst mit der Lightmap Baked mit 256 samples und maximal 3 bounces gerendert wurde. Im zweiten Beispiel wurde die erzeugte Bilddatei mit Hilfe der Open Image Denoise-Bibliothek entrauscht. Die Ergebnisse sehen deutlich besser aus, da das Rauschen weitgehend verschwunden ist.

Original

"Cornell box scene with one point light, fully baked lightmap"

Entrauscht

"Cornell box scene with the lightmaps denoised"

Ein einfacher, Qt-basierter Befehlszeilen-Wrapper für OIDN, der mit den von Qt Quick 3D erzeugten qlm_*.exr Bildern arbeitet, ist unter https://git.qt.io/laagocs/qlmdenoiser verfügbar . Er muss derzeit aus dem Quellcode erstellt werden und es sind keine vorgefertigten Binärdateien verfügbar.

Lightmap-UVs

Lightmap-UV-Koordinaten verwenden nicht die gleichen UV-Daten wie reguläre Texturen. Beim Rendering mit Lightmaps werden weder die UV0- noch die UV1-Daten vom Renderer beim Sampling der Lightmap verwendet. Stattdessen gibt es einen zusätzlichen, dedizierten UV-Kanal im Mesh, der UV-Charts enthält, die so angeordnet sind, dass sie für die Zwecke des Lightmappings geeignet sind. Dazu gehört, dass Überschneidungen vermieden werden und gegebenenfalls Polsterungen vorhanden sind. Für reguläre UV-Daten gibt es keine derartigen Anforderungen, und man kann sehr wohl die gleichen U- und V-Koordinaten für mehr als einen Scheitelpunkt verwenden wollen.

Der Prozess der Erzeugung eines geeigneten UV-Sets wird Lightmap-UV-Unwrapping genannt. Qt ist immer in der Lage, dies zur Laufzeit (Ladezeit) durchzuführen, sowohl beim Backen von Lightmaps als auch beim normalen Rendern einer Szene.

Um die Ladezeiten von Meshes zu verbessern, indem die Erzeugung von Lightmap-UV-Daten für Lightmap-Modelle zur Laufzeit vermieden wird, gibt es zwei Möglichkeiten:

  • Für Modelle, für die keine Lightmap-UV-Daten verfügbar sind, gibt der Lightmap-Backprozess ebenfalls einen Satz von qlm_*.mesh Dateien aus, deren Namen auf der Grundlage von BakedLightmap::key generiert werden, ähnlich wie bei den .exr Bildern. Wenn die Anwendung dies wünscht, kann sie diese zusätzlichen .mesh Dateien zusammen mit den .exr Assets ausliefern. Wenn sie vorhanden sind, werden diese Mesh-Dateien anstelle der regulären Modelldaten verwendet, wobei die mit der Lichtabbildung zusammenhängenden Daten ohne weiteres verfügbar sind. Dies ist jedoch völlig optional. Wenn kein qlm_key.mesh zur Laufzeit gefunden wird, wird das UV-Unwrapping zur Laufzeit durchgeführt, transparent für die Anwendung.
  • Alternativ bietet das Balsam-Tool die Möglichkeit, die Lightmap-UV-Daten zum Zeitpunkt des Asset-Imports vorzugenerieren. Das bedeutet, dass die .mesh Datei des Modells von Anfang an die notwendigen Daten enthält und keine zusätzlichen Meshes während des Lightmap-Backens generiert werden, so dass keine zusätzlichen Assets mit der Anwendung ausgeliefert werden müssen (abgesehen von den Lightmap-Bildern natürlich). Um dies zu tun, übergeben Sie --generateLightmapUV an balsam.

Größe der Lightmap-Textur

Für jedes Modell, einschließlich aller Submeshes, bestimmt der Lightmap-Backprozess während der Lightmap-UV-Erzeugungsphase eine geeignete Lightmap-Texturgröße. Dies hat Auswirkungen auf die Qualität, die Leistung und den Ressourcenverbrauch (sowohl auf der Festplatte als auch im Speicher).

Die Standardeinstellung ist oft geeignet und muss nicht angepasst werden, insbesondere bei Modellen mit mittlerer bis hoher Komplexität.

Bei sehr einfachen Modellen kann es jedoch wünschenswert sein, die Größe manuell zu verringern, da eine geringere Größe der Lichtkarte immer noch visuell gut aussehende Ergebnisse liefern kann, während die Verringerung der Größe des Assets (Lichtkartenbild) sowohl Festplattenplatz als auch Speicherplatz spart. Setzen Sie dazu lightmapBaseResolution auf einen angemessenen Wert. Übliche Werte sind 256, 512 oder 1024, aber es kann auch eine andere Zahl sein, wobei 128 das Minimum ist. Die tatsächliche Breite und Höhe der Lichtkarte wird wahrscheinlich anders sein, aber in etwa der angegebenen Größe entsprechen.

Wenn man den Wert ändert, sollte man die Lightmaps immer neu erstellen und die Ergebnisse visuell überprüfen, um die Auswirkungen der geänderten Lightmap-Größe zu beurteilen.

Verwendung von Lightmaps zur Laufzeit

Eigenschaften und Typen, die bei der Verwendung der vorgebackenen Lightmaps zur Laufzeit relevant sind:

Nach erfolgreichem Abschluss des Backvorgangs wird die Anwendung bei normaler Ausführung (ohne Befehlszeilenargument oder Umgebungsvariable) die erzeugten Lightmap-Bilder aufnehmen und korrekt rendern, was erst nach dem Backen der Lightmaps möglich ist. Falls gewünscht, kann die Anwendung diese an einem anderen Ort ablegen oder sie als Teil der ausführbaren Datei über das Qt Resource System ausliefern. Dies wird durch die Eigenschaft BakedLightmap::loadPrefix ermöglicht.

Nimmt man den Beispielcode mit der Kugel und den vier Rechtecken von oben, so erzeugt der Backprozess fünf .exr Dateien (qlm_sphere1.exr, qlm_rect1.exr, qml_rect2.exr, usw.) und eine Listendatei qlm_list.txt, die als Eingabe für Entrauschungsprogramme nützlich ist, die die Verarbeitung mehrerer Dateien in einem Durchgang unterstützen, aber ansonsten zur Laufzeit nicht verwendet wird. Die Anwendung muss die Dateien .exr ausliefern, damit sie von der Engine gefunden werden können, entweder im gleichen Verzeichnis wie die enthaltende Komponente oder an dem von loadPrefix angegebenen Ort.

Die Laderegeln gelten auch für die optionalen .mesh Dateien, wie qlm_sphere1.mesh oder qlm_rect1.mesh. Wenn die Anwendung die Ladezeiten der Szene beschleunigen möchte, sollte sie diese zusätzlichen .mesh Dateien neben den .exr Lightmap-Bildern mitliefern.

Siehe auch Qt Quick 3D - Baked Lightmap Beispiel.

© 2025 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.