CG 2/3 Übungen, SS 2003 Abschnitt Nr. 3 Lipp, Markus, 0125260, 532 Summereder, Felix, 0126504, 535

### Interceptor

Starten Sie das Spiel über cg2.exe im bin\ Verzeichnisse.
Steuerung:
Im Hauptmenü:
space: Spiel starten
enter: Intro wiederholen
ALT-F4: Exit
1 ... 9: Direkte Levelauswahl
Im Spiel:
space Zu wichtigem Objekt ausrichten
Cursor oben, unten: Geschwindigkeit
Cursor links, rechts: Sliden
Mausbewegung: Rotieren
Linke Maus: Schießen
einfg: Turm absetzen
entf: Schiff rufen
Effekte-Toggle:
F2: Bumpmapping
F3: Volumetric Fog (nur Level 1-3)
F4: Glow (nur Level 4,6)
Gameplay , Effekte , Engine

Bekannte Fehler, welche hoffentlich bis 23.06.2003 behoben sind:
In letzter Sekunde hat sich ein Bug eingeschlichen, welcher Level 7 und 9 zum Absturtz bringt.
Ab und zu ist am Anfang des Levels der Bildschirm für ein paar Sekunden grau.
Bei häufigem benützen der Level-Cheat Tasten kann das Programm abstürzen.

### Gameplay:

Das Gameplay wurde im Vergleich zur letzten Abgabe signifikant verändert.
Anstatt einer einzigen Schlacht mit mehreren Phasen und einer sich an der
Punktezahl orientierenden Anzahl von Gegnern und Verbündeten folgt das Spiel
nun einem Missionsbaum von 9 Missionen mit steigendem Schwierigkeitsgrad und
gescripteten Ereignissen. Auch wurden 2 neue, komplexere Levels integriert.
Dadurch wurden ursprüngliche Konzepte (zB Minen und High-Score Listen) obsolet
und daher auch nicht implementiert. Anstelle einer Savefunktion wurde die Möglichkeit
eingebaut, direkt zu jeder beliebigen Mission zu springen.

### Effekte:

#### Object-Space Bumpmapping (Normalmapping):

Zuerst wird eine Normalmap im Object-Space mit dem Ati-Normalmapper erstellt. Diese stellt die Normalen für eine Per-Pixel Beleuchtung zur Verfügung. Zur Zeit läuft der Effekt auf >=NVidia Geforce3 + >= ATI Radeon9500. Mittels in "cg2::initshader" erstellten NVidia Registercombiner-Settings wird das Bumpmapping durchgeführt. Der Vertex-Shader "NVIDIA_bumpmap.vsh" stellt die Vertices passend zur Verfügung. Die Version für ATI Radeon>9500 ist in "bumpmap.psh" und "bumpmap.vsh" implementiert.
Known Bug: Die Farben werden auf NVidia-Karten vervälscht (viel zu intensiv). Bis 23.06.2003 sollte dies behoben sein.

#### Object-Space Cube-Mapped Bumpmapping:

links: Ati Radeon9500.
NVidia Geforce4: Zur Zeit funktioniert der Effekt hier nicht richtig, der Asteroid wird schwarz dargestellt. Bei der 2. Abgabe hat er schon einmal auf der Geforce4 funktioniert. Bis zum 23.6.2003 funktioniert er hoffentlich wieder.
Die Normalen stellen hier Koordinaten für eine Cubemap dar. Mittels in "cg2::initshader" erstellten NVidia Registercombiner-Settings werden die Texturkoordinaten berechnet. Der Vertex-Shader "NVIDIA_bumpcubemap.vsh" stellt die Vertices passend zur Verfügung. Die Version für ATI Radeon>9500 ist in "bumpcubemap.psh" und "bumpcubemap.vsh" implementiert.

#### Glow, Glare, Flare:

Screenshot: Ati Radeon9500, sollte ab Geforce2 gleich ausschauen
Dieser Effekt ist unter http://developer.nvidia.com/view.asp?IO=3240#Flare beschrieben. Im Gegensatz zu dem dort vorgeschlagenem Effekt wird bei Interceptor eine eigene Glow-Textur benützt. Dadurch ist die Glow-Gestaltung sehr flexibel.
In "cg2::RenderGlowTextureNoPBuffer" wird eine Glow Textur erstellt. Zuerst wird eine Glow-Source Textur gerendert (Alle Objekte werden mit ihrer Glow-Textur gerendert). Diese wird durch mehrmaliges additives, verschobenes Rendern auf eine Textur verwischt, und am Ende über die Szene geblendet.
Im Level4 glüht die Station, im Level 6 die Fracht.
Anmerkung: Auf der CG2/3 Homepage ist dieser Effekt nicht aufgelistet. Punkte-Vorschlag: Dieser Effekt relativ aufwendig, deshalb 2 Punkte.

#### Polygonal Volumetric Fog:

Screenshot: Ati Radeon9500.
Auf der NVidia-Homepage ist dieser Effekt beschrieben:
http://developer.nvidia.com/view.asp?IO=FogPolygonVolumes Getestet ist der Effekt auf Radeon9500&9700. Auf GeforceFX sollte er auch funktionieren, dort ist er jedoch nicht getestet.
In "cg2::RenderVolfogTextureNoPBuffer()" wird eine Volumetric-Fog Textur gerendert, und dann über die Szene geblendet. Die Shader "depthrgbencode.vsh", "depthrgbencode_plust3.vsh", "depthcomparedecide.psh" und "calculatevolfog.psh" werden dabei verwendet.
Anmerkung: Auf der CG2/3 Homepage ist dieser Effekt nicht aufgelistet. Punkte-Vorschlag: Dieser Effekt ist sehr aufwendig und schwierig zu implementieren, deshalb 3 Punkte.

#### Sparks:

Drei ineinandergeschachtelte Zylinder, mit animierten Texturkoordinaten und der Textur "sparks.tga" ergeben diesen Effekt.
Anmerkung: Auf der CG2/3 Homepage ist dieser Effekt nicht aufgelistet. Punkte-Vorschlag: Dieser Effekt ist relativ einfach, schaut dafür aber gut aus, deshalb 1 Punkt.

#### Membran-Beleuchtung:

In "membrane.vsh" ist der Effekt in Form eines Vertex-Shaders implementiert. Inspiriert von dem gleichnamigen Effekt im Nvidia-Effectsbrowser, umgeschrieben auf ARB_VERTEX_PROGRAM. Bei dem NVidia-Effects-Browser ist der Effekt erklärt.
Anmerkung: Auf der CG2/3 Homepage ist dieser Effekt nicht aufgelistet. Punkte-Vorschlag: Dieser Effekt ist relativ einfach, schaut dafür aber gut aus, deshalb 1 Punkt.

#### Cube-Envrionmental Mapping:

Bei der Initialisierung des Spiels werden die 6-Faces für das Cubemapping in "cg2::RenderCubemapNoPBuffer" gerendert und in eine Textur kopiert. Um die Map etwas aufzuhellen wird beim Rendern um die Kamera eine Sphere mit einer chrome-Textur gelegt und mit Alpha-Blending gerendert.
Bei den Vertex-Shadern "cubeenv.vsh", "cuberefr.vsh" und "cubeenvrefr.vsh" wird diese Textur benützt. "cubeenv.vsh" implementiert Reflektion, "cuberefr.vsh" eine (nicht sehr überzeugende) "Refraktion" und "cubeenvrefr.vsh" beides gleichzeitig für Multitexturing. Alle feindlichen Schiffe werden mit "cubeenv.vsh" gerendert.

#### Space-Debris:

