TERRORISTICA


Known Bugs / Issues:

- Die Load-/Save-Funktion hat es leider nicht mehr in dieses Release geschafft, weil es immer noch Probleme beim Sharen der von OpenGL verwendeten Objekte gibt bzw. die Spielstände noch nicht korrekt gespeichert werden. Im Moment werden lediglich Dummy-Dateien geschrieben.

- Die Performance auf dem Übungsrechner ist miserabel. Läuft am Freitag bei der Präsentation schneller, da ich meinen eigenen Rechner mitnehmen werde. Vielleicht könnten wir nach der Pause oder überhaupt als letzte Gruppe drankommen (zwecks Computer aufstellen, Umbau, etc.)


Besonderheiten:

- Waffen: Es sind 8 Waffen implementiert: Eine Schlagwaffe (Brechstange), 3 Schusswaffen (Shotgun, Maschinengewehr, Raketenwerfer) und 4 mathematische Waffen. Um mathematische Waffen bedienen zu können, muss zuerst das entsprechende Mathematik-Buch gefunden werden, welches in jedem Level auf jeden Fall vorhanden ist. Einzige Ausnahme ist die stärkste Waffe (der Convolution Filter), für den ALLE Bücher benötigt werden. Falls ein Buch für die ausgewählte Waffe noch nicht gefunden wurde, wird dies rechts unten am Bildschirm (unter dem Namen der Waffe) angezeigt.
Mathematische Waffen haben den Vorteil, dass sie keine Munition benötigen, da sie vollständig auf geistigen Fähigkeiten beruhen. Terroristen können mathematische Waffen nicht verwenden.

- Cheat-Mode: Mit F1 werden mögliche Optionen eingeblendet. So ist z.B. auch ein GOD-Mode vorhanden, sowie eine Funktion, um alle Waffen und Gegenstände zu bekommen. Durch Drücken von F12 werden alle Gegner im Level getötet, sodass man bequem alle Levels / Levelsequenzen / Outro / Models / Freihaus-Geometrie sehen kann.

- Prof. B.: Wird im 4. und letzten Level in einem Raum von Terroristen bewacht. Mehr wird nicht verraten (vor allem nicht, wie das Spiel ausgeht!).


Kurzbeschreibung der Implementierung:

Zur Darstellung der statischen Geometrie wird ein BSP-Baum verwendet. Dabei werden im wesentlichen Quake3-Maps verwendet, welche allerdings davor in unser Datenformat konvertiert werden müssen. Hierfür haben wir einen eigenen Konverter geschrieben, der sich auf ein paar Codezeilen beläuft. Im Grunde wird die Quake3-Map etwas abgespeckt, da wir nicht alle Informationen für unser Spiel benötigen.

Zur Darstellung der Models verwenden wir das .MD3-Format, welches es erlaubt, Unter- und Oberkörper sowie den Kopf getrennt voneinander zu animieren. Die Models selbst haben wir dabei aus dem Internet, wobei Prof. B. von uns ein eigenes Skin erhielt, um dem Original ähnlich zu schauen.

Bei der Beleuchtung hat sich einiges geändert: Lightmaps werden zwar noch geladen, aber nicht mehr dargestellt, da alle vorkommenden Lichtquellen
in unserem Spiel vollkommen dynamisch sind. Für das Konzept der Lightmaps fällt uns vielleicht noch etwas ein, um sie mit den dynamischen Schatten integrieren zu können, ansonsten werden wir wohl auf Lightmaps verzichten.
Die Models selbst werden in einem Vertex-Shader beleuchtet, welcher im Prinzip die Standard-OpenGL-Beleuchtung nachahmt, den einzelnen Models jedoch auch Self-Shadows verleiht, was ansonsten nicht möglich wäre.

Gekrümmte Oberflächen können in Terroristica durch sogenannte Bezier-Patches dargestellt werden, welche beim Laden des Levels mit einstellbarem Tesselierungsgrad in einzelne Dreiecke umgerechnet werden. In dieser Version kommen allerdings keine Bezier Patches zum Einsatz, da diese im Freihaus nicht auftreten.


Features:

Culling:

- BSP-Trees: Für das Culling der statischen Geometrie kommen BSP-Trees zum Einsatz. Dabei wird für jedes Frame ein sogenannter Cluster bestimmt, in dem sich die Kamera gerade befindet. Von diesem Node des BSP-Trees ausgehend wird der Baum traversiert, um alle sichtbaren Flächen zu gewinnen.

- PVS (Potentially Visible Sets): Mit Hilfe von PVS wird für jedes Cluster bestimmt, welche anderen Cluster möglicherweise sichtbar sind. Einzelne Cluster werden dabei durch angrenzende Portale definiert. Zur Laufzeit kann mit Hilfe von Bittests bestimmt werden, welche Cluster auf keinen Fall von der aktuellen Kamera-Position aus sichtbar sind.

- Frustum-Culling: Alle sichtbaren Dinge wie statische Geometrie, Models, Gegenstände, Lichtquellen, etc. werden zusätzlich noch mit Frustum-Culling verworfen, wenn sie sich nicht im aktuellen Kamera-Frustum befinden.

- Occlusion-Culling: Da der gesamte Level mit voll-dynamischen Lichtquellen ausgeleuchtet wird, müssen auch Lichtquellen auf irgendeine Art und Weise verworfen werden, da selbst die beste Grafikkarte ein Multipass-Rendering von ca. 15 Passes für alle Lichtquellen nicht mit akzeptabler Geschwindigkeit durchführen kann.
Aus diesem Grund kommt für Lichtquellen die neue Occlusion-Query-Extension zum Einsatz: Für jede Lichtquelle wird ihre Bounding-Box, also der Bereich in den sie Licht abstrahlt, ohne Z-Write und ohne Color-Write mit eingeschalteter Occlusion-Query gerendert. Ist dabei mehr als ein Pixel sichtbar, wird die gesamte Lichtquelle als sichtbar angenommen, sofern diese nicht schon zuvor mit Hilfe einer anderen Culling-Methode verworfen wurde. Dadurch treten bei geschickter Platzierung der Lichtquellen maximal 4 oder 5 gleichzeitig auf, sodass das Spiel auch auf einer GeForce 4 noch spielbar ist.


Models:

- Keyframe-Animation: Die Models werden über sogenannte Keyframes animiert. Dabei ist das Model in mehrere Animationsphasen eingeteilt (Schiessen, Gehen, Springen, Laufen, Sterben, etc.), wobei für bestimmte Frames dieser Phasen für die einzelnen Körperteile (Unterkörper, Oberkörper und Kopf) die Transformationsmatrizen abgespeichert sind. Zur Laufzeit werden diese Matrizen in Quaternions umgewandelt, mit SLERP (Spherical Linear Interpolation) der Quaternions entsprechend transformiert und wieder in Matrizen zurückgewandelt, welche dann an OpenGL für die jeweiligen Körperteile übergeben werden können.

- Physik: Wert haben wir auf ein etwas realistischeres Verhalten der Models gelegt. Bei einer Bewegung z.B. ist leicht festzustellen, dass der Spieler einer geringen Beschleunigung ausgesetzt ist, wodurch er bei schnellen Drehungen oder abruptem Stoppen noch einen Teil der Geschwindigkeit behält. Durch Implementierung von Gravitation ist es auch möglich, Sprünge bzw. das automatische Auf- und Ablaufen von Stiegen zu realisieren.


Collision Detection / Collision Response:

- Models <-> Geometrie: Diese Art der Collision Detection wird mit Hilfe von Bounding Boxes und dem BSP-Tree bewältigt. Dabei wird im Wesentlichen die Bounding Box des zu testenden Models den BSP-Tree "hinuntergeschoben". Für die Collision Response wird eine sogenannte "Sliding Plane" ermittelt, die der Spieler bei einer Kollision entlanggeht, abhängig von seiner Geschwindigkeit.

- Models <-> Models: Hier funktioniert die Collision Detection auf dem Prinzip der Bounding Spheres, wobei der Spieler bei einer Kollision in die Richtung des Normalvektors des Punktes bewegt wird, an dem er kollidiert ist.


- Models, Geometrie <-> Projektile: Hier wird ein Strahl durch den gesamten BSP-Tree geschossen und ein exakter Schnittpunkt ermittelt, an dem das Projektil auf der Wand auftrifft. Für Models wird der Schnittpunkt mit der Bounding Sphere ermittelt.


Sound:

- Models, Waffen: Jedes im Spiel vorkommende Model hat eigene Sounds, welche über FMOD abgespielt werden. Ebenso hat jede Waffe ihren völlig individuellen Sound beim Abfeuern.

- Hintergrundmusik: Für jedes Level kann eine eigene Hintergrundmusik definiert werden. Dazu muss lediglich ein File verändert werden.


Content:

- Freihaus: Wie man an den folgenden Screenshots erkennen kann, kommt unser Freihaus dem Original sehr nahe. In mehr als 3-monatiger Arbeit wurde das Freihaus vermessen und in einem Level-Editor nachgebildet. Alle Texturen wurden mit einer Digitalkamera photographiert und anschließend nachbearbeitet. Im einem weiteren Bearbeitungsschritt wurden Normal-Maps für die jeweiligen Texturen erstellt, welche beim DOT3-BumpMapping zum Einsatz kommen (mehr dazu später).
Auch Kleinigkeiten (welche uns jedoch sehr wichtig waren), wie z.B. Schaukästen, Stiegenhausschilder, Beschriftungen, etc. sind vorhanden. Dies ist auch sehr gut auf dem zweiten Screenshot zu erkennen.


