Licht

Licht lässt eine Szene realistischer wirken. Es gibt prinzipiell folgende Arten von Lichtquellen:
  • Ambient Light - Umgebungslicht. Eine Lichtquelle lässt sich nicht ausmachen (z.B. bei bedecktem Himmel)
  • Directional Light - Licht dessen Strahlen parallel aus einer bestimmten Richtung kommen (z.B bei tiefstehender Sonne)
  • Point Light - Eine Punktlichtquelle, dessen Lichtstrahlen kugelförmig emittiert werden (z.B. eine Glühlampe)
  • Spot Light - Eine Punktlichtquelle, die kegelförmig gerichtete Lichtstrahlen aussendet (z.B. die Taschenlampe)
Das folgende Bild zeigt eine Szene ohne Lichtquellen:

Szene ohne Lightmaps

Nun ja, eigentlich stimmt das nicht ganz. Zum einen sieht man ganz deutlich die beiden rechteckigen Strahler an der Wand. Zum anderen wäre eine Szene ohne Licht Schwarz wie die Nacht. Man dürfte also garnix sehen. In der Tat ist ein gewisser Anteil von Umgebungslicht durch die Farbgebung der Texturen implizit vorgegeben.

Soll die Szene aber differenziert ausgeleuchtet werden, muss die Farbhelligkeit der einzelnen Texturpixel gemäß der Summe der einfallenden Lichtstrahlen berechnet werden.

Die RGB-Farbwerte eines Pixel werden vor dem Rendern mit einem Faktor multipliziert. Je kleiner der Faktor, umso dunkler wird das Pixel und umgekehrt. Der Wertebereich des Faktors liegt zwischen 0 und 1. Hat man getrennte Faktoren für die einzelnen RGB-Werte, kann man mit einer wahlfreien Lichtfarbe ausleuchten. Ein Faktor für alle drei Komponenten, bedeutet weißes Licht.

Der Faktor wird aus der Summe aller einwirkenden Lichtquellen ermitteln. Für das Ambient Light wird eine Konstante vorgegeben (z.B. 0.4, bzw. 40%) Für das Directional Light wird ebenfalls eine Obergrenze vorgegeben (z.B. 0.3, bzw. 30%). Dieser Wert gilt aber nur bei senkrechtem Einfallswinkel auf die Textur. Kommt das Licht seitlich, oder gar parallel zur Texturebene, wird die Intensität entsprechend vermindert, bzw. ganz eliminiert. Dieser Faktor muss nur einmal für ein Polygon berechnet werden und gilt dann für alle Texturpixel. Bei einem Point Light muß neben dem Einfallswinkel auch die Entfernung zur Lichtquelle berücksichtigt werden, da die Lichtintensität mit der Entfernung abnimmt. Das macht die Sache kompliziert und rechenintensiv zumal potentiell viele Punktlichtquellen auf eine Polygontextur einwirken können.

Das berechnen der Faktoren kann nicht on the fly während des Rendervorgangs erfolgen. Die Rechenzeit wäre dafür viel zu lang. Stattdessen werden sogenannte Lightmaps für alle Polygone einmal vorberechnet. Das können sehr viele werden. Um den Speicherverbrauch in Grenzen zu halten, ist eine Lightmap als Byte-Array organisiert, wobei der Faktor 1.0 dem Bytewert 255 entspricht.

Wird die Engine gestartet, legt sie erstmal ein paar Gedenksekunden ein, lädt Geometrien, Lichtquellen und Texturen und berechnet alle Lightmaps. Erst dannach wird erstmalig die Szene gerendert.

Das folgende Bild zeigt eine Szene mit Lichtquellen:

Szene mit Lightmaps

Bemerkung: Anfangs wurden die Lightmap-Werte einzeln brute force berechnet. Mit immer komplexeren 3D-Szenen dauerte die Berechnung bis zu 10 Minuten, was entschieden zu lang war. Daraufhin wurde der Algorithmus umgeändert: Jetzt werden nur noch 32 * 32 Stützstellen direkt berechnet. Die Werte dazwischen werden durch bilineare Interpolation ermittelt. Damit wurde die Startup-Zeit auf max. 5 sek. verkürzt.