Am Ender der "cg2::createDisplayList" werden per Zufall Dreiecke in einem Bereich erstellt und in eine Displaylist gespeichert. Diese Displaylist wird dann in Renderpass aufgerufen. Der Raum wird dafür in Würfel mit dem Zufallsbereich als Seitenlänge aufgeteilt. Der aktuelle und alle angrenzenden sichtbaren Würfel werden bestimmt, und die Displaylist dort gerendert.
Anmerkung: Auf der CG2/3 Homepage ist dieser Effekt nicht aufgelistet. Punkte-Vorschlag: Dieser Effekt ist relativ einfach, deshalb 1 Punkt.

#### Schockwellen:

Eine Schockwelle besteht aus zwei Komponenten: Dem sichtbaren, sich ausbreitenden Ring, und einem Vertex-Shader, welcher die Geometrie im bereich der Schockwelle verzerrt. Um den Ring effizient darzustellen, wird zuerst in "cg2::createDisplayList" eine Triangle-Strip Displaylist erstellt. Mit sin() und cos() werden jeweils Positionen an einem Kreis berechnet. Bei allen Vertices des Außenrings wird nun diese Position in die Vertex-Position geschrieben, und der Farbwert des Vertices auf null gesetzt. Bei der Innenseite wird umgekehrt vorgegangen. In dem Vertexshader "Shockwave.vsh" wird nun der Abstand des Innen-, und Außenrandes übernommen. Die Position wird nun mit dem Radius des Außenrandes multipliziert, die Farbe mit dem Innenradius. Diese zwei Werte werden zusammenaddiert ergeben die Endposition des Vertices, welche dann noch Transformiert wird. Durch diesen Trick erspart man sich eine Kostspielige Neudefinition der Displaylist. Auch hat man volle Kontrolle über die Schockwellenbreite. Ein normales Mesh einfach nur mit einer Matrix zu vergrößern bietet diese Kontrolle nicht, und schaut für eine Schockwelle unpassend aus.
Das Verzerren der Geometrie wird jeweils in den Shadern "*_shockwave.vsh" implementiert. Durch eine über Assembler erstellte Dreieckfunktion wird abhängig von der Entfernung der Schockwelle der Vertex mehr oder weniger bewegt. Danach wird die normale Funktionalität des Shaders "*.vsh" durchgeführt.
Anmerkung: Auf der CG2/3 Homepage ist dieser Effekt nicht aufgelistet. Punkte-Vorschlag: 1 Punkt für die dargestellte Shockwelle + 1 Punkt für das Verzerren.

#### Lensflares:

In "cg2::RenderPass()" wird das Lensflare gerendert. Dazu wird zuerst mit "gluProject" die Sonnenposition auf den Bildschirm projeziert. Diese Koordinaten werden in den Bereich [-1,1] transformiert. Durch multiplikation der x und y-Werte mit Faktoren zwischen [-1,1] werden die Positionen der Flares ermittelt. Dort wird dann ein Quad mit der Flaretextur über den Bildschirm geblendet.
Mit "glBeginOcclusionQueryNV" und "OcclusionQueryHP" wurde versucht, überdeckungen mit der Geometrie aufzulösen, jedoch stellten sich beide Extensions als sehr instabil heraus, deshalb wurden beide deaktiviert. Das Lensflare wird also immer gezeichnet.

#### Kondensstreifen:

In "CTrailParticleSystem" wird ein Trianglestrip generiert und mit der Zeit aktualisiert. Dazu wird bei der Position des Raumschiffes in gewissen Zeitabständen ein Vertice erstellt. Mit sin() und cos() Funktionen werden die Streifen beim erzeugen getwistet. Mittels push_front() und pop_pack() einer std::deque werden die Vertices gemanagt.
Anmerkung: Auf der CG2/3 Homepage ist dieser Effekt nicht aufgelistet. Punkte-Vorschlag: 1 Punkt.

#### Lightrays:

