WebGL Demo of animated Character

I finally finished my WebGL demo to render an animated character. To create the JSON File, I changed my ParrotEngine Blender Export Script to output a JSON file instead of XML.

The demo was tested on Firefox 7 and 8, Opera 12 and Google Chrome 15 – each was running fine. Internet Explorer does not support WebGL – and probably never will, so you have to use another browser to see the demo…
Continue reading

Order of Matrix multipliation and its effect on transformations

One thing that I stuggle regularily with, is the order in which matrices should be multiplied to achieve a specific result. So I decided to get this clear for myself for good and all.

As you know, matrices (at least in our context of 3D graphics) represent transformations. Multiple transformation matrices can be combined using marix multiplication. But since this operation is not commutative, the order of the multiplication is important.

Since matrices represent transformations, they build new coordinate systems, too: These new systems are defined by axis vectors that have been transformed using the matrix. An example will clarify this fact:

In the examples used in this post, I will use a rotation matrix around 30 degrees, because \sin(30^\circ) = \frac{1}{2} and \cos(30^\circ) = \sqrt{\frac{3}{4}}, which is easy to write down and we still stay exact when calculating with it.

Part 1: A single transformation matrix

Given the origin system with the axis vectors \left(\begin{array}{c}1 \\ 0 \\ 0 \end{array}\right) and \left(\begin{array}{c}0 \\ 1 \\ 0 \end{array}\right), when we rotate these vectors around 30 degrees, we get the vectors \left(\begin{array}{c}\sqrt{\frac{3}{4}} \\ \frac{1}{2} \\ 0 \end{array}\right) and \left(\begin{array}{c}-\frac{1}{2} \\ \sqrt{\frac{3}{4}} \\ 0 \end{array}\right)
Continue reading

Main Character für die “Parrot Quest”

Der Hauptcharakter der Parrot Quest

Der Hauptcharakter der Parrot Quest

Das Spiel das ich als Demo für die ParrotEngine gerade erstelle benötigt natürlich einen Hauptdarsteller und wie der Name der Engine unschwer verrät wird es ein Papagei werden. Rechts seht ihr den aktuellen Stand des 3D Models. Ich erstelle alle Modelle in Blender. Der Papagei ist aktuell bereits gerigged und animiert.
Damit es voran geht, werde ich als erstes dieses Model verwenden um ein spielbares Level zu implementieren. Die Feinarbeiten kommen irgendwann später. Falls dies hier ein 3D-Artist liest und dieser fit in Blender ist, nehme ich auch gerne Hilfe an!

Die erste Testmap wird sehr simpel gestrickt sein. Auf dem Screenshot links sieht man den Weg der zurückgelegt werden muss. Links unten ist der Startpunkt (Player Spawn Point) und rechts der Bereich bei dessen Erreichen die Map als erfolgreich erledigt erkannt wird. Der Spieler wird diesen Bereich nicht verlassen können – auf diese Weise kann man sich später im Spiel nicht um Gegner und Hindernisse “herummogeln”. Geheimgänge, Abkürzungen und sonstige Geheimnisse müssen in einer Map gezielt eingebaut werden.

Screenshot des Mapeditors

Screenshot des Mapeditors

Um meine Engine nicht alleinig auf Jump’n Run Spiele auszurichten habe ich eine Zwischenschicht eingeführt: Das “JumpNRun Modul”. Dieses enthält neben dem auf diese Art Spiele spezialisierten Map-Editor auch weitere dafür benötigte Hilfsklassen. So bleibt die Engine zwar weniger “mächtig”, dafür aber allgemeingültig und kann später auch für eventuelle weitere Module verwendet werden. Ich denke da an soetwas wie ein “FirstPerson Modul” oder ein “Platform Modul”… doch eins nach dem anderen.

Resource Collections in der Parrotengine

Derzeit programmiere ich an einem Map-Editor. Dieser soll sowohl einfach zu bedienen, also auch vollständig bezüglich der Funktionalität sein. Dabei stellte sich mir das Problem wie ich sicherstellen kann, dass ein Spiel auf genau die gleichen Resourcen zugreifen kann wie der Editor: Schließlich werden die Elemente die im Editor in die Map platziert wurden auch vom Spiel benötigt wenn dieses die Map einladen und darstellen möchte.

Struktur der Resource Collections

Struktur der Resource Collections

Als Lösung für dieses Problem habe ich die Resource-Collections ins Leben gerufen. Es handelt sich hier um eine Datei im XML Format die eine Liste aller Resourcen enthält die ausgehend vom Ort der resource-collection.xml Datei erreichbar sind. Da die Engine bisher für alle Zugriffe auf Resourcen InputStreamSource-Objekte verwendet, nutzt das Konzept für die Collections diese natürlich ebenfalls. Das bedeutet, dass ein Programm, welches über irgendein InputStreamSource-Objekt an eine resource-collection.xml Datei kam, über genau das gleiche Objekt alle in der XML erwähnten Resource Objekte laden kann!

Die Engine selbst besitzt standardmäßig eine eigene ResourceCollection. Diese enthält neben dem Engine-Logo auch die Standard-Fonts, default-Texturen und Standard-Skyboxen. Damit Programme die die Engine nutzen den Satz an verfügbaren Resourcen ergänzen können gibt es das ResourceCollectionSet. Dieses enthält eine Liste von Resource-Collections.

Das ResourceCollectionSet kann jederzeit um weitere Resource-Collections ergänzt werden. Wird vom Spiel aus eine Resource angefordert, so geschieht das über die ReaderFacade:

 ReaderFacade facade = engine.getReaderFacade();
 MeshPrototype m = facade.readMeshPrototype("meshes/mesh1.xml");
 

Die Methodefacade.readMeshPrototype(…)ruft hier das ResourceCollectionSet auf und dieses sucht dann der Reihe nach in allen registrierten ResourceCollections nach “meshes/mesh1.xml”. Der erste Fundort wird dann genutzt um das Objekt zu laden.

Jede ResourceCollections kann dabei eine andere InputStreamSource besitzen: Netzwerk, ZIP-Archiv, lokales Fileystem, Klassenpfad,… alles ist hier erlaubt.

Um nun auf den eigentlichen Grund dafür zurückzukommen: Es genügt nun die Übergabe eines InputStreamSource Objekts sowie eine dafür gültige Pfadangabe zu einer resource-collection.xml um sicherzustellen, dass eine Menge von Resourcen genau definiert ist. Für die meisten Anwendungsfälle wird es wohl so sein, dass während der Entwicklungszeit das InputStreamSource Objekt eine Instanz vonDirectoryInputStreamSource ist, welches einfach auf ein Filesystem-Verzeichnis verweist. Später, in einem Release wird dies wohl eher ein Verweis auf ein ZIP oder JAR-Archiv sein.

Das ResourceCollectionSet-System ist derzeit nur im Subversion-Repository vorhanden. Es wird aber im nächsten Release der Engine enthalten sein zusammen mit Beispielprogrammen.

ParrotEngine 0.2 released

Terrain Rendering

Terrain Rendering

Ab sofort ist die Version 0.2 der 3D Parrot Engine verfügbar! Gegenüber der Vorversion wurde die grundlegende Struktur der Engine überarbeitet, das Renderverfahren flexibler gestaltet und eine Menge Performanceoptimierungen sowie Verbesserungen an der Klassenstruktur vorgenommen.

Dieses Release hat als Hauptaufgabe die Basisinfrastruktur der Engine so zu stabilisieren, dass eine feste Grundlage entsteht auf der alle weiteren Erweiterungen implementiert werden können ohne eine erneute Anpassung der Grundstruktur zu erfordern.

Mit dieser Version kommen nun auch einige Beispielprogramme um den Einstieg in die Programmierung mit der Engine zu erleichtern und auch um die Features zu demonstrieren. Das Build-System wurde komplett überarbeitet so dass nun ein einzelnes build.xml alle Aufgaben erledigen kann: Auch das Starten der Beispielprogramme.

Ein Getting-Started Tutorial zeigt, wie einfach mit der Entwicklung mit der Engine begonnen werden kann. Angefangen von der Einrichtung der Entwicklungsumgebung bis hin zum ersten lauffähigen Programm. Die Downloads und weiteren Links befinden sich wie gehabt auf der Hauptseite der Engine.

RenderState Sortierung und Optimierung

Renderstate Verwaltung

Renderstate Verwaltung

Jedes Objekt einer Szene kann ein oder mehrere Materialien verwenden. Ein Material wird über einen RenderState repräsentiert, welcher neben den üblichen OpenGL Material-Settings auch alle Textureinstellungen, die Shader-Programme, En- und Disabled Eigenschaften, den zu verwendenden Polygon Mode, Blend Operationen und viele weitere Eigenschaften enthält. Bei jedem Wechsel des aktiven RenderStates werden nur die OpenGL calls ausgeführt die wirklich notwendig sind. Es ist außerdem nicht notwendig, dass irgendein Objekt weiß welche Einstellungen in OpenGL vorliegen bevor es sich zeichnet – durch das Setzen seines RenderStates kann es sicher sein, dass genau nur die von ihm geforderten Einstellungen aktiv sind.

Realtime Graphanzeige

Realtime Graphanzeige

Ein Timer-Framework hilft dabei Performance-Engpässe zu erkennen und zu beseitigen.

Shader-Support

Die Engine unterstützt Vertex- und Fragmentshader in GLSL. Die Shader sind in die RenderStates eingebettet und werden so als Teil der Materialien angesehen. Die Shader können deklarativ mit Properties im Programm verknüpft werden. Auf diesem Weg können Parameter an die Shader übergeben werden.

Console

Steuerungskonsole

Steuerungskonsole

Um zur Laufzeit eine gute Kontrolle über die Engine zu haben und auch um auf ein laufendes Programm direkt Einfluss zu nehmen, gibt es die Console. Sie wird mit der Taste “^” eingeblendet und verfügt unter anderem über eine Historie der Eingabezeilen, Scrollback-Funktion und auch eine Eingabehilfe mit der Tabulator-Taste. Es ist für jedes Objekt sehr einfach möglich Variablen oder Kommandos in der Console zu registrieren und diese damit zur Laufzeit aufrufbar zu machen. Die der Console bereitgestellten Variablen sind so implemetiert, dass kein Performanceverlust dadurch entsteht. Es besteht also kein Grund darin, mit den Console-Variablen sparsam umzugehen.

Frustum Culling

Jedes Objekt im Szenenbaum besitzt eine Kugel die es komplett einschließt. Bevor Objekte gezeichnet werden, wird zunächst diese Kugel auf Sichtbarkeit geprüft und erst wenn die Kugel zumindest teilweise den aktiven Frustum berührt, wird das Objekt selbst auch gezeichnet. Das Terrain wird sogar in viele kleine Teile zerlegt und diese werden dann geprüft – allerdings werden die Terrainteile in Blöcke und nicht in Kugeln eingefasst.

Partikeleditor

Der Partikelsystem-Editor

Der Partikelsystem-Editor

Mit dem Partikeleditor kann komfortabel ein Partikelsystem aus mehreren Partikelströmen erzeugt werden. Der Editor unterstützt das Live-Verändern von Texturen, Bewegungseinstellungen, Farbverläufen, Größenänderungen, Schwerkraftverlauf, Emitterstärke und einiges mehr. Die so erzeugten Partikelsysteme können in einer XML-Datei exportiert und dann im eigenen Programm durch die Engine geladen in den Szenenbaum eingehangen werden.

Fontcreator

Der Bitmapfont-Creator

Der Bitmapfont-Creator

Der Fontcreator erzeugt aus TTF-Fonts Schrifttexturen die als Bitmapfonts verwendet werden können.

3D-TTF Text

3D Fonts aus Truetype Fonts

3D Fonts aus Truetype Fonts

Die Engine kann aus TTF-Dateien 3D-Texte erzeugen. Die Qualität der Texte kann beeinflusst werden und somit ist eine Steuerung der Menge an Geometriedaten möglich die erzeugt werden. Die 3D-Texte sind nach ihrer Erstellung normale 3D-Objekte und auch mit Texturkoordinaten versehen, so dass die normalen Objektoperationen damit möglich sind.

Terrain Rendering mit LOD

Terrain Rendering

Terrain Rendering

Aus einer Heightmap in Verbindung mit einer optionalen Textur kann ein Terrain erzeugt werden. Das Terrain wird unterteilt in ein NxN Raster von Blöcken. Diese werden – je nach Entfernung vom Betrachter – in unterschiedlichen Levels-of-Detail (LOD) dargestellt um die Menge an zu zeichnenden Geometriedaten zu optimieren.

Skybox

Einer Szene kann eine Skybox zugewiesen werden – dadurch ist es einfach möglich einer Szene einen Hintergrund zu geben der sich entsprechend bei der Änderung der Blickrichtung so verhält, als würde er eine weite umliegende Welt darstellen.

Input Handling

Über eine Abstraktionsschicht werden die Benutzereingaben gekapselt und vorverarbeitet. Die Eingaben landen in einer Queue die dann an die in dieser Queue registrierte Listener verteilt werden. Diese Listener erhalten dann die Möglichkeit exklusiv die Eingaben zu verarbeiten oder aber auch nur als Proxy zu fungieren und unverändert passieren zu lassen. Durch dieses Verfahren ist es einfach möglich eine Mouselook-Funktion für ein Programm zu implementieren: Einfach einen TurntableRotator instanzieren und in die Queue einhängen – wenn nun für jedes Frame der Frustum des TurntableRotators geholt und in die Engine gesetzt wird kann man sich schon mit der Maus frei umsehen.

Endlicher Automat

Zur Verwaltung von Spielzuständen und deren Wechsel untereinander ist ein endlicher Automat integriert.

Audio-System

Das integrierte Audio-System unterstützt das Abspielen von mehreren gleichzeitigen Sounds im WAV als auch im OGG-Format.

Blender Export Script

Zur Erstellung von 3D-Objekten ist ein Python Export-Skript für Blender bei der Engine dabei. Dieses Skript muss lediglich in den Skript-Path von Blender kopiert werden und ist anschließend in den Export-Modulen von Blender zu finden. Das Skript exportiert alle selektierten Objekte in einzelne XML-Dateien die jeweils den Namen des Objekts tragen. Wenn Texturen zugeordnet sind, werden diese ebenfalls exportiert. Empties (leere Objekte in Blender) landen als Marker Objekte in den exportierten Objektdateien – damit kann von Applikationen über den Namen des Markers auf deren Position und Ausrichtung innerhalb eines Objekts zugegriffen werden. Die Partikel-Demo nutzt dieses Feature zum Beispiel um die Position des Partikelsystems im Holzstapel zu bestimmen.