Die Skybox als Panoramahintergrund in Spielen

Ich werde versuchen, hier die wesentlichen Geheimnisse der Skybox und anderer bekannter Himmelsimitationen zu lüften. Außerdem wird noch ein Weg gezeigt, wie man künstliche Panoramatexturen für Skyboxen selbst generieren kann, und am Schluss wird es eine Skybox-Demoanwendung inkl. Quelltext und Beispieltextur geben.

Inhalt:

1. Skybox-FAQ
2. Die Skyplane
3.
Illusion ist alles
4. Der Skydome
5. Die Skysphere
6. Die Skybox
7. Erzeugen einer Skybox-Textur
8. Skybox-Demo

 

Skybox-FAQ:

Die meisten dürften schon von einer Skybox gehört haben - gemeint ist dieser nahtlose Panoramahintergrund in vielen Spielen. Trotz der theoretischen Einfachheit (wo liegt schon das Problem einen texturierten Würfel zu programmieren?) gibt es immer wieder offene Fragen:

Sicher gibt es noch weitere Fragen. Aber erstmal weiterlesen, das meiste wird sich sicher klären!

Zuerst zu den Unterschieden und Gemeinsamkeiten. Was genau sind eigentlich Skybox, Skydome, Skysphere, Skyplane?

 

Die Skyplane
Die Skyplane dürfte am einfachsten zu erklären sein: das ist einfach eine mit Himmel texturierte Fläche über der Szene. Aber wer sich schoneinmal daran versucht hat, ist evtl. über folgende Probleme gestolpert: Wenn die Fläche zu hoch ist, gibts Probleme mit der Darstellung (die Fläche muss ja noch innerhalb der Far Clipping Plane sein und trotzdem bis zum Horizont reichen). Wenn sie aber zu niedrig ist, sieht das eher nach einer angemalten Zimmerdecke als nach echtem Himmel aus, sobald man sich in der Szene bewegt. Außerdem schneidet sie hohe Objekte wie z.B. Türme ab.

Illusion ist alles
Die Lösung liefert ein Trick, der die Illusion einer sehr weit entfernten Fläche erzeugt. Dazu sollte man sich einmal in eine Häuserschlucht (Bäume
tun's auch) stellen und in den Himmel schauen. Ich meine im Real Life, nicht dass sich jetzt jemand eine Anwendung dafür schreibt ;) Wenn man nun nach vorn geht, scheinen alle Objekte wie gewohnt nach hinten zu verschwinden, während der Himmel scheinbar mit einem mitgeht. Und genau das machen wir auch im Programm: das Himmelspolygon wird einfach mit der Spielerposition mitbewegt, auch in der Höhe. Wie hoch über dem Spielerkopf die Skyplane tatsächlich ist, ist dabei zweitrangig, solange dieser Abstand konstant bleibt. Wichtig ist, dass natürlich nur die Position der Kamera übernommen wird, nicht die Drehung. Die Skyplane bleibt an den Achsen der Weltkoordinaten ausgerichtet.
Die Illusion funktioniert übrigens auch mit Skyplanes, die nur 1 Meter über der Spielerfingur sind!

Damit sind wir schon beim zweiten Problem und dessen Lösung. Damit das Polygon auch immer hinter den höchsten Objekten ist (wer will schon, dass plötzlich eine Turmspitze von der Skyplane abgeschnitten wird, nur weil der Spieler eine Treppe hinuntersteigt?), gibt es noch einen weiteren Trick: Die Skyplane wird in jedem Frame als erstes Objekt mit deaktiviertem Z-Buffer gerendert. Somit erscheinen alle später gerenderten Objekte immer VOR (d.h. unterhalb) der Skyplane, auch wenn sie höher sind als diese, da sie dort keinen Z-Buffer-Eintrag finden - die Illusion ist perfekt. Mit diesen beiden Tricks - Mitbewegen mit der Kameraposition und deaktivierter Z-Buffer - arbeiten übrigens alle Sky-Imitationen.

Bild 1: Die Skyplane wurde sehr tief gesetzt, um einen fernen Horizont (kleine schmale Wolken) zu erzielen. Leider wird dabei die Turmspitze abgeschnitten. Je höher das Quad sitzt, desto größer muss es sein, um den Hoirizonteffekt zu erzielen. Es kann aber nicht größer werden als die Far Clipping Plane entfernt ist.

Bild 2: Die Lösung: die Skyplane hängt immer noch gleich tief, allerdings wurde für sie der Z-Buffer deaktiviert - die Turmspitze wird somit gerendert.

Bild 3: Beim Positionswechsel der Kamera ist die Kirche auf uns zugekommen, der Himmel sieht aber unverändert aus. Er muss wohl sehr hoch und weit weg sein ;)

unten: die verwendete Textur, die über das gesamte Quad in jeder Richtung 10-fach gekachelt wurde.

Da die Textur für eine Skyplane nicht verzerrt werden muss, eignet sie sich z.B. gut für Wolkenanimation über Texturkoordinaten. Hierzu muss die Textur eine Kachel sein, die endlos aneinandergereiht werden kann. Verschiebt man nun in jedem Frame die Texturkoordinaten, hat man einen dahinziehenden Wolkenhimmel.

 

Der Skydome
Kommen wir zum Skydome - der Himmelskuppel. Nicht immer reicht eine einfache Fläche aus. Manchmal möchte man ein Panorama bis zum Horizont, das auch weit entfernte Berge usw. darstellt. Dazu krümmt man die Skyplane zu einer Halbkugel, eine Art Käseglocke über der Szene. Der Z-Buffer- und Bewegen-Trick funktioniert auch hier perfekt. Man sollte sich nur darüber im klaren sein, dass man die fernen Berge nie erreichen wird, egal wie lange man darauf zusteuert ;)

Eine Skydome-Textur mit einer fernen Bergkette. Die Textur ist nach oben so verzerrt, dass sie beim Mapping auf die Halbkugel automatisch wieder entzerrt wird. Am unteren Bildrand wurde ein kleiner grauer Verlauf eingefügt, der später mit der Hintergrundfarbe verschmilzt und zu fernem "Bodennebel" wird.

Um die Textur in OpenGL benutzen zu können, wurde sie in zwei Streifen zerlegt und Kopf an Kopf aneinandergestoßen. So entstand eine brauchbare 256x256-Pixel-Textur.

Bild 1: Wie bei der Skyplane die Höhe keine Rolle spielt, ist hier der Durchmesser des Domes ebenso wie bei der anschließend behandelten Sphere und Box völlig egal, solange ihr Radius zwischen Near- und Far Clipping Plane passt. Der Spieler befindet sich in der Mitte der offenen Kreisfläche des Domes.

Bild 2: Dieselbe(!) Szene mit für den Dome deaktiviertem Z-Buffer aus Spielersicht. Durch die oben erwähnten Tricks sieht es immer so aus, als wäre das Panorama sehr weit weg, selbst wenn der Dome den Spieler mit einem Durchmesser von nur wenigen Metern umschließt.

Bild 3: Blick von oben auf den Skydome. Ein Problem bereitet generell die Singularität des Himmelspols, wo selbst bei guter Filterung oft störende "schmale Pixel" erkennbar sind. Erst recht, wenn das Auge an dieser Stelle Details erwartet. Bei der anschließend behandelten Skysphere gibt es sogar zwei dieser Pole.

 

Die Skysphere
Ein Skydome nach unten zu einer Kugel vervollständigt ergibt eine Skysphere für das perfekte Rundumpanorama. Z.B. im Weltall, wo es ja keine
Begrenzung durch den Horizont gibt. Aber auch für Produktpräsentationen wie Innenräume von Autos, Architektur oder Locations im allgemeinen, auch Motive im Freien, wird diese Technik genutzt. Da es Panoramakameras mit Speziallinsen und Raytracer mit Fisheye-Projektion gibt, ist die Erstellung von echten sowie künstlichen Umgebungstexturen für Skyspheres kein unlösbares Problem. Selbst für das Aneinanderreihen einzelner Foto- oder Videoaufnahmen gibt es Tools, die sich fast automatisch um die richtige Verzerrung und nahtlose Übergänge kümmern.

Hier eine typische Skysphere-Textur. Der Äquator befindet sich horizontal in der Bildmitte, von links nach rechts sind es 360 Grad, von oben nach unten 180 Grad. Die gesamte obere bzw. untere Kante stellt den Nord- bzw. Südpol dar und wird beim Sphere-Mapping auf einen Punkt zusammengeschoben. Befindet man sich in der fertigen Skysphere, sind alle Linien wieder gewohnt gerade. Das Resultat ist nicht von dem der Skybox zu unterscheiden.

 

Die Skybox
Bei Spielen benutzt man oft keine Skysphere, sondern die geometrisch vereinfachte Form, die Skybox. Welche übrigens keine sichtbaren Ecken hat, wenn man die richtigen Texturen benutzt. Leider kann man die typischen Panoramatexturen hier nicht verwenden - die Verzerrung ist eine andere.
Man muss also jede Würfelseite einzeln behandeln, was nahtlos passende Realaufnahmen sehr schwierig macht. Dafür kann man Skybox-Texturen sehr einfach künstlich erzeugen (siehe nächster Abschnitt).