In "cg2::CreateDisplayLists" wird ein Mesh für die Lichtstrahlen erstellt. Mittels rand() Funktionen werden dafür Triangles in alle Richtungen erstellt. Benützt man zwei solcher Meshes zusammen mit der Textur "lightray.tga" & "lightray2.tga", und rotiert die Meshes mit der Zeit, ergibt sich der Effekt.
Anmerkung: Auf der CG2/3 Homepage ist dieser Effekt nicht aufgelistet. Punkte-Vorschlag: Der Effekt ist vom Prinzip her einfach. Es ist jedoch sehr viel Zeit in das Tweaken des Meshes geflossen. Deshalb: 1 Punkt.

#### Anisotropische Beleuchtung:

In alight.vsh ist der Effekt in Form eines Vertex-Shaders implementiert. Der Effekt soll die anisotropische Lichtausbreitung bei Metall simulieren. Inspiriert von dem gleichnamigen Effekt im Nvidia-Effectsbrowser, umgeschrieben auf ARB_VERTEX_PROGRAM. Bei dem NVidia-Effects-Browser ist der Effekt erklärt. Zur Zeit wird er auf alle "Freundlichen" Raumschiffen angewandt.
Anmerkung: Auf der CG2/3 Homepage ist dieser Effekt nicht aufgelistet. Punkte-Vorschlag: 1 Punkt.

#### Partikel System:

In "CExtendedParticleSystem" ist ein Partikelsystem implementiert. Über Definition von Start- und Endwerten für Größe und Farbe, Partikelgenerationsrate,Startpartikel, Startgeschwindigkeit und Startrichtung mit Zufallsbereich können eine Vielzahl von Effekten erreicht werden.
Als Partikel werden aus "CObject" abgeleitete "cParticleObject" benützt. Bei der Erstellung werden sie mit den oben erläuterten Parametern versehen. In der "Framemove" Funktion werden die Partikel über die Zeit integriert, und je nach Lebenszeit zerstört. Die "Render"-Funktion setzt für jede Partikel Parameter für den Vertex-Shader "Spherical-Billboard.vsh". Dann wird die dem Partikel zugeordnete Displaylist aufgerufen (Zurzeit ein Quad), der Vertexshader übernimmt Größen- und Farbänderung als auch Billboarding.
Dieses Partikelsystem wird zurzeit für Explosionen und Rauch eingesezt.

#### Beleuchtung:

In dem Vertexshader "vlight.vsh" ist eine Directional, Point und Ambient-Light implementiert. Laserschüsse des Spielers verändern die Pointlight-Color, die Pointlightposition wird auf die Position der Camera gesetzt.

### Engine

#### Datenstrukturen für die Geometrie:

Die Geometrie wird durch das externe Programm "Stripgen" (in "src\src-stripgen") zuerst von einer 3DS-File in das proprietäres str-fileformat konvertiert. Ziel ist die Erstellung eines Optimalen Meshs aus Triangle-Strips. Sowohl NvTristrip von NVidia als auch ein 3DS-Loader von DigiBen (gametutorials.com) helfen bei dieser Aufgabe. Stripgen selbst weist diese Komponenten an und schreibt das File im Binären Format ab. Zusätzlich zu der Geometrie werden auch Materialien mit zugeordneten Texturen aus der 3DS-File extrahiert und in der Ausgabedatei gespeichert.
In der Klasse "cg2" liest die Funktion "CreateDisplaylists" diese Datei aus. Zuerst werden Texturen über "CreateTexture" erstellt. Dann wird jedes Mesh-Objekt aus der Datei gelesen und direkt in eine Displaylist geschrieben.

#### Rendering-Scenegraph:

Ziel ist die Minimierung von State-Changes und flexible 3D-Objekt Erstellung und Zerstörung. Folgender Scenegraph hilft dabei: Die Klasse "CRenderingTechnique" enthält einen Vector mit Verweisen auf mehrere "CMesh"-Objekte. In "CMesh" wiederum werden in einer std-list mehrere verweise auf "CObject"-Instanzen gehalten. CObject kapselt die 3D-Orientierung und Position, CMesh die Displaylist und die zu verwendete Textur. Die Sub-Klassen von "CRenderingTechnique" enthalten verweise auf die zu verwendenden Vertex- und Pixel Shader.
In der Funktion "RenderPass" werden nun immer die States für eine "CRenderingTechnique" gesetzt. Dann wird die Funktion "RenderTechnique" mit der aktuellen "CRenderingTechnique" als Parameter aufgerufen. "RenderTechnique" setzt nun die Shader. Dann werden alle zugewiesenen "CMesh" durchlaufen. Jeweils wird zuerst die Textur und die Farbe gesetzt. Dann wird für alle "CObject" jeweils die Transformationsmatrix gesetzt, und die Displaylist aus "CMesh" aufgerufen. Durch geschickte Reihung der "CRenderingTechnique" aufrufe in "RenderPass" kann man nun die State-changes minimieren. Unter der Annahme, dass eine Textur immer nur für ein Mesh benützt wird, sind die Texture-Changes automatisch minimal.
Die Probleme bei diesem Scenegraph sind erstens die nicht vorhandene Räumliche Unterteilung, und zweitens eine unhandliche Repräsentation für Modifikationen an der Scene. Die Lösung für das zweite Problem stellen Hilfsfunktionen wie "AddShip" und "DeleteShip" dar, welche automatisch die richtigen Objekte dem richtigen Mesh zuordnen. Partikel-Systeme und Laserstrahlen werden nicht über dieses Modell beschrieben, hier kapseln eigene Klassen mit Framemove- und Renderfunktionen die darzustellenden Objekte.

#### Collision-Detection:

Um möglichst viele Laserstrahlen darstellen zu können, wird folgendes Schema benützt: Ein 3D-Array aus "CColissionCell" unterteilt dem Raum. Die Seitenlänge einer ColissionCell wird mit 2^n festgesetzt. Nun kann man durch drei n-Rechts-Shifts von einer gegebenen Position die zugehörige Zelle bestimmen: cell((int)p2.x>>RIGHTSHIFT,(int)p2.y>>RIGHTSHIFT,(int)p2.z>>RIGHTSHIFT );
Da ein Laserstrahl bei der Kollision als Punkt behandelt wird, ist dieser extrem schnell einer Zelle zuzuordnen. Bei Bounding-Spheres ist zumindest die Grundzelle gleich schnell zu finden, Überlappungen jedoch benötigen mehr Aufwand. Zur Zeit wird nur die Grundzelle bestimmt (Im Sourcecode ist die Bestimmung der angrenzenden Zellen mit Überlappung aufgrund von Fehlern ausgeklammert, soll jedoch später wieder aktiviert werden). Diese Vereinfachung wirkt sich nur bei großen Objekten am Rand von Zellen negativ aus, im Spiel fällt es selten auf. Ein weiteres Problem ist der begrenzte Kollisions-Raum. Da sich das Spielgeschehen um zentrale Objekte dreht kann diese Einschränkung angenommen werden.
Die eigentliche Collision-Detection erfordert zuerst ein zuweisen der statischen und dynamischen Objekte zu Zellen. Dann werden in den Zellen Alle Objekte gegeneinander und schließlich gegen die Laserstrahlen getestet. Im Sourcecode "ColissionDetection.h" ist das Verfahren genauer beschrieben.

#### Visibility Culling:

Ein einfaches Boundingsphere-Frustum Culling wird durchgeführt. Werden mehrere Rendering-Passes benötigt, wird die Visibility-Information vom ersten Pass wiederverwendet.

#### Windows-Framework:

Das Win32-Framework ist eine erweiterte Version des "NeHe"-Frameworks, zu finden unter http://nehe.gamedev.net/. In "main.cpp" ist der Code detailiert beschrieben.

#### 3D-Sound

Mittels fmod.dll wird 3D-Sound realisiert. Da dies wenig mit cg2 gemein hat, wird hier nicht näher darauf eingegangen.