 |
Flat Shadows mit DirectX 8
Von Christian Rogge
Allgemein
Flat-Shadows sind eine Methode um sehr schnellen, dynamischen, aber nicht
sehr schönen Schatten zu erzeugen.
Vorteile
- Sehr schnell
- Recht einfach zu verstehen und zu implementieren
- Meistens recht einfach in eine bestehende Engine zu integrieren
- Braucht keine besondere Hardware (z.B. Stencil-Buffer o. ä.)
- Braucht keine komplizierten Objekt-Objekt-Beziehungen
- Gut in der Performance skalierbar.
Nachteile
- Keine Soft-Shadows (hat also "harte" Kanten)
- Funktioniert nur auf einer Ebene, passt sich also keiner komplizierten
Geometrie an
- Der Schatten befindet sich immer nur auf einer Ebene
Das Prinzip
Begriffe
Zuerst einige Begriffe (in Klammern das Kürzel für den Begriff):
- Occluder (OC): Ein Objekt, das den Schatten verursacht. Es befindet
sich zwischen einem Licht und dem Receiver.
- Receiver (RE): bekommt den Schatten. Der RE beim Flat-Shading ist
immer eine Ebene.
- Shadow-Caster (SC): Ein Objekt, das einem Licht entspricht. In einer
Engine könnte der SC z. B. die Position eines PointLights repräsentieren.
Ich schreibe mit Absicht Shadow-Caster und nicht Light, da es in der
Praxis Sinn macht, diese beiden Objekte zu trennen.
So geht's
Situation:
- 1 SC, das ein Licht repräsentiert.
- 1 Objekt, das als OC dient.
- 1 Ebene, die als RE dient.
- Man definiert eine Ebene, auf der der Schatten liegen soll. Dies
könnte z. B. der Boden bei einem Shooter sein.
- Man erstellt eine "ShadowMatrix". Diese Matrix wird die Geometrie des
OC so verändern, dass sie in die Ebene "geflatted" wird. Die Matrix ist
abhängig von der Position des SC und der Ebene.
- Man multipliziert die ShadowMatrix mit der Matrix des OC, also der
Matrix, die seine Verschiebung und Verdrehung in der Welt beschreibt.
Daraus bekommt man eine Matrix, die beim späteren Rendern gesetzt wird.
- Man rendert den Shadow. Dazu setzt man die erzeugte Matrix und rendert
die Geometrie des OC. Damit die gerenderte Geometrie wie ein Schatten
aussieht, benutzt man das folgende Vertex- Format: D3DFVF_XYZ |
D3DFVF_DIFFUSE
Nachfolgend etwas Code zur Verdeutlichung. Den Code habe ich auf die
Schnelle aus meiner Engine extrahiert und leicht geändert. Er soll in erster
Linie das Prinzip verdeutlichen.
[Quellcode 1]
Tips und Ideen zur Verbesserung
Im Sample wird der Schatten in einen dynamischen Vertexbuffer gerendert.
Für nicht animierte Meshes kann man stattdessen einen eigenen statischen VB
für die Shadow-Vertices erstellen und diesen rendern.
Man kann auch reduzierte Geometrie für den Schatten nehmen. Es bietet
sich ein Mesh in geringerer Auflösung oder auch die Kollisions-Geometrie an.
Wenn ein SC sich nahe an einem OC befindet, kann der Schatten sehr riesig
werden. Man kann den Effekt abmildern, indem man "parallelen" Schatten
berechnet. Man berechnet den Vektor vom Mittelpunkt des Objektes zur
SC-Position und verschiebt den SC entlang dieses Vektors in eine sehr hohe
Entfernung.
Beispiel einer angepassten create_shadow_matrix()- Funktion:
[Quellcode 2] |