In der Regel werden sechs einzelne Texturen in den Speicher geladen. Eine brauchbare Qualität bei noch guter Performance bieten Texturen von 512x512 Pixel je Würfelseite. Die Singularitäten verteilen sich auf 8 Pole (die Würfelecken), die dortige Pixelverzerrung ist dadurch weitaus geringer als bei einer Kugeltextur.

Die Verwendung der Skybox geschieht analog zur Skysphere: Kamera in der Mitte platzieren, Boxposition ständig der Kameraposition anpassen und Skybox als erstes Objekt der Szene ohne Depth-Test rendern.

Hier ein Beispiel eines typischen 6er-Skybox-Textursets. Die einzelnen Texturen wurden für diese Abbildung wie die Flächen einer Faltschachtel aneinandergereiht. In der fertigen Skybox sind die Knicke an den Texturübergängen nicht mehr sichtbar - das Ergebnis gleicht dem der Skysphere.

Noch ein Tip: da gerade bei Skysphere und Skybox sichergestellt ist, dass gleich als erstes im Frame der gesamte Bildschirm übermalt wird, kann man sich das Löschen des Draw-Buffers sparen.

 

Erzeugen einer Skybox-Textur
Das Erzeugen einer Skybox-Textur ist im Prinzip nichts anderes als die Projektion einer beliebigen 3D-Szene auf die 6 Seiten eines Würfels. Um nun eine Skyboxtextur mit DirectX, OpenGL oder einem Raytracer zu erzeugen, muss man sich zuerst die zu projizierende Szene aufbauen. Ob das nun Einzelbilder von Planeten und Galaxien sind, die als Decals am Himmel kleben, oder hochaufgelöste importierte 3D-Objekte, ist dabei egal. Echtzeitfähigkeit spielt dabei auch keine Rolle, da wir ja zur Projektion alle Zeit der Welt haben. Die Szene muss auch nur von einem Punkt aus perfekt aussehen: dem Mittelpunkt der Projektion. Dafür aber in allen Richtungen. Es sollten natürlich nur Objekte sein, die in der späteren
Spielszene nicht erreichbar (da zu weit weg) sind, wie ferne Galaxien, Planeten, Wolken, Berge, Meer usw. und bei denen der Spieler keine Größen- oder Positionsänderung erwartet, wenn er sich bewegt.

Sind alle Objekte plaziert, setzt man die Kamera in die Mitte der Szene, benutzt ein quadratisches View Frustum mit 90 Grad Öffnungswinkel von Seite zu Seite und rendert das Ganze auf die gewünschte Texturgröße (z.B. 512x512 Pixel). Und das insgesamt vier mal jeweils um 90 Grad um die Hochachse gedreht (für die vier Himmelsrichtungen) sowie nochmal senkrecht nach oben und nach unten. Diese sechs Texturen kann man dann direkt für seine Skybox verwenden.

Auf diese Weise entstand auch die Landschaft, die in der Demoanwendung benutzt wird.

 

Skybox-Demo

Den Download inkl. 256er Textur und Quelltext (C++6.0-Arbeitsbereich) gibt es hier (ca. 600 kb).

Wenn man das Programm startet, erscheint ein texturierter Würfel (Bild links), den man mit der Maus (klicken und ziehen) drehen kann. Mit der Taste "i" wechselt man ins Innere der Skybox wie sie der Spieler sieht (Bild rechts). Man glaubt es kaum, aber es ist immer noch derselbe Würfel.

Wer jetzt die Nahtstellen (vergeblich!) sucht, kann sich mit "k" die Würfelkanten anzeigen lassen. Erneutes "k" lässt die Kanten wieder verschwinden. Mit "a" wechselt man zurück in die Außenansicht.

Das Programm wurde mit Hilfe von OpenGL verwirklicht. Eine Umsetzung in DirectX dürfte aber kein Problem darstellen, da es sich eigentlich nur um einen texturierten Würfel handelt.

 

Ein brauchbares Tool: Der Raytracer zum Programmieren

Die hier gezeigten Texturen wurden bis auf die Skyplane (Photoshop) mit dem Freeware-Raytracer Persistence of Vision generiert. Der Raytracer hat keinen üblichen 3D-Editor, die Szene wird durch eine makrofähige Scriptsprache beschrieben. Was sich für einen Programmierer eher als Vor- denn als Nachteil erweist. Neben der fotorealistischen Beleuchtung aller Objekte wahlweise auch mit dem Radiosity-Algorithmus, Anti-Aliasing uvm., bietet dieses Programm auch eine Fülle mathematischer Texturen, die beliebig kombiniert und eingefärbt sowie als Bumpmap oder Heightfield benutzt werden können. Nicht zu vergessen verschiedene Projektionsarten und beliebige Renderformate.

Viel Spaß!
Jochen Diehl (joeydee)