Augmented Reality Game mit Open Source

Aus Winfwiki

Wechseln zu: Navigation, Suche
Name des Autors / der Autoren: Serdar Calik, Sascha Flöter
Titel der Arbeit: "Augmented Reality Game mit Open Source"
Hochschule und Studienort: Fachhochschule für Oekonomie und Management in Hamburg


Inhaltsverzeichnis


1 Einleitung

Augmented Reality ist zurzeit ein Thema das sich in unterschiedlichen Bereichen, wie z.B. in der Unterhaltungselektronik (Spielkonsolen und andere Multimedianwendungen) und in der Verbraucherinformation verbreitet. Dies ist zum großen Teil der aktuellen leistungsfähigeren Hardware, wie z.B. Mobiltelefonen und portablen Geräten zu verdanken. Aber was ist genau Augmented Reality, welche Plattformen gibt es im Open Source Bereich und was kann damit genau machen? Diese Fallstudie soll zeigen, wie mit einer Open Source Entwicklerplattform eine Augmented Reality Spielanwendung entwickeln wird, was bei der Entwicklung wichtig ist und welche Möglichkeiten die Entwicklungsplattformen ermöglichen. Als Resultat der Fallstudie soll ein eigener Prototyp entwickelt werden. Dieser Prototyp soll eine Augmented Reality Spielanwendung sein, das mittels Markererkennung die Fahrzeuge auf einer Spielfläche steuert.

2 Grundlagen

2.1 Augmented Reality

Unter Augmented Reality (AR) wird die Erweiterung der realen Welt mit der virtuellen Welt verstanden. Dies geschieden dadurch, dass in Echtzeit 2D oder 3D-Objekte in das Videobild der realen Welt hinzugefügt werden.[1]Im Jahr 1968 erstellte eine Arbeitsgruppe unter der Führung von Ivan Sutherland das erste VR-System und AR-System. Es benutzte eine einfache „Wire-Frame“ Grafik und ein schwerfälliges HMD-System und war der Anfang von Augmented Reality.[2]

Es werden drei charakteristische Merkmale eines Augmented Reality-System beschrieben:[3]

  • Kombination von realer und virtueller Welt.
  • Interaktivität und Echtzeitfähigkeit.
  • Registrierung von realen und virtuellen Objekte miteinander.

2.1.1 Abgrenzung

Es gibt auf der einen Seite die Augmented Reality, die Informationen mittels technischen Hilfsmitten, wie z.B. Bildschirm oder Head-Mounted-Display das Erfassungsvermögen der realen Welt erweitert zum anderen gibt es die Augmented Virtuality die im Gegensatz zum Augmented Reality eine reine virtuelle Welt darstellt mit eigenen physikalischen Gesetzten und fiktiven Welten. Das Zusammenführen der Technologien Augmented Reality und Augmented Virtuality wird als Mixed Reality bezeichnet und wird von Professor Paul Migram in seiner Veröffentlichung „Augmented Reality: A class of display on the reality-virtuality continumm“ beschrieben.[4]

Quelle: Milgram et al. (1994) S. 283.Abbildung 1: Darstellung des „Reality-Virtuality continumm“
Quelle: Milgram et al. (1994) S. 283.
Abbildung 1: Darstellung des „Reality-Virtuality continumm“

2.1.2 Funktionsprinzip

Das Grundprinzip eines AR-Systems erlaubt es virtuelle Objekte auf ein Live-Video-Stream der realen Welt mittels Verwendung von sogenannten Tracking-Marker zu überlagern. Das Funktionsprinzip des Systems wird wie folgt beschrieben:[5]

  1. Die Kamera nimmt das Videobild der realen Welt auf und schickt es an den Computer.
  2. Die Software auf dem Computer durchsucht jedes Video-Bild nach einem Marker.
  3. Die Software verwendet mathematische Berechnungen um die Position der Kamera im Bezug zum Marker zu ermitteln.
  4. Ist die Position der Kamera bekannt wird das virtuelle Objekt auf die gleiche Position gezogen.
  5. Das virtuelle Objekt ist im Videobild der realen Welt auf den Marker positioniert.
  6. Durch die Verwendung z.B. eines Handheld Display und die Betrachtung durch dieses erkennt der Betrachter die Vermischung der realen Welt und der virtuellen Welt.

In der folgenden Abbildung werden die einzelnen Schritte dargestellt:

Quelle: o.V. HITL (2009b)Abbildung 2: Funktionsprinzip eines AR-Systems
Quelle: o.V. HITL (2009b)
Abbildung 2: Funktionsprinzip eines AR-Systems

2.2 Software

Es werden einige Plattformen für die Entwicklung von AR-Anwendungen vorgestellt:

Augmented Reality System
Beschreibung
ARTag ARTag ist eine Entwicklerplattform für eigene Augmented Reality Anwendungen, die von Dr. Mark Fiala von der „National Research Council of Canada labs“ entwickelt wurde.[6]
Goblin XNA

Goblin XNA ist eine Plattform für die Entwicklung von 3D-Benuztzeroberflächen, einschließlich AR- und VR-Anwendungen mit einem Schwerpunkt auf Spielentwicklung. Goblin XNA nimmt unterschiedliche Technologien, wie ARTag, ALVAR, DirectShow und Newton Game Dynamics auf.[7]
ARToolKit ARToolKit ist ein spezielle auf die Entwicklung von Augmented Reality Anwendungen ausgerichtet.[8]
ARToolKitPlus ARToolKit Plus ist eine Weiterentwicklung vom ARToolKit und ist im Zusammenhang eines Handheld AR-Projekts der Universität Graz entstanden. Es ist in der Programmiersprache C++ geschrieben und ist im Gegensatz zum ARToolKit objektorientiert aufgebaut.[9]
JARToolKit JARToolKIT ist eine Java-Entwicklerplattform, welches die Funktionalitäten des ARToolKits beinhaltet.[10]

Tabelle 1: Augmented Reality Systeme

2.3 Hardware

Die Aufgabe eines AR-System ist es, die reale Welt mit Informationen von Computergenerierten Daten zu erweitern oder zu ergänzen.[11]

Ein AR-System besteht aus fünf wesentlichen Hardwaresystemen:

  • Rechnereinheit für die Verarbeitung der Informationen(Renderer und Mischer).
  • Anzeigesystem, wie Bildschirm oder Head-Mounted-Display (HMD).
  • Trackingsystem, dient dazu die Position der realen Welt und der virtuellen Welt zu synchronisieren.
  • Aufnahmesensorik (Kamera)
  • Eingabegeräte, wie Tastatur und Maus.


Es gibt vier verschiedene Visualisierungsverfahren, Sie werden durch die jeweiligen Hardwarekombinationen unterschieden:[12][13]

  • Video See Through (VST)
    • Mittels Kamera wird die Umgebung erfasst und auf ein Head-Mounted-Display das vor den Augen positioniert ist mit virtuellen Informationen(Render/Mischer) erweitert.
  • Optical See Through (OST)
    • Beim OST wird mittels Bildteilungssystem(optischer Mischer) das sich vor den Augen befindet die reale Welt dargestellt und das virtuelle Bild zur realen Welt hinzugefügt.
  • Projektive Augmented Reality (PAR)
    • Das virtuelle Objekt wird auf eine Projektionsfläche z.B. Tisch abgebildet und dadurch wird die reale Welt um den virtuellen Bestandteil erweitert.[14]
  • Monitor Augmented Reality (MAR)
    • Die reale Welt wird durch eine Kamera erfasst und mit dem virtuellen Anteil erweitert. Das erweiterte Bild(Virtuell und Real) wird auf einem Bildschirm dargestellt.

3 Open Source Plattformen für Augmented Reality Entwicklungen

3.1 Umsetzung mittels ARToolKit

ARToolKit ist von HITLAB(Human Interface Technology Laborty) an der Universität von Washington (Seattle) für die Betriebssysteme SGI IRIX, Linux, MacOS und Windows entwickelt worden und unterliegt der GNU General Public License, das heißt ARToolKit ist für den freien nicht kommerziellen Betrieb freigegeben.[15] Desweitern ist das HITLabNZ der Universität Canterbury in Christchruch, Neuseeland an der Entwicklung beteiligt. Das Team vom HITLAB um Hirokazon Kato und Mark Billinghurst begann 1999 mit der Entwicklung des ARToolKits.[16]

3.1.1 Inbetriebnahme vom ARToolKit

Bevor ARToolKit zur Entwicklung von eigenen Anwendungen verwendet werden kann sind einige Voraussetzungen zu erfüllen. Es wird zur Entwicklung das Microsoft Visual C++ 2008 Express Edition[17] benötig. Für die Fallstudie wurde das Visual Studio 2008 Professional Edition (SP1)(MSDNAA) verwendet aber das VS C++ 2008 Express Edition ist ausreichend um eignende Anwendungen zu erstellen. Es gibt aber auch freie Softwareentwicklungsumgebungen wie z.B. „Cygwin“ auf die nicht näher eingegangen wird.[18] Es werden zum ARToolKit weitere Softwarepakte benötig die im nächsten Kapitel näher beschrieben werden. Die Softwarepakte sollten in ein separates Download-Verzeichnis für die spätere Installation gelegt werden.

3.1.1.1 Software Voraussetzung

Folgende Softwarepakte werden benötigt:[19]

Software
Beschreibung
ARToolKit 2.72[20] ARToolKit ist ein Werkzeugkasten, dass die Entwicklung von eigenen Augmented Reality Anwendungen ermöglicht.
OpenVRML-0.143-bin-win32[21] OpenVRML ist ein freies Open-Source Projekt, das dreidimensionalen Objekte im VRML und X3D-Format für internetbasierte Anwendungen konzipiert wurde.[22]
DSVideoLib-0.0.8b-win32[23] DSVideoLib dient zur Kommunikation zwischen den Betriebssystem und des Kameratreibers.
GLUT 3.76[24] GLUT ist eine Bibliothek um OPENGL Anwendungen zu schreiben. In ARTooKit wird es zum Zeichen von 3D-Objekten verwendet.[25]
MSVCR71D.DLL und MSVCP71D.DLL[26] Die Dll´s sind Runtime Library Module von Microsoft und sind im Microsoft® Visual Studio .NET vorhanden. Sie müssen aber ggf. separat heruntergeladen werden, wenn Sie nicht in der Express Version vom Studio .Net vorhanden sind.[27]
LIBPNG-1.2.24[28], JPEG-6b-4-LIB.ZIP[29]und JPEG-6b-4-BIN.ZIP[30] LIBPNG ist eine Referenzbibliothek, die Funktionen enthält mit den PNG-Bilder verarbeitet werden können.[31]JPEG-6b-4 ist ein standardisiere Kompressions-Methode für Farb- und Graustufenbilder.[32]
DirectX SDK (March 2009)[33] Das DirectX SDK Pakte wird zur Entwicklung von dreidimensionalen Grafikanwendungen verwendet.

Tabelle 2: Software Voraussetzung ARToolKit

3.1.1.2 Hardware Voraussetzung

Die Entwickler von ARTooKit nennen keinen speziellen Hardwareanforderungen, aber um ein Überblick zu bekommen werden folgende technische Anforderungen genannt:[34]

  • Prozessor: ab 1.0 GHz
  • Arbeitsspeicher: min. 512 MB RAM
  • Grafikkarte: High-End Grafikkarte
  • Kamera: Digital Video Kamera (DirectShow, Videre DCAM, Point Grey)
3.1.1.3 Installation von ARToolKit

In den folgenden Punkten wird die Installation von ARToolKit beschrieben:

  1. Entpacken von ARToolKit in ein Verzeichnis der eigene Wahl (z.B. Laufwerk\Programme\ARToolkit).
  2. Entpacken der DSVideoLib.zip in das ARToolKit Verzeichnis (..\ARToolkit\DSVL). Die Dateien DSVL.dll und DSVLd.dll in das ..\ARToolkit\bin\ Verzeichnis kopieren.
  3. Die GLUT32.dll aus dem glut-3.7.6-bin.zip Archive in das ..\Windows\system32 Verzeichnis kopieren.
  4. Die GLUT32.lib in ..\Programme\Microsoft Visual Studio 9.0\VC\lib\ kopieren.
  5. GLUT.h in ..\Programme\Microsoft Visual Studio 9.0\VC\include\GL\ kopieren.

Folgende Einstellungen sind beim Visual Studio C++ 2008 Express vorzunehmen:

  1. Die Configure.win32.bat ausführen. Es sollte unter ..\Programme\ARToolkit\include\AR\ die Datei "config.h" vorhanden sein.
  2. Die Datei "ARToolKit.sln" muss als nächstes ausgeführt werden. Das VS 2008 Express konvertiert es auf das VS 2008 Format um.
  3. Die Projektmappenkonfigurationen von DEBUG auf Release umstellen und die ARlib im Projektmappen-Explorer erstellen.
  4. Die OpenVRML-0.14.3-win32.zip in das ARToolKit Verzeichnis kopieren.
  5. Die js32.dll Datei aus den ..\Programme\ARToolKit\OpenVRML\bin Verzeichnis in das ..\Programme\ARToolKit\bin kopieren.
  6. Vorkompilierte Bibliotheksdateien (lib.zip)[35] in das ..\Programme\ARToolKit\lib Verzeichnis kopieren.
  7. Im Konfigurations-Manager jeweils bei libARvrml und simpleVRML den Haken bei „Erstellen“ setzen.
  8. Als letztes auf "Erstellen/Projektmappe erstellen" gehen und das Projekt erstellen.

Die Grundinstallation des ARToolKits ist hiermit abgeschlossen.[36][37]

Durch die Auswahl des Projektes „simpleTest“ im Projektmappen-Explorers des Visual Studio und Kompilierung(rechtsklick des Projekts und „Neu Erstellung“) kann die Funktionalität des Projektes überprüft werden. Danach sollte eine neue „simpleTest.exe“ Datei im Ordner "..\Programme\ARToolKit\bin\" mit einem neuen Zeitstempel liegen. Die Anwendung „simpleTest.exe“ kann gestartet werden und das vorher ausgedruckte PDF-Dokument „patHiro.pdf“ im Ordner "..\Programme\ARToolKit\patterns\" muss vor der Kamera liegen. Nach dem Start der "simpleTest.exe" Datei erscheint auf dem Hiro-Pattern ein Würfel.[38] Um die Erkennungsrate der Pattern zu erhöhen muss die Kameraeinstellungen neu kalibriert werden. Dieses wird im Kapitel „3.1.2.1 Kamera Steuerung (Kameraeinstellungen kalibrieren)“ näher beschrieben.

3.1.2 Vorgehensweise bei der Entwicklung einer Anwendung

3.1.2.1 Kameraeinstellungen kalibrieren

Um bestmögliche Ergebnisse bei der Erkennung der Marker zu erzielen muss die Kamera eingestellt werden. Diese Informationen werden in einer Kalibrierungsdatei gespeichert. Die Kalibrierungsparameter in der Kalibrierungsdatei werden bei ARToolKit in der Datei „camera_para.dat“ gespeichert. Diese Datei befindet sich unter den Verzeichnis „..\Programme\ARToolkit\bin\Data\“.[39]

Um die Kalibrierung durchzuführen werden zwei Dateien benötigt. Die Dateien „calib_dist.pdf“ und „cpara.pdf“(..\Programme\ARToolkit\ARToolkit\patterns). Bevor die PDF-Dateien ausgedruckt werden ist die Skalierung der Dateien so zu wählen, dass zwischen den Rasterpunkten und den Rasterlinien der Abstand exakt 40mm beträgt. Dieses kann nach dem Ausdruck mittels Lineal überprüft werden. Desweiteren werden die Programme „calib_dist.exe“ und „cparam.exe“ (..\Programme\ARToolkit\bin) benötigt. Bevor die Programme gestartet werden montieren Sie die beiden Muster auf einen festen Gegenstand. Die Muster müssen soweit positioniert werden, dass die Muster vollständig im Kamerabild vorhanden sind.[40]

Um die Kalibrierung zu starten wird das Programm „calib_dist.exe“ benötigt. Nach dem Start des Programmes werden zwei Fenster geöffnet(Dialogbox/Konsole). In der Dialogbox müssen die Informationen zum Videoformat angeben werden.[41]


Folgende Daten sind in der Dialogbox zu wählen:

  • Farbbereich/Kompression = RGB24
  • Ausgabegröße = 800/600 Pixel
  • Framerate = 15 fps


Folgende Zeilen die das Programm „calib_dist.exe“ berechnet werden für die darauffolgenden Kalibrierungsschritt benötigt. Die berechneten Werte könnten folgendermaßen Aussehen:

  • Center X: 455.000000
  • Center Y: 245.000000
  • Dist Factor: 2.400000
  • Size Adjust: 1.001447


Als nächstes wird die Kamera mit den Programm „calib_cparam.exe“ kalibriert. Dazu werden die vorher notierten Daten gebraucht, die dann im Konsolenfenster eingeben werden. Es sind die Anzahl der horizontale und vertikale Lienen anzugeben die auf den Ausdruck(calib_cparam.pdf) zusehen sind. Die Werte für „Number of iteration“, „Distance amony lines“ und „Distance to move“ können durch drücken der „ENTER“-Taste übersprungen werden. In der Dialogbox die als nächstes erscheint wird eine Auflösung „800x600“ ausgewählt.[42] Der Ausdruck wird auf ein festen Gegenstand senkrecht auf z.B. auf ein Karton vor der Kamera montieren. Es ist darauf zu achten, dass genügen Platz hinter der Kamera vorhanden ist, da jeweils nach jeden Durchgang(5 Erfassungen) der Karton um 10 cm nach hinten verschoben wird. Durch drücken der linken Maustaste im Kamerafenster wird das Kamerabild eingefroren. Es erscheint eine horizontale weiße Linie. Mit den Cursortasten([UPARROW], [DOWNARROW]) werden die Linien positioniert. Mit den Tasten [RIGHTARROW] und [LEFTARROW] können die Line gedreht werden. Es soll als erstes die oberste Linie so angepasst werden, dass die weiße Line mit der obersten Line komplett abgedeckt wird. Durch drücken der [ENTER]-Taste wird die Line fixiert und blau dargestellt. Es müssen alle Linien genauso positioniert werden. Dieser Vorgang wird viermal wiederholt und danach werden die Kameraparameter berechnet. Die Kameraparameter sind folgendermaßen abzuspeichern: „C:\Programme\ARToolkit\bin\Data\camera_para.dat“.[43]

3.1.2.2 Entwerfen von eigenen Marker

Die Beispielprogramme die ARToolKit zur Verfügung stellt benutzen unterschiedliche vordefinierte Marker. Diese Marker werden in den Quellcode der jeweiligen Anwendung definiert. Die Quellcodedateien der Beispielanwendungen befinden sich im Verzeichnis „C:\Programme\ARToolKit\examples\“. und um die Einbindung und Funktionsweise zu betrachten wird die Datei „simpleTest.c“ aus dem Verzeichnis „ARToolKit\examples\simple\“ benötigt. Dies werden mit der Entwicklungsumgebung des Visual Studios geöffnet und werden im nächsten Abschnitt näher beschrieben.[44]

Die Zeile mit den Quellcode: char *patt_name=„Data/patt.hiro;“ wird soweit korrigieren, dass in der Zeile eine eigene Markerbezeichnung vorhanden ist z.B. char *patt_name=„Data/patt.Test_01. Diese Datei wird unter den Namen „simpleTest.c“ gespeichert. Danach wird im Ordner „..\Programme\ARToolKit\“ die Datei „ARToolKit.sln“ mit der Entwicklungsumgebung geöffnet. Die Anwendung „simpleTest“ im Projektmappen-Explorer wird mit ein Rechtsklick ausgewählt und der Punkt „NEU ERSTELLEN“ erstellt die Datei mit neuem Zeitstempel.[45] Um einen Marker zu definieren, kann mit einem Bildbearbeitungsprogramm wie z.B. „Paint.net“ die Datei „blankPatt.gif“ im Verzeichnis „..\Programme\ARToolKit\patterns\“ bearbeitet werden. Das weiße Quadrat sollte am besten mit einem einfachen asymmetrischen Muster gefüllt werden, da dieses Muster am besten erkannt wird. Die Datei muss in das GIF-Format abgespeichert werden.[46]

In Anlehnung an Vgl. Höhl (2009) S. 186.Abbildung 3: Die Datei „blankPatt.gif“ im Verzeichnis „..\Programme\ARToolKit\patterns\“
In Anlehnung an Vgl. Höhl (2009) S. 186.
Abbildung 3: Die Datei „blankPatt.gif“ im Verzeichnis „..\Programme\ARToolKit\patterns\“
In Anlehnung an Vgl. Höhl (2009) S. 184.Abbildung 4: Selbst definierter Patter
In Anlehnung an Vgl. Höhl (2009) S. 184.
Abbildung 4: Selbst definierter Patter

Um den neuen Marker der Anwendung „simpleTest.exe“ zuzuweisen wird das Programm „mk_patt.exe“ benötigt, diese Anwendung ist im Ordner „..\Programme\ARToolkit\bin\“ zu finden. Nach dem Start der Anwendung, öffnet sich ein Kamerafenster und der Ausdruck des Marker muss vor der Kamera positioniert werden. Im Kamerafenster sind zwei rote und grüne Kanten zu sehen. Der Ausdruck des Markers muss soweit gedreht werden, dass die rote Ecke links oben und die grüne Kante rechts unten dargestellt wird. Die Koordinaten sind so zu sehen, dass die positive X-Achse am unten Bildrand liegt und nach der rechten Seite läuft und die positive Y-Achse nach oben läuft, auf die aufgespannte XY-Fläche steht die Z-Achse.[47]

Ist das Ergebnis der Erfassung soweit korrekt wird durch drücken der linken Maustaste im Kamerafenster das Bild eingefroren und der Anwender wird aufgefordert in der Konsole ein Dateinamen einzugeben. Der Dateiname muss mit den in der Datei „simpletest.c“ übereinstimmen (z.B. „..\Programme\ARToolKit\bin\Data\ patt.Test_01). Durch die Bestätigung der Eingabe mit der [ENTER] Taste wird die Datei abgespeichert und steht der Anwendung „simpleTest.exe“ zur Verfügung. Nach dem Start der Anwendung erscheint auf den selbst erstellten Marker ein blauer Würfel.[48]

In Anlehnung an Vgl. Höhl (2009) S. 188.Abbildung 5: Erkennung des Markers im Kamerafenster (grüne X-Achse und rote Y-Achse)
In Anlehnung an Vgl. Höhl (2009) S. 188.
Abbildung 5: Erkennung des Markers im Kamerafenster (grüne X-Achse und rote Y-Achse)
Abbildung 6: Darstellung des Würfels auf den neu definierten Marker
Abbildung 6: Darstellung des Würfels auf den neu definierten Marker
3.1.2.3 Programmablauf

Bei der Entwicklung von Anwendung mittels ARToolKit sind zwei Punkte zu beachten, einmal die Verwendung von Routinen zur Bildverarbeitung und zum anderen deren Verbindung mit den Markern in der realen Welt, die in den Anwendungen verwendet werden.[49]


Folge Punkte zeigen den Ablauf einer AR-Anwendung:

Quelle: o.V. HITL (2009c)Abbildung 7: Ablauf einer ARToolKit Anwendung
Quelle: o.V. HITL (2009c)
Abbildung 7: Ablauf einer ARToolKit Anwendung
1. Initialisieren der Kamera(Video-Capture)und einlesen der Marker-Pattern-Dateien und Kamera-Parameter.


2. Einlesen des Video-Eingangssignals.
3. Erkennung der Markierungen und der erkannten Muster im Video-Eingangssignal.
4. Berechnung der Kamera-Transformation im Vergleich zu den erkannten Marker.
5. Zeichnen des virtuellen Objektes auf den erkannten Marke.



6. Schließen des Videosignals






Die Schritte 2 bis 5 werden kontinuierlich wiederholt bis zum beenden der Videoanwendung (Punkt 6). Punkte 1 und 6 werden beim starten bzw. beim beenden der Anwendung durchgeführt. Zusätzlich zu den Maßnahmen werden z.B. Maus- und Tastatureingaben bei bestimmten Ereignissen berücksichtigt.[50]

3.1.3 Beispiel Anwendungen

In diesem Abschnitt werden einige Projekte im Augmented Reality Bereich dargestellt:

Projekt Bezeichnung
ARQuake


Die Entwicklung des ARQuake Projekt wurde im Jahr 1998 von Dr. Bruce Thomas und einigen Studenten an der „Wearable Computer Lab an der University of South Australia“ gestartet. Es handelt sich um eine Umsetzung des Ego-Shooter Spiels Quake von der Firma ID-Soft. QuakeAR war das erste voll funktionsfähige Augmented Reality Spiel das für den Außeneinsatz konzipiert wurde. Das System setzte sich aus verschiedenen Komponenten, wie ein GPS, HMD, und ein Laptop zusammen.[51]
AR JAM

An der HITLABNZ wurde von Duenser in Zusammenarbeit mit der „New Media Division of The BBC“ das Projekt AR Jam entwickelt. Ziel des Projektes ist es Kinder zwischen 5 und 7 Jahren eine neuartige Lehrmethode mittels Augmented-Reality näher zu bringen, dass die Kinder interaktive in die Lehrinhalte eingreifen können.[52]
The Invisible Train „The Invisible Train“ ist eine Handheld Multiplayer Augmented Reality Anwendung die von Daniel Wagner, Thomas Pintaric und Dieter Schmalstieg von der Technischen Universität Wien entwickelt wurden. Der Spieler kontrolliert virtuelle Züge die in der realen Welt auf Holzbahngleise fahren und nur durch das betrachten im Handheld sichtbar sind. Ziel des Spiels ist es, dass die virtuellen Züge nicht kollidieren.[53]

3.2 Umsetzung mittels Goblin XNA

Goblin XNA ist eine Entwicklerplattform für die Erstellung von 3D Benutzeroberflächen, einschließlich Augumented Reality und Virtual Reality mit dem Schwerpunkt Spiele. Goblin XNA ist Entwickelt durch Ohan Oda und Steven K. Feiner an der Columbia University Department of Computer Science New York und steht unter der BSD-Lizenz[54]. Die Entwicklerplattform ist in C# geschrieben und basiert auf der Microsoft XNA-Plattform. Die Entwicklerplattform unterstützt derzeit 6-DOF (Six degress of freedom) Positionen und Ausrichtungstracking mit Markerbasierte Kamera-Tracking auf Basis von ARTag oder ALVAR mit OpenCV. Goblin XNA unterschützt auch DirectShow und InterSense Hybrid-Trackers. In Goblin XNA wird die Physikeigenschaft durch BulletX und Newton Game Dynamics Bibliothek unterstützt. Für die Entwicklung von netzwerkfähigen Spielen wird die Lidgren-Bibliothek in Goblin XNA eingesetzt. Die Entwicklungsumgebung enthält viele Hilfsklassen für eine vereinfachte Erstellung von Anwendungen.[55]

3.2.1 Inbetriebnahme vom Goblin XNA

3.2.1.1 Software Voraussetzung

Damit Goblin XNA auf den Rechner funktionsfähig wird, werden noch einige Softwarepakete und Bibliotheken benötigt.[56]

Software
Beschreibung
Goblin XNA[57] Main Framwork für die Entwicklung von Spiele.
Microsoft Visual Studio C# Visual Studio wird für die Erstellung (Code) benötigt. Es gibt zwei Versionen die benutzt werden können. Microsoft Visual Studio 2008 Professional oder Microsoft Visual Studio 2008 C# Express. Bei der Professional Version handelt es sich um eine kostenpflichtige Version wobei die Express Version frei Verfügbar ist.
XNA Game Studio[58] XNA Game Studio ist eine kostenlose und freiverfügbare Anwendung von Microsoft, die speziell für die Entwicklung von Spielanwendungen konzipiert wurde.
Newton Dynamics SDK[59] Die Newton Dynamics SDK Plattform dient zur Erstellung und Berechnung von physikalischen Eigenschaften von Objekten. In Goblin XNA wird die alte Version von Newton Dynamics SDK eingesetzt.
Lidgren-Network[60] Lidgren-Network ist eine Bibliothek für die Erstellung von netzwerkfähigen Spielen. Es basiert auf der .NET Framework von Microsoft.
DirectShow.NET[61] Das DirectShow.NET ist eine Entwicklungsumgebung für das aufzeichne von Video Signalen.
TaoFramework[62] Das TaoFramwork ist eine Sammlung von Bibliotheken zur erleichterten Erstellung von Multimedia Anwendungen.
ALVAR[63] ALVAR ist eine Software Bibliothek für die Erstellung von Virtuell- und Augmented Reality-Anwendungen. ALVAR ist von VTT Technical Research Centre of Finland entwickelt.
OpenVC 1.0[64] OpenVC ist eine Bibliothek mit Funktionen für Echtzeitprogrammierung.
ARTag[65] ARTag ist eine Augumented Reality Entwicklungsumgebung. ARTag wurde entwickelt von der „National Research Council of Canada labs“.

Tabelle 3: Software Voraussetzung Goblin XNA

3.2.1.2 Hardware Voraussetzung

Für Goblin XNA ist keine Spezifische Hardware Voraussetzung von den Entwickler vorgegeben. Es wird die Entwicklungsumgebung Visual Studio 2008 eingesetzt dafür werden folgende Systemkonfiguration benötigt:[66]

  • Computer mit 1,6-GHz- oder schnellerem Prozessor
  • Monitor mit einer Auflösung von 1024 x 768 oder höher
  • Mindestens 384 MB RAM (bei Windows Vista mindestens 768 MB RAM)
  • 2,2 GB verfügbarer Speicherplatz auf der Festplatte
  • USB 2.0 Anschluss
  • Webcam mit USB 2.0 Schnittstelle
3.2.1.3 Installation von Goblin XNA

Für die Installation von Goblin werden die folgenden Schritte durchgeführt:[67]

  1. Installieren von Microsoft Visual Studio 2008 Professional Edition oder Microsoft Visual C# & C++ 2008 Express Edition. Falls das Service Pack 1 von Visual Studio nicht in der Installation integriert ist so muss dies noch installiert werden.
  2. Herunterladen und Entpacken der Goblin XNA Entwicklungsumgebung in ein frei gewähltes Arbeitsverzeichnis.
  3. Herunterladen und Installieren von Microsoft XNA Game Studio 3.1.
  4. Herunterladen und Installieren von Newton Dynamics SDK 1.53. Die Version 1.53 ist eine ältere Version von Newton Dynamics SDK. Aktuell ist die Version Newton Dynamics SDK 2.15 verfügbar. Nach der Installation von Newton Dynamics SDK wird die Dll Datei Newton.dll benötigt. Dies ist in dem Verzeichnis "...\Programmme\NewtonSDK\sdk\dll" zu finden. Die Dll Datei wird in das "...\GoblinXNA\bin" Verzeichnis kopiert.
  5. Herunterladen und Entpacken von Lidgren-Network. In dem Entpackten Verzeichnis wird die Datei AllSamples.sln ausgeführt. Damit die benötigte dll Datei Lidgren.Network.dll in das "...\GoblinXNA\bin" Verzeichnis kopiert werden kann muss das Projekt im Release Modus Kompiliert werden. Anschließend ist die Dll Datei Lidgren.Network.dll im Verzeichnis "...\lidgren-network\Lidgren.Network\bin\Release" zu finden.
  6. Herunterladen und Entpacken von DirectShow.NET. Für das Herunterladen der Datei wird ein Konto benötigt. Das Registrieren auf der Webseite ist kostenlos. In dem Entpackten Verzeichnis wird die Datei CaptureTest.sln ausgeführt. In der Projektmappe sind drei Projekte vorhanden (CaptureTest, DirectX.Capture und DShowNET). Als erstes wird das Projekt DShowNET kompiliert in dem man auf das Projekt mit der der rechten Maustaste das Kontexmenü öffnet und anschließend Erstellen auswählt. Im nächsten Schritt wird in dem Projekt DirectX.Capture unter dem Order Verweise der Verweis auf die Dll Datei DShowNET angepasst. Diese liegt in dem Verzeichnis "...DShowNET\bin\Release". Nun kann jetzt das Projekt DirectX.Capture auch kompiliert werden. Die beiden Dll Dateien "...\DirectX.Capture\bin\Release\DirectX.Capture.dll" und "...\DShowNET\bin\Release\DShowNET.dll" können jetzt in das Verzeichnis "GoblinXNA\bin" kopiert werden.
  7. Herunterladen und Installieren von TaoFramework. In dem Installierten Verzeichnis werden die Dlls "...\Programme\TaoFramework\bin\Tao.FreeGlut.dll" , "...\Programme\TaoFramework\bin\Tao.OpenGL.dll" und "...\Programme\TaoFramework\lib\freeglut.dll" in das Verzeichnis "...\GoblinXNA\bin" kopiert.
  8. Für die Augmented Reality Steuerung gibt es zwei Entwicklungsumgebungen ALVAR und ARTag. Die Entwicklungsumgebung ALVAR wird in dieser Fallstudie nicht angewandt. Um die ARTag Entwicklungsumgebung zu bekommen wird der Kauf des Buchs "Augmented Reality - A Practical Guide" vorausgesetzt. In diesem Buch wird ARTag ausführlich beschrieben. Nach dem ARTag heruntergeladen ist wird die Datei entpackt. Die Dll Datei ARTagWrapper.dll wird in das Verzeichnis "...\GoblinXNA\bin" kopiert, diese ist in der ZIP Datei CSharp_ARTagWrapper.zip vorhanden.

3.2.2 Vorgehensweise bei der Entwicklung einer Anwendung

3.2.2.1 Kameraeinstellungen kalibrieren

Das Videosignal wir mit Hilfe der Klasse DirectShowCapture erfasst.Für eine optimale Darstellung des Videosignals und das lokalisieren von Marker wird eine Auflösung von 640x480 vorausgesetzt. Die Einstellung der Auflösung wird in der Methode public void SetupMarkerTracking() eingestellt. Es kann folgendermaßen aussehen:[68]

public void SetupMarkerTracking()
       {
       //Erstellen einer neuen Instanz von der Klasse DirectShowCapture.
       DirectShowCapture captureDevice = new DirectShowCapture();
       //Definieren der Eigenschaften von der Kamera.
       captureDevice.InitVideoCapture(0, FrameRate._60Hz, Resolution._640x480, ImageFormat.R8G8B8_24, false);
       //Hinzufügen der Kameraeigenschaften in die Spiel Szene.
       scene.AddVideoCaptureDevice(captureDevice);
       //Initialisierung der Variable
       IMarkerTracker tracker = null;
       //Erstellen einer neuen Instanz von der Kalsse ARTagTracker.
       tracker = new ARTagTracker();
       //Definieren der Eigenschaften für die Suchen von Markern im Videobild.
       tracker.InitTracker(638.052f, 633.673f, captureDevice.Width, captureDevice.Height, false, "ARTag.cf");
       //Hinzufügen der Definierten Markereingeschaften der Spielszene.
       scene.MarkerTracker = tracker;
       //Aktivieren des Videosignals in der Spielszene.
       scene.ShowCameraImage = true;
       }
3.2.2.2 Entwerfen von eigenen Marker

In Goblin XNA gibt es ein Tool zur Erstellung von eigenen Markern. Das Tool ist in "...GoblinXNA\tools\MarkerLayout". Zum Starten der Anwendung wird die Datei MarkerLayout.sln ausgeführt es handelt sich dabei um eine Visual Studio Projekt Datei. Im Projekt wird zwischen ALVAR und ARTag unterschieden. Für ALVAR wird als Grundlage der Marker das Dateiformat PNG verwendet. Nach der Marker Erstellung wird vom Programm eine TXT-Datei erstellt mit den entsprechenden grafischen Informationen als Dezimalzahlen. Bei ARTag werden die Marker im PGM Format vom Programm eingelesen die grafischen Marker die als JPEG oder PNG vorhanden sind müssen in das PGM Format umgewandelt werden. Nach dem das Programm ausgeführt worden ist erstellt es eine .CF Datei. In der Datei hat jeder einzelne Marker eine ID die so aussehen könnte:

coordframe
name="ground"
min_points=4 marker id=4 //-list of corners cw from top left vtx=0,0,0 //upper left vtx=0,10,0 //upper right vtx=10,10,0 //lower right vtx=10,0,0 //lower left /marker
3.2.2.3 Programmablauf
Quelle: Oda/Feiner(2009b) S.8 Abbildung 8: Funktionsprinzip von Goblin XNA
Quelle: Oda/Feiner(2009b) S.8
Abbildung 8: Funktionsprinzip von Goblin XNA

Der Programmablauf von Goblin XNA ist hierarchisch aufgebaut. Es wird in einer Szene das Spiel initialisiert, die Szene bilde gleichzeitig den Root vom Spiel. Auf dieser Szene könne die ganzen Objekte aufgebaut werden. Zu einer Szene gehört ein Objekt „Kamera“. Im Objekt Kamera werden die Eigenschaften für die Webcam oder die Ansicht auf das Spielfeld definiert. Auf der Szene wird auch die Beleuchtung und Schattenfunktion für die Objekte initialisiert. Die Erkennung von Markern wird mit der Szene verbunden, damit ist es möglich das die Marker die im Videosignal erkannt werden Objekte darstellen können. Die einzelnen grafischen Objekte wie Kugel, Zylinder, Würfel oder auch Modelle haben einen Geometrieknoten. Die grafischen Objekte werden mit einem Transformationsknoten über ihre Geometrieknoten auf die Szene positioniert dabei werden auch die Eigenschaften von dem jeweiligen Objekt übergeben. Soll z.B. ein Crash Sound wiedergegeben werden wenn ein Fahrzeug eine Kollision verursacht so wird der Soundeffekt mit dem Geometrieknoten vom grafischen Objekt verbunden.[69]





3.2.3 Beispiel Anwendungen

Hier werden einige Beispiel Spiele gezeigt die mit Goblin XNA Entwickelt worden sind:[70]

Projekt Bezeichnung
AR Racing Game Dieses Spiel ist mit XNA Racing Game Starter Kit Entwickelt worden. Die Bewegung des Fahrzeuges wird mit Marken gesteuert. Dabei wird die Lenkung anhand der Rotation vom Marker erkannt und das Fahrzeug lenkt in die entsprechende Richtung. Das Gleiche gilt auch für das Beschleunigen und Bremsen.
Domino Knockdown Das Domino Knockdown Spiel ist entwickelt worden um die Funktionalität mit einem Portablen Gerät zu Demonstrieren. Im Spiel geht es darum Domino Steine auf ein Feld zu Positionieren und anschließend dies mit Bällen abzuschießen. In diesem Spiel werden auch die Funktionen von Goblin XNA und Newton Game Dynamics simuliert. Das Domino Knockdown Spiel ist in der Goblin XNA Entwicklungsumgebung vorhanden.

4 Erstellung eines Prototyps

4.1 Zielsetzung

Ziel der Fallstudie ist es einen Prototyp zu entwickeln, dieser Prototyp soll eine einfache Spielanwendung darstellen.

4.2 Entwicklung

Für die Erstellung des Prototyps wird die Entwicklungsumgebung Goblin XNA verwendet. Goblin XNA hat den Schwerpunkt auf Spielentwicklung es sind Methoden und Funktionen vorhanden die die Entwicklung vereinfachen, wobei ARToolKit generell AR-Entwicklungen unterstützt. Als Markertracking wird ARTag eingesetzt.

4.2.1 Erstellung der Spielfläche

Als erstes wird eine Spielszene erstellt. Auf dieser Spielszene wird eine Fläche definier. Die Fläche besteht aus einem 3D-Rechteck (Dimension X=85, Y=66, Z=0,1)) und wird in der Methode private void CreateGround() erstellt. Damit die erstellte Fläche in der Kamera dargestellt werden kann wird mit Hilfe der Methode public void SetupMarkerTracking() die Marker im Videobild gesucht bei Übereinstimmung wird die Fläche auf den gefundenen Marker positioniert. Als Marker dient die Datei "...\GoblinXNA\tutorials\Tutorial8 - Optical Marker Tracking\ground.pdf" für die Spielfläche. Für eine 3D Darstellung wird in der Methode private void CreateLights() die Beleuchtungs- und Schatten-Eigenschaften definiert.

Abbildung 9: Spielfläche
Abbildung 9: Spielfläche

4.2.2 Erstellung der Objekt

In der ersten Entwicklungsphase des Prototyps sind vier Wände mit den physikalischen Eigenschaften (Kollisionserkennung) erstellt worden, durch den Aufruf der Methode private void CreateObjects() wurden diese Objekte in die Spielfläche hinzugefügt.

Es folgt eine exemplarische Darstellung eines Quellcodeabschnittes in der private void CreateObjects() -Methode. Hierbei handelt es sich um eine Seite der vier Wände des Prototyps:

...
// Box1 Exterior wall
// Objekt erstellen
GeometryNode box1Node = new GeometryNode("Box1");
// Objektgröße definieren (Länge,Breite,Höhe)
box1Node.Model = new Box(82, 2, WALL_HEIGHT);
// Physikeigenschaften aktiveren
box1Node.Physics.Collidable = true;
box1Node.AddToPhysicsEngine = true;
// Den Objekt die physikalische Eigenschaft „Box“ zuweisen
box1Node.Physics.Shape = ShapeType.Box;
// Schatteneigenschaften aktivieren
box1Node.Model.CastShadows = true;
box1Node.Model.ReceiveShadows = true;
// Initialisierung der Grundfläche
groundMarkerNode = new MarkerNode(scene.MarkerTracker, "ground");
// Instanziierung
TransformNode box1TransNode = new TransformNode();
// Initialisierung der Objektposition
box1TransNode.Translation = new Vector3(40, 62, 0);
// Materialeigenschaften definieren
Material box1Material = new Material();
box1Material.Diffuse = Color.DarkRed.ToVector4();
box1Material.Specular = Color.White.ToVector4();
box1Material.SpecularPower = 10;
// Materialeigenschaften zum Objekt hinzufügen
box1Node.Material = box1Material;
// Marker mit der Spielszene verbinden
scene.RootNode.AddChild(groundMarkerNode);
// Definierte Position auf die Spielfläche setzen
groundMarkerNode.AddChild(box1TransNode);
// Objekt auf die definierte Position setzen
box1TransNode.AddChild(box1Node);
...
Abbildung 10: Erstellen der vier Seitenwände
Abbildung 10: Erstellen der vier Seitenwände

Als nächstes wurde eine Kugel in die Spielfläche hinzugefügt. Ziel war es die Kugel per Tastatursteuerung zu lenken und später diese Steuerung durch die Veränderung der Lange der Spielfläche zu realisieren.

Abbildung 11: Setzen eines Objekts(Kugel) auf die Spielfläche
Abbildung 11: Setzen eines Objekts(Kugel) auf die Spielfläche

Die Spielfläche und die Objekte wurden soweit erweitert und angepasst, dass Effekte, wie Kollision, Beschleunigung und Abbremsung der Objekte analysiert werden konnten. Die Interaktion der Objekte untereinander wird im Punkt 4.2.3 „Kollision mit Objekte“ näher betrachtet.

Abbildung 12: Anpassung der Spielfläche und Austausch des Objekts (Tastatursteuerung)
Abbildung 12: Anpassung der Spielfläche und Austausch des Objekts (Tastatursteuerung)

Bei der Weiterentwicklung des Prototyps haben sich folgende Punkte verändert:

  • Erhöhung der Wände, da sonst das Fahrzeug über dies hinweg fahren würden.
  • Die Wände wurden farbliche angepasst.
  • Austausch der Tastatursteuerung durch die Steuerung mit Markern. Dies wird im Punkt 4.2.4.2 „Erweiterte Steuerung“ beschrieben.
Abbildung 13: Anpassung der Spielfläche (Markersteuerung)
Abbildung 13: Anpassung der Spielfläche (Markersteuerung)

4.2.3 Kollision mit Objekten

In dem Prototyp wird die Kollision der Objekte erkannt und gesteuert. Den Objekten werden physikalische Eigenschaften zugewiesen. Für die Berechnung der Kollisionssteuerung ist in Goblin XNA die Entwicklungsumgebung Newton Dynamics SDK verantwortlich. Es ist nicht erforderlich eine eigene Kollisionsberechnung durchzuführen es ist nur nötig die Funktion zu aktivieren dies geschieht mit beispielsweise sphereNode.Physics.Collidable = true; mit dieser Zeile wir die Kollision für die Kugel aktiviert.

4.2.4 Steuerung

4.2.4.1 Einfache Steuerung

In der ersten Entwicklungsphase sollte eine Kugel auf der Spielfläche bewegt werden. Dabei zeigte sich die Schwierigkeit, dass die Gravitation im Spiel in eine andere Richtung zeigt. Die Kugel bewegte sich immer seitlich von der Spielfläche weg. Die Standard Gravitationseinstellung in Goblin XNA ist auf die negative Y-Achse eingestellt. Mit der Veränderung der Gravitation auf die Negative Z-Achse ist die Kugel auf der Spielfläche stehen geblieben.

// Die Eigenschaften von Vector3 sind (valueX, valueY, valueZ)
scene.PhysicsEngine.GravityDirection = new Vector3(0, 0, -1);  

In der nächsten Phase wurde die Überlegung getan die Kugel anhand der Spielflächenneigung (Marker) zu bewegen. Dies wurde in der späteren Entwicklungsphase durch die Tastatursteuerung ersetzt. Als Eingabesteuerung werden die Pfeiltasten auf der Tastatur verwendet.

Für die Berechnung der Vorwärts- und Rückwärtsbewegung des Fahrzeugs wird die Methode public override void SetTireTorque verwendet und an die beiden hinteren Räder übergeben. In der Methode public override void SetTireTorque wird die Lenkgeschwindichkeit und der Lenkwinkel berechnet und an die beiden Vorderräder übergeben. Dies beiden Methoden werden permanent durch die Spiellaufzeit in der Methode protected override void Draw(GameTime gameTime) aufgerufen.

Abbildung 14: Achsenverteilung auf dem Marker
Abbildung 14: Achsenverteilung auf dem Marker
4.2.4.2 Erweiterte Steuerung

Als ein Augmente Reality Spielanwendung sollte die Steuerung nicht mit einer klassischen Tastatur erfolgen sondern auch mit virtuellen Eingabemöglichkeiten. Für diesen Gedanken wurde die Steuerung erweitert. Die Steuerung wird mit acht Markern umprogrammiert. Als Grundlage der Marker wird die Datei „…\GoblinXNA\tutorials\Tutorial8 - Optical Marker Tracking\toolbar0_7.pdf“ verwendet. Jeder Marker bekommt eine Bewegungseigenschaft zugewiesen die folgendermaßen aussieht:

MarkerID Funktion Fahrzeug Marker Abbildung
Toolbar0 Vorwärts Car 1
Abbildung 15: Makersteuerung: Car 1
Abbildung 15: Makersteuerung: Car 1
Toolbar1 Rückwärts
Toolbar2 Links
Toolbar3 Rechts
Toolbar4 Vorwärts Car 2
Abbildung 16: Makersteuerung: Car 2
Abbildung 16: Makersteuerung: Car 2
Toolbar5 Rückwärts
Toolbar6 Links
Toolbar7 Rechts

4.3 Ergebnis

4.3.1 Klassendiagramm

Der Prototyp ist in vier Klassen unterteilt und die Klassen werden wie folgt beschrieben:

Klasse: Program

Abbildung 17: Klasse: „Program“
Abbildung 17: Klasse: „Program“

Die Klasse „Program“ ist die Hauptklasse und beinhalte die Main-Methode Sie dient dazu das Programm zu starten.

Klasse: VehicleCreator

Abbildung 18: Klasse: „VehicleCreator“
Abbildung 18: Klasse: „VehicleCreator“

In der Klasse „VehicleCreator“ werden die Eigenschaften, wie Farbe, Größe, Schattenwurf und physikalischen Eigenschaften der Komponenten (Fahrwerk, Reifen) definiert. Die Klasse wurde aus dem Tutorial12 (Tutorial12 - Advanced Physics) entnommen und für diese Fallstudie modifiziert.

Methoden:

  • AddRaceCar(): Diese Methode ruft die Klasse RaceCar auf und erstellt das Fahrzeug.
  • CreateTire(): In dieser Methode werden die Eigenschaften für die Reifen definiert dazu wird die Klasse NewtonTire verwende. In dieser Klasse sind die physikalischen Eigenschaften vordefiniert.

Klasse: RaceCar

Abbildung 19: Klasse: „RaceCar“
Abbildung 19: Klasse: „RaceCar“

Die Klasse „RaceCar“ dient dazu erweitertet physikalischen Eigenschaften zu definieren, wie Beschleunigung, abbremsen der Reifen und die Masse des Fahrzeuges. Die Klasse wird zur Spiellaufzeit immer wieder aufgerufen. Die Klasse wurde aus dem Tutorial12 (Tutorial12 - Advanced Physics) entnommen und für diese Fallstudie modifiziert.

Methoden:

  • ApplyHandBrakes(): Diese Methode dient zum abbremsen des Fahrzeuges.
  • GetSpeed(): Gibt die aktuelle Fahrzeuggeschwindigkeit wieder.
  • RaceCar(): Definiert die physikalischen Eigenschaften und Position des Fahrzeuges.
  • Respawn(): Wiederherstellen der Fahrzeuge und des Balls wenn sie die Spielfläche verlassen.
  • SetSteering(): Dient zur Lenkung der Vorderräder des Fahrzeuges.
  • SetTireTorque(): Festlegung des Drehmomentes der Reifen. (Beschleunigung=1, Abbremsung=-1, Stillstand=0).

Klasse: FallstudieAR

Abbildung 20: Klasse: „FallstudieAR“
Abbildung 20: Klasse: „FallstudieAR“

Die „FallstudieAR“ Klasse hat folgende Funktionen:

  • Initialisierung des GoblinXNA Frameworks.
  • Aktivierung Newton Physik Engine (Kollisionserkennung).

Methoden:

  • CreateGround(): Erstellung der Spielfläche mit allen physikalischen und visuellen Eigenschaften.
  • CreateLights(): Erstellung der Beleuchtungseigenschaften und Schattenfunktion.
  • CreateObjects(): Erstellung aller Objekte (Fahrzeuge, Wände).
  • Draw(): Zeichen der Fahrzeuge und Fahrzeugsteuerung (Marker).
  • FallstudieAR(): Dient zur Grafiksteuerung.
  • Initialize(): Initialisierung der Spielszene.
  • LoadContent(): Hat die Funktion der Textinformationen in die Spielszene einzublenden.
  • SetupMarkerTracking(): Siehe Punkt „3.2.2.1 Kameraeinstellungen kalibrieren“.
  • UnloadContent(): Beenden der Spielszene.
  • Update(): Überprüfung zur Laufzeit, ob Eingaben getätigt wurden (Markersteuerung).

4.3.2 AR-Prototyp-Spielanwendung

Da Prototyping eine fortlaufende Weiterentwicklung von Software ist, wurde der Prototyp soweit fertiggestellt, dass eine spielbare Version der Spielanwendung zur Verfügung steht. Es wurden alle Erfahrungen die mit den davor gewonnenen Prototyp gemacht wurden in die Spielanwendung intrigiert.

In der Mitte des Spielfeldes befindet sich eine Spielkugel jeweils gegenüber befindet sich je ein Fahrzeug. Ziel des Spiels ist es, das jedes Fahrzeug versucht die Kugel in das gegnerische Tor zu rollen. Die Steuerung wird über eine Markersteuerung geregelt.

Abbildung 21: AR-Prototyp-Spielanwendung - Seitenansicht
Abbildung 21: AR-Prototyp-Spielanwendung - Seitenansicht

4.3.3 Erweiterungsmöglichkeiten

4.3.3.1 Verbesserung der Spielanwendung

Zum Jahreswechsel hat die Bibliothek ARTagWrapper.dll ihre Gültigkeit verloren. Die Dll Datei wird benötigt damit die Kamera angesprochen wird und die Marker im Kamerabild erkannt werden. Das Herunterladen einer neuen Version war möglich, nur hat sich in der neuen Bibliothek die API geändert. Als Konsequenz dieser Änderung funktioniert die Anwendung nicht mehr. Dies wurde auch von dem Entwickler bestätigt es wird auch keine weiter Entwicklung mit ARTag im Moment möglich sein. Die Umstellung auf die alternative Entwicklungsumgebung ALVAR ist in dieser kurzen Zeit nicht mehr möglich. Als Übergangslösung wird vor der Inbetriebnahme der Anwendung die Systemzeit auf dem Rechner zurückgestellt z. B. 01.12.2009.[71]

4.3.3.2 Verbesserung des Spielgefühls

Um das Spielgefühl zu verbessern wäre es denkbar ein Spielscore und eine Spielzeit einzubauen. Damit soll den Spieler das Gefühl gegeben werden das es sich um ein reales Fußballspiel handelt. Als optische Verbesserung können die Fahrzeuge durch 3D Modelle ausgetauscht werden dafür eignet sich das XNA RacingGame Starter-Kit. Die Grundfläche kann durch eine Fußballrasenfläche (JPEG Datai) ersetzt werden. Um eine Verbesserung des Spielspaßes zu erreichen, wäre die Einbindung von Musik und Soundeffekten in das Spiel möglich dies wäre Unterumständen mit DirectX umsetzbar. Die Anzahl der Fahrzeuge könnte erhöht werde die durch den Computer gesteuert werden und somit als Gegner oder als Mitspieler eingesetzt werden.

5 Fazit

In dieser Fallstudie wurde dargestellt welche Möglichkeiten es gibt ein Augmented Reality Spielanwendung zu entwickeln. Was bei der Analyse der beiden Entwicklerplattformen aufgefallen ist, das Goblin XNA für die Konzipierung von Spielanwendungen ausgerichtet ist. Bei Goblin XNA sind Funktionalitäten von DirectX und den XNA Game Studio vorhanden. Mit den integrierten Funktionen und Quellcodebeispielen ist es möglich eigene Spielanwendungen zu erstellen. Wiederum ist das ARToolKit eine reine AR-Entwicklerplattform.

Ein wichtiger, zu beachtender Punkt bei Augmented Reality Anwendungen ist die Interaktion der Benutzter mit der Markersteuerung und die Wahrnehmung der 3D Welt. Übertragen auf den Prototyp bedeutet dies, dass der Benutzer ohne ein Blickwechsel von Spielgeschehen die Fahrzeuge bewegen kann. Damit ist der Benutzter mit der 3D Welt verbunden.

6 Abkürzungsverzeichnis

AbkürzungBedeutung
AR

Augmented Reality, die Erweiterung der realen Welt durch Computergestützte Informationen.
Dll
Dynamic Link Library bezeichnet allgemein eine Dynamische Bibliothek.
GIF
Graphics Interchange Format ist ein verbreitetes Grafikformat.
GPS

Global Positioning System ist ein globales Navigationssatellitensystem zur Positionsbestimmung und Zeitmessung.
HITLAB

Human Interface Technology Laborty das für die Entwicklung des ARTooKit verantwortlich ist.
HITLABNZ

The Human Interface Technology Laboratory New Zealand ist an der Entwicklung des ARTooKits beteiligt.
HMD


Ein Head-Mounted Display ist ein auf dem Kopf getragenes visuelles Ausgabegerät, das Computer erzeugte virtuelle Bilder auf einem Flüssigkristallbildschirm direkt vor den Augen darstellt oder auf die Netzhaut projiziert.
JPEG

Die Joint Photographic Experts Group ist für die Entwicklung des Grafikstandards JPEG und JEPEG 2000 zuständig.
MAR

Monitor Augmented Reality ist ein Visualisierungsverfahren.
MSDNAA

Microsoft Developer Network Academic Alliance ist ein Lizenzprogramm der Firma Microsoft.
OST
Optical See Through ist ein Visualisierungsverfahren.
PAR

Projektive Augmented Reality ist ein Visualisierungsverfahren.
PDF

Das Portable Document Format ist ein plattformunabhängiges Dateiformat für Dokumente.
PNG

Portable Network Graphics ist ein Grafikformat für Rastergrafiken mit verlustfreier Bildkompression.
RAM

Random Access Memory ist ein Speicher der besonders bei Computern als Arbeitsspeicher Verwendung findet.
SDK

Ein Software Development Kit ist eine Sammlung von Werkzeugen und Anwendungen, um eine Software zu erstellen.
USB

Der Universal Serial Bus ist ein serielles Bussystem zur Verbindung eines Computers mit externen Geräten.
VR

Virtual Reality wird die Darstellung einer in Echtzeit computergenerierten, interaktiven virtuellen Umgebung bezeichnet.
HMD


Ein Head-Mounted Display ist ein auf dem Kopf getragenes visuelles Ausgabegerät, das Computer erzeugte virtuelle Bilder auf einem Flüssigkristallbildschirm direkt vor den Augen darstellt oder auf die Netzhaut projiziert.
VRML/VRML97

Die Virtual Reality Modeling Language (VRML) auch als VRML97 bezeichnet ist ein Format zur Beschreibung von 3D-Objekten und Welten.
VS
Visual Studio ist eine Entwicklerplattform der Firma Microsoft.
VST
Video See Through ist ein Visualisierungsverfahren. (siehe Punkt 2.3 Hardware).
X3D

X3D ist eine Dateiformat das Informationen für die Darstellung von 3D-Inhalten nach den ISO-Standard beinhalten und ist der Nachfolger von VRML/VRML97.
XNA

XNA vereint verschiedene Spiele-Entwicklungs-Programmierschnittstellen, unter anderem Direct3D aus DirectX für die Darstellung von 2D und 3D Grafiken.

7 Abbildungsverzeichnis

Abb.-Nr.Abbildung
1Darstellung des „Reality-Virtuality continumm“
2Funktionsprinzip eines AR-Systems
3Die Datei „blankPatt.gif“ im Verzeichnis „..\Programme\ARToolKit\patterns\“
4Selbst definierter Patter
5Erkennung des Markers im Kamerafenster (grüne X-Achse und rote Y-Achse)
6Darstellung des Würfels auf den neu definierten Marker
7Ablauf einer ARToolKit Anwendung
8Funktionsprinzip von Goblin XNA
9Spielfläche
10Erstellen der vier Seitenwände
11Setzen eines Objekts(Kugel) auf die Spielfläche
12Anpassung der Spielfläche und Austausch des Objekts (Tastatursteuerung)
13Anpassung der Spielfläche (Markersteuerung)
14Achsenverteilung auf dem Marker
15Makersteuerung: Car 1
16Makersteuerung: Car 2
17Klasse: „Program“
18Klasse: „VehicleCreator“
19Klasse: „RaceCar“
20Klasse: „FallstudieAR“
21AR-Prototyp-Spileanwendung - Seitenansicht

8 Tabellenverzeichnis

Tab.-Nr.Tabelle
1Augmented Reality Systeme
2Software Voraussetzung ARToolKit
3Software Voraussetzung Goblin XNA

9 Anhang

Klasse FallstudieAR

//Copyright (c) 2009-2010, Columbia University
//All rights reserved.

using System;
using System.Collections.Generic;
using System.Linq;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

using GoblinXNA;
using GoblinXNA.Graphics;
using GoblinXNA.SceneGraph;
using Model = GoblinXNA.Graphics.Model;
using GoblinXNA.Graphics.Geometry;
using GoblinXNA.Device.Capture;
using GoblinXNA.Device.Vision;
using GoblinXNA.Device.Vision.Marker;
using GoblinXNA.Device.Util;
using GoblinXNA.Physics;
using GoblinXNA.Helpers;
using GoblinXNA.Device.Generic;
using GoblinXNA.UI;
using GoblinXNA.UI.UI2D;
using GoblinXNA.UI.UI3D;
using NewtonDynamics;


namespace FallstudieAR
{
   enum MarkerLibrary
   {
       ARTag,
       ALVAR
   }
    
   public class FallstudieAR : Microsoft.Xna.Framework.Game
   {
       GraphicsDeviceManager graphics;

       Scene scene;
       MarkerNode groundMarkerNode, forwardMarkerNodecar1, reversMarkerNodecar1, leftMarkerNodecar1, rightMarkerNodecar1,
           forwardMarkerNodecar2, reversMarkerNodecar2, leftMarkerNodecar2, rightMarkerNodecar2;
       MarkerLibrary markerLibrary;
       SpriteFont textFont;
       RaceCar car1,car2;

       public static float WALL_HEIGHT = 10.0f;


       public FallstudieAR()
       {
           graphics = new GraphicsDeviceManager(this);
           Content.RootDirectory = "Content";

       }

       protected override void Initialize()
       {
           this.IsMouseVisible = true;

           // Initialize the GoblinXNA framework
           State.InitGoblin(graphics, Content, "");

           // Initialize the scene graph
           scene = new Scene(this);

           // Use the newton physics engine to perform collision detection
           scene.PhysicsEngine = new NewtonPhysics();

           // Use ARTag marker tracking library
           markerLibrary = MarkerLibrary.ARTag;

           if (markerLibrary == MarkerLibrary.ARTag)
               State.IsMultiCore = false;

           // Set up optical marker tracking
           SetupMarkerTracking();

           // Set up the lights used in the scene
           CreateLights();

           // Create 3D objects
           CreateObjects();

           // Create the ground that represents the physical ground marker array
           CreateGround();

           scene.PreferPerPixelLighting = true;
           scene.PhysicsEngine.GravityDirection = new Vector3(0, 0, -1);

           scene.EnableShadowMapping = true;

           // Show Frames-Per-Second on the screen for debugging
           State.ShowFPS = true;

           base.Initialize();
       }

       private void CreateLights()
       {
           // Create a directional light source
           LightSource lightSource = new LightSource();
           lightSource.Direction = new Vector3(1, -1, -1);
           lightSource.Diffuse = Color.White.ToVector4();
           lightSource.Specular = new Vector4(0.6f, 0.6f, 0.6f, 1);

           // Create a light node to hold the light source
           LightNode lightNode = new LightNode();
           lightNode.LightSources.Add(lightSource);

           scene.RootNode.AddChild(lightNode);
       }

       public void SetupMarkerTracking()
       {
           DirectShowCapture captureDevice0 = new DirectShowCapture();
           DirectShowCapture captureDevice1 = new DirectShowCapture();
           captureDevice0.InitVideoCapture(0, FrameRate._30Hz, Resolution._640x480, ImageFormat.R8G8B8_24, false);
           scene.AddVideoCaptureDevice(captureDevice0);
           captureDevice1.InitVideoCapture(1, FrameRate._60Hz, Resolution._640x480, ImageFormat.R8G8B8_24, false);
           scene.AddVideoCaptureDevice(captureDevice1);
           IMarkerTracker tracker = null;
           tracker = new ARTagTracker();
           tracker.InitTracker(638.052f, 633.673f, captureDevice0.Width, captureDevice0.Height, false, "ARTag.cf");
           scene.MarkerTracker = tracker;
           scene.ShowCameraImage = true;
           scene.OverlayVideoID = 0;
           scene.TrackerVideoID = 1;
       }

       private void CreateGround()
       {
           GeometryNode groundNode = new GeometryNode("Ground");
           groundNode.Model = new Box(85, 66, 0.1f);

           groundNode.IsOccluder = false;
           groundNode.Model.ReceiveShadows = true;
           groundNode.Physics.Collidable = true;
           groundNode.AddToPhysicsEngine = true;

           Material groundMaterial = new Material();
           groundMaterial.Diffuse = Color.Gray.ToVector4();
           groundMaterial.Specular = Color.White.ToVector4();
           groundMaterial.SpecularPower = 20;

           TransformNode groundTrans = new TransformNode();
           groundTrans.Translation = new Vector3(40, 30, 0);

           groundNode.Material = groundMaterial;

           groundMarkerNode = new MarkerNode(scene.MarkerTracker, "ground");

           scene.RootNode.AddChild(groundMarkerNode);
           groundMarkerNode.AddChild(groundTrans);
           groundTrans.AddChild(groundNode);
       }

       private void CreateObjects()
       {
           GeometryNode sphereNode = new GeometryNode("sphere");
           sphereNode.Model = new Sphere(2, 7, 7);
           sphereNode.Physics.Collidable = true;
           sphereNode.Physics.Interactable = true;
           sphereNode.Physics.ApplyGravity = true;
           sphereNode.Physics.Mass = 20;
           sphereNode.AddToPhysicsEngine = true;
           sphereNode.Physics.Shape = ShapeType.Sphere;
           sphereNode.Model.CastShadows = true;
           sphereNode.Model.ReceiveShadows = true;

           groundMarkerNode = new MarkerNode(scene.MarkerTracker, "ground");

           TransformNode sphereTransNode = new TransformNode();
           sphereTransNode.Translation = new Vector3(40,30,0.1f);
           
           Material sphereMaterial = new Material();
           sphereMaterial.Diffuse = Color.Green.ToVector4();
           sphereMaterial.Specular = Color.White.ToVector4();
           sphereMaterial.SpecularPower = 10;
           sphereNode.Material = sphereMaterial;

           scene.RootNode.AddChild(groundMarkerNode);
           groundMarkerNode.AddChild(sphereTransNode);
           sphereTransNode.AddChild(sphereNode);

           //Box1 Exterior wall
           GeometryNode box1Node = new GeometryNode("Box1");
           box1Node.Model = new Box(82, 2, WALL_HEIGHT);
           box1Node.Physics.Collidable = true;
           box1Node.AddToPhysicsEngine = true;
           box1Node.Physics.Shape = ShapeType.Box;
           box1Node.Model.CastShadows = true;
           box1Node.Model.ReceiveShadows = true;

           groundMarkerNode = new MarkerNode(scene.MarkerTracker, "ground");

           TransformNode box1TransNode = new TransformNode();
           box1TransNode.Translation = new Vector3(40, 62, 0);

           Material box1Material = new Material();
           box1Material.Diffuse = Color.DarkRed.ToVector4();
           box1Material.Specular = Color.White.ToVector4();
           box1Material.SpecularPower = 10;
           box1Node.Material = box1Material;

           scene.RootNode.AddChild(groundMarkerNode);
           groundMarkerNode.AddChild(box1TransNode);
           box1TransNode.AddChild(box1Node);

           //Box2 Exterior wall
           GeometryNode boxNode2 = new GeometryNode("Box2");
           boxNode2.Model = new Box(2, 23, WALL_HEIGHT);
           boxNode2.Physics.Collidable = true;
           boxNode2.AddToPhysicsEngine = true;
           boxNode2.Physics.Shape = ShapeType.Box;
           boxNode2.Model.CastShadows = true;
           boxNode2.Model.ReceiveShadows = true;

           groundMarkerNode = new MarkerNode(scene.MarkerTracker, "ground");

           TransformNode boxTransNode2 = new TransformNode();
           boxTransNode2.Translation = new Vector3(82, 51.5f, 0);

           Material boxMaterial2 = new Material();
           boxMaterial2.Diffuse = Color.DarkRed.ToVector4();
           boxMaterial2.Specular = Color.White.ToVector4();
           boxMaterial2.SpecularPower = 10;
           boxNode2.Material = boxMaterial2;

           scene.RootNode.AddChild(groundMarkerNode);
           groundMarkerNode.AddChild(boxTransNode2);
           boxTransNode2.AddChild(boxNode2);

           //Box3 Exterior wall
           GeometryNode boxNode3 = new GeometryNode("Box3");
           boxNode3.Model = new Box(2, 23, WALL_HEIGHT);
           boxNode3.Physics.Collidable = true;
           boxNode3.AddToPhysicsEngine = true;
           boxNode3.Physics.Shape = ShapeType.Box;
           boxNode3.Model.CastShadows = true;
           boxNode3.Model.ReceiveShadows = true;

           groundMarkerNode = new MarkerNode(scene.MarkerTracker, "ground");

           TransformNode boxTransNode3 = new TransformNode();
           boxTransNode3.Translation = new Vector3(-2, 51.5f, 0);

           Material boxMaterial3 = new Material();
           boxMaterial3.Diffuse = Color.DarkRed.ToVector4();
           boxMaterial3.Specular = Color.White.ToVector4();
           boxMaterial3.SpecularPower = 10;
           boxNode3.Material = boxMaterial3;

           scene.RootNode.AddChild(groundMarkerNode);
           groundMarkerNode.AddChild(boxTransNode3);
           boxTransNode3.AddChild(boxNode3);

           //Box4 Exterior wall
           GeometryNode box4Node = new GeometryNode("Box4");
           box4Node.Model = new Box(82, 2, WALL_HEIGHT);
           box4Node.Physics.Collidable = true;
           box4Node.AddToPhysicsEngine = true;
           box4Node.Physics.Shape = ShapeType.Box;
           box4Node.Model.CastShadows = true;
           box4Node.Model.ReceiveShadows = true;

           groundMarkerNode = new MarkerNode(scene.MarkerTracker, "ground");

           TransformNode box4TransNode = new TransformNode();
           box4TransNode.Translation = new Vector3(40, -2, 0);

           Material box4Material = new Material();
           box4Material.Diffuse = Color.DarkRed.ToVector4();
           box4Material.Specular = Color.White.ToVector4();
           box4Material.SpecularPower = 10;
           box4Node.Material = box4Material;

           scene.RootNode.AddChild(groundMarkerNode);
           groundMarkerNode.AddChild(box4TransNode);
           box4TransNode.AddChild(box4Node);

           //Box5 Exterior wall
           GeometryNode boxNode5 = new GeometryNode("Box5");
           boxNode5.Model = new Box(2, 20, WALL_HEIGHT);
           boxNode5.Physics.Collidable = true;
           boxNode5.AddToPhysicsEngine = true;
           boxNode5.Physics.Shape = ShapeType.Box;
           boxNode5.Model.CastShadows = true;
           boxNode5.Model.ReceiveShadows = true;

           groundMarkerNode = new MarkerNode(scene.MarkerTracker, "ground");

           TransformNode boxTransNode5 = new TransformNode();
           boxTransNode5.Translation = new Vector3(82, 7, 0);

           Material boxMaterial5 = new Material();
           boxMaterial5.Diffuse = Color.DarkRed.ToVector4();
           boxMaterial5.Specular = Color.White.ToVector4();
           boxMaterial5.SpecularPower = 10;
           boxNode5.Material = boxMaterial5;

           scene.RootNode.AddChild(groundMarkerNode);
           groundMarkerNode.AddChild(boxTransNode5);
           boxTransNode5.AddChild(boxNode5);

           //Box6 Tor Exterior wall
           GeometryNode boxNode6 = new GeometryNode("Box6");
           boxNode6.Model = new Box(0.2f, 23, WALL_HEIGHT);
           boxNode6.Physics.Collidable = true;
           boxNode6.AddToPhysicsEngine = true;
           boxNode6.Physics.Shape = ShapeType.Box;
           boxNode6.Model.CastShadows = true;
           boxNode6.Model.ReceiveShadows = true;

           groundMarkerNode = new MarkerNode(scene.MarkerTracker, "ground");

           TransformNode boxTransNode6 = new TransformNode();
           boxTransNode6.Translation = new Vector3(83, 28.5f, 0);

           Material boxMaterial6 = new Material();
           boxMaterial6.Diffuse = Color.DarkSlateBlue.ToVector4();
           boxMaterial6.Specular = Color.White.ToVector4();
           boxMaterial6.SpecularPower = 10;
           boxNode6.Material = boxMaterial6;

           scene.RootNode.AddChild(groundMarkerNode);
           groundMarkerNode.AddChild(boxTransNode6);
           boxTransNode6.AddChild(boxNode6);

           //Box7 Exterior wall
           GeometryNode boxNode7 = new GeometryNode("Box7");
           boxNode7.Model = new Box(2, 20, WALL_HEIGHT);
           boxNode7.Physics.Collidable = true;
           boxNode7.AddToPhysicsEngine = true;
           boxNode7.Physics.Shape = ShapeType.Box;
           boxNode7.Model.CastShadows = true;
           boxNode7.Model.ReceiveShadows = true;

           groundMarkerNode = new MarkerNode(scene.MarkerTracker, "ground");

           TransformNode boxTransNode7 = new TransformNode();
           boxTransNode7.Translation = new Vector3(-2, 7, 0);

           Material boxMaterial7 = new Material();
           boxMaterial7.Diffuse = Color.DarkRed.ToVector4();
           boxMaterial7.Specular = Color.White.ToVector4();
           boxMaterial7.SpecularPower = 10;
           boxNode7.Material = boxMaterial7;

           scene.RootNode.AddChild(groundMarkerNode);
           groundMarkerNode.AddChild(boxTransNode7);
           boxTransNode7.AddChild(boxNode7);

           //Box8 Tor Exterior wall
           GeometryNode boxNode8 = new GeometryNode("Box8");
           boxNode8.Model = new Box(0.2f, 23, WALL_HEIGHT);
           boxNode8.Physics.Collidable = true;
           boxNode8.AddToPhysicsEngine = true;
           boxNode8.Physics.Shape = ShapeType.Box;
           boxNode8.Model.CastShadows = true;
           boxNode8.Model.ReceiveShadows = true;

           groundMarkerNode = new MarkerNode(scene.MarkerTracker, "ground");

           TransformNode boxTransNode8 = new TransformNode();
           boxTransNode8.Translation = new Vector3(-3, 28.5f, 0);

           Material boxMaterial8 = new Material();
           boxMaterial8.Diffuse = Color.Orange.ToVector4();
           boxMaterial8.Specular = Color.White.ToVector4();
           boxMaterial8.SpecularPower = 10;
           boxNode8.Material = boxMaterial8;

           scene.RootNode.AddChild(groundMarkerNode);
           groundMarkerNode.AddChild(boxTransNode8);
           boxTransNode8.AddChild(boxNode8);

 
           int Car1ID = 1;
           groundMarkerNode = new MarkerNode(scene.MarkerTracker, "ground");
           TransformNode carTransNode = new TransformNode();
           carTransNode.Translation = new Vector3(2, 30, 0.5f);
           carTransNode.Rotation = Quaternion.CreateFromAxisAngle(Vector3.UnitZ,160);

           scene.RootNode.AddChild(groundMarkerNode);
           groundMarkerNode.AddChild(carTransNode);
           car1 = VehicleCreator.AddRaceCar(scene, carTransNode, Car1ID);

           int Car2ID = 2;
           groundMarkerNode = new MarkerNode(scene.MarkerTracker, "ground");
           TransformNode carTransNode2 = new TransformNode();
           carTransNode2.Translation = new Vector3(78, 30, 0.5f);
           scene.RootNode.AddChild(groundMarkerNode);
           groundMarkerNode.AddChild(carTransNode2);
           car2 = VehicleCreator.AddRaceCar(scene, carTransNode2, Car2ID);
           

           forwardMarkerNodecar1 = new MarkerNode(scene.MarkerTracker, "toolbar0");
           scene.RootNode.AddChild(forwardMarkerNodecar1);

           reversMarkerNodecar1 = new MarkerNode(scene.MarkerTracker, "toolbar1");
           scene.RootNode.AddChild(reversMarkerNodecar1);

           leftMarkerNodecar1 = new MarkerNode(scene.MarkerTracker, "toolbar2");
           scene.RootNode.AddChild(leftMarkerNodecar1);

           rightMarkerNodecar1 = new MarkerNode(scene.MarkerTracker, "toolbar3");
           scene.RootNode.AddChild(rightMarkerNodecar1);

           forwardMarkerNodecar2 = new MarkerNode(scene.MarkerTracker, "toolbar4");
           scene.RootNode.AddChild(forwardMarkerNodecar2);

           reversMarkerNodecar2 = new MarkerNode(scene.MarkerTracker, "toolbar5");
           scene.RootNode.AddChild(reversMarkerNodecar2);

           leftMarkerNodecar2 = new MarkerNode(scene.MarkerTracker, "toolbar6");
           scene.RootNode.AddChild(leftMarkerNodecar2);

           rightMarkerNodecar2 = new MarkerNode(scene.MarkerTracker, "toolbar7");
           scene.RootNode.AddChild(rightMarkerNodecar2);

       }

       protected override void UnloadContent()
       {
           Content.Unload();
       }

       protected override void LoadContent()
       {
           State.ShowNotifications = true;
           textFont = Content.Load<SpriteFont>("Sample");
       }

       protected override void Update(GameTime gameTime)
       {
           base.Update(gameTime);
       }

       protected override void Draw(GameTime gameTime)
       {
           if (car1 != null && ((NewtonPhysics)scene.PhysicsEngine).GetBody(car1) != IntPtr.Zero)
           {
               if (forwardMarkerNodecar1.MarkerFound)
                   car1.SetTireTorque(1);
               else if (reversMarkerNodecar1.MarkerFound)
                   car1.SetTireTorque(-1);
               else
                   car1.SetTireTorque(0);

               if (leftMarkerNodecar1.MarkerFound)
                   car1.SetSteering(1);
               else if (rightMarkerNodecar1.MarkerFound)
                   car1.SetSteering(-1);
               else
                   car1.SetSteering(0);
           }

           if (car2 != null && ((NewtonPhysics)scene.PhysicsEngine).GetBody(car2) != IntPtr.Zero)
           {
               if (forwardMarkerNodecar2.MarkerFound)
                   car2.SetTireTorque(1);
               else if (reversMarkerNodecar2.MarkerFound)
                   car2.SetTireTorque(-1);
               else
                   car2.SetTireTorque(0);

               if (leftMarkerNodecar2.MarkerFound)
                   car2.SetSteering(1);
               else if (rightMarkerNodecar2.MarkerFound)
                   car2.SetSteering(-1);
               else
                   car2.SetSteering(0);
           }
          
          base.Draw(gameTime);
       }
   }
}

Kalsse VehicleCreator

//Copyright (c) 2009-2010, Columbia University
//All rights reserved.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

using GoblinXNA;
using GoblinXNA.SceneGraph;
using GoblinXNA.Graphics;
using GoblinXNA.Graphics.ParticleEffects;
using GoblinXNA.Device.Capture;
using GoblinXNA.Device.Vision.Marker;
using GoblinXNA.Device.Generic;
using GoblinXNA.Device;
using Model = GoblinXNA.Graphics.Model;
using GoblinXNA.Graphics.Geometry;
using GoblinXNA.Physics;
using GoblinXNA.Helpers;

using NewtonDynamics;

namespace FallstudieAR
{
   public class VehicleCreator
   {
       public static RaceCar AddRaceCar(Scene scene, TransformNode parentTrans, int cars)
       {
           int CarID = cars;
           TransformNode transNode = new TransformNode();
           transNode.Translation = new Vector3(0, 0, 0.5f);

           Material carMat = new Material();

           if(cars==1)
               carMat.Diffuse = Color.Pink.ToVector4();
           else
               carMat.Diffuse = Color.DarkSlateBlue.ToVector4();

           carMat.Specular = Color.White.ToVector4();
           carMat.SpecularPower = 10;

           GeometryNode carNode = new GeometryNode("Race Car"+cars);
           carNode.Model = new Box(3, 1.0f, 2);
           carNode.Material = carMat;
           carNode.Model.CastShadows = true;
           carNode.Model.ReceiveShadows = true;

           NewtonPhysics physicsEngine = (NewtonPhysics)scene.PhysicsEngine;

           RaceCar car = new RaceCar(carNode, physicsEngine);
           for (int i = 0; i < 4; i++)
               car.Tires[i] = CreateTire((TireID)Enum.ToObject(typeof(TireID), i),
                   car.TireTransformNode[i], carNode, scene.PhysicsEngine.Gravity, cars);

           car.Collidable = true;
           car.Interactable = true;

           carNode.Physics = car;
           carNode.Physics.NeverDeactivate = true;
           carNode.AddToPhysicsEngine = true;

           parentTrans.AddChild(transNode);
           transNode.AddChild(carNode);

           Newton.NewtonSetBodyLeaveWorldEvent(physicsEngine.NewtonWorld,
               car.LeaveWorldCallback);

           return car;
       }

       private static NewtonTire CreateTire(TireID tireID, TransformNode tireTrans,
           GeometryNode carNode, float gravity, int carID)
       {
           int cars = carID;
           NewtonTire tire = new NewtonTire();

           Material tireMat = new Material();
           tireMat.Diffuse = Color.Orange.ToVector4();
           tireMat.Specular = Color.White.ToVector4();
           tireMat.SpecularPower = 10;

           float tireRadius = 0.7f;
           GeometryNode tireNode = new GeometryNode("Race Car "+cars+ tireID + " Tire"+cars);
           tireNode.Model = new Cylinder(tireRadius, tireRadius, 0.3f, 20);
           tireNode.Material = tireMat;

           carNode.AddChild(tireTrans);
           tireTrans.AddChild(tireNode);

           tire.Mass = 5.0f;
           tire.Width = 0.3f * 1.25f;
           tire.Radius = tireRadius;

           switch (tireID)
           {
               case TireID.FrontLeft:
                   tire.TireOffsetMatrix = Matrix.CreateTranslation(new Vector3(-1.5f, 0, -1f));
                   break;
               case TireID.FrontRight:
                   tire.TireOffsetMatrix = Matrix.CreateTranslation(new Vector3(-1.5f, 0, 1f));
                   break;
               case TireID.RearLeft:
                   tire.TireOffsetMatrix = Matrix.CreateTranslation(new Vector3(1.5f, 0, -1f));
                   break;
               case TireID.RearRight:
                   tire.TireOffsetMatrix = Matrix.CreateTranslation(new Vector3(1.5f, 0, 1f));
                   break;
           }

           // the tire will spin around the lateral axis of the same tire space
           tire.Pin = Vector3.UnitZ;

           tire.SuspensionLength = RaceCar.SUSPENSION_LENGTH;

           float x = RaceCar.SUSPENSION_LENGTH;
           tire.SuspensionSpring = (200.0f * (float)Math.Abs(gravity)) / x;

           float w = (float)Math.Sqrt(tire.SuspensionSpring);

           tire.SuspensionShock = 1.0f * w;

           tire.CollisionID = 0x100;

           return tire;
       }
   }
}

Klasse RaceCar

//Copyright (c) 2009-2010, Columbia University
//All rights reserved.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

using GoblinXNA;
using GoblinXNA.SceneGraph;
using GoblinXNA.Graphics;
using GoblinXNA.Graphics.ParticleEffects;
using GoblinXNA.Device.Capture;
using GoblinXNA.Device.Vision.Marker;
using GoblinXNA.Device.Generic;
using GoblinXNA.Device;
using Model = GoblinXNA.Graphics.Model;
using GoblinXNA.Graphics.Geometry;
using GoblinXNA.Physics;
using GoblinXNA.Helpers;
using GoblinXNA.UI;

using NewtonDynamics;

namespace FallstudieAR
{
   public class RaceCar : NewtonVehicle
   {
       public static float MAX_TORQUE = 1400.0f;
       public static float VEHICLE_MASS = 1000.0f;
       public static float SUSPENSION_FREQUENCE = 2.0f;
       public static float SUSPENSION_LENGTH = 0.3f;

       public static float MAX_STEER_ANGLE = 30.0f * MathHelper.Pi / 180.0f;

       private NewtonPhysics engine;

       // A callback triggered when this car1 leaves the newton world (outside of the
       // simulation bound)
       private Newton.NewtonBodyLeaveWorld bodyLeaveCallback;

       private TransformNode[] tireTransNode;

       public RaceCar(Object container, NewtonPhysics engine)
           : base(container)
       {
           this.engine = engine;

           tireTransNode = new TransformNode[4];
           for (int i = 0; i < 4; i++)
               tireTransNode[i] = new TransformNode();

           // set the mass of the race car1
           mass = VEHICLE_MASS;

           // lower the center of the mass for a race car1
           centerOfMass = -Vector3.UnitY * 1.5f;

           // sets up the callback function when body moves in the simulation
           transformCallback = delegate(IntPtr body, float[] matrix)
           {
               Matrix mat = MatrixHelper.FloatsToMatrix(matrix);

               // set the transformation of the vehicle body
               PhysicsWorldTransform = mat;

               Matrix invMat = Matrix.Invert(mat);
               float[] tireMatrix = new float[16];
               NewtonTire tire = null;
               float sign = 0;
               float angle = 0;
               float brakePosition = 0;

               // set the global matrix for each tire
               for (IntPtr tyreId = Newton.NewtonVehicleGetFirstTireID(joint);
                   tyreId != IntPtr.Zero; tyreId = Newton.NewtonVehicleGetNextTireID(joint, tyreId))
               {
                   int tireID = (int)GetTireID(tyreId);
                   tire = tires[tireID];
                   Newton.NewtonVehicleGetTireMatrix(joint, tyreId, tireMatrix);

                   // calculate the local matrix
                   Matrix tireMat = MatrixHelper.GetRotationMatrix(
                       MatrixHelper.FloatsToMatrix(tireMatrix) * invMat) * tire.TireOffsetMatrix;
                   tire.TireMatrix = tireMat;
                   tireTransNode[tireID].WorldTransformation = Matrix.CreateRotationX(MathHelper.PiOver2)
                       * tireMat;

                   // calcualte the parametric brake position
                   brakePosition = tireMat.Translation.Y - tire.TireRefHeight;
                   tire.BrakeMatrix = Matrix.CreateTranslation(0, tire.BrakeRefPosition.Y + brakePosition, 0);

                   // set suspensionMatrix
                   sign = (tire.BrakeRefPosition.Z > 0) ? 1 : -1;
                   angle = (float)Math.Atan2(sign * brakePosition, Math.Abs(tire.BrakeRefPosition.Z));
                   Matrix rotationMatrix = new Matrix(
                       1, 0, 0, 0,
                       0, (float)Math.Cos(angle), (float)Math.Sin(angle), 0,
                       0, -(float)Math.Sin(angle), (float)Math.Cos(angle), 0,
                       0, 0, 0, 1);
                   tire.AxelMatrix = rotationMatrix * tire.AxelMatrix;
                   tire.SuspensionTopMatrix = rotationMatrix * tire.SuspensionTopMatrix;
                   tire.SuspensionBottomMatrix = rotationMatrix * tire.SuspensionBottomMatrix;
               }
           };

           forceCallback = delegate(IntPtr body)
           {
               float Ixx = 0, Iyy = 0, Izz = 0, tmpMass = 0;

               Newton.NewtonBodyGetMassMatrix(body, ref tmpMass, ref Ixx, ref Iyy, ref Izz);
               tmpMass *= (1.0f + (float)Math.Abs(GetSpeed()) / 20.0f);
               float[] force = Vector3Helper.ToFloats(engine.GravityDirection * engine.Gravity * tmpMass);

               Newton.NewtonBodySetForce(body, force);
           };

           tireUpdate = delegate(IntPtr vehicleJoint)
           {
               NewtonTire tire = null;

               for (IntPtr tyreId = Newton.NewtonVehicleGetFirstTireID(vehicleJoint);
                   tyreId != IntPtr.Zero; tyreId = Newton.NewtonVehicleGetNextTireID(vehicleJoint, tyreId))
               {
                   tire = tires[(int)GetTireID(tyreId)];

                   // If the tire is a front tire
                   if ((tire == tires[(int)TireID.FrontLeft]) || (tire == tires[(int)TireID.FrontRight]))
                   {
                       float currSteerAngle = Newton.NewtonVehicleGetTireSteerAngle(vehicleJoint, tyreId);
                       Newton.NewtonVehicleSetTireSteerAngle(vehicleJoint, tyreId,
                           currSteerAngle + (tire.Steer - currSteerAngle) * 0.035f);
                   }
                   else // if the tire is a rear tire
                   {
                       Newton.NewtonVehicleSetTireTorque(vehicleJoint, tyreId, tire.Torque);

                       if (tire.Brakes > 0)
                       {
                           // ask Newton for the precise acceleration needed to stop the tire
                           float brakeAcceleration =
                               Newton.NewtonVehicleTireCalculateMaxBrakeAcceleration(vehicleJoint, tyreId);
                           Newton.NewtonVehicleTireSetBrakeAcceleration(vehicleJoint, tyreId,
                               brakeAcceleration, 10000.0f);

                           // set some side slip as function of the linear speed
                           float speed = Newton.NewtonVehicleGetTireLongitudinalSpeed(vehicleJoint, tyreId);
                           Newton.NewtonVehicleSetTireMaxSideSleepSpeed(vehicleJoint, tyreId, speed * 0.1f);
                       }
                   }
               }
           };

           bodyLeaveCallback = delegate(IntPtr body)
           {
               Respawn(body);
           };
       }

       public TransformNode[] TireTransformNode
       {
           get { return tireTransNode; }
       }

       public Newton.NewtonBodyLeaveWorld LeaveWorldCallback
       {
           get { return bodyLeaveCallback; }
       }

       public float GetSpeed()
       {
           return Vector3.Dot(this.PhysicsWorldTransform.Forward, engine.GetVelocity(this));
       }

       public override void SetSteering(float value)
       {
           float speed = (float)Math.Abs(GetSpeed());
           float scale = ((1.0f - speed / 60.0f) > 0.1f) ? (1.0f - speed / 60.0f) : 0.1f;
           if (value > 0)
               value = MAX_STEER_ANGLE * scale;
           else if (value < 0)
               value = -MAX_STEER_ANGLE * scale;
           else
               value = 0;

           tires[(int)TireID.FrontRight].Steer = value;
           tires[(int)TireID.FrontLeft].Steer = value;
       }

       public override void SetTireTorque(float value)
       {
           float speed = (float)Math.Abs((float)Math.Abs(GetSpeed()));

           if (value > 0)
               value = MAX_TORQUE;// *(1.0f - speed / 2000.0f);
           else if (value < 0)
               value = -MAX_TORQUE;// * (1.0f - speed / 2000.0f);
           else
               value = 0;

           tires[(int)TireID.RearRight].Torque = value;
           tires[(int)TireID.RearLeft].Torque = value;
       }

       public override void ApplyHandBrakes(float value)
       {
           tires[(int)TireID.RearRight].Brakes = value;
           tires[(int)TireID.RearLeft].Brakes = value;
       }

       public void Respawn(IntPtr body)
       {
           Notifier.AddMessage("Wiederherstellen");
           Matrix mat = Matrix.CreateTranslation(30, 30, 5f);
           Newton.NewtonBodySetMatrixRecursive(body, MatrixHelper.ToFloats(mat));
       }
   }
}

Klasse Program

using System;

namespace FallstudieAR
{
   static class Program
   {
       /// <summary>
       /// The main entry point for the application.
       /// </summary>
       static void Main(string[] args)
       {
           using (FallstudieAR game = new FallstudieAR())
           {
               game.Run();
           }
       }
   }
}

10 Fußnoten

  1. Vgl. Cawood/Fiala (2008) S. 1.
  2. Vgl. Cawood/Fiala (2008) S. 2.
  3. Vgl. Azuma et al. (2001) S. 34.
  4. Vgl. Milgram et al. (1994) S. 283.
  5. Vgl. o.V. HITL (2009b)
  6. Vgl. Cawood/Fiala (2008) S. 303.
  7. Vgl. Oda/Feiner(2009a)
  8. Vgl. o.V. HITL (2009a)
  9. Vgl. Tjaden (2009)
  10. Vgl. Larios et al. (2004)
  11. Vgl. Höhl (2009) S. 12.
  12. Vgl. Höhl (2009) S. 12.
  13. Vgl. Milgram et al. (1994) S. 284.
  14. Vgl. Vögele (2006)
  15. Vgl. o.V. HITL (2009a)
  16. Vgl. Höhl (2009) S. 166.
  17. Microsoft Visual C++ 2008 Express Edition, Microsoft Deutschland GmbH, http://www.microsoft.com/germany/express/ (03.12.2009, 13:30)
  18. Vgl. Höhl (2009) S. 172.
  19. Vgl. Höhl (2009) S. 30 f. und S. 172.
  20. ARToolKit 2.72, Human Interface Technology Laboratory, University of Washington, http://sourceforge.net/projects/artoolkit/files/artoolkit/2.72.1/ARToolKit-2.72.1-bin-win32.zip/download (03.12.2009, 15:34)
  21. OpenVRML-0.143-bin-win32, SourceForge, Inc., http://sourceforge.net/projects/artoolkit/files/artoolkit/2.72.1/OpenVRML-0.14.3-win32.zip/download (03.12.2009, 15:44)
  22. OpenVRML User's Guide, http://openvrml.org/doc/index.html (03.12.2009, 16:20)
  23. DSVideoLib-0.0.8b-win32, GNU General Public License (GPL), http://sourceforge.net/projects/artoolkit/files/artoolkit/2.72.1/DSVL-0.0.8b.zip/download (03.12.2009, 16:40)
  24. GLUT 3.76, The Industry's Foundation for High Performance Graphics, http://www.opengl.org/resources/libraries/glut/glut_downloads.php (03.12.2009, 16:50)
  25. The OpenGL Utility Toolkit (GLUT) Programming Interface API Version 3, http://www.opengl.org/resources/libraries/glut/spec3/spec3.html (03.12.2009, 17:10)
  26. MSVCR71D.DLL und MSVCP71D.DLL, flit international ab. Lokforaregatan 17c. Lund, sk 2223, http://www.dll-files.com/dllindex/index-m.shtml (03.12.2009, 17:20)
  27. ProcessLibrary.com, http://www.processlibrary.com/de/directory/files/msvcr71d/ (03.12.2009, 17:30)
  28. LIBPNG-1.2.24, GNU General Public License (GPL), http://sourceforge.net/projects/gnuwin32/files/libpng/ (03.12.2009, 17:33)
  29. JPEG-6b-4-LIB.ZIP,GNU General Public License (GPL), http://sourceforge.net/projects/gnuwin32/files/jpeg/ (03.12.2009, 17:40)
  30. JPEG-6b-4-BIN.ZIP,GNU General Public License (GPL), http://sourceforge.net/projects/gnuwin32/files/jpeg/ (03.12.2009, 17:38)
  31. libpng, http://www.libpng.org/pub/png/libpng.html ,(03.12.2009, 18:05)
  32. JPEG-6b-4, http://gnuwin32.sourceforge.net/packages/jpeg.htm (03.12.2009, 18:10)
  33. DirectX Software Development Kit, http://www.microsoft.com/downloads/details.aspx?FamilyID=24a541d6-0486-4453-8641-1eee9e21b282&displaylang=en (04.12.2009, 16:00)
  34. Vgl. Höhl (2009) S. 27.
  35. Vorkompilierte Bibliotheksdateien,Institut für Informatik - LFE Medieninformatik, http://www.medien.ifi.lmu.de/team/fabian.hennecke/files/lib.zip (05.12.2009, 15:30)
  36. Vgl. o.V. Institut für Informatik - LFE Medieninformatik (2009)
  37. Vgl. Höhl (2009) S. 172 ff.
  38. Vgl. Höhl (2009) S. 178.
  39. Vgl. Höhl (2009) S. 180.
  40. Vgl. Höhl (2009) S. 180.
  41. Vgl. Höhl (2009) S. 180.
  42. Vgl. Höhl (2009) S. 184.
  43. Vgl. Höhl (2009) S. 184.
  44. Vgl. Höhl (2009) S. 186.
  45. Vgl. Höhl (2009) S. 186.
  46. Vgl. Höhl (2009) S. 186.
  47. Vgl. Höhl (2009) S. 188.
  48. Vgl. Höhl (2009) S. 188.
  49. Vgl. o.V. HITL (2009c)
  50. Vgl. o.V. HITL (2009c)
  51. Vgl. Cawood/Fiala (2008) S. 7.
  52. Vgl. Cawood/Fiala (2008) S. 8.
  53. Vgl. Cawood/Fiala (2008) S. 9 ff.
  54. Die BSD-Lizenz ist eine Lizenz für freie Software http://www.opensource.org/licenses/bsd-license.php (01.01.2010, 20:26)
  55. Vgl. Oda/Feiner (2009c)
  56. Vgl. Oda/Feiner (2009b) S. 5.
  57. Goblin XNA Entwicklungsumgebung http://goblinxna.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=34502 (02.01.2010, 15:16)
  58. Microsoft XNA Game Studio 3.1 http://www.microsoft.com/downloads/details.aspx?FamilyID=80782277-D584-42D2-8024-893FCD9D3E82&displaylang=en (02.01.2010, 15:36)
  59. Newton Dynamics SDK 1.53 http://newtondynamics.com/forum/newton.php (02.01.2010, 15:46)
  60. Lidgren-Network http://code.google.com/p/lidgren-network/ (02.01.2010, 15:56)
  61. DirectShow.NET http://www.codeproject.com/KB/directx/DirXVidStrm.aspx?df=100&forumid=73014 (02.01.2010, 16:10)
  62. TaoFramework 2.1.0 http://www.taoframework.com/Home (02.01.2010, 16:25)
  63. ALVAR http://virtual.vtt.fi/virtual/proj2/multimedia/alvar.html (02.01.2010, 16:31)
  64. OpenVC 1.0 http://opencv.willowgarage.com/wiki/ (02.01.2010, 16:38)
  65. ARTag http://www.artag.net/ (02.01.2010, 16:40)
  66. Vgl. o.V. Micorsoft (2009)
  67. Vgl. Oda/Feiner (2009a) S. 1 ff.
  68. Vgl. Oda/Feiner (2009b) S. 21 ff.
  69. Vgl. Oda/Feiner (2009b) S.8ff
  70. Vgl. Oda/Feiner (2009c)
  71. Vgl. http://goblinxna.codeplex.com/Thread/View.aspx?ThreadId=79625 (10.01.2010, 14:35)

11 Literaturverzeichnis

Azuma et al. (2001)

Azuma, R., Baillot, Y., Behringer, R., Feiner, S., Julier, S., MacIntyre, B.: Recent Advances in Augmented Reality, IEEE Computer Graphics and Applications 21, 6 (Nov/Dec 2001) http://www.cs.unc.edu/~azuma/cga2001.pdf (25.12.2009, 16:24)
Cawood/Fiala (2008)
Cawood, S. und Fiala, M.: Augmented Reality - A Practical Guide, Pragmatic Programmers, USA 2008
Höhl (2009)
Höhl, W.: Interaktive Ambiente mit Open-Source-Software, Springer-Verlag/Wien, Wien 2009
Larios et al. (2004)
Larios, V.,Ramos, F. F.,Unger, H.: Advanced Distributed Systems, Springer-Verlag Berlin Heidelber, Berlin Heidelber 2004
Milgram et al. (1994)

Milgram, P., Takemura, H., Utsumi, A., Kishino, F.: Augmented Reality: A class of display on the reality-virtuality continumm (1994) http://vered.rose.utoronto.ca/publication/1994/Milgram_Takemura_SPIE1994.pdf (27.12.2009, 14:15)
o.V. HITL (2009a)
o.V.,Human Interface Technology Laboratory:ARToolKit Installation Guide, University of Washington http://www.hitl.washington.edu/artoolkit/ (27.12.2009, 15:44)
o.V. HITL (2009b)

o.V.,Human Interface Technology Laboratory:ARToolKit Basic Principles, University of Washington http://www.hitl.washington.edu/artoolkit/documentation/userarwork.htm (27.12.2009, 15:49)
o.V. HITL (2009c)

o.V.,Human Interface Technology Laboratory:ARToolKit Development Principles, University of Washington http://www.hitl.washington.edu/artoolkit/documentation/devprinciple.htm (27.12.2009, 15:51)
o.V. Institut für Informatik - LFE Medieninformatik (2009)
o.V.,Kurzinstallationsanleitung zu ARToolKit http://www.medien.ifi.lmu.de/lehre/ss09/ar/Installation_vom_ARToolKit.pdf (23.12.2009, 15:33)
o.V. Micorsoft (2009)

o.V., Microsoft: Visual Studio 2008 Professional Edition, http://www.microsoft.com/downloads/details.aspx?displaylang=de&FamilyID=83c3a1ec-ed72-4a79-8961-25635db0192b#Requirements (30.12.2009, 21:56)
Oda/Feiner(2009a)

Oda, O. und Feiner, S.:Goblin XNA Installation Guide v3.3, Department of Computer Science Columbia University http://goblinxna.codeplex.com/Project/Download/FileDownload.aspx?DownloadId=89271 (28.12.2009, 14:04)
Oda/Feiner(2009b)

Oda, O. und Feiner, S.:Goblin XNA User Manual v3.3, Department of Computer Science Columbia University http://goblinxna.codeplex.com/Project/Download/FileDownload.aspx?DownloadId=87958 (27.12.2009, 13:04)
Oda/Feiner(2009c)

Oda, O. und Feiner, S.:Goblin XNA: A Platform for 3D AR and VR Research and Education, Department of Computer Science Columbia University http://graphics.cs.columbia.edu/projects/goblin/ (30.12.2009, 17:55)
Tjaden (2009)

Tjaden, H.: Medieninformatik FH-Wiesbaden, ARToolKIT, http://www.mi.fh-wiesbaden.de/~schwan/Projects/CG/CarreraCV/doku/extrinsisch/extrinsisch.htm#3 (12.01.2010, 16:38)
Vögele (2006)

Vögele, M.: Projektive Augmented Reality , http://campar.in.tum.de/twiki/pub/Chair/TeachingWS05AugmentedRealityAnwendungen/MichaelVgele.pdf (11.01.2010, 23:21)
Persönliche Werkzeuge