Einführung
Ich beschäftige mich in meiner Freizeit mit der Entwicklung von Computerspielen und der Grafikprogrammierung. Irgendwann stellte ich mir die Frage ob ich Spiele programmieren will oder nicht.
Diese triviale Frage hört sich sicher unlogisch an, ist aber wichtig um sich selbst Ziele zu setzen. Wenn ich ein Spiel programmieren will halte ich mich nicht unnötig mit der Frage auf wie ich DirectX oder OpenGL richtig initialisiere. Oder wie ich Vertexdaten am effektivsten an die Grafikkarte schicke. Mein Interesse ging mehr in die Richtung der Grafikprogrammierung auf einer tieferen Ebene und nicht so sehr der Entwicklung von Computerspielen.
Das giDX³ Projekt
Bevor ich Ihnen etwas über das giDX³ Projekt sage möchte ich einen Blick auf die Vergangenheit werfen. Die Programmierung war und ist für mich immer ein Hobby. Es ist auch schon mal vorgekommen dass ich den Compiler zwei Jahre nicht gestartet habe. Wenn Sie jetzt erwarten dass ich ein erfahrener Programmierer bin und Ihnen etwas über die Entwicklung von 3D Engines sage liegen Sie leider falsch. Ich gehöre zu der Art von Hobbyprogrammierer die sich am Abend mal ein zwei Stunden vor den PC setzen und sich ansehen wie man mit DirectX oder OpenGL ein Dreieck rendert. Und es war einer dieser Abende als ich mir ein Tutorial über DirectDraw7 durchlas und mich fragte warum das ganze so kompliziert ist.
Damals programmierte ich auch mit BGI (Borland Graphic Interface) und ich fand die Nutzung dieser Schnittstelle wirklich sehr einfach. Ich wollte die Nutzung von DirectDraw7 genauso einfach gestallten. So entstand die Idee ein 2D Engine zu entwickeln die ohne DirectX und Windows Kenntnisse genutzt werden konnte. Ich nannte die 2D Engine giDX² (graphic interface DirectX, die ² steht für 2D)
Dann legte ich eine sehr lange Pause ein. Vor ein paar Tagen startete ich den Compiler neu. Ich nutze Visual C++ Net und hatte auf der Festplatte noch Visual C++ 2008 Express installiert. Ich schaute mir ein paar Direct3D Beispiele an und überlegte mir die Idee von giDX² auf 3D zu übertragen.
Ich schaute mir noch ein paar Videos von 3D Engines an. Darunter waren Untiy3D, Unreal4 und die CryEngine. Und schon legte ich die Idee eine 3D Engine zu programmieren bei Seite.
Das was dort gezeigt wurde kann ich nicht programmieren. Dazu ist meine Erfahrung und mein Wissen nicht ausreichend, aber das Wetter ist so kalt und ich habe noch ein paar Tage Urlaub also legte ich los. Mal sehen wie weit die Entwicklung kommt.
Das Ziel und die Grenzen des Projekts
Ich bin Realist und habe auch nicht das Ziel und schon gar nicht die Zeit etwas vergleichbares, wie eines der vielen tollen 3D Engines zu programmieren. Und weil ich ein Hobbyprogrammierer bin, möchte ich dass dieses Projekt auch als solches gesehen wird. Es erhebt keinen Anspruch auf Professionalität oder auf Vollständigkeit.
Die Engine soll eine Möglichkeit bieten auf einfache Weise Primitive zu rendern. Sie soll funktional und beschreibend sein. Das Bedeutet ich sage der Engine wie mein Würfel auszusehen hat und den Rest erledigt die Software. Dieses Verhältnismäßig einfache Ziel schien mir in zwei Wochen realisierbar zu sein.
Was ist ein 3D Engine
Eine Sammlung von Funktionen ist für mich keine 3D Engine. Ich verstehe unter einer Engine ein selbständig laufendes Programm oder ein Teil eines Programms. Und genau das kann die giDX³ Engine. Es kann 3D Objekt selber verwalten und organisieren.
Die Idee
Alle Programme, auch Spiele verarbeiten Daten. Wenn man sich das einmal klar gemacht hat wird alles ein wenig verständlicher.
Das Spiel Snake kennt sicher jeder. In diesem Spiel steuert man eine Schlange. Das Spielfeld ist ein n mal n großes Array. Ist eine Variable auf 1 ist das Feld voll ist es 0 ist es eben nicht voll. Und die Schlange ist nur eine Reihe von Variablen auf diesen Array welche auf 1 gesetzt sind. Das geschickte setzen und Löschen von Speicherinhalten simuliert eine sich bewegende Schlange.
Auch eine 3D Engine macht nichts anders als Daten verwalten. Ich habe mir als erstes Gedanken über die Organisation der Daten gemacht. Und weil Computer nichts anderes machen als Daten zu verarbeiten war das erste Ziel die Entwicklung einer Datenverwaltung.
Brush, Mesh und Surface
Die Engine arbeitet mit drei Strukturen. Die drei Strukturen Brush, Mesh und Surface speichern alle Informationen die nötig sind um ein 3D Model zu rendern.
Ein Brush speichert Daten über die Textur und das Material. Für die Texturen und das Material gibt es je einen eigenen Manager. Dieser verhindert das Daten doppelt im Speicher vorkommen. Er lädt die Textur oder erstellt das Material und übergibt dem Brush einen Zeiger auf die Ressourcen.
Das Mesh speichert Daten über die Rotation, Ausrichtung die Position. Auch Daten über Kollision oder Physik können in dieser Struktur gespeichert sein.
Das Surface speichert den Vertexbuffer und Indexbuffer. Die giDX³ 3D Engine arbeitete mit mehreren Streams. Die Vertexdaten, Tetxurkoordinaten, Vertexnormale … werden in eigenen Strömen gespeichert und an die Grafikkarte weitergeleitet.
Diese Drei Strukturen sind auch miteinander Verbunden. Ein Mesh gehört immer zu einem Brush. Ein Surface gehört immer zu einem Mesh.
Jeder Brush kann mehrere Meshes haben, aber auch jeder Mesh kann mehrere Surface haben. Zur Verdeutlichung eine Skizze.
Die Strukturen werden von einem Objektmanager organisiert. Es gibt immer einen Standardbrush. Dieser wird beim Start der Engine erstellt und alle Mesh, die ohne eine Zuweisung zu einem bestimmten Brush ertellt wurden, werden an dieses Standandbrush angehängt. Ein Mesh kann auch verschoben werden und einem anderen Brush zugewiesen werden. Dabei werden alle Surface die zu einem Mesh gehören mitverschoben (siehe Skizze unten)
Der Rendervorgang
Der Objektmanager ist auch beim Rendervorgang mit dabei. Es schickt die Objekte zum rendern. Dabei wird immer erst das Brush an den Renderer gesendet. Es setzt das Material und die Texturen. Danach das Mesh, welches die Position, Rotation, Skalierung…. Setzt und zum Schluss das Surface. Dieses ruft die Methode DrawPrimitive() auf.
Code: Alles auswählen
// Ein Mesh erstellen. Im Standardbrush
LPENTITY triangle = NULL;
createmesh(&triangle);
// Ein Surface erstellen und an Mesh anhängen
LPSURFACE surface=NULL;
createsurface(&surface, triangle);
// Vertexdaten
addvertex(surface, 0.0, 0.0,0.0); vertexcolor(surface,d3dColors::Green);
vertexnormal(surface,0,0,-1);
addvertex(surface, 1.0,-1.0,0.0);
vertexcolor(surface,d3dColors::Green);
vertexnormal(surface,0,0,-1);
addvertex(surface,-1.0,-1.0,0.0);
vertexcolor(surface,d3dColors::Green);
vertexnormal(surface,0,0,-1);
// Ein Dreieck
addtriangle(surface,0,1,2);
// Buffer befüllen
bufferfill(surface);
// Objekt vor die Kamera positionieren
positionentity(triangle,2,0,5);
Code: Alles auswählen
while(gidxloop() && !keyhit(DIK_ESCAPE))
{
statkey();
renderworld();
}
Die giDX³ 3D Engine beschreibt die Vertexstruktur über die Vertexdeklaration. Die Beschreibung der Vertexstruktur wird an das Programm in Form von Flags übergeben. Das Programm setzt selbständig die Vertexstruktur zusammen und erstellt die Vertexdeklaration. Die Vertexdeklaration wird in der Struktur Brush gespeichert. Die Surface-Struktur stellt nach Angaben aus dem Brush Speicher für die Daten bereit.
Die Datenbehälter (Vertexbuffer und Indexbuffer) werden je nach Bedarf erstellt und befüllt. Die Surface schickt nur die notwendigen Daten an die Grafikkarte zum rendern.
Kamera und Licht
Die Engine betrachtet die Kamera und auch Lichter wie ein Mesh. Zum Positionieren und zum Rotieren sind die gleichen Funktionen anwendbar. Auch ist es möglich ein Mesh zu einer Kamera zu machen. Man sieht dann das was auch das Mesh sieht.
API Spezifikation
Programme die mit der giDX³ 3D Engine erstellt werden müssen mit
einem int main()beginnen. Die Funktion main()wird vom Hauptprogramm, welches im Hintergrund läuft aufgerufen.
Beispiel: Ein vollständiges giDX³ Progamm.
Code: Alles auswählen
#include"gidx.h"
int main()
{
if (graphic(640,480,true)!=0)
return 1;
while(gidxloop() && !keyhit(DIK_ESCAPE))
{
statkey();
renderworld();
}
return 0;
}
Auf der linken Seite der C/C++ Quellcode und auf der rechten Seite der Blitz3D Quellcode. Beide Programme erzeugen das selbe Bild.
Was kann giDX³ 3D
• Einfache Direct3D Initialisierung
• Primitive rendern
• Multitexturierung
• Kamera
• DirectX Licht
• Vertexdeklaration
• Funktionale Schnittstelle
• Bewegung, Rotation, Skalierung
Wie geht es weiter
Ich habe giDX³ 3D in den Feiertage programmiert. Es ist sicher noch viel Verbesserungspotenzial vorhanden, aber ob ich noch Zeit dafür habe ist ungewiss.
Es wird ein Hobbyprojekt bleiben an dem ich abends mal ein zwei Stunden etwas mache. Es gibt so viele tolle 3D Engines auf dem Markt und ich habe weder das Wissen noch die Erfahrung und die Zeit mehr aus giDX³ zu machen.