Bild 1 - Freihaus, 2. Stock, grüner Bereich - Stiegenhaus




Bild 2 - Freihaus, 3. Stock, gelber Bereich - Schaukästen, Türschild, "Rauchen Verboten"-Schild, Beschriftungen, etc.


Beleuchtung:

- Per-Pixel DOT3 Bump Mapping: Jede Textur in unserem Spiel besteht aus einer sogenannten "Base-Texture" und einer "Normal-Map". Zur Laufzeit wird mit Hilfe von Register-Combiners das Bump Mapping realisiert. Auf Bump Mapping bei den Models haben wir verzichtet, da es sehr schwierig ist, Normal-Maps händisch zu erstellen und uns High-Poly-Counterparts der Models nicht zur Verfügung stehen. Auf folgendem Screenshot kommt das Bump Mapping besonders gut zur Geltung:


Bild 3 - Bump Mapping auf gesamter Geometrie


- Per-Pixel Lighting: Alle Lichtquellen fungieren mit Per-Pixel Lighting, d.h. mit Hilfe von geeigneten "Attenuation-Maps"; das sind im Wesentlichen 3D-Texturen mit vorberechnetem Lichtabfall in alle Richtungen.

- Dynamische erstellbare Lichtquellen: Durch Gewehrfeuer, Raketen, etc. können dynamisch neue Lichtquellen eingebunden werden. Dabei ist es z.B. auch möglich, Projektilen eine eigene Lichtquelle zuzuweisen, was vor allem bei den mächtigeren Schusswaffen (z.B. Raketenwerfer) zum Einsatz kommt.

- Dynamisch konfigurierbare Lichtquellen: Lichtquellen bestehen im Prinzip aus mehreren Komponenten: Einer Position, einer Farbe, einer zugehörigen Textur, einem Typ und einer sogenannten Lighting-Function. Der Typ gibt dabei an, ob die Lichtquelle statisch ist oder z.B. an einem Kabel baumelt und schwingt. Die Lighting-Function gibt an, ob die Lichtquelle kurz Aufblitzen soll, ob sie flackert, etc. Dabei ist jede beliebige Kombination möglich - desweiteren können jederzeit neue Lighting-Functions für völlig neue Lichtquellen implementiert werden. Hierzu muss lediglich eine mathematische Funktion für das Verhalten der Lichtquelle implementiert werden.

- Echtzeitschatten: Da alle Lichtquellen dynamisch sind, werden auch alle Schatten sowohl für Geometrie als auch für Models in Echtzeit dargestellt. Dabei kommt ein etwas abgeänderter Shadowmap-Approach zum Einsatz, welcher auch für Pointlights funktioniert. Der Trick dabei ist, eine mit Distanz-Werten vorberechnete 3D-Textur zu verwenden, welche mit aktiviertem Z-Test in ein Cube-Map Render-Target gerendert wird. Diese Shadow-Map wird später beim Rendern der Geometrie in einem Vertex-Shader passend transformiert, sodass alle Pixel, welche von der Lichtquelle aus nicht sichtbar sind, schattiert werden.
Durch die Verwendung von Shadow-Maps hat man einige Vorteile gegenüber dem von z.B. DOOM 3 verwendeten Stencil-Shadow-Algorithmus: Unser Approach funktioniert auch für transparente Geometrie, was bei Stencil-Shadows einfach nicht möglich ist - außer man modelliert alle transparenten Teile einzeln, was jedoch zu einer ENORMEN Fillrate-Belastung der Grafikkarte führt und deshalb noch nirgends zu sehen ist.
Weiters ist Self-Shadowing der einzelnen Objekte automatisch vorhanden, d.h. der Schatten eines Models kann auch auf das Model selbst fallen.
Echtzeitschatten sieht man auf den folgenden Screenshots besonders gut:


Bild 4 - Echtzeitschatten für mehrere Lichtquellen auf mehreren Models, Self-Shadowing



Bild 5 - Echtzeitschatten für die gesamte Geometrie, Lichteinfall einer zweiten Lichtquelle



Bild 6 - Transparente Echtzeitschatten einer schwingenden Lichtquelle - in dieser Form mit Stencil-Shadows definitiv nicht möglich


AI (Artificial Intelligence):

- Event-Driven Finite State Machine: Alle Actors, welche nicht vom Spieler gesteuert werden, verfügen über eine eigene AI, welche im Prinzip über einen endlichen Automaten konzipiert ist. Dabei kann sich jeder Actor in einem bestimmten Zustand befinden (z.B. Gehen, Angreifen, Alarm, Bewachen, etc.) - durch äußere Einflüsse werden diese Zustände verändert, z.B. wenn ein Terrorist getroffen wird, wenn er den Spieler sehen kann, etc.
Für die Bewegung selbst sind 3 Sensoren zuständig, die von der Position des Actors ausgehend die umliegende Geometrie abtasten und jeden Actor so durch die Map navigieren.


Programmiertechnisches:

- Modulares Design: Das gesamte Spiel ist so konzipiert / programmiert, dass im Prinzip jederzeit ein MOD erstellt werden könnte. Alle Texturen, Effekte, Explosionen, Rauchspuren, Waffen, Models, Sounds, Intro, Levelsequences, Maps, Levels, etc. können jederzeit durch anderen Content ersetzt werden. Auch Lichtquellen, Actors, Gegenstände, etc. können durch einfaches Ändern eines Textfiles völlig anders positioniert werden.

- Vertex Shaders: Alle Passes, die in unserem Spiel gerendert werden müssen, werden von einem Vertex Shader durchgeführt.

- Register Combiners: Ebenso wie Vertex Shader werden alle Per-Pixel-Operationen mit Hilfe von Register Combiners realisiert.


Sonstiges:

- Curved Surfaces / Bezier Patches: Wie bei der 2. Abgabe bereits sichtbar, können mit Hilfe von Quadratic Bezier Patches gekrümmte Oberflächen erstellt werden, welche erst beim Laden des Levels in Dreiecke tesseliert werden. Da im Freihaus solche Oberflächen aber nicht vorkommen, sind diese in der 3. Abgabe auch nicht mehr zu sehen, da wir den Freihaus-Content so original wie möglich gestalten wollten.

- Smoke Trails, Explosionen: Mit Hilfe von Billboards können für jede Waffe völlig eigene Smoke Trails, Projektile und Explosionen definiert werden. Größe, Animation, Geschwindigkeit, Aussehen, etc. sind dabei völlig variabel und können für jede Waffe individuell eingestellt werden. Um einer Waffe einer anderes Aussehen zu verpassen, müssen lediglich das Model / die Texturen verändert und ein paar Parameter getweakt werden.

- Decals: Einschusslöcher können für jede Waffe eigens definiert werden. Auch animierte Decals (Maschinengewehr) sind dabei möglich. Größe, Aussehen, Animation, etc. sind dabei natürlich wieder völlig variabel einstellbar. So hinterlässt jede Waffe z.B. völlig unterschiedliche Einschusslöcher, wenn ein Projektil auf der Wand auftrifft. Auch Blut und Blutspritzer sind dadurch reichlich vorhanden, wie man auf dem folgenden Screenshot sehen kann:


Bild 7 - Decals: Einschusslöcher, Blut


- 2D Bump Mapping: Im Menü ist 2D Bump Mapping implementiert, welches früher sehr häufig verwendet wurde und für 2D-Graphik recht schöne Ergebnisse liefert. Die Idee dahinter ist die Gleiche wie bei Emboss Bump Mapping.
Dadurch bekommen die einzelnen Menüpunkte ein etwas plastischeres Aussehen - es entsteht der Eindruck, als würden sie sich vom Hintergrund abheben:



Bild 8 - 2D Bump Mapping


Verwendete Libraries:


Sämtliche Render-Algorithmen, AI, Collision Detection, etc. wurden von uns implementiert. Lediglich der Sound wird über eine externe Library, nämlich FMOD, realisiert.


Verwendete Tools:

Die gesamte Level-Geometrie wurde mit GtkRadiant, einem Editor für Quake3-Maps, erstellt. Zum Kompilieren der Maps wurde der Q3Map2-Compiler verwendet, welcher eine erweiterte und verbesserte Version des Original-Compilers von id-Software darstellt.
Alle Texturen wurden mit Adobe Photoshop nachbearbeitet, und die Normal-Maps mit NVidias Normal-Map-Filter (Photoshop-Plugin) erstellt.


Links / Referenzen:

Quake3-Maps, BSP-Trees, PVS, MD3-Models, Keyframe-Animation: www.gametutorials.com
Per-Pixel Lighting, Per-Pixel DOT3 Bump Mapping, Shadow Mapping, Vertex Shaders, Register Combiners: developer.nvidia.com
Quake3-Map-Editor, GtkRadiant: www.qeradiant.com
Quake3-Map-Compiler, Q3Map2: shaderlab.com/q3map2
Sound, FMOD-Library: www.fmod.org