You are currently browsing the monthly archive for Dezember 2008.

Fortschritt:

Eine ganze Menge!

Ein supertoller Scheduler ist mein neuester Stolz. Nach der Idee aus Game Programming gems 3 rattert das Ding mittlerweile fröhlich die Rahmen runter.

Models können nun in sogenannte Unions zusammengefasst werden. Realisiert wird das Ganze durch ein von mir erdachtes „Hook-Konzept“, welches (um es kurz zu sagen) die logische Position eines Models von seiner zu zeichnenden Position trennt. Damit ist es nun auch möglich eine Union zu Drehen, ohne das sich die relativen Positionen der Models ändern.

Nach einigem Einlesen in einschlägige Literatur habe ich nun ausserdem meine Physikengine im Grundgerüst fertig:
Jede Interactable ist eine Masse. Eine Masse besitzt Masse, Geschwindigkeit und Beschleunigung, und kann in bestimmte Kräfte eingeklinkt werden die dann auf diese Masse wirken. In bestimmten Zeitabschnitten wird die Geschwindigkeit nach der Euler-Methode aktualisiert.

So kann ich mein Auto nun lustig durch die Gegend schießen(unter Schwerkraft!).

Ausserdem: Ein kleiner Manager zur Darstellung von Rastertext.

Probleme:

Collision Detection. Ich habe mich zwar eingelesen und mich mit den Algorithmen vertraut gemacht, aber irgendwie habe ich das Gefühl eben jene wird mir noch eine Weile nachhängen.

Ausserdem: Mit dem Rastertext kommt mein Laptop-Grafikchip an seine Grenzen. Das Problem ist dass alle Buchstaben in jeweils eine eigene Displaylist im Grafikspeicher geschoben werden, und der kleine Racker nun an jene Grenzen kommt, die ich auch von kommerziellen Spielen her kenne :( .Als Zwischenlösung schalte ich die Schriften ab während ich am Laptop arbeite, auf Dauer müssen jedoch sowieso „richtige“ Schriften her.

ToDo:

Collision Detection ist das Thema der Woche. Dann zieht die Schwerkraft mein Auto hoffentlich nicht mehr durch das Terrain J. Sollte ich die geschafft haben, kommt die Auto-Physik. Das Ziel ist, nicht das Auto zu bewegen, sondern den Schub der Triebwerke am Auto zu verändern, ebenso soll Lenkung nicht durch Drehen des Autos umgesetzt werden sondern durch drehen der Räder.

Als Schmankerl gibts endlich auch ein Bild:

Gerendert werden ca. 65000 Polygone, die Gesamtgröße ist 26 km², erstellt wird eine Map dieser Größe in ca. 15 Sekunden (von ca. 2 Minuten runteroptimiert). Die Performance liegt mit 15 FPS im Moment noch im inakzeptablen Bereich, doch das Optimizing kommt ja noch.

Ich arbeite ja im Moment sehr fleißig an meiner Grafikengine. Ein Problem über dass ich stolperte, erinnerte mich wieder daran wie wichtig es ist über die Sprache und die Bibliotheken mit denen man arbeitet Bescheid zu wissen. Diese Erfahrung möchte ich euch natürlich nicht vorenthalten :)

Schauen wir uns mal folgenden Versuchsaufbau an:

class Drawable{
public:
float position3f[3];
}

Irgendwo rufe ich nun auf: glLightfv(GL_LIGHT+light.index,GL_POSITION,light.position), wobei light natürlich von Drawable abgeleitet wird.

Das alles funktioniert so lange, wie ich den Code nicht folgendermaßen erweitere:

class Drawable{
public:
float position3f[3];
bool active;
}

Die Änderung führt dazu dass die OpenGL-Beleuchtung nicht mehr funktioniert. Idee warum?
Ein kleiner Tipp: Die Beleuchtung funktionierte wieder wenn ich active vor position deklariere.

Gelöst? Nicht schlimm, auch ich kam nicht auf Anhieb darauf.
Die Lösung des Ganzen erfordert Hintergrundwissen sowohl in OpenGL als auch in Speicherverwaltung:

  1. OpenGL arbeitet wenn es um Positionierung (= Verschiebung) geht mit affinen Abbildungen (3×3 Matrix + Verschiebung), was durch die Nutzung von 4×4 Matrizen umgesetzt wird. Jetzt schnackelts. Ich nutze einen Vektor mit 3 Komponenten, OpenGL will aber 4. Die Vierte (sogenannte w-)Komponente ist eigentlich überflüssig, kann aber als Flag genutzt werden(wie in diesem Fall). Ich gehe mal davon aus dass openGL auf irgendeine Art eine 0 aus dem bad-pointer machte, so genau will ich das gar nicht wissen.
  2. Die Variable position3f liegt auf dem Stack. Durch das übergeben des Pointers an glLightfv wurde für das vierte Element „ins Leere gegriffen“. Sicher warf dies irgendwo intern eine Exception, aber openGL verzichtet in solchen Fällen vollständig auf Funktionsrückgaben – Warum auch immer o.O
  3. Jedenfalls. Durch Erstellen einer zweiten Variable auf dem Stack war der Bereich nach der 3. Float-Komponente nicht mehr leer, ganz fatal: Er war sogar von einem anderen Datentyp belegt. Und OpenGL liefert keinen Fehlercode, nein, die ganze Beleuchtung schaltet sich einfach aus.

Ich behob das Ganze natürlich damit dass ich position um eins vergrößerte. Kudos an Prof. Hahn und Prof. Kriha für die 1A-Vorlesungen in dem Bereich. An solchen Fehlern wird man ohne eingehendes Wissen über Kompiler und Sprache verzweifeln. Darum mein Aufruf:

Leute guckt euch gut an mit was ihr arbeitet!  Im Java-Sandkasten mag man sich austoben können, aber gerade in C hat man kaum eine Chance sauber zu programmieren, wenn man die Konzepte nicht versteht!

PS.: Bevor Missverständnisse aufkommen: C ist natürlich trotzdem (oder gerade deshalb) viel cooler als Java :)

Fortschritt:

Das Terrain kann nun durch eine einfache Funktion erzeugt werden, die Höhe wird automatisch richtig hinskaliert und Texturierung \ Normalen tun auch (Worauf ich mächtig stolz bin). Zur Glättung habe ich noch einen wunderschönen Hightband-Filter implementiert, der mir das ganze erst so richtig realistisch macht. Die Reifen sind nun übrigens auch kein Problem mehr.

Probleme:

Mein Algorithmus zur Überprüfung der Normalen bei Models funktioniert nicht richtig, da er nicht alle angrenzenden Flächen miteinbeziehen kann. Am besten wäre es ich setzte die Normalen selbst und speicherte das Ganze danach. Allerdings habe ich im Moment keine Zeit dafür, als temporary Fix setze ich ein Flag beim Laden des Models, welches ein Invertieren aller Normalen bewirkt.

Einen riesen Schreck bekam ich als plötzlich die Beleuchtung nicht mehr tat. Zum Glück konnte ich das Problem in wenigen Minuten lösen, einen eigenen Eintrag ist mir das ganze trotzdem wert. Folgt in Kürze.

ToDo:

Physik und Collision-Detection sind die nächsten großen Themen. Allerdings muss ich auch noch ein paar logische Strukturen zum Zusammenfassen meiner einzelnen Models schreiben. Kommt alles noch. Mal sehen wie viel ich über die Feiertage hin bekomme.

Fortschritt:

Die Leaks sind nun kein Problem mehr. Ich hatte mich einige Male nicht an grundsätzliche Regeln gehalten und wies Zeigern Adressen von Stack-Speicher zu. Klingt banal, kann aber passieren wenn das Ganze durch Listen und Smart-Pointer kaschiert wird - Lektion gelernt.

Das Terrain steht in den Grundzügen: Ich kann nun eine Heightmap erstellen, sieht richtig schick aus.

Mein Obj-Loader parst nun auch .mtl-Dateien und lädt damit u.a. auch Texturen.

Probleme:

Zum Obj-Loader:

Die Normalen machen leider Probleme, da sie wohl in einem mit dem Uhrzeigersinn ausgerichteten Koordinatensystem erstellt wurden (praktisch heißt das dass sie in die entgegengesetzte Richtung zeigen, und damit das Modell falsch herum beleuchtet ist).

Ausserdem sind die Reifen meines Autos erstmals mit Dreiecken versehen, die ich im Moment noch nicht zeichnen kann. Sollte nicht viel arbeit sein, Zeit dafür hatte ich jedoch noch nicht.

ToDo:

Am Terrain muss noch einiges besser werden. Ich muss mit Parametern anständig die Höhe und die Glättung des Terrains einstellen können, ausserdem gehören Texturen und Normalen darauf.

Oben genannte Probleme müssen geflickt werden.

Fortschritt:

Der Obj-Loader steht nun. Geparsed wird bis jetzt alles was im Milkshape-Loader auch geparsed wurde – Bis auf die Ambient-Material-Eigenschaften tut auch alles. Mein Auto (Dank an Felix für das modeln) kann ich jetzt also erfolgreich laden. Viel mehr habe ich sonst nicht geschafft, da:

Probleme:

Ein Fehler dass ich noch nicht versucht hatte die Engine zu beenden, denn die Release-All Funktion erzeugt Speicherlecks. Nachdem ich lange lange Zeit damit verbracht habe diese zu beheben habe ich das Problem erst einmal ruhen lassen. Einige Leaks konnte ich entfernen, ein paar stehen noch aus. Da die Zeit voranschreitet konzentriere ich mich jedoch erst einmal lieber auf das nötigste.

ToDo:

Nächste Woche ist das Terrain (ja, nun schon 3 Wochen rausgeschoben) entgültig dran.

Gebaut wird das ganze durch fraktale Fault-Formations. In der selben Woche sollte ich auch die Physikbasics ausarbeiten (Schwerkraft, Kollisionsabfrage), damit ich bald mit der Implementierung eben jener beginnen kann. Generell ist es Zeit sich über die InGame-Datenstrukturen gedanken zu machen.

Fortschritt:

Der Texturmanager steht, der Modelloader wurde teilweise wieder über den Haufen geworfen und neu aufgesetzt, und das Gamestate-ist nun zufriedenstellend implementiert.

Dem Gamestate-Manager werden Gamestates (Intro, Cutscene, Menu und Ingame) hinzugefügt. Diese Gamestates liefern bei ihrer Erstellung alle nötigen Informationen zu Darstellung, Ablauf, EventHandling usw. Wird der Gamestate gewechselt, ist es Aufgabe des Vorherigen alle Systeme und Resourcen wieder frei zu geben.

Dank einer eigenen update()-Methode im Kernel kann der Gamestate nun den gesamten Spielablauf steuern.

Probleme:

Der Modelloader ist schlecht. Ich habe keine Ahnung warum die Herren von Nehe auf Milkshape zurückgreifen, jedoch bringt das Format einige Unannehmlichkeiten mit sich, die mich dazu bringen wohl doch einen eigenen(!) .obj-Loader zu bauen. Die Syntax habe ich mir dazu schon angeschaut.

Einige Designmängel Tauchen immer noch auf, auch wenn es bald wirklich keine mehr geben KANN. o.O

Todo:

Ich bleibe bei meinem Plan diese Woche mit dem Gelände zu beginnen. Zusätzlich muss ich jedoch noch einen effizienten obj-Loader implementieren, angesichts der Tatsache dass sich kein wirklich gut zu nutzendes Material im Netz gibt bin ich mal vorsichtig. Ach ja: DisplayLists sollte ich noch kurz reinhauen.