HUNT THE ALP 2008


Steuerung:

WSAD bzw. Cursortasten ... bewegen


Ziel:

Der erste, der 1000 Punkte erreicht, hat gewonnen. Punkteschlssel siehe Doku "Gamelogik". Viel Spa beim Kistensammeln und Alp jagen :-)



Effektliste:

Terminologie: Immer wenn von Koordinaten die Rede ist, beziehen sich diese auf das right-handed coordinate frame, also insbesondere ist die y-Achse "die Hhe".


## Shadow Maps	3	Direktionale oder omnidirektionale Shadow Maps mit Self Shadowing auf den Objekten.

Es wurde die nicht-erweiterte "klassische" Shadowmapping Technik implementiert. Als Quelle dienten hier vor allem die Folien aus Echtzeitgraphik[8] und auch [3a], [3b]. Es gibt eine globale Lichtquelle, "die Sonne".

Zuerst wird die Kamera auf die Position der Lichtquelle gesetzt. Da nicht das gesamte Gelnde mit einer shadowmap "abgedeckt" werden kann, ohne zu groe Kompromisse bei der Schattenqualitt einzugehen, wird die Kamera immer in einer konstanten Entfernung zum Spieler mitbewegt. Zustzlich wird der FOV der Schattenkamera im Vergleich zur "Hauptkamera" vergrert (um zustzlich eine grere Flche abzudecken). Eigentlich sollte die Sonne in der Szene ja direktionales Licht sein - trotzdem wird eine perspektivische Kamera verwendet - je nher man an den Rand der shadowmap gelangt, desto strker "verzerrt" erscheint der Schatten dann auch.

Von dieser neuen Kamera(-position) aus wird nun jedes Objekt der Szene in ein FBO gerendert, welches potentiell einen Schatten werfen knnen soll. Dieses FBO stellt enthlt dann die gewnschte shadowmap.

Was ntzt uns jetzt diese diskretisierte Information ber die Szene und wie knnen wir darauf zugreifen? Einfach weiterlesen :-)

Jetzt wird die gesamte Szene "normal" von der Hauptkamera aus gerendert. Dabei wird jedoch die vorher generierte und in der shadowmap gespeicherte Information verwendet:

Die eyespace vertex positions (modelview matrix * object space vertex position) werden mittels der inversen view matrix der "Hauptkamera" zuerst in den worldspace zurcktransformiert und dann mit der view- und projection matrix der Lichtquellenkamera / "der Lichtquelle" in deren postperspective space (postperspective space: nach perspektivischer Transformation, vor perspektivischer Division durch die homogene Koordinate). Da im postperspective space die spteren screen coordinates im Interval [-1,+1]x[-1,+1] liegen, eine 2D Textur (in diesem Fall eben die shadowmap) aber mit [0,1]x[0,1] adressiert wird, mu zustzlich noch mit 0.5 skaliert und um 0.5 translated werden.

Man erhlt nun einen Vektor (s', t', r', q') im vertex shader; die GPU reicht diese Koordinaten jedoch perspektivisch korrekt an den fragmentshader weiter - d.h. falls der Inputvertex die postperspektivischen Koordinaten (x, y, z, w) hat, kommt im fragment shader folgendes an: (s, t, r, q) = (s'/w, t'/w, r'/w, q'/w)  (siehe [8])

Das mapping jeder fragment position auf dem screen in die shadowmap ist somit bewerkstelligt! Jetzt reicht es, einen shadowmap lookup mit den ermittelten Koordinaten durchzufhren. Dabei verwendet man von den transformierten Koordinaten s/q, t/q um die shadowmap auszulesen und der ausgelesene Wert wird mit r/q verglichen. Ist der transformierte Punkt weiter von der Lichtquelle entfernt, als der nheste Occluder zur Lichtkamera (<==> Schattenentscheidung entspricht Sichtbarkeitsentscheidung!) - dies ist der Fall, falls "r/q > shadowmap[s/q, t/q]" - wird dieses Fragment einfach ein wenig dnkler dargestellt, da es ja bzgl. dieser Lichtquelle im Schatten liegt.

Anm.1: in GLSL wird statt ".strq" ".stpq" verwendet, da in ".rgba" der r-qualifier schon als "1.Strukturelement" vorkommt und damit eine Mehrdeutigkeit vorliegen wrde... kann sein, da in dieser Doku mal statt 'r' 'p' steht - nur damit klar ist, da eigentlich in beiden Fllen dieselbe Koordinate gemeint ist.

Anm.2: man bentigt die 2.Division (durch q), da man ja in den real-space der Lichtkamera kommen will/mu, man sich aber vorerst in deren homogeneous space wieder findet (eben q nicht notwendigerweise == 1.0). Dies ist informell auch so einzusehen, da man ja auch 2 perspektivische Transformationen durchfhrt - nmlich eine von der Hauptkamera aus und die zweite von der Lichtkamera aus...

Anm.3: Speziell frs selfshadowing wird ein "polygon offset" verwendet, wenn die shadowmap generiert wird. Der polygon offset "schiebt" die gesamte Szene ein wenig von der Kamera weg. Da die shadowmap "nur" eine diskretiesierte Information ber die Szene darstellt, macht man einen inherenten Fehler mit dieser Methode. Dieser Fehler uert sich dann in flschlicherweisem selfshadowing ("surface acne") - einem sehr offensichtlichen und strenden aliasing Artefakt. Mit eben erwhntem polygon offset kann man diesem Problem ein wenig entgegenwirken, da man "sicherstellt", da eine Oberflche selber in der shadowmap weiter entfernt erscheint, als sie tatschlich gerendert wird, wordurch sie nicht "in ihrem eigenen Schatten liegt", selbst wenn man mit der shadowmap diesen "kleinen" Fehler macht...

Anm.4: die shadowmap wird als bilinear zu interpolierende depth texture (im Prinzip/meist eine 24 bit luminance -d.h. nur ein Kanal = intensity- texture)  definiert. Im Shader kann man dann eine spezielle shadowmap texturelookup Funktion bemhen, die selbst schon die perspektivische Division (eben durch q) durchfhrt und zustzlich 4 samples "auf einmal" aus der shadowmap ausliest (~HW PCF = percentage closer filtering). Somit werden die Schatten quasi ohne performance penalty etwas geblurred und damit auch schner anzuschauen :-) 




## Spotlights/projizierte Texturen	2	Eine dynamische Textur die mit projektivem Texturing auf Geometrie aufgebracht wird.

Mal davon abgesehen, da der shadowmap Algorithmus eigentlich ja bereits projektives Texturing ist (der lookup-Wert ist halt keine Farbe, sondern eine Tiefeninformation), werden auch 2 screenspace Texturen auf die Szene projiziert, nmlich fr die Reflektion und Refraktion auf der Wasseroberflche (mehr dazu bei der Beschreibung des Wassereffekts). Screenspace Texturen auf die Szene zu projizieren ist "etwas leichter", da sich Projektor und Hauptkamera bereits an derselben Stelle befinden und die Kameraparameter (camera coordinate frame, ... und im wesentlichen auch FOV). Die momentane fragmentposition wird also einfach nur mit dem 0.5 scale + translate transformiert, um die jeweilige Textur zu indizieren. Falls man spter auch die Texturkoordinaten leicht verndert, um einen "verzerrenden Spiegelungseffekt" zu erzielen, ist es keine schlechte Idee beim rendering der Refraktions- und Reflektionstextur den FOV etwas zu erhhen. Somit erhlt man an den Rndern nicht "falsche" Infos aus der jeweiligen Map, auch wenn man schon Fragments "auerhalb des screens" bentigen wrde - diese Rnder werden ja eben durch den etwas greren FOV mit einer hohen Wahrscheinlichkeit abgedeckt sein (um einen guten Wert zu finden, bietet sich trial and error an...).

Auch die "dynamic boat wakes" werden mittels screenspace projective texturing realisiert. Zuerst werden quads, die auf der xz Ebene bei y=0 (und somit direkt "auf dem Wasser") liegen gerendert. Im fragment shader wird dann eine simple Wellensimulation mit der Mglichkeit zu Interferenzen ausgewertet (im Prinzip einfache Punktwellen, die sich "konzentrisch" ausbreiten). Die Grauwerte die sich ergeben landen dann in einem FBO, welches dann als projective texture dient. Spter, wenn das Wasser generiert wird (siehe weiter unten in der Effektliste beim Punkt "Wasser"), wird einfach dieser Wert zur Wasserhhe dazuaddiert (mittels "Werteshift" kann das Wasser durchaus auch tiefer werden nach so einer Addition).

Ein weiteres mal kommt projective texturing beim Wasseroberflchenshading zum Einsatz: Die oben generierte boat wake displacement texture wird zustzlich dazu verwendet, eine world space normal map zu berechnen (partielle Ableitungen nach x und z, sowie ein crossproduct ergeben eine komplette normalmap) (wieder gilt: siehe weiter unten in der Effektliste beim Punkt "Wasser" und beim Punkt "normal/parallax mapping"). Wird also ein Oberflchenpunkt gezeichnet, wird zustzlich mittels projective texturing in dieser boat wake dynamic water displacement normal texture nachgesehen. 

Die Mglichkeit, die Wasseroberflche zustzlich interaktiv zu verndern, wird zwar in [2] kurz erwhnt, jedoch gibt es weder Details zur Implementation, noch ist die Technik im ausfhrbaren Demo implementiert.


Um die jeweiligen projective texturing textures zu sehen, reicht es in Hunt the Alp auf 'i' zu drcken - enjoy!



## Levels of Detail fr Terrain	

Um das Terrain zu generieren, wird einmal ein entsprechend groes VBO mit 2 index arrays (dazu spter mehr) auf die GPU hochgeladen. Ausgehend von der Hauptkamera wird eine sampling Kamera so justiert, da jedes von ihr sichtbare Pixel einen Schnitt mit der baseplane hat (xz Ebene, y=0) - es darf natrlich auch kein "back-firing" geben. 

Gute/typische VBO Gren bewegen sich in etwa im Bereich 256x256 bis 512x512 vertices.

Whrend in [2] diese Methode mit vertex texture fetches (im folgenden VTF) zum Einsatz kommt, wird in der Hunt the Alp engine das berBuffers Konzept von OpenGL verwendet (und zwar in der Form von "Render to Vertex Array/Buffer). Der Vorteil davon ist, da erstens mipmapping der fragment shader unit verwendet werden kann (ist ja ein Ding der Unmglichkeit im vertex shader, da erst screen space derivatives fr die Wahl des mipmap levels ausgewertet werden), zweitens VTF (immer noch?) langsamer ist als ein texture fetch im fragment processor und drittens selbst ltere Karten wie GeForce5, die ja kein VTF knnen, mit dieser Technik zurecht kommen. 

Ausgehend von der sampling camera wird in ein float FBO die Schnittposition (ray-plane intersection, wobei fr jeden pixel ein ray/eine ray equation "hergeleitet" werden kann) mit jedem Pixel gespeichert. 

Fr die ray equation: ein screen-aligned quad wird gerendered, die texture coordinates "kombiniert" mit den Kameraachsen ergibt eine ray direction, wodurch eine Gerade hergeleitet werden kann.

Sobald man die xz Koordinaten kennt, kann man den vertex entlang y verschieben (displacement mapping). Der entsprechende y-Verschiebungswert kommt aus einer 16 bit luminance texture (diese texture ist die heightmap). Der automatisch ermittelte mipmap level (der streng genommen nur fr ein komplett flaches Gelnde - y konstant 0 - "korrekt" ist) reicht alleine nicht aus, um ein ausreichendes sampling zu erreichen, also werden zustzliche samples aus den "lower mips" gelesen und mit in die Hhenberechnung einbezogen. Um dem "swimming effect" weiter entgegenzuwirken wird noch eine weitere Methode eingesetzt, jetzt aber vorerst noch zum mesh Generierungsproblem.... 

Okay, was nutzt mir also jetzt ein farbiges float FBO wenn ich doch eigentlich vertex positions / ein VBO brauche? Wieder soll der geduldige Leser belohnt werden ;-)

Der Begriff Render to vertex buffer (im folgenden R2VB) ist ja bereits gefallen. Der Vorgang funktioniert wie folgt: das generierte VBO, wird als PBO gebunden. Nun kann mittels glReadPixels() der Inhalt des FBOs ins PBO(und somit VBO!) kopiert werden. Der OpenGL Treiber sollte diese Operation alle "auf der GPU/innerhalb des VRAMs/auf der server side" durchfhren knnen, wodurch es nicht wie sonst bei glReadPixels zu einem Tranfser von GPU-VRAM in CPU-RAM (und wieder zurck frs "updated VBO") kommt...

Prinzipielle Vorteile der projected grid Methode: continuous LOD, watertight mesh, verglichen zu anderen LOD Techniken einfache Implementierung, view frustum culling "fr umsonst", near equsized quads in screenspace und vermutlich noch einige mehr [wird in Hunt the Alp verwendet? - Mu ja gut sein! ;-)] 

Verbesserungen gegenber [1], Auszug aus der Doku zur 2.Abgabe:

purpously slightly non-linear tesselation in screen space depending on camera-orientation
to avoid swimming effect in the distance; when aiming the camera to the ground, a uniform tesselation is blended with the distorted mapping, so that we have the best of the 2 extreme cases for the projector. In other words: when aiming at the horizon (we have to sample mostly distant parts of the terrain), more sample points are needed in the distance, so that the grid is distorted accordingly, in a non-linear way. On the other hand, when looking straight down, this distortion is not necessary any more and we would like to cover the ground with unifromly spaced sample points.
Additionally, the sampling camera "height-offset" is interpolated based on the viewdirection - when aiming at the horizon, it is better to have the sampling camera slightly higher than the main (=viewing) camera to leverage the problematic intersections at grazing angles. Again, when looking straight down, a sampling camera that is higher than the main camera unnecessarily scatters the sampling points over a larger area than the area that is seen from the main camera, so now it is better when the sampling camera's height is approximately at the same height as the main camera - this way the vertex efficiency is improved without introducing artifacts.  

While the basic algorithm was explained in [1], the only proposal to address the undesired swimming artifact was the lower LOD heightmap access based on the distance. The sampling camera height adjustments were touched in [2]. The distortion of the grid tesselation were developed "incrementally by trial and error".
The R2VB implementation was only mentioned in a pseudo-code snippet in [2], but without implementation details, since this feature wasn't available in HW back then. In [1] vertex texture fetches are needed to displace the raycasted projection points on the baseplane, whereas the presented method works on older cards without VTF, too :-)



Ad "2 index arrays": Fr die Reflektion und Refraktion wird zwar dasselbe VBO verwendet, jedoch wird durch den Einsatz eines anderen Indexarrays nur jeder n-te vertex gezeichnet (im jetzigen release: n=2). Das Gelnde wird dadurch zwar nicht mehr so detailgetreu wiedergegeben, jedoch fllt dies in der Reflektion/Refraktion ohnedies kaum auf. Auf jeden Fall spart man einige Polygone und kann dadurch die performance ohne groen Aufwand erhhen.






## Environment Mapping	1	Sphere- oder Cube Mapping auf beweglichen Objekten. Wenn die Environment Map jeden Frame upgedatet wird bekommt ihr 1 Extrapunkt

Die cubemap skybox wird in die screenspace reflection- & refraction maps gerendert und somit "indirekt" im lookup verwendet.



## Per Pixel Lighting	2	Phong-Beleuchtung im Fragment Shader.
Beleuchtungsmodell basierend auf [7] auf den MD2 Modellen.
Auch das Gelnde wird per pixel gelighted wobei auch hier aufgrund der Speicherplatzeffizienz keine vorberechnete normalmap zum Einsatz kommt, sondern wieder mittels gradient Berechnung die surface normal on the fly approximiert wird.


## Normal/Parallax Mapping	3	Normal Mapping, bei dem ihr den Tangent Space selber berechnet. Dieser Effekt zhlt nur wenn er auf komplexen Objekten aufgebracht ist und nicht auf axis-aligned Quads oder Boxen! In diesem Effekt ist Per Pixel Lighting bereits inkludiert.

Bei den dynamic boat wakes wird on the fly eine world space normal map berechnet und diese kommt beim shading der Wasseroberflche (zustzlich) zum Einsatz. Genaueres steht bereits bei Punkt "spotlights / projective texturing".


## Kaustiken	1	Ein Lichtbrechungseffekt unter Wasser, der als animierte Texturschicht ber die normale Oberflchentextur geblendet wird. Wenn ihr die Kaustiken-Textur selbst dynamisch jeden Frame neu generiert bekommt ihr 1 Extrapunkt

Das Wellenmodell wird beim Zeichnen der refraction map ausgewertet, und abhngig von der Wellenhhe wird ein Intensittswert on the fly generiert. Dieser Wert wird zustzlich noch nichtlinear mit der Wasserhhe verringert (somit nimmt die Kausikintensitt mit zunehmender Wassertiefe ab). Je grer der Intensittswert, desto "weier" wird nun der "Meeresboden" gezeichnet.



## Wasser	1	Sich dynamisch ndernde Wellen-Geometrie und eine Texturanimation.

"animated watersurface with geometric displacement"

Weil das geometric displacement der Wasseroberflche vergleichsweise klein ist (etwa im Vergleich zum Gelnde), reicht es, ein kleineres VBO zu verwenden. Gute/typische Werte sind 64x64 bis 128x128.

In einer frhen Version wurde das Wasser genau wie das Gelnde generiert (durch ray-plane intersections im fragment shader). Mittlerweile wurde die unglaubliche ;-) Hunt the Alp engine jedoch erweitert - hnlich wie in [2] wird nun mit Matrizen gerechnet... was das bringt? Man kann mit der "normalen" Pipeline zustzliche perturbations (in Geometrie!!!) ins WasserFBO/VBO rendern (der aufmerksame Leser hat diese Info bereits im Punkt "projective texturing" erfahren)!!! Wenn man jedoch die Projektion "manuell" mit oben erwhnten ray-plane intersections durchfhrt, mu man dabei sicherstellen, wirklich jeden "(scaling) Faktor" mit einzubeziehen, der whrend der transformation pipeline auftritt (screen ratios, near- und farplanes, etc.)...
Anders als in [2] wird jedoch keine explizite "invert matrix" Funktion verwendet - ja, oft ist man halt ein wenig faul - andererseits macht die Not erfinderisch: es folgen Auszge aus EZG.cpp sowie der Doku von der 2.Abgabe welche das Prinzip genau erklren...


height values are read from a 3D texture (z-coord used for animation -> "Daumenkino")
rendered in a similar way as the terrain (R2VB), only this time not through raycasts, but by projecting only the 4 corner points of the screen-aligned grid (in clipspace) onto the baseplane (xz plane with y=0 in the standard OpenGL right handed coordinate system)
this yields 4 world-space intersection points with a homogeneous component that is in general != 1.0

A matrix is needed that transforms from clipspace to worldspace [doesn't yield a point yet, but an entire line ... so stay tuned - there is a solution ;-) ]


explanation taken from the implementation (see EZG.cpp):

Calculate intersection points with the baseplane
by back-projecting the clipspace corner-points
along the auxiliary camera's parameters (viewMatrix & projectionMatrix).
The auxiliary camera is the projector for the
projected grid



     * In the following:
     *
     * P ... perspective matrix
     * M ... model matrix
     * V ... view matrix
     * MV = V * M ... modelview matrix
     *
     * 
     * V is composed as follows:
     *
     * CamRot * CamTranslate    
     *     and is applied to as: V * Vert_world
     *
     * CamRot is made up of "negative rotation angles" that orient the cam
     *  in other words: the frame has orthonormal axes <CamX, CamY, CamZ>.
     *  If we ignore camera translation and look at rotation only, then
     *  the matrix with these vectors as columns transforms from 
     *  eyespace to worldspace. Since the basisvectors that make up
     *  the matrix are orthogonal to each other, the matrix's inverse is
     *  equal to its transpose [and transforms from worldspace to eyespace]!
     *  To conclude:   CamRot^(-1) == CamRot^T
     *
     *  This means that, based on the Rotation-part of the current viewMat, 
     *  simply use glMultTransposeMatrix(viewMat) to achieve the desired effect.
     *  
     * CamTranslate is glTranslatef(-CamPos)
     *
     * 
     *    mapping from worldspace to clipspace:
     *
     *        Vert_clip = P * MV * Vert_obj
     *                  = P * V * (M * Vert_obj)
     *                  = P * V * Vert_world
     *                  = P * CamRot * CamTranslate * Vert_world
     *
     *
     *    mapping from clipspace to worldspace:
     *
     *        Vert_world = V^(-1) * P^(-1) * Vert_clip
     *                   = CamTranslate^(-1) * CamRot^(-1) * P^(-1) * Vert_clip
     *                   = clip2worldMatrix * Vert_clip
     *
     *
     * with CamTranslate^(-1):
     *   glTranslatef(+CamPos)
     *
     * Since we don't know a priori, which coordinates a point on the baseplane
     * (xz-plane, y=0, y-axis=plane_normal= <0,1,0>) will have from the current view
     * (neither in worldspace, nor in clipspace), we transform each 
     * clipspace-viewfrustum-cornerpoint twice by "clip2worldMatrix", 
     * once with a depth-value
     * (= z-coordinate again z is from clipspace) of z=-1.0, and once with z=1.0 
     *
     * [ nearplane <==> z=-1.0 ]
     *
     * Then, with these 2 points, perform intersection with baseplane ->
     * yields intersection point along this line of sight in homogeneous coordinates
     
By decompositing the rather complex matrix into simpler matrices as described above, the lazy programmer doesn't even need to write a full-fledged (and expensive) matrix-invert function ;-)

We pass the 4 homogeneous intersection points as uniforms to the fragment shader, where the points are interpolated bilinearly (also interpolate the 4th component!) based on the texture coords of the screen-aligned quad that is rendered when the fragment shader is bound. When we now divide the interpolated points xyz components through the interpolated point's 4th component, we end up with the real-space intersection point just as if we had back-projected the according point in the screen-aligned grid (e.g. by a raycast / ray-plane-intersection).

Now we have a "1:1 fixed-pipeline conform mapping" to perform render to texture in separate (even fixed function pipeline is possible, since the actual "pipeline transformation matrices" are used) render passes and then, by projective texture mapping, altering the waterheights (=> dynamic boat wakes) when sampling the wateranimation displacement texture

Auf jeden Fall hat man wieder alle ntigen Positionen in einem FBO, welches man ganz analog zum terrain in ein VBO "kopiert/einliest".

Die Animation wird durch eine 3D Textur bewerkstelligt. Jeder slice entspricht einer "Momentaufnahme" der Animation. Die Texures ist seamless in xyz (xy ist das "rtliche" wrap around und z entspricht dem "zeitlichen" wrap around - Achtung, dies widerspricht der oben eingefhrten Konvention laut welcher y die "Hhenkoordinate" sein sollte...). Die Textur besteht aus Grauwerten, die wie ein heightfield interpretiert werden. Die dynamic boat wakes knnen den Hhenwert zustzlich beeinflussen.


Die Wellendisplacement Textur wird auch fr die surface normals herangezogen. Whrend das geometric displacment mit nur einem lookup bestimmt wird, wird die surface normal zustzlich mit lower- und higher frequencies kombiniert (d.h. basierend auf den "displacement lookup" Koordinaten werden diese einmal "gestretched" und einmal "verkeinert") - dieser Zusatzaufwand macht sich bezahlt bei der Lichtberechnung (simpler phong Term, siehe[7]) und den lookups in die "local (screen-space) reflection- & refraction maps"! Auch beim reflection- & refraction map lookup wird basierend auf der surface normal die Texturkoordinate leicht verschoben. Dies ergibt einen realistischeren Eindruck, da das Wasser ansonsten wie ein Spiegel aussehen wrde.

Die blending weights fr die reflection- & refraction map kommen aus einer Fresnelterm Approximation. In der Reflektion kommt einerseits die "lokale" Reflektion von der "Umgebung" und andererseits die "globale" Reflektion von der cubemap-skybox zum Zug. Im Prinzip ist dies ein bump mapped environment mapping...


Jetzt ist hier auerdem schon die ganze Zeit die Rede von local reflection- & refraction maps. Wie generiert man die eigentlich?

Per fragment culling:
Da das Wasser keine planare Flche ist, bekommt man bei Verwendung einer cliplane unschne reflection- refraction leakages an den seams wo sich Wasser und Terrain treffen. Deshalb wird abhngig von der Wellenhhe im fragment shader auf fragment level "discarded".


wie wird reflection map generiert?
Fr die reflection map wird das Gelnde gespiegelt um die Wasserebene gezeichnet.


XXXXXXXXXXXXXX

For further information, XXX (fragment level clipping involved in rendering the reflection- and refraction maps, deep watercolor simulation, caustics, ...).

XXXXXXXXXXXXXX


## Partikelsystem	1	Rauch, Feuer, Explosionen...

Das einzige, dafr recht ausgereifte Partikelsystem sind die Dynamic boat wakes die bereits beschrieben wurden. 



## Planare Spiegelungen	2	Die Szene wird gespiegelt mit Stencil Buffer oder in eine Textur gerendert und dann auf eine planare Oberflche aufgebracht. Dieser Effekt lsst sich beispielsweise fr Spiegel verwenden, und lsst sich auch sehr gut mit Wasser kombinieren.

Siehe unter dem Punkt Wasser - es wird "sogar" per fragment culling verwendet, nicht "nur" mit einer clip plane.


Parallax Mapping + Normal Mapping
Auf dem Gelnde kann man mittels 'b' parallax mapping einschalten/ausschalten (2 versch. bump scales).
Mittels des Gradienten wird ein lokales Koordinatensystem erstellt, welches gleichzeitig der Tangentspace ist. In einer heightmap wird dann ein Wert gelesen, der die texcoord entlang des view vectors anpat (Berechnung im Tangentspace => vorher viewvector in TS transformieren -> Parallaxe berechnen -> Parallaxe zurcktransformieren. An der nun angepaten texcoord wird nun nochmals die surface normal mittels Gradient berechnet - wieder ergibt sich ein TS-frame und man kann den normal vector aus der normalmap aus dem TS in den WS transformieren und dort fr die Lichtberechnung verwenden. Zustzlich wird die normal aus der normalmap nur verwendet, wenn die Makrostruktur (die "Normale" aus dem Terrain) berhaupt zur Lichtquelle gerichtet ist.

Hitzeflimmern + Depth Of Field
Die Szene wird zuerst in ein FBO gerendert, wobei im Alphakanal die Entfernungen zw. [0;1] kodiert sind. Dieser Wert wird im postprocessing verwendet, um einen strkeren Blur zu generieren (fr DOF sim; "strkerer" Blur durch lineare "Aufspreizung" des Filterkernels abh. von der Tiefe im Alphakanal) und auch um einen wieder linear davon abhngigen texcoord-shift durchzufhren fr einen Hitzeflimmer Effekt. Die Flimmeranimation kommt aus der 3D Wasseranimationstextur ;-)


Zustzliche Schmankerl:
-) realtime texture synthesis for terrain texturing:

4 layers (2 grass layers, 1 stone layer, 1 sand layer where each texture tiles seamlessly and they all have a rather low resolution compared to the size of complete terrain) are combined based on height and slope
on-the-fly normal calculation.

specular highlights -> gloss map (based on the stone-texture and sand-texture layer, since grass is not specular!) + perturbed normals

detail texture map for additional high frequency detail


<<<<>>>>
NOTE: the engine handles rendering of the complete world ("at least" land+water) and even dynamic modifications to the watersurface (based on later object movement) on the GPU - this leaves the CPU idle for physics, AI, sound and (other) gamelogic! 
<<<<>>>>




Modelle und Animationen:

Unserer Welt besteht aus Objekte die statisch und/oder dynamisch sind.
Alle Objekte sind von uns modelliert, texturiert und animiert worden.
Die Texturgren liegen zwischen 512x512 und 1024x1024 Pixeln. 

Der "main character" handsome-Teddy ist mit einem Biped verbunden (Zweibeiner aus 3d-Studio Max). Zustzlich ist ein Physics Controller auf dem "Biped" angwandt damit die Meshstruktur ohne Verzehrungen animiert werden kann. Eine Laufbewegung haben wir fr den Br erstellt.  

Ein weiterer wichtiger Charakter ist unser Alp. Der Alp, welcher auf  einem alten Piratenschiff lebt und Diamanten verschiet, wurde mit dem Bend-Modifier (3DS-Max) animiert (Flgelschlge).

Weitere Gegner sind die evil-Teddies die alle versuchen uns die Diamanten wegzuschnappen. Diese haben eine andere Textur als der "handsome" Br.
Animation und Mesh entsprechen dem "handsome" Br.

Die Diamanten haben mehrere Animationsphasen, die je nach Zustand im Spiel unterschiedlich abgespielt werden knnen.

Zum Schlu haben wir noch die Ente (Robinson Duck), die "lazy boy trees", Apfelbume und die Pilze. Die Animationen wurden mit dem Bend-, Twist- und Strechmodifier erstellt. "Lasst uns alle miteinander tanzen" :-)

Tools und Exporter:

Die Modelle und Animation wurden in 3D-Studio und Blender erzeugt. Die Texturen haben wir in Photoshop und Gimp gezeichnet.

Als Fileformat fr die Game-Engine verwenden wir das MD2-Fileformat.
Wir haben dafr den Exporter von "herby - www.planetquake.com" zum exportiern aus dem 3D-Studio verwendet. Wir muten diesen Exporter anpassen da er keine Animationcycles untersttzte.


Physik:

Fr die Spiel-Physik haben wir uns fr eine bereits bestehende "Lib", nmlich Ageia,  entschieden (Version 2.8.0).

Welche Physik Komponenten verweden wir (grob): "Meshe-Tiles" , "Plane", "Static Bounding Boxes",  "Dynamic Bounding Boxes", "Rays" und "Kinematic Actors"

Das Terrain wird aus einer "heightmap - 16-Bit Integer", um feine Abstufungen der Hhenunterschiede zu erreichen, erzeugt.
		
Ageia implementiert bereits eine Datenstruktur "NxHeightField", die dafr vorgesehen sein sollte, um Terrains aus "heightmaps" zu erzeugen. Das Problem war aber, da diese fr groe "heightmaps"  2048x2048 und grere ungeeignet war. Wir haben im Zuge userer Experimente starke Performance einbusen bemerkt. Diese Struktur drfte speziell fr den PhysX-Beschleuniger optimiert sein.

Um trotzdem schnelle "Collisions" und "Response" Berechnugen durchfhren zuknnen 
haben wir "Tile-Meshes" aus dem "heightfields" erzeugt. Dies war ein groer Performancegewinn. 
Die Physik-Engine berechnet mehrere Phasen fr die "Collision Detection". Unteranderem wird in der ersten Phase "Broadphase - hier wird ein axis-aligned bounding boxes (AABB) Verfahren verwendet" getestet, so wird im optimal Fall nur in wenigen Tiles getestet welches fr unser groes Terrain einen Performancegewinn ist.

Wir haben uns dann dafr entschlossen  einzelne "Mesh-Tiles" zu generieren, welche vom Typ NxMesh (Ageia) sind. 
Die einzelnen Mesh-Tiles haben wir dann so in die Datenstruktur von Ageia integriert, da sie "seamless" zu einander passen. Das war notwendig, da an den Kanten zwischen den einzelnen "tiles" die Physik nicht korrekt funktionieren wrde. 

Weiters werden dann die einzelnen Mesh-Tiles "gecooked", das bedeuted das die Mesh-Datenstrukturen in ein Zugriff- und Speicher effizientes Format (fr Ageia) konvertiert wird. Diese werden dann in Files abgespeichert um Sie bei bedarf laden zu knnen.

Fr unser Wasser verwenden wir eine Ebene fr die Kollisionstests (NxPlane).

Beides, die Kollisionsobjekte die das Terrain und das Wasser beschreiben, bekommen eigene Oberfacheneigenschaften um das Fahrverhalten des Spielers noch interresanter zu gestalten.

Das Hovercraft des Spielers besitzt als Kollisonsobjekt einen Quarder. Um nun ein halbwegs realistisches Fahrverhalten zu berechnen gingen wir so vor:   

Wir schieen von jedem Eckpunkt der Bodenflches des Quaders einen Strahl um einen Kollisionstest mit der Welt bzw. dem Wasser zu berechnen. Weiters besitzt jeder Strahl eine fixe Lnge somit wird dann bei einem Test mit der Umgeben eine entgegenwirkende Kraft berechnet die quadratisch, abhngig von der Kollisionsdistanz, abnimmt. So hat man das Gefhl das der Spieler ber dem Boden schweben bleibt. Durch diese Verfahren wrde der Spieler noch nicht stabil ber dem Boden schweben. Deshalb berechnen wir Torsionskrfte entsprechend der Rotationsachsen (X, Z) damit das Spielerobjekt stabilisiert bzw. gedmpft wird. Zum Schu wird je nach Tastatureingabe ein Kraft einsprechend der Eingaberichtung  erzeugt. Bei keiner eingabe verzgert das Fahrzeug entsprechend der letzten Fahrtrichtungeingabe.

Die statischen Objekte werden entsprechend der Surface-Normal ausgerichtet (Gradientenbestimmung).

Der Alp ist bei uns ein kinematikes Objekt welches in die physikalischen bestimmenden Eigenschaften der Welt nicht eingebunden wird (z.B Gravitation).

Gamelogik:

In unserem Spiel werden vom Alp (Feid) Diamanten weggeschossen, dieser fliegt mit seinem Piratenschiff ber die Insel. Der Spieler (handsome Teddy) und die feindlichen AI-Gegner (evil Teddies) mssen jetzt so schnell wie mglich eine gewisse Anzahl von Punkten erreichen um das Spiel zu gewinnen. Der Wert eines Diamanten erhht sich je nach dem wie viele der Spieler an einem Diamanten interressiert sind. Eine Wertnderung macht sich dadurch bemerkbar, da der Diamant sein Form ndert. Wenn einer der Spieler die maximale Punkteanzahl erreicht hat, hat er das Spiel gewonnen. 

Artificial Itelligence:

Die AI nutzt genauso wie die Physik die Ageia Engine. Es gibt zwei direkt Ai gesteuerte Objekttypen im Spiel: die gegnerischen Hovercrafts und den Alp. Der Alp whlt zufllig einen Punkt auf der Welt aus und steuert diesen an. Wenn er diesen Punkt in einer gewissen Umgebung erreicht hat (in einer Epsilonumgebung die als Ziel anerkannt wird) oder ein Timer abgelaufen ist, wird ein neuer Punkt ausgewhlt und angesteuert. 

Der Alp verschiet immer wieder eine bestimmte Anzahl an Diamanten. Der zeitliche Abstand ist zufllig auf ein Interval verteilt. Die Diamanten werden je zur Hlfte nach links und rechts abgeschossen. Die genaue Kraft die auf die Diamanten wirkt, wird wieder zufllig auf einem Interval bestimmt. 

Der Alp bewegt sich horizontal so, dass er versucht auf einer bestimmten Y - Distanz zur Welt ausrichtet ist. Dabei bremst er seine Vorwrtsbewegung ab, wenn diese Distanz zu kleine wird. Auf diese Weise verhindert er, dass sich das Objekt in das Gelnde bohrt wenn seine Steiggeschwindigkeit gering ist. Der Verzgerungfaktor hngt von der Distanz zum Boden ab.

Die Ai Gegener kennen grundsatzlich zwei Arten von Zielen. Erstens, wenn die Diamanten in der Welt existieren, dann whlen sie den mit der geringsten Distanz aus. Zweitens, der Alp ist ihr Ziel. Wenn sich die AI auf ihr Ziel ausrichtet, bremst sie, wenn der Winkel zwischen eigener Ausrichtung und dem Ziel zu gro wird. Auf diese Weise konnten wir die Zielsicherheit der Ai (gegenber der rsprunglichen gleichbleibenden Geschwindigkeit) stark erhhen. 

Weiters versucht die Ai anderen Objekten (Pflanzen, Spieler andere Ai's) im Spiel auszuweichen. Die Ai erkennt Objekte die in ihrem Weg liegen durch collision boxes (Trigger) welche auf der AI montiert ist.

Ein weiteres Ai hnliches Objekt ist der Diamant. Er hat ebenfalls eine collision box und einen Trigger um sein Objekt und registriert damit wenn es eingesammelt wird. Ein Fahrzeug, dass einen Diamant eingesammelt hat bekommt die Punkte dafr gutgeschrieben und der Diamant gibt sein graphisches Model an eine Verwaltungsstelle zurck, damit es wiederverwendet werden kann. Dadurch werden weniger VBOs erzeugt werden. 

Weiters bekommen Diamanten mitgeteilt, wenn eine Ai sie anvisiert. Dadurch entsteht ein Multiplier. Dieser ermglicht es den Wert des Diamanten zu erhhen. Um graphisch darzustellen, wie viel ein Object wert ist, haben wir beschlossen dessen graphische Darstelung zu ndern. Dafr haben die Diamanten mehrere Zustnde, bei einem Zustandswechsel ndert dieser seinen Wert. Bei einem Zustandswechsel wird eine Animation abgespielt. Diese stellt das morphen von einer Objektform in die Andere dar. Falls zu viele nderungen passieren, werden Teile der Animation bersprungen. Diamanten verschwinden, wenn sie nicht innerhalb einer bestimmten Zeit eingesammelt werden.

Audio:

Fr die Audioeffekte wurde die FMOD Bibliothek verwendet. Einerseits wird stndig eine Hintergrundmusik abgepielt, wobei sich mehrere Lieder abwechseln. Weiters werden eventgesteuert Sounds abgespielt. Die Laustrke dieser Sounds ist entfernungsabhngig. Die Soundeffekte selbst wurden mit Hilfe von Audacity erstellt.

		



Quellen:

[1] Yotam Livny, Neta Sokolovsky, Tal Grinshpoun, Jihad El-Sana "Persistent Grid Mapping: A
GPU-based Framework for Interactive Terrain Rendering", Department of Computer Science,
Ben-Gurion University of the Negev, Beer-Sheva, Israel

[2] Claes Johanson, "Real-time water rendering, Introducing the projected grid concept",
Master of Science thesis March 2004, Lund University

[3a] Randi Rost, "OpenGL Shading Language, 2nd Edition", better know as the "Orange book", p.341

[3b] http://www.cs.cmu.edu/afs/cs/academic/class/15462/web.06s/asst/project3/shadowmap/index.html

[4] Kevin Hawkins, Dave Astle, "OpenGL game programming", Prima Tech, 2001

[5 - 6] Im Text nicht referenzierte Eingebungen aus dem "Nirvana" ;-)

[7] Hearn, Baker, "Computer Graphics with OpenGL, 3rd Edition"

[8] Michael Wimmer, et. al. Folien zur VO Echtzeitgraphik, www.cg.tuwien.ac.at/courses/...