WordPress.com ist eine gute Sache, vor allem für Anfänger was Blogging oder Webklitsche im allgemeinen angeht. Doch die meisten einigermaßen ambitionierten Blogger kommen mit den konzeptbedingten Einschränkungen irgendwann an ihre Grenzen, so also auch ich.

Der Käse war so lieb mir auf  p-shuttle.de etwas Platz zu leihen, wo seit einigen Monaten nun mein eigenes WordPress tuckert. Bevor ich aber entgültig umzog, wollte ich erst einmal abwarten bis die Seite korrekt von Googles‘ Spinnchen erfasst wird. Da alles soweit funktioniert und ich mein Blog in der neuen Form wohl behalte hier die neue Adresse, von mir, für euch:

>>mumpitz.p-shuttle.de <<

Bitte seid so nett und ändert die Adresse in eurem Blogroll ab, da ich die wordpress.com-Adresse zwar noch eine Weile leben lasse, jedoch ab jetzt nicht mehr aktualisieren werde.

Ich möchte mich abschließend formell bei den Machern von WordPress.com bedanken: es ist großartig wie solche Projekte es heute wirklich jedermann ermöglichen eine eigene Stimme im Web zu bekommen ohne sich mit Webspace, Domainredirection, Suchmaschinenoptimierung etc. auseinandersetzen zu müssen! Kudos!

Bis bald auf mumpitz.p-shuttle.de 🙂

Johannes

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.

Fortschritt:

Viele viele Wartungsarbeiten (Kommentare, Strukturierung, Datei- und Klassennamen geändert).

Das erste Fenster steht jetzt. Der Windows-Callback sowie das Fenster selbst wird nun im Kernel initialisiert, in einer gekapselten CWindow-Klasse (spätere Implementationen für Linux/Mac stehen so offen).

Es gibt nun eine Functor-Utility, die Funktionspointer verwaltet. Im Callback wird nun eine Array aus Functors durchiteriert und somit die Nachrichten abgearbeitet.

Fertig ist nun auch der Input-Task, der bisher Nachrichten zu Maus und Joystick verarbeitet und in Strukturen speichert.

Ein Modelloader ist nun auch fertig, implementiert mit Hilfe der Nehe-Tutorials, jedoch mit ein paar nützlichen Änderungen. Ein Texturmanager ist gerade in Arbeit.

Probleme:

Der Texturmanager sollte nicht an OpenGL gebunden sein, was natürlich Probleme mit de r loadTextures-Funktion gibt. Die Texturen selbst müssen also im Renderer geladen werden, was dann aber Abhängigkeiten zum Texturmannager schafft. Wie ich das Ganze mache muss ich mir diese Woche ausdenken.

ToDo:

Den Texturmanager fertig programmieren, endlich mein erstes Model zeichnen und einen Gamestate-Manager bauen. Falls noch Zeit ist auch noch den Soundmanager programmieren.

Danach (also nächste Woche) geht es dann an mein Hauptthema: Prozedural erzeugtes Gelände 🙂

Auf lange Sicht kommt dann die Kollisionsabfrage und abstrakte Spiel-Objekte (wie Events, Sounds, Physik).

Fortschritt:

Der Kernel ist nun Komplett, und mit ihm Soundtask und Renderer. Zusätzlich gibt es einen GlobalTimer, der die Frames per Second berechnet und die Vergangene Zeit seit dem letzten Frame(was wichtig wird wenn es um Framerate-unabhängige Bewegung geht.)

Der Renderer ist so gekapselt dass man als CRenderingDevice (später) noch alternative Geräte nutzen kann (DirectX steht für das nächste Semester auf dem Plan).

Probleme:

Es gibt noch grundsätzliche Probleme beim Aufbau des Kernel. Es war mir nicht möglich GLUT zu nutzen, da das Toolkit seine Eigene Mainloop nutzt. Die Funktionalität einen Durchlauf nur einmal durchzuführen existiert zwar in FreeGlut, doch traten hier starke (Kompatibilitäts? – ) Probleme auf. Letztendlich muss ich also auf plain Open-GL zurückgreifen. Nun ist die Frage wo ich das Fenster verwalte und die (Windows-) Callbacks mit meinen eigenen Tasks in Einklang bringe ohne den Kernel in Abhängigkeit seiner Tasks zu bringen.

ToDo:

Bis nächste Woche muss das erste Fenster stehen. Der Input-Task muss fertig sein und wenn möglich auch schon die Weltobjekt-Hierarchie stehen (Drawable – Polygon – Mesh – Model). Ausserdem wird es Zeit den Resourcenmanager zu nutzen um eben diese Weltobjekte zu verwalten.

Fortschritt:

Der Settingsmanager ist komplett, es wurden mal alle Compiler-Warnungen weggecoded und die Dokumentation ausgefeilt. Zusätzlich gibt es noch einen Dator, der dazu da ist einfache Datentypen in String zu konvertieren und zurück(std::string ist das Interface des Settingsmanager).

Zu viel mehr hat es aufgrund von Krankheit leider nicht gereicht, aber die meiste “Verwaltungsarbeit” sollte jetzt hinter mir liegen.

Probleme:

Der Settingsmanager ist doch um einiges einfacher geworden als er werden sollte, da ich ein bisschen gehangen war und die Aufgabe nicht in Zeit ausarten lassen wollte. Anstatt den Manager jetzt die Datentyp-Umwandlungen regeln zu lassen und wieder mit Templates um mich zu werfen nutzt der Manager jetzt nur noch std::strings und um die Umwandlung in andere Typen(int, float…) muss sich der User kümmern.

Als kleine Hilfe habe ich Macros geschrieben welche Variablen mit Hilfe des Dators sehr schnell umwandeln umwandeln. Das Ganze schaut dann beispielsweise so aus:
int res = TO(int, someString);

ToDo:

Es geht weiter mit dem Kernel, der die Mainloop enthält und in dem Tasks registriert werden können. Danach geht es endlich an die eigentlichen Tasks, nämlich Sound, Grafik, Netzwerk und Eingabe.

Kategorien

Seitenstreifen

Diese Woche im Angebot: