FXpo

Aus toolbox_interaktion
Wechseln zu: Navigation, Suche
Projekt Plakat (WS15/16)
Projekt Plakat (SS16)

„FXpo | A Celebration of Innovation“ - ein Projekt von Nick Maley. Dahinter steckt die Idee eines Museums oder einer Ausstellung die dem 21. Jahrhundert würdig ist. Es soll ein interaktives Museeum entstehen, das den Besucher mit einbezieht. Keine langweiligen Schaukästen oder starre Exponate. Es geht Nick Maley darum, eine ganzheitliche Illusion zu erwecken, die es den Interessierten möglich macht in eine völlig neue Welt der Spezialeffekte einzutauchen. Inhalt der Ausstellung soll ein Einblick hinter die Kullissen von bekannten Spielfilmen sein. Das Material besteht aus einer Auswahl spannender Geschichten, Interviews mit Darstellern und anderen Mitwirkenden, Requisiten des Orginalfilmsets und weiteren Insiderinformationen.[1]

Um den Besucher in eine andere Welt eintauchen zu lassen, sollen die Spezial-Effekte mit viel technischer Finesse zur Schau gestellt werden. Dramatisch ausgeleuchtete Raumkonzepte sowie interaktive Exponate. Warum in den nächsten Ausstellungsraum laufen, wenn der Ausstellungsraum sich in Echtzeit um dich herum verändern, und neu entstehen kann?

Beginnen möchte Nick Maley seine Ausstellung mit dem Thema StarWars. Er selbst hat an den ersten Filmen mitgewirkt und die Figur des „Yoda“ entwickelt. Innerhalb dieses Museums sollen verschiedene Exponate mit Hologrammen im Stil von „Pepper's Ghost“ realisiert werden, mit denen der Besucher interagieren kann. Unsere Aufgabe war es, eine interaktive Menüsteuerung für diese Hologramme zu entwerfen.

Derzeit ist Nick Maley noch auf der Suche nach Sponsoren für seine Vision.[2] Ihm ist bewusst, dass Sponsoren erst verstehen, was sein Plan ist, wenn er Ihnen handfeste Konzepte vorlegt. Auf der Suche nach kreativen Köpfen hat er es uns ermöglicht, Teil seines Projekts zu werden. Ziel ist es am Ende des Sommersemesters 2016 unsere Ergebnisse in einer gemeinsamen Ausstellung der Öffentlichkeit zu präsentieren.


Inhaltsverzeichnis

Konzeption

Der Prozess der Ideenfindung war ein langer Weg und großer Bestandteil unseres Projekts. Die Ungeduld sofort anfangen zu wollen musste unter Kontrolle gehalten werden. In mehreren Brainstormingsessions haben wir viele Ideen zusammengetragen. Oft haben wir diese schnell wieder verworfen, oder auch weitergeführt. Ziemlich am Anfang begannen wir damit zu recherchieren, was es bereits an Interaktiven Medien gibt. Ich habe mir alte Projekte von Vorgängern unseres Studiengangs angesehen und auch weitere Homepages gefunden die spannende und innovative Ideen zur interaktiven Aufbereitung von Inhalt behandeln.

Nach einiger Zeit entschieden wir uns für die ursprüngliche Idee, die Projektion eines Menüs mit verschiedenen Unterpunkten an eine Wand. Die Auswahl der Menüpunkte erfolgt über einfache Handgesten oder -bewegungen. Eine Person die vor der Projektion steht wird über eine Kinect Xbox 360 getrackt und in Echzeit als „DarthVader“- Figur in die bestehende Projektion abgebildet. Nach der Auswahl eines Menüpunktes soll ein Hologramm gestartet werden.

Diese Idee bildet den Ausgangspunkt unseres Projektes. Allerdings soll die Menüauswahl mit zwei verschiedenen Hardwarekomponenten realisiert werden. Mit der „Leap Motion“ werden nur die Handgesten getrackt. Die andere Hardwarekomponente „Kinect XBox 360“ trackt die ganze Person. Im zweiten Projektabschnitt kommt das Konzept für eine interaktive Kugelsteuerung hinzu, mit Hilfe von Distanzsensoren.

Hologramm-Präsenter

Konzept

Grobaufbau von Nick Maley
Hologramm-Bauplan
Überarbeitetes Hologramm

Nachdem mit dem Menü ein Hologramm im Stil von „Peppers Ghost“ gesteuert werden sollte, haben wir uns dazu entschlossen, für Versuchszwecke einen Prototyp dieses Hologramm-Präsenters zu bauen. Für die Wiedergabe von Hologrammen gibt es mehrere Varianten in verschiedenen Ausführungen. Um den Effekt zu testen und auf persönlichen Wunsch von Nick Maley einigten wir uns auf die einfachste Variante: eine Displayprojektion wird auf eine Plexiglasscheibe projiziert und erzeugt dadurch den Hologramm-Effekt.

Gemeinsam machten wir uns den Aufbau eines Hologramm-Präsenters zu konzeptionieren. Angefangen mit kleinen Skizzen bis hin zur finalen Version, werden Höhen, sowie Winkel berechnet und eine Materialliste erstellt. Die folgende Skizze von Nick Maley bildet die Grundlage für den Hologrammpräsenter. Er verwendete einen 92 cm Display und der Aufbau sollte möglichst weit oben platziert werden, um den Fernseher zu verstecken.

Um eine Diagonale von ca. 92 cm zu erhalten wird ein 40“ Fernseher verwendet und alle Höhen und Größen darauf angepasst. Eine weitere Herausforderung ist die Stabilität, da das Gestell den Fernseher tragen muss. Um das zu erreichen, wird ein Gestell mit 4-Kanthölzer und eingearbeiteten Querverstrebungen gebaut. Winkel an den Verbindungsstellen sollten für zusätzliche Stabilität sorgen. Um einen besseren Transport zu ermöglichen, wird der Plexiglas-Aufsatz so konstruiert, dass er abnehmbar ist. Das Entscheidende am Aufsatz war die Montage der Plexiglasscheibe im 45° Winkel um einen möglichst realistischen Hologramm-Effekt zu erzeugen. Die Visualisierung des Aufbaus mit dem Programm Adobe Illustrator war eine meiner weiteren Aufgaben. Diese Illustration dient als Basis für die Umsetzung und für die Materialbeschaffung.

Prototypbau

Das Bauen des Prototyp erfolgte an zwei Tagen, aufgrund der verzögerten Lieferzeit des Fernsehers. Wie der obigen Skizze zu entnehmen ist, sind der Aufsatz und die Verkleidung ohne diesen nicht realisierbar. In Zusammenarbeit aller Teammitglieder wurde der Prototyp gebaut und fertiggestellt. Das Gestell wurde mit schwarzen Molton-Stoff verkleidet. Um helle Reflexe in der Plexiglasscheibe zu vermeiden wurde der Aufsatz schwarz lackiert. Sowohl der Stoff als auch die Plexiglasscheibe werden mit Klettverschluss montiert. Das Testen des Prototyps erfolgte im Anschluss der Fertigstellung des Roh-Gestells. Nach Lieferung und Integration des Fernsehers wurde der Prototyp finalisiert und nochmals getestet. Das Ergebnis ist für das Team äußerst zufriedenstellend und der Hologramm-Effekt wird realistisch wiedergegeben.

Umbau

Für die Ausstellung wurde unser Hologramm-Präsenter etwas gekürzt und in Zusammenarbeit mit Nick Maley das äußere Erscheinungsbild verändert. Dabei wurde das Gestell verbreitert und mit einfachen Gegenständen verkleidet.

Interaktive Menüsteuerungen

Be Darth Vader

Konzept

Konzept
Überarbeitetes Konzept

Da es bei StarWars um „die Macht" geht,  soll das Menü auch über diese steuerbar sein. Ohne echte Berührung und ohne Controller. Hierfür bietet sich die Kinect perfekt an, da sie Mensch und Hintergrund bereits über die Verarbeitung von Tiefeninformationen trennt. Das Skelett des Nutzers wird getrackt und auf das virtuelle Skelett eines animierten Darth Vaders gemappt. Das Menü wird um diesen abgebildet. Jede Bewegung des Besuchers wird nun auch mit dem Avatar synchronisiert. Dadurch ist es dem Nutzer möglich, einen der Menüpunkte auszuwählen.

Der Aufbau des Menüs besteht aus vier Einzelkomponenten die über OSC miteinander kommunizieren.

Diese haben wir wie folgt geplant:

5 BME FXpo Kinect Aufbauvariante.jpg

Hardware Komponenten

Rechner

Die Umsetzung erfolgte auf zwei verschiedenen Plattformen:

  • OS X 10.11.x
  • Linux Ubuntu 15.x
Microsoft Kinect360

Die Kinect ist eigentlich eine Hardware zur Steuerung der Videospielkonsole Xbox 360. Mittels dieser können Spieler allein durch Körperbewegungen die Software bedienen.[3] Diese Art der Steuerung wird durch Kombination von einem Tiefensensor, einem 3D-Mikrofon, einer Farbkamera und Software ermöglich.

Die Kinect kann verschiedene Nutzer erkennen. Pro aktivem Nutzer kann man sich auch das „Skelett-Modell“ der Nutzer mit 20 möglichen Gelenken anzeigen lassen. Das Verfahren nennt man „Skeletonization“. Die Kinect verfolgt dann den aktiven Nutzer im Raum. Die Positionen der einzelnen Gelenke können nun abgerufen werden.

FRITZ!Box 7390

Zur Umsetzung der OSC-Kommunikation wurde ein eigenes Netzwerk mittels der Fritz!Box eingerichtet. Dadurch wurde die OSC-Kommunikation sicherer und stabiler.

Software Komponenten

openFrameworks

Unsere Hauptsoftwarekomponente ist openFrameworks. OpenFrameworks ist ein Open-Source-Toolkit, das in C++ geschrieben und auf einer Vielzahl von Betriebssystemen lauffähig ist. Für openFrameworks gibt es eine Vielzahl von Addons, welche die Einbindung verschiedenster Komponenten wie die Kinect-Anbindung, Videowiedergabe und Lichtsteuerung erleichtert.[4] Wir nutzen openFrameworks in der alten Version 0.8.4, da das Addon openNI2 damit deutlich besser läuft. Auf unseren Mac-Rechnern nutzen wir openFrameworks unter der Entwicklungsumgebung Xcode. Unter Linux nutzen wir CodeBlocks als Entwicklungsumgebung.

Addons
ofxNI2
Skelett-Modell

Für das Skelett-Tracking setzen wir auf das openFrameworks Addon openNI2. Das Addon wird von uns außerdem etwas angepasst, sodass nur noch eine Person mit Skelett versehen wird. Dadurch funktioniert unsere Menüsteuerung stabiler und es werden Probleme behoben, die entstehen, wenn andere Personen zusätzlich in das Kamerabild laufen.

ofxAssimpModelLoader

Da wir in unserem Menü ein Modell eines 3D-Darth-Vaders steuern, brauchen wir ein entsprechendes Addon, welches das Modell lädt und anzeigt. Außerdem müssen die „Bones“ des Skeletts den einzelnen Knotenpunkten des Kinect-Skeletts zugewiesen werden.

ofxOsc

Um eine Schnittstelle zwischen allen Komponenten (Hard- und Software) zu realisieren, nutzen wir OSC. Hierfür definieren wir eine einheitliche Adressierung, die in alle Programmkomponenten integriert werden kann.

ofxDmx

Die Lichtsteuerung wird komplett per DMX angesteuert. Hierfür gibt es für openFrameworks das Addon ofxDmx, mit dem auf ganz einfache Weise bestimmte DMX-Werte für eine DMX-Adresse an ein entsprechendes Interface weitergegeben werden können. Dieses gibt die Werte dann entsprechend an die DMX-Geräte weiter.

ofxXmlSettings

Um eine möglichst schnelle und einfache Konfiguration zu ermöglichen, versuchen wir die wichtigsten Einstellungen über XML. Hierzu gibt es das Addon ofxXMLSettings, welches standardmäßig bei openFrameworks dabei ist. Da die XML-Einstellungen eine geringere Priorität bei uns haben, werden sie nur im Ansatz realisiert und getestet. In der aktuellen Softwareversion kommen sie noch nicht zum Einsatz.

Menügestaltung

Menü Design
Finales Menü Design

Auf Basis der Skizze wurden die einzelnen Menübestandteile gestaltet. Semantisch passende Icons zum jeweiligen Menüpunkt und außerdem das zugehörige Hover-Icon werden mit Adobe Illustrator erstellt, um die Möglichkeit der freien Skalierbarkeit beizubehalten. Ein neuer Cursor in Form eines Yoda-Kopfes wird erstellt. Der Ladebalken besteht aus einem Kreis, der sich um den Mauszeiger herum abbildet und sich während der Ladezeit immer weiter füllt. Diesen „Ladebalken“ wird in Adobe Photoshop erstellt und als PNG Stream abgespeichert. Außerdem wird ein Spritsheet erstellt um Ladezeiten der Einzelbilder zu vermeiden. Im zweiten Projektabschnitt wird das komplette Design noch einmal überarbeitet. Auch der Ladebalken wird hierbei angepasst. Er besteht nun nicht mehr aus einzelnen Bildern, sondern wird direkt in openFrameworks generiert und ist damit Bestandteil des Programmcodes.

Lichtsteuerung

Bereits bei der Ideenfindung kamen wir immer wieder auf das Thema Raumkonzept und damit auch auf das Thema Licht zu sprechen. Hierbei ging es sowohl um Licht für das Raumambiente, aber auch um Licht, mit dem interagiert werden kann. Als erstes war die Idee bei jedem Video, das ausgewählt wird, das Raumlicht entsprechend zu verändern, bzw. andere Ausstellungsstücke durch Beleuchtung in den Vordergrund zu stellen. Dies wurde für die Präsentation durch verschiedene Farben des Raumlichts simuliert. Eine weitere Idee war, dass man mit einem Licht signalisieren kann, ob ein Besucher richtig steht und somit das Menü steuern kann. Zusätzlich sollte ein Punkt mit einem Moving Head auf dem Boden markiert werden, um dem Besucher zu zeigen an welcher Stelle er stehen sollte. Bei der abschließenden Ausstellung wird nur letztes verwendet, da Nick Maley sich ansonsten um die komplette Beleuchtung der Ausstellung kümmert. Realisiert wird alles mit dem Standard Addon ofxDmx von openFrameworks und dem Enttec USBDMX PRO Interface. Als zusätzliches Feature wurde noch eine Smartphone/Tablet Steuerung mithilfe von touchOSC realisiert, um beim Präsentationsaufbau die Farben und Helligkeiten der einzelnen LED PARs schnell und leicht einzustellen. Außerdem kann so die Lichtsteuerung losgelöst von allen anderen Programmen getestet werden.

Zusammenspiel mit den anderen Programmen

OSC-Licht-Kommunikation

Im ersten Projektabschnitt kamen noch vier MacBooks zum Einsatz, auf denen jeweils ein Programm lief: eines zum Skelett-Tracking, eines für die Menüanzeige, eines für die Videowiedergabe am Hologramm, eines für die Lichtsteuerung. Diese kommunizierten alle über OSC miteinander. Im zweiten Abschnitt und für die Ausstellung wurden nur noch zwei Computer genutzt. Dies ist möglich, da wir die Menüanzeige und das Skelett-Tracking in einem Programm zusammengefasst haben. Somit läuft nun das Skelett-Tracking mit Menüausgabe und die abgespeckte Lichtsteuerung auf einem MacBook und die Videowiedergabe auf einem Linux Computer. Alle Programme nutzen nach wie vor OSC zur Kommunikation.

OSC Kommunikation

Befehlsstruktur

Grundsätzlich besteht der Wunsch einer gemeinsamen Schnittstelle zwischen allen Geräten, Menüs und Ausgaben. Da wir allerdings sehr unterschiedliche Steuerungen und Menüausgaben nutzen müssen wir einige Gemeinsamkeiten finden. Für die Schnittstelle wird eine allgemein gültige Befehlsstruktur für Open Sound Control (OSC) ausgearbeitet. OSC bietet sich hierfür an, weil es eine sehr einfach Möglichkeit ist Zahlen und Texte zwischen verschiedenen Computern über eine (W-)Lan Verbindung zu übertragen. Für die Menüsteuerung werden von uns folgende Gesten festgelegt: left, right, up, down. Außerdem gibt es die Möglichkeit Koordinaten als Zahlenwerte zu übertragen. Um die richtigen Videos abspielen zu können, werden nach Auswahl der entsprechende Videoname per OSC gesendet, wodurch der Computer am Ausgabegerät das richtige Video abspielen kann.

OSC-Kommunikation

Umsetzung auf Linux

Bereits im ersten Projektabschnitt haben wir viel Zeit in die Verwendung von openFrameworks unter Linux gesteckt, ohne großen Erfolg. Deshalb wird die Arbeit im zweiten Projektabschnitt weitergeführt. Die meiste Zeit nutzen wir für Recherchen im Internet, um entsprechende Lösungen zu finden. Nach mehrfachem neu aufsetzen des Computers gelingt es openFrameworks in der Version 0.8.4 auf Linux unter CodeBlocks lauffähig nutzen zu können. Die nächste Aufgabe ist alle Addons unter Linux verwenden zu können. Die Idee ist bewusst eine ältere Version von openFrameworks zu nutzen da wir mit neueren Versionen bereits unter OS X Probleme hatten. Mit Hilfe verschiedener Internetseiten gelingt es die Kinect zu verwenden (siehe auch) und das Beispiel zu dem Addon ofxKinect zu starten. Das nächste Problem ist aber das ausschlaggebende Addon ofxNI2, welches für die Skeletterkennung zuständig ist, unter Linux nutzen zu können. Dieses Problem bleibt leider weiterhin bestehen. Daher sind wir bis zum Schluss auf ein Mac mit OS X angewiesen.



Engage the Jedi

Konzept

Konzept

Hierbei ist die Idee eine Menüsteuerung mit Hilfe einer Leap Motion zu realisieren. Die Grundidee besteht darin mit Hilfe der „Jedi-Geste“ zwischen verschiedenen Videos auswählen zu können. Um das Menü möglichst flexibel zu gestalten, soll ein unendlich drehbares Rondell mit allen Wahlmöglichkeiten entstehen. Der Nutzer kann dann nach rechts oder links wischen um die Auswahl zu verändern. Mit einer Handgeste nach oben kann dann die vordere Auswahl abgespielt werden. Im ersten Projektabschnitt war dieses Menü noch auf einer separaten Anzeige losgelöst von einer Ausgabe an einem Hologramm geplant. Später wanderte das Menü dann in die Ausgabe selbst. Somit wird das Menü nun in einer der pseudoholographischen Darstellungen angezeigt und der Nutzer kann direkt mit dem Hologramm interagieren.

Hardware Komponenten

Rechner

Zu Beginn lief das Programm vollständig auf einem MacBook mit OS X 10.11.x. Mittlerweile ist die Anwendung komplett für Linux angepasst und läuft unter Ubuntu.

Leap Motion

Die Leap Motion ist eine Infrarotkamera, welche ein Handskelett mit bis zu 60 FPS in einem 3 dimensionalen Koordinatensystem aufzeichnet. Da ein Menü für mehrere Plattformen (Mac, Windows und Linux) angefordert wurde, fiel die Wahl auf OpenFrameworks, ein Open-Source-Toolkit, welches auf der Programmiersprache C++ basiert. Zunächst testeten wir die verfügbaren Add Ons von OpenFrameworks für die Leap Motion und haben uns für das „ofxLeapMotion2“ Add On von „genekogan“ entschieden. Als primäre Plattform nutzten wir Xcode auf OS X.

Software Komponenten

openFrameworks

Auch bei diesem Menü setzen wir auf Open-Source-Toolkit openFrameworks. Mit dem Unterschied, dass hier die aktuelle Version 0.9.3 zum Einsatz kommt, da alle benötigten Addons auch in der neuen Version funktionieren. Unter OS X wird es auch hier in der Entwicklungsumgebung Xcode von Apple verwendet. Bei Linux wird ab openFrameworks 0.9.x Qt Creator als Entwicklungsumgebung empfohlen, weshalb wir diese entsprechend nutzen.

Addons
ofxLeapMotion2

Das Addon von genekogan ist eine angepasste Version des ofxLeapMotion Addons. Es unterstützt die neue LeapMotion SDK, welche das Skelett-Tracking der Hand unterstützt.

ofxVboParticles

Dieses Addon gibt einem die Möglichkeit, sich bewegende Partikel in das Programm einzubauen. In unserem Fall soll damit der Hologramm-Effekt in dem Menü verstärkt werden. Hierfür testeten wir einige Partikel-Addons und entschieden uns zum Schluss für ofxVboParticles.

ofxAssimpModelLoader

Im Laufe der Projektarbeit wird beschlossen, dass ein 3D-Modell einer Hand, als Feedback für den Nutzer, angezeigt werden soll. Hierfür nutzen wir wieder das Addon ofxAssimpModelLoader. Leider ist es uns bis zum Schluss nicht gelungen die Bewegungen den Finger auf das Modell zu übertragen. Lediglich die Anzeige des Modells ist derzeit möglich.

Menügestaltung

Die Anforderungen an das Menü sind beliebige Erweiterbarkeit, einfacher Überblick und leichte Bedienbarkeit. Das Menü ist auf eine minimale Anzahl von 3 Charakteren ausgelegt, um das Gefühl des 3 dimensionalen Raumes zu verstärken worin sich das Handskelett der Leap Motion bewegt. Die Bilder liegen auf einem beliebig erweiterbaren Kreisbogen, auf dem sich die Bilder nach links oder rechts bewegen können. Um das Menü später direkt im Hologramm nutzen zu können, werden einige Designanpassungen vorgenommen. Zum Beispiel wird der Hintergrund entfernt und ein Partikel-Effekt eingefügt. Ansonsten wird die Grundgestaltung beibehalten.

Gestenerkennung

Es wurden zu Beginn die Standardgesten der Leap Motion implementiert. Von diesen verwenden wir die Left/Right Swipe, dies ist eine Wischbewegung auf der X-Achse. Sowie die Up/Down Swipe Geste, welche eine Auf- bzw. Abwärtsbewegung auf der Y-Achse darstellt.[5] Für das Definieren eigener Gesten reichte leider die Zeit nicht mehr aus.

Bildimplementierung

Um die 3 Menüpunkte darzustellen, haben wir zuerst 3 Bilder an die Positionen eingefügt. Um ein Bild implementieren zu können, muss dieses zu Anfang in den korrekten Xcode Order gespeichert werden. Danach muss das Bild im Code geladen werden. Im „Draw“-Abschnitt wird dann das Bild mit Hilfe von image.draw(); gezeichnet. Man muss berücksichtigen, dass das Bild in einem 3 dimensionalen Koordinatensystem abgebildet wird, was bedeutet, je weiter hinten das Bild auf der Z-Achse liegt, desto kleiner erscheint das Bild.
Dies haben wir uns zu Nutze gemacht und konnten somit einen guten 3D- Kreisbogen-Effekt hervorrufen.

Videoimplementierung

Die Videoauswahl wird auch über den gesture_Status gesteuert und ist in 2 Schritte jeweils un- tergliedert. Wird die Auswahl eines Videos bzw. gesture_Status auf 6 gesetzt, dann erfolgt der Aufruf der Funktion prepareVideo(). Diese setzt die Transparenz der 3 zu sehenden Bilder stufenweise im Menü bis auf 0 her- unter. Die restlichen Elemente sind nicht im Sichtfenster und haben bereits den Wert 0. Sobald dert Wert 0 erreicht ist, wird die nächste Bedinung 1 mal aufgerufen. Diese lässt sich die Nummer des abzuspielenden Videos mit get_Video_Number() zurückgeben und setzt mit setLoopState(OF_LOOP_NONE) die permanente Wiederholung außer Kraft. Anschließend wird der Befehl gegeben das Video abzuspielen und der gesture_Status auf 66 gesetzt. Dadurch wird die nächste Funktion ausgeführt, diese startet die „Zeichnung“ des Videos in der draw() Methode. playVideo() ist in eine eigene Funktion, welche das Video noch an das Hologramm anpasst und dann über den Befehl videoPlayer[charVector[1]->get_Video_Number()].draw(-960,-500, 1920, 1080) das video „zeichnet“. Zudem wird der boolean playing_video auf true gesetzt. Dadurch werden andere Sachen wäh- renddessen nicht gezeichntet. Gleichzeitig werden in der update() auch die Frames des Videos stetig aktualisiert. Diese setzt nach Beendigung des Videos durch getIsMovieDone() den gesture_Status automatisch auf 5, was dem Abbrechen mit einer Geste gleichkommt. Wird ein Video durch eine Geste oder automatisch beendet, wird der gesture_Status auf 5 gesetzt und das Video gestoppt. Die vorigen Bedingungen treffen nicht mehr zu, so dass es auch nicht mehr geupdated oder gezeichnet wird. Anschließend wird der gesture_Status auf 55 gesetzt. Nun wird die prepareMenu() Methode aufgerufen, welche das genaue Gegenteil der prepareVideo() ist und die Transparenzwerte der 3 Bilder wieder langsam hochsetzt. Durch playing_video = false können auch wieder alle Komponenten gezeichnet werden. Sobald die Bilder mit maximaler Transparenz dargestellt sind, wird der gesture_Status auf 0 gesetzt und es können neue Gesten erkannt werden.

Programmstruktur

Grundeinstellungen

Die ofApp.cpp beinhaltet die gesamte Menüstruktur, alle Parameter sowie Einstellungen. Zuerst werden zu Beginn in der setup() Methode alle wichtigen Parameter gesetzt, sowie geladen. Der Hintergrund wird mit 0% der RGB Farben initialisiert. Dies entspricht einem totalen Schwarzwert.

Es folgen die spezifischen Einstellungen für die Leap Motion. Die Framerate setzten, Aktivierung der Kamera sowie der Standardgesten. Im 2 Codeblock wird ein Listener und ein Controller für die Gesten bereitgestellt und die spezifischen Typen aktiviert. TYPE_SWIPE beinhaltet 6 Gestenvarianten: Wischbewegungen auf der X-Achse links+rechts, auf der Y- Achse hoch+runter sowie auf der Z-Achse vor+zurück. TYPE_CIRCLE sind Rotationen mit dem Zeigefinger, entweder im oder gegen den Uhrzeigersinn. TYPE_KEY_TAP ist wie ein Tippen auf der Tastatur mit dem Zeigerfinger. TYPE_SCREEN_TAP entspricht der Bewegung eines Tippens auf dem Touchscreen mit dem Zeigefinger. Zur besseren Visualisierung ist eine Grafik über dem Codeausschnitt eingefügt.

ofSetFrameRate(60);
ofSetVerticalSync(true);
ofSetLogLevel(OF_LOG_VERBOSE);
leap.open(); 
leap.setupGestures();
cam.setOrientation(ofPoint(-20, 0, 0)); 
 
//Gesten aktivieren
Leap::Listener Samplelistener;
Leap::Controller controller; 
controller.addListener(Samplelistener);
controller.enableGesture(Leap::Gesture::TYPE_SWIPE);
controller.enableGesture(Leap::Gesture::TYPE_CIRCLE);
controller.enableGesture(Leap::Gesture::TYPE_KEY_TAP);
controller.enableGesture(Leap::Gesture::TYPE_SCREEN_TAP);
controller.config().setFloat("Gesture.Swipe.MinLength", 100.0);
controller.config().setFloat("Gesture.Swipe.MinVelocity", 200);
controller.config().setFloat("Gesture.ScreenTap.MinForwardVelocity",1);
//controller.config().setFloat("Gesture.ScreenTap.HistorySeconds", 0.01);
controller.config().setFloat("Gesture.ScreenTap.MinDistance",1.0);
controller.config().save();

Die Genauigkeiten der verwendeten Gesten wurden angepasst um eine feinere Steuerung zu gewährleisten. Der Wert für jeweils „MinLength“ und „MinDistance“ entspricht mm sowie für „MinVelocity“ mm/s. Anschließend wurden die Änderungen gespeichert.

Vektor

Es wird zuert ein Vektor in der ofApp.h definiert. Er beinhaltet als Elemente Zeiger auf die Elementklasse. Dies dient zur Veringerung von Speicherbedarf sowie zur Performanceverbesserung. Um diesen nun zu verwenden, müssen noch Elemente bereitgestellt werden. In diesem Code sind es 4, aber es können beliebig viele mehr sein, jedoch mindestens 3. Jetzt kann der Vektor mit diesen in der CPP-Datei befüllt werden. Dabei wird immer der Konstruktor der Elementklasse aufgerufen und die Parameter in der definierten Reihenfolge übergeben. Zuerst der Name des Bildes mit Dateityp, dann die 3 Koordinaten X,Y und Z. Darauf folgt die Nummer des Videos bzw. Players sowie der Wert für die Transparenz. Die ersten 3 Elemente haben den Wert 255, da diese zu Beginn sichtbar sind.
Das 4. sowie alle darauffolgen Elemente bekommen bei Erstellung den Wert 0 zugewiesen und sind demzufolge nicht sichtbar. Nach Durchlaufen des Konstruktors kann das jeweilige Elemente mit dem Befehl push_back() in den Vektor eingefügt werden. Es wird mit einer Referenz (&) eingefügt und immer nach dem letzten Element im Vektor eingereiht.

//character loading
one = Element("Leap_DavidBarclay.png",X_img_ONE,Y_img_ONE,Z_img_ONE,0,255);
charVector.push_back(&one);
two = Element("Leap_NickMaley_muppets.png",X_img_TWO,Y_img_TWO, Z_img_TWO,1,255);
charVector.push_back(&two);
three = Element("Leap_RobertWatts.png",X_img_THREE,Y_img_THREE, Z_img_THREE,2,255);
charVector.push_back(&three);
four = Element("Leap_NickMaley_yodaDesign.png",X_img_FOUR,Y_img_FOUR,Z_img_FOUR,3,0);
charVector.push_back(&four);

Die Koordinatenwerte für die Bilder befinden sich in der header-Datei. Diese wurden durch viele Tests ermittelt, um beispielsweise Überschneidungen der Bilder beim Verschieben zu vermeiden. Wie der Kommentar im Code beschreibt, wird beim Hinzufügen eines neuen Elementes der X-Wert des Letzten genommen und um 2500 erhöht, der Y-Wert um 1375 verringert sowie der Z-Wert um 5000. Alle Werte sind durch 125 teilbar, da dies die Anzahl der Schritte beschreibt, die ein Bild bis zur nächsten Position benötigt, bzw die entsprechende Funktion.

Im folgenden vernschaulicht eine Grafik den genannten Aufbau. Das erste Element (one) ist links, das Zweite (two) in der Mitte sowie das 3 (three) rechts. Alle weiteren Elemente werden rechts angefügt und sind zu Beginn nicht sichtbar.

FXpo LeapMotion Menu.png

Jedes Element besitzt ein Video. Dafür wird ein Videoplayer als Array in der header-Datei definiert. Da sich 4 Elemente im Menü befinden und jedes ein Video besitzt, benötigen wir auch 4 Videos, weshalb die Größe des Arrays 4 ist.

Anschließend wird in der cpp-Datei der Videoplayer mit den einzelnen Videos gefüllt. Dies erklärt nun weshalb das erste Element die Videonummer (vid_number) 0 hat. Es ist im Array der erste Eintrag.

Gesten

Das Gesamte Menü ist auf verschiedenen Statuswerten aufgebaut, dem Integer gesture_Status. Dieser muss nur verändert werden und das gesamte Menü ist darüber bedienbar. Hintergrund ist zum einen die einfache OSC-Einbindung, sowie zum anderen, die Anlehnung an die Werte der Gesten der Leap Motion. So hat beispielsweise der „Left Swipe“ (eine Wischbewegung nach links) den Gestenwert (gesture) 4 und setzt bei Ausführung den gesture_Status auch auf 4. Dies soll nur geschehen, wenn gerade kein Video abgespielt wird und auch keine andere Verschiebung stattfindet. Deshalb ist die Bedingung hinzugefügt, das der gesture_Status 0 ist. Dies entspricht dem Menü in Ruhe. 6 repräsentiert die Auswahl eines Videos. Aufgrund von verschiedenen Auswahlmöglichkeiten setzten mehrer Gesten den Wert auf 6. Wenn die gleiche Geste bei erneuter Ausführung das Video wieder beenden soll, dann wird eine weitere Bedingung hinzugefügt: charVector[0]->getTransparency()==0. Dieser Befehl fragt das 1 Element des Vektores welche Transparenz das Bild hat. Über die Elementklasse wird der angefragte Wert zurückgegeben. Sobald dieser 0 ist, wird gerade ein Video abgespielt und die Bedingung trifft zu (der gesture_Status ist auch nicht mehr 0 weshalb die 1 Bedingung nicht zutrifft). Durch setzten des Wertes 5 für den gesture_Status wird das Video beendet . Andere nicht verwendete Gesten sind für einen späteren möglichen Nutzen vorerst nur implementiert.

if(gesture == 1){
    //Forward Poke
    if(gesture_Status==0){
        gesture_Status=6;
    }
    if(charVector[0]->getTransparency()==0){
        gesture_Status=5;
    }
}else if(gesture == 2){
    //Down Tap
}else if(gesture == 3&&gesture_Status==0){
    //Right Swipe
    gesture_Status=3;
}else if(gesture == 4&&gesture_Status==0){
    //Left Swipe
    if(gesture_Status ==0){ gesture_Status=4;}
}else if(gesture == 5&& charVector[0]->getTransparency()==0){
    //Down Swipe
    gesture_Status=5;
}else if(gesture == 6&&gesture_Status==0){
    //Up Swipe
    gesture_Status=6;
}else if(gesture == 7){
    //Push swipe
    if(gesture_Status==0){
gesture_Status=6;}
    if(charVector[0]->getTransparency()==0){ 
        gesture_Status=5;
    }
}else if(gesture == 8){
    //Pull swipe
}else if(gesture == 9){
    //counter-clockwise Rotation
}else if(gesture == 10){
    //Clockwise Rotation
}
Menüstruktur

In der update() Funktion wird zuerst geschaut ob eine Hand sowie Gesten über die Leap Motion erkannt wurden und diese aktualisiert. Nun wird stets überprüft welcher Menüstatus (gesture_Status) gerade gesetzt ist.
Bei 0 passiert nichts und das Menü befindet sich in Ruhe (kein Video spielt).
Wird bei einer Wischbewegung nach links der Wert auf 4 gesetzt, wird die Funktion move_Left() aufgerufen und nach deren Beendigung der Wert auf 44 gesetzt. Damit wird die nächste Funktion move_Left_To_The_End() ausgeführt. Das Wechseln zum nächsten Menüpunkt/Charakter ist in 2 Schritte unterteilt, was später noch genauer erläutert wird. Das Gleiche gilt für die Rechtsbewgung nur mit den Werten 3 und 33.

Die move_Left() Methode wird solange ausgeführt bis sich der gesture_Status ändert. Zur Vermeidung einer permanenten Ausführung dieser Geste wird gesture auf 0 gesetzt, so dass die Geste quasi nur 1 mal gesendet wird. Nun wird durch den gesamten Vektor iteriert, dabei wird für das 1 + 2 Element (i<=1) bzw. das linke und mittlere Bild eine Bewegung definiert, sowie für alle restlichen Elemente. Hintergrund ist, dass sich die Bilder auf einen Bogen bewegen, somit verschiebt sich das 1+2 anders als die darauffolgenden. Der negative Parameter move_X setzt die Verschiebung auf der X-Achse, welche für alle gleich ist. An der Y-Achse bewegt sich das 1+2 Element nach oben, durch das negative Vorzeichen (diese Achse ist vertauscht) und die anderen Elemente nach unten (positves Vorzeichen). Bei der Z-Achse verschieben sich wieder die 2 ersten Bilder in negative Richtung sowie alle Weiteren in die Positive. Die Parameter für die einzelnen Koordinaten sind in der Header-Datei festgelegt und ergebn sich durch die Differenz zwischen 2 Bildern anhand der Schritte der Verschiebung (immer 125). Z.B. für den X-Wert ist es 2500/125=20=move_X. Das linke Bild (charVector[0]) wird „verschwinden“, weshalb sich die Transparenz stets verringert. Da die Tranzparenz mit einem Wert von 255 sich nicht durch 125 teilen ließ, erfolgt, vor Beendigung des letzten Aufrufs der Methode move_Left(), eine manuelle Anpassung für das linke Bild um auf exakt 0 zu kommen. Für das 4 Element trifft das Gegenteilige zu. Es wird langsam „erscheinen“ und somit seinen Transparentwert von 0 erhöhen. Durch Tests wurde die bestmögliche Position ermittelt, bei der die Bilder gleichmäßig verschwinden/auftauchen ohne ein „aufploppen“ zu verursachen. Bei jedem Aufruf der Methode wird der dif_counter um 1 erhöht. Für das 4 Elment wird erst begonnen die Transparenz zu setzten, sobald der dif_counter über 37 ist und somit die Funktion schon 37 mal aufgerufen wurde. Das Bild befindet sich nun komplett im sichtbaren Fenster und beginnt seine Transparenz zu erhöhen. Dadurch soll auch verhindert werden, dass Besucher durch ein angeschnittenes Bild den Rand des Hologramms bzw. des Fernsehers erkennen. Da sich das 1 Element wieder hinter den anderen Bildern ganz rechts einreihen muss, braucht es neue Positionsangaben. Es wird grundsätzlich immer von einem weitern Element nach dem Letzten ausgegeangen. In diesem fall das 5., dafür sind nur feste Positionswerte in der Header-Datei gestzt (X_Last, Y_Last, Z_Last). Um zu wissen, um wie viele Schritte sich dieses Element bewegt hätte, wird der dif_counter genutzt. Durch setLocation wird dem 1 Element eine neue Position mitgeteilt. Nun wird das 1 Element auf die Position des nicht vorhandenen 5. gesetzt und um die Schritte, welche die anderen Bildern zurückgelegt haben, nachgeschoben (vgl. dif_counter*move_X für die X-Koordinate). Nachdem es versetzt wurde, wird der gesture_Status auf 44 gesetzt und die Funktion wird nicht mehr aufgerufen. Mit gesture_Status = 44 wird die nächste Funktion move_Left_To_The_End() aufgerufen. Zuerst wird der 1. Codeblock mit der for Schleife betrachtet. Hierbei wird, wie zuvor, durch den gesamten Vektor iteriert und jedes Element an den 3 Achsen verschoben. Unterschied je- doch, dass nun das 1. Element (one) was sich jetzt an 5 Stelle im Menü befindet, auch wie die anderen Bilder in positive Y sowie Z Richtung bewegt. Lediglich das 2. Element (two) verschiebt sich weiter auf allen Achsen mit in negative Richtung. Der Transparenzwert wird weiterhin stetig für Element four erhöht. Nun wird der untere Codeblock betrachtet. Dieser wird ausgeführt, sobald Element two die Position X_pos_left erreicht. Dies sind feste Parameter in der Header-Datei und dienen zur Orientierung für die Bilder wann sie ihre neue Position erreichen. Da beim Erreichen des 2. Elementes der neuen Position die unter for-Schleife noch aktiv ist, verschieben die Bilder sich einen Schritt zu weit und werden um diesen zurückgesetzt. Wie schon erwähnt, muss hier auch wieder der Transparenzwert noch nachjustiert werden um exakt auf 255 (Maximum) zu kommen. Nun haben alle Bilder ihre richtige Position und die Reihenfolge im Vektor wird angepasst. Es wird das 1. Element des Vektors ausgewählt durch charVector.begin() bis zu charVector.begin()+1. Durch den Befehl copy() wird dieses Elment an die letzte Stelle des Vektors über den Ausdruck back_inserter() eingefügt. Nun befindet sich folgende Elemente im Vektor: one, two, three, four, Kopie von one. Im Menü sind nun beide Bilder von one an 4. Stelle ganz rechts außerhalb des Bildschirmfensters mit Transparenzwert 0. Nun kann mit charVector.erase(charVector.begin()) das 1. Element des Vektors gelöscht werden und die Gesamtanzahl ist wieder 4. Zum Schluss wird noch der dif_counter auf 0 sowie der gesture_Status auf 0 gesetzt um eine erneute Ausführung aller Gesten zu gewährleisten.

Charakterwechsel

Die Wischbewegung nach rechts und die damit verknüpfte Methode move_Right() sowie move_Right_To_The_End() verhalten sich ählich bzw. fast ausschließlich gegensätzlich und es wird nur noch auf die Unterschiede zur move_Left() sowie move_Left_To_The_End() eingegangen. Mit gesture_Status=3 und der ausgeführten move_Right() erfolgt eine Rechtsbewegung. Es bewegt sich nur das linke Menübild in positive Z sowie Y Richtung. Die restlichen Bilder bewegen sich in negative Richtung. Mit dem Befehl

if(charVector[0]->getX()==(-1140) ){
    charVector[charVector.size()-1]->setLocation(
        X_First+(dif_counter*move_X),
        Y_First+(dif_counter*move_Y),
        Z_First+(dif_counter*scale_Z)
    );
}

wird das letzte Element des Vektors angesprochen. Dieses wird beim Erreichen der wieder durch Tests ermittelten Position versetzt. Diesmal wird auch noch von einem weiteren Element ausgegangen, welches sich noch vor dem 1. befindet, quasi an Position 0. Hierfür sind auch feste Parameter (X_First, Y_First, Z_First) als Orientierung vorhanden. Nach dem Versetzen wird der gesture_Status auf 33 gesetzt und die move_Right_To_The_End() Funktion ausgeführt. Die Transparenz wird erst in dieser Methode für das verschobene Element erhöht, dafür aber in höheren Werten. Der größte Unterschied ist die Neueingliederung in den Vektor. Die Reihenfolge der Elemente nach Verschiebung wäre: four, one, two, three. 
Somit muss Element four auch an die 1. Stelle im Vektor. Mit dem Befehl back_inserter() konnte etwas an letzter Stelle des Vektors angehangen werden. Leider ist die Methode front_inserter() nicht vorhanden um ein Element an vorderster Stelle zu plazieren. Deshalb löst der nachfolgende Codeauschnitt das Problem. Hierbei wird zuerst die Größe des momentanen Vektors in einer Variable current_vec_size gespeichert, aber um 1 verringert. Nun wird mit copy(charVector.begin(), charVector.end()-1, back_inserter(charVector)) der gesamte Vekor bis auf die letzte Stelle (Element four), an den Vektor angefügt. Somit stehen im Vektor folgende Elemente: one, two, three, four, one, two, three. Aschließend werden die Elemente von Beginn des Vektors gelöscht. Die zuvor gespeicherte Variable current_vec_size gibt dabei Auskunft über die zu löschende Anzahl. Dies ist in unserem Beispiel 4 – 1 = 3, somit werden die 3 vordersten Elemente gelöscht und es sind folgende Elemente im Vektor: four, one, two, three. Somit stimmt die Reihenfolge im dargestellten Menü sowie auch im Vektor.

Portierung Mac auf Linux

Bei der Portierung des Programmcodes von Xcode auf Linux in den Qt Creator, ergaben sich einige Änderungen. Die zuvor gezeigt Ausführung war die zur Präsentation unter Linux. Eigentlich sollte jedes Element im Vektor einen eigenen Videoplayer (ofVideoPlayer) haben. Dies war mit den unter Linux verwendeten „gstreamer“ nicht möglich. Es kam zu starken Frameeinbrüchen der Videos in Full HD. Es wurde nur ca. 1 Bild alle 3 Sekunden wiedergegeben, was nicht akzeptabel war. Da es sich programmiertechnisch um die elegantere Variante handelt und diese auch unter Mac mit dem quicktime ofVideoPlayer läuft, wird sie im folgenden erläutert. Statt der Nummer eines Players wird in der Mac-Version den Elementen jeweils ein String mit dem genauen Namen des Videos mitgegeben. Dieser wird dann zu Beginn mit dem Aufruf vid.loadMovie(vid_string) direkt in den Videoplayer (vid) reingeladen. Wird in der 
ofApp die PlayVideo aufgerufen, verläuft es etwas anders. Zuerst wird nun die Setup() Funktion des Elementes in dessen Klasse aufgerufen.

void ofApp::playVideo(){
    if(playing_video==false){
        charVector[1]->setup(); 
        playing_video==true;
    }
    charVector[1]->update();
}

In dieser wird der Befehl gegeben das Video zu starten und die permanenten Wiederholung zu deaktivieren:

void Element::setup(){
    vid.play();
    vid.setLoopState(OF_LOOP_NONE);
}

Anschließend wird der Boolean playing_video auf true gesetzt und nun immer wieder die Update Funktion der Elementklasse aufgerufen (charVector[1]->update();). In dieser werden die Frames des Videos stetig aktualisiert:

void Element::update(){
    vid.update();
}

Gleichzeitig wird in der draw() Funktion der ofApp Klasse der Befehl charVector[1]-
>videoPlayer() aufgerufen, welcher das Video in der Elementklasse beginnt zu zeichnen. Dies geschieht nach Anpassung an das Hologramm mit dem Befehl vid.draw(-960,-500, 1920, 1080). Die Methode getEndofVideo() ist auch in die Elementklasse ausgelagert und gibt Rückmeldung sobald das Video beendet ist.

bool Element::getEndofVideo(){
    return vid.getIsMovieDone();
}

Somit sind fast alle Funktionen die die Wiedergabe eines Videos betreffen aus der Hauptklasse ausgelagert. Zudem besitzt automatisch jedes Element einen eigenen Videoplayer und es muss nicht noch ein Array aus diesen erstellt werden. Ein weiteres Problem war, dass die Erkennung der Hand durch die Leap Motion unter
 Linux zum Absturtz des Programmes führte. Schuld daran war ein Vektor welcher beim Zeichnen der Hand gegeben war. Dieser war bereits im Addon „ofxLeapMotion2“ auf
 dem unser geschriebenes Programm basiert enthalten. Durch deaktivieren konnte trotzdem eine Erkennung und Zeichnung der Hand gewährleistet werden. Die Implementiertung des 3D-Modells der Hand mitsamt der Textur konnte hingegen nur unter Linux realisiert werden. Zudem führte die stärkere Hardware des Desktoprechners im Vergleich zum MacBook zu einem Perforemancegewinn. Das gesamte Menü läuft nach Umstellung der Videowiedergabe sehr flüssig. Die Protierung war somit zu 100% erfolgreich und alle Funktionen unter Mac laufen auch unter Linux mit Anpassungen.

Partikeleffekt

Als Grundlage für den Partikeleffekt wurde das Addon Beispiel „Example Moving“ verwendet. Dies erfüllt jedoch noch nicht den Zweck, den es am Ende haben sollte. Geplant war ein Partikeleffekt, der an eine sich bewegende Galaxie erinnert. Dies wurde durch die Veränderung verschiedener Parameter im Addon Beispiel realisiert. Natürlich dürfen die Partikel während eines Videos nicht sichtbar sein, um die Atmosphäre des Hologramms nicht zu zerstören. Somit wurde folgender Befehl implementiert:

if(!playing_video) {
    glPushMatrix();
    glTranslated(0, 0, -1000);
    ofRotate(90);
    ofRotate(ofGetElapsedTimef() * 40, 1, 0, 0);
    vboPartciles->draw();
    glPopMatrix();
}

Diese If-Schleife beschreibt folgendes: Wenn kein Video spielt, sollen die Partikel um 90 Grad gedreht mit einer bestimmten Rotationsgeschwindigkeit auf einer Matrix gezeichnet werden. Die 90 Grad sind hierbei wichtig, da die Partikel ja unterhalb des gesamten Menüs gezeichnet werden sollen. Da das Menü um 90 Grad gedreht ist, kann dies mit ofRotate(90) realisiert werden. Die Partikel selbst werden in der Setup der Klasse ofApp.cpp genauer definiert. Somit kann man die maximale Anzahl an Partikeln, welche erscheinen sollen angeben. Auch die Größe der Partikel ist einstellbar. So kann man entscheiden, ob man eher gröbere oder feinere Partikel haben möchte.

vboPartciles = new ofxVboParticles(16000, 6000);

Die erste Zahl (16000) beschreibt hierbei die maximale Anzahl an Partikeln und die zweite Zahl (6000) ist die Größe der Partikel.



Death Star

Konzept

Konzept

Die Idee für die Todesstern-Steuerung war zuerst nur die Steuerung von Hologrammen durch Abstandssensoren. Hierzu sollten jeweils rechts, links und oben an der Kugel ein Infrarot-Abstandssensor mit einem Messbereich von 4-30 cm eingebaut werden. Der Benutzer sollte dann mit Hilfe des linken und rechten Sensors zwischen den verschiedenen Hologrammen wechseln und durch den oben angebrachten Sensor das ausgewählte Hologramm abspielen oder beenden können. Im Laufe der Entwicklung kam jedoch Nick Maley auf uns zu und hat uns gebeten eine Steuerung für ein einzelnes Pseudo-Hologramm in seiner geplanten Ausstellung an der Hochschule zu entwickeln. Dieses Hologramm sollte ein einziges Video abspielen und unsere Steuerung sollte erkennen, ob sich aktuell eine Person vor dem Hologramm befindet und in diesem Fall das besagte Video im Hologramm-Präsenter abspielen. Wenn dies nicht der Fall war, dann sollte die Steuerung erkennen, dass sich aktuell kein Benutzer vor dem Pseudo-Hologramm befand und das Video stoppen und auf das erste Frame zurücksetzen. Diese veränderte Steuerung brachte auch eine Änderung der Sensoren mit sich. Denn zum Erkennen von Personen vor dem Todesstern wurden Sensoren mit einem größeren Messbereich benötigt, weshalb wir letztendlich zwei verschiedene Arten von Sensoren in den Todesstern einbauten. Zum einen zwei große Sensoren mit einem Messbereich von 20-150 cm, welche für die Personenerkennung zuständig waren und zum anderen zwei kleine Sensoren mit einem Messbereich von 4-30 cm, welche zur Navigation zwischen verschiedenen Hologrammen gedacht waren. Diese wurden in der finalen Version des Todessterns jedoch nicht verwendet, da für die Ausstellung nur ein einzelnes Pseudo-Hologramm zur Verfügung stand und deshalb keine Navigation benötigt wurde. Sie sind jedoch angeschlossen und implementiert, d.h. man könnte mit ihnen problemlos eine Navigation zwischen Hologrammen ermöglichen.

Hardware Komponenten

Rechner

MacBook Pro mit OS X 10.11.x

Arduino Uno

Der Arduino Uno ist ein Mikrocontroller-Board mit 14 digitalen Ein- und Ausgängen und 6 analogen Eingängen. Außerdem hat es eine Power-LED, einen USB- und Stromanschluss, einen ICSP-Header und einen Reset-Knopf. Der Arduino Uno hat alles, was für den Betrieb des Mikrocontrollers notwendig ist. Um zu funktionieren, muss er lediglich via USB an einen Computer angeschlossen oder durch ein Netzteil mit Strom versorgt werden.

Infrarot-Abstandssensoren

Es wurden zwei Arten von analogen IR-Abstandssensoren verwendet, welche beide den selben Hersteller Sharp haben. Zum einen der GP2Y0A41SK0F-Sensor, welcher Objekte auf eine Entfernung von 4-30 cm erkennen kann und zum anderen der GP2Y0A02YK0F- Sensor, welcher Werte innerhalb eines Bereichs von 20-150 cm messen kann.

Software Komponenten

Arduino Software

Die kostenlose Open Source Software ist eine integrierte Entwicklungsumgebung (IDE), welche es dem Anwender leicht gestaltet Code zu schreiben und diesen direkt auf das Arduino Board hochzuladen. Die Entwicklungsumgebung ist eine Java-Anwendung und basiert auf der IDE von Processing. Die Programmierung selbst erfolgt dagegen in C++, wobei technische Details wie Header-Dateien weitgehend vor dem Anwender verborgen werden und umfangreiche Libraries und Beispiele die Programmierung vereinfachen. Die IDE ist mit jedem der verschiedenen Arduino Boards kompatibel und läuft auf Windows, OS X und Linux.

openFrameworks

openFrameworks ist eine kostenlose Open Source Entwicklungsumgebung auf Basis der Programmiersprache C++ und außerdem speziell auf die Unterstützung von kreativen Projekten ausgelegt. Als Entwicklungsumgebungen wird von uns Xcode genutzt. Für das Projekt wurde die openFrameworks Version 0.9.2 verwendet.

Addons
ofxOsc

Für die Kommunikation zwischen dem Programm zur Videowiedergabe und dem Programm zur Auswertung der Sensordaten wurde das Addon ofxOsc verwendet.

Bau des Todesstern

Ausgedruckte Todesstern Textur

Eine Styroporkugel mit 30 cm Durchmesser wurde mit Klarlack besprüht, damit das Material haltbarer ist und nicht durch Kleber o.ä. angegriffen wird. Danach wurden im Internet gefundene Bastelbögen auf normalem Papier farbig ausgedruckt. Darauf waren 51 einzelne Streifen sowie diverse andere Teiles des Todessterns aufgedruckt, welche von Hand ausgeschnitten werden mussten. Die Streifen waren nummeriert und wurden in aufsteigender Reihenfolge von 1-8 abwechselnd auf die Styroporkugel aufgeklebt. Die Streifen A, B und C, welche die Markierung für die Laserkanone aufgedruckt haben, wurden an einer beliebigen Stelle nach einem Streifen mit der Nr. 8 aufgeklebt. Nachdem alle Streifen aufgeklebt waren, wurde an der markierten Stelle eine Mulde für den Laserstrahl in die Kugel geschnitten und der entsprechende Teil des Bastelbogens aufgeklebt. Zu guter Letzt wurden an den gewünschten Stellen der Sensoren Löcher in die Kugel geschnitten, damit die Sensoren von innen durchgesteckt werden können und sie dadurch möglichst unauffällig sind.

Abstandssensoren

Aufbau der IR-Abstandssensoren

Sender und Empfänger des IR-Signals liegen beide innerhalb eines Sensors und werden jeweils durch eine Linse fokussiert. Die Sensoren haben alle einen 3-poligen Anschluss und können direkt an den A/D-Wandler eines Mikrocontrollers angeschlossen werden.

Funktionsweise der Abstandssensoren

Der Sender strahlt einen durch die Linse stark gebündelten Infrarot-Strahl aus, der von einem Objekt oder einer Person, welche sich innerhalb des Messbereichs befindet, reflektiert wird. Die Berechnung der Entfernung erfolgt mittels Triangulation . Je weiter entfernt das reflektierende Objekt ist, desto kleiner ist der Winkel zwischen emittiertem und reflektiertem Lichtstrahl. Anstelle einer üblichen Photodiode enthalten die Sharp-Sensoren ein PSD (Position Sensitive Device), eine Art "langgezogene" Photodiode. Je nachdem, an welcher Stelle der empfangene Lichtstrahl auf die Photofläche trifft, teilt sich der Photostrom entsprechend der Position des Punktes in zwei Teile. Aus dem Quotienten von Differenz und Summe der beiden Ströme erhält man ein von der Lichtleistung unabhängiges Positionssignal.

Anschließen der Abstandssensoren

Die Abstandssensoren wurden an die analogen Eingänge des Arduino Uno und an ein Steckbrett angeschlossen. Die zwei großen Abstandssensoren wurden auf der unteren Halbkugel unterhalb der Laserkanone angebracht und die zwei kleinen Sensoren jeweils links und rechts auf der oberen Halbkugel.

Testen der Abstandssensoren

Zum Testen der Abstandssensoren wurde im openFrameworks-Programm, welches für die Weiterverarbeitung der rohen Sensorwerte zuständig ist, eine Oberfläche implementiert, welche laufend die Distanzwerte der Sensoren in cm und die normalisierten Sensorwerte ausgibt. Dadurch fiel beim Testen der Sensoren auf, dass sie sehr oft falsche Werte lieferten. Normalerweise sollte der normalisierte Wert bei -1 liegen, wenn sich kein Objekt innerhalb des Messbereichs der Sensoren befindet. Jedoch traten alle paar Sekunden willkürliche Werte auf, die keinen Sinn ergaben. Als die Versuche, diesen Fehler innerhalb des Codes zu beheben, kein ausreichendes Ergebnis lieferten, haben wir uns ins Labor der Medizintechnik begeben, um dort mit Hilfe eines Oszilloskops umfangreichere Tests durchzuführen.

Fehlerbehebung der Abstandssensoren

Zuerst wurden Folienkondensatoren zum kurzschließen hochfrequenter Störungen an die einzelnen Sensoren gelötet. Nachdem die Fehlwerte dadurch jedoch noch nicht eliminiert werden konnten, wurde festgestellt, dass das Steckbrett der Auslöser war. Deshalb wurden die Sensoren dann fest auf eine leere Platine gelötet. Damit war das Problem behoben und die Sensoren lieferten endlich korrekte Werte.

Programmcode

Der Programmcode für den Todesstern ist in drei Teilprogramme aufgegliedert. Zum einen ein Arduino-Programm, welches für das Empfangen der Sensorwerte zuständig ist und zum anderen zwei openFrameworks-Programme, ein Sender- und ein Empfänger- Programm. Das Sender-Programm holt sich zuerst die Sensorwerte vom Arduino. Danach verarbeitet es diese weiter, um anschließend eine OSC-Nachricht an das Empfänger- Programm zu verschicken. Das Empfänger-Programm hört ständig auf eingehende OSC- Nachrichten des Sender-Programms, verarbeitet diese und löst entsprechend der einkommenden OSC-Nachricht eine Ausgabe aus.
Im Folgenden wird nicht immer zusammenhängender oder vollständiger Code gezeigt. Zu sehen sind die wichtigsten Funktionen und Elemente, die zum Verständnis der Funktionsweise beitragen sollen.

Sensordaten mit Arduino auslesen

Mit analogRead(pin) können Werte von einem bestimmten analogen Pin des Arduino ausgelesen werden. Der Parameter pin gibt hierbei die Nummer des auszulesenden analogen Input-Pins an. Beim Arduino Uno ist es eine Nummer von 0-5, da er nur 6 analoge Input-Pins besitzt. Die Funktion wandelt Eingangsspannungen zwischen 0 und 5 Volt in Integer-Werte zwischen 0 und 1023 um und gibt diese zurück.

Kommunikation über Firmata

Das Firmata-Protokoll basiert auf dem MIDI-Message-Format und ermöglicht es, von einem Computer aus mit einem Arduino zu kommunizieren. Standardmäßig ist auf dem Arduino kein Firmata installiert, deshalb muss man dies manuell erledigen. Dazu startet man die Arduino IDE und verbindet den Arduino per USB mit dem Mac. Über den Menüpunkt "Werkzeuge" müssen anschließend Platine und Port ausgewählt werden, damit der Upload-Prozess vom Mac auf das Arduino-Board und damit die Installation von Firmata reibungslos funktioniert. Als nächstes öffnet man über das Menü den „StandardFirmata“-Sketch, welcher sich im Ordner „Beispiele“ unter „Firmata“ befindet. Dabei handelt es sich um eine Datei, welche den Code für Firmata enthält. Diesen lädt man über den „Hochladen“-Button auf das Arduino-Board. Damit ist die Installation abgeschlossen und Firmata steht auf dem Arduino bereit.



Silhouettes

Konzept

Konzept

In der Ausstellung soll im Eingangsbereich eine Station realisiert werden, die keine Menüsteuerung beinhaltet, sondern einen spielerischen Effekt im Eingangsbereich zeigt. Beim Brainstorming wird überlegt, was für ein Effekt den Benutzer am Eingang erwarten soll und wie dieser realisiert werden kann. Ziemlich schnell begeistert das Projekt „OHMinteractive“ aus dem Jahr 2014. Die ehemaligen Media Engineering Studenten präsentierten damals ein Teilprojekt, bei dem ein Benutzer seine Silhouette an einer Wand vor ihm sieht und seine Bewegungen dort nachgezeichnet werden. Zusätzlich dazu reagierte ein Schwarm Vögel auf die Interaktion. Es wird entschieden, dass dieses Projekt als Vorlage für die neue Station in der Ausstellung verwendet werden soll. Aufgrund der beschränkten Zeit soll erstmal nur das Grundprinzip (Ausgabe der Silhouette und der nachgezogenen Spur) umgesetzt werden.

Hardware Komponenten

Rechner

Es kommt ein DELL Notebook mit Windows 7 (64 Bit) zum Einsatz.

Microsoft Kinect

Als Kamera wird die Kinect von Microsoft genutzt. Diese gibt uns direkt ein Tiefenbild, welches weiterverarbeitet werden kann. Grundsätzlich wäre für das Konzept auch die Benutzung einer normale Kamera möglich, solange das Bild nicht auf eine bestimmte Distanz begrenzt werden soll.

Software Komponenten

openFrameworks

Auch in diesem Teilprojekt wird mit openFrameworks gearbeitet. In diesem Fall in der Version 0.9.2 unter Windows. Hierbei wird die Entwicklungsumgebung Visual Studio genutzt.

Umsetzung

Nach Absprache mit den Projektbetreuern wird festgelegt, dass auch diese Station mit openFrameworks realisiert werden soll. Für die weitere Umsetzung wird die Tiefenbildkamera „Kinect“ von Microsoft verwendet. Bei der fertigen Station steht der Besucher, geführt durch aufgestellte Styroporwände, vor einer weißen Wand und sieht dort eine Projektion von sich selbst. Hinter dem Benutzer befindet sich die Kinect- Kamera und ein Beamer. Die Kamera ist in der Lage ein Tiefenbild zu erzeugen und damit in einem Bild hintereinanderliegende Objekte zu erkennen und zu unterscheiden. Zusätzlich dazu kann die Kinect-Kamera Konturen erkennen. Diese beiden Funktionen werden genutzt, um in der Projektion den Umriss des Benutzers auszugeben. Als zusätzlicher Effekt zieht jede Bewegung eine Spur nach sich. Das wird dadurch realisiert, dass die Kontur des Benutzers in kurzen Abständen immer wieder gezeichnet und ausgegeben werden. Die älteren Umrisse verblassen dabei langsam.

Der Code dafür wird wie folgt realisiert:

In der Header-Datei:

ofxKinect kinect;
ofxCvGrayscaleImage grayImage; //Graustufen- und Tiefenbild 
ofxCvGrayscaleImage grayThreshNear; //Nahes Schwellenwert-Bild 
ofxCvGrayscaleImage grayThreshFar; //Entferntes Schwellenwert-Bild
 
bool bThreshWithOpenCV;
int farThreshold; 
int nearThreshold;
 
ofxCvContourFinder contourFinder; 
ofFbo fbo;
ofPath path;
ofTexture texture;

Damit die Kinect-Kamera auch verwendet werden kann, wird ein ofxKinect Element (kinect) angelegt. Außerdem werden sowohl ein Graustufen- und Tiefenbild namens grayImage, als auch zwei Schwellenwert-Bilder (ein nahes und ein entferntes) grayThreshNear und grayThreshFar benötigt. Die Schwellenwerte sollen jederzeit veränderbar sein und deshalb werden die Variablen namens farThreshold und nearThreshold deklariert. Außerdem wird ein sogenannter contourFinder für die Umrisserkennung angelegt. Ein fbo (Framebuffer Object), ein path (Pfad) und ein texture (Textur) Element werden zudem deklariert. Sie werden benötigt, um die Silhouette zu zeichnen und auszugeben.

In der ofApp.cpp werden einige Funktionen angelegt. Eine davon ist die Setup Funktion, die wie folgt umgesetzt wird:

kinect.setRegistration(true);
kinect.init();
kinect.open(); //Öffnet die erste vefügbare Kinect
 
grayImage.allocate(kinect.width, kinect.height); 
grayThreshNear.allocate(kinect.width, kinect.height); 
grayThreshFar.allocate(kinect.width, kinect.height);
 
nearThreshold = 230; 
farThreshold = 150; 
bThreshWithOpenCV = true;
 
ofSetFrameRate(60);
fbo.allocate(640, 480); //Größe des FBO Feldes 
 
fbo.begin();
ofClear(255,255,255);
fbo.end();
 
texture.allocate(640, 480, GL_RGBA); //gleiche Größe wie fbo

In den ersten drei Zeilen dieser Funktion wird die Verbindung zur Kinect-Kamera hergestellt. Danach werden dem Graustufen- und Tiefenbild (grayImage) und den zwei Schwellenwert-Bilder (grayThreshNear und grayThreshFar) sowohl die Breite, als auch die Höhe des Kinect-Kamerabildes zugewiesen. Anschließend werden die beiden Variablen nearThreshold und farThreshold initialisiert. Außerdem wird die Größe des Framebuffer Object (fbo) festgelegt. Damit sich keine Daten aus vorhergehenden Projekten im FBO befinden, wird ein Feld angelegt, mit der Funktion ofClear(...) bereinigt und wieder geschlossen. Danach bekommt die Texture die gleiche Größe, wie das Framebuffer Object.

Auf die Setup- folgt die Update-Funktion:

kinect.update();
if(kinect.isFrameNew()) { //wenn die Kinect verbunden ist und einen neuen Frame erhält
    //das Graustufen- und Tiefenbild der Kinect laden:
    grayImage.setFromPixels(kinect.getDepthPixels(), kinect.width, kinect.height);
 
    //nahes und entferntes Schwellenwert-Bild erzeugen:
    grayThreshNear = grayImage;
    grayThreshFar = grayImage; 
    grayThreshNear.threshold(nearThreshold, true); 
    grayThreshFar.threshold(farThreshold);
 
    //Vereinigung der verschiedenen Bilder erhalten:
    cvAnd(grayThreshNear.getCvImage(), grayThreshFar.getCvImage(), grayImage.getCvImage(), NULL);
 
    //CV Bild des Graustufen- und Tiefenbildes aktualisieren:
    grayImage.flagImageChanged(); 
}
 
//ContourFinder aktivieren
contourFinder.findContours(grayImage, 500, (ofGetWidth() * ofGetHeight())/2,3, false, true);

Wenn die Kinect-Kamera ein neues Bild empfängt, wird ein Graustufen- und Tiefenbild geladen. Anschließend wird sowohl ein nahes, als auch ein entferntes Schwellenwert-Bild erzeugt. Danach werden der Funktion cvAnd(...) die CV-Bilder der beiden Schwellenwert-Bilder und des Graustufen-/Tiefenbildes übergeben, um eine Vereinigung der verschiedenen Bilder zu erhalten. Danach wird das CV Bild des Graustufen- und Tiefenbildes aktualisiert. Unabhängig davon, ob die Kinect-Kamera ein neues Bild empfängt (if-Schleife), wird der ContourFinder (Konturenerkennung) mit den entsprechenden Parametern aktiviert.

Anschließend wird die Draw-Funktion initialisiert:

//Textur des FBO in die extra angelegte Textur laden:
texture = fbo.getTextureReference();
 
fbo.begin();
 
ofSetColor(0,200,200); //Farbe für texture bestimmen (dunkler) 
texture.draw(0,0,640,480);
ofSetColor(0, 209, 230); //Farbe für Spurlänge bestimmen (heller)
 
path.clear();
 
for(int i = 0; i < (int)contourFinder.blobs.size(); i++){ //für jeden Blob im ContourFinder in den Path laden
    path.clear(); //Pfad leeren 
    path.setStrokeWidth(0);
    for(int j = 0; j < contourFinder.blobs[i].nPts; j++ ){ //neuen Punkt hinzufügen 
        path.curveTo(contourFinder.blobs[i].pts[j]);
    }
 
    path.close(); //sichergehen, dass er gefüllt ist 
    path.draw();
}
 
fbo.end();
fbo.draw(0,0,(800.0/480)*640, 800);

Als erstes wird die Textur des Framebuffer Object in die angelegte texture geladen. Außerdem wird das FBO Feld geöffnet, eine dunkelblaue Farbe festgelegt und die Texture (in dieser Farbe) gezeichnet. Danach wird die Farbe auf ein helleres Blau festgesetzt, um die nachgezogene Spur in dieser Farbe zu zeichnen. In der ersten for-Schleife soll für jeden gefundenen Blob im ContourFinder die Kontur in den Pfad geladen werden. Dieser wird zuerst geleert und erhält dann (in der nächsten for-Schleife) jeden einzelnen Punkt der Kontur. Nach dieser zweiten Schleife wird der Pfad geschlossen um sicherzustellen, dass er gefüllt ist. Anschließend wird er gezeichnet. Damit endet auch die erste for-Schleife und das Framebuffer Object wird zum einen geschlossen und zum anderen ausgegeben.


miniFXpo Ausstellung

Aufbau der Ausstellung

miniFXpo: Raumplan

Die Ausstellung war geplant für den Raum BB.008, welcher über 100 Quadratmeter misst. Dieser musste zuerst ausgeräumt und gesäubert werden. Aber eine Ausstellung in Form eines Museums in einem großen viereckigen Raum stattfinden zu lassen, hat absolut keinen Charme. Daher wurden schwarze Styroporwände, welche aus 1 Meter mal 50 Zentimeter großen Styroporplatten hergestellt wurden, angebracht. Diese galt es schwarz zu streichen und in richtiger Konstruktion zusammenzusetzen. War dies erledigt, mussten die, durch den Bauschaum entstandenen Lücken zwischen den Platten, verputzt und erneut gestrichen werden. Danach ging es um die Feinheiten. Das Ausbessern von Kleinigkeiten an den Styropor-Wänden. Das Anbringen von Sicherheitsmaßnahmen. Das Aufstellen der Ausstellungsstücke, wie beispielsweise diverse Stormtrooper oder Yoda. Ebenfalls mussten die Hologramm-Präsenter zusammengebaut und dekoriert werden. Dies wurde mit Kanthölzern und verschiedenen Accessories erreicht. Am Ende stand eine perfekte Ausstellung, die an jedem Tag sehr gut besucht war.

Aufbau unserer Hardware

Nachdem alle Komponenten eingerichtet und getestet waren, müssen diese in der Ausstellung aufgebaut werden. Hierbei achten wir darauf, dass alle Computer möglichst gut versteckt sind und für den Besucher nicht sichtbar sind. Da sie hierbei hinter Vorhängen und Ausstellungs-Figuren versteckt werden, muss besonders darauf geachtet werden, dass dennoch ausreichend Luft an die Lüfter gelangt. Die Computer sind bei dieser Ausstellung circa neun Stunden in dauerhaftem Betrieb und werden dabei sehr warm. Neben den Computer ist es uns auch wichtig, dass alle Kabel möglichst unauffällig und ordentlich verlegt sind. Der Besucher soll sich auf die Ausstellungsstücke konzentrieren und nicht durch auffallende Kabel abgelenkt werden. Der Moving Head wird über den Köpfen der Besucher an einer Traverse aufgehängt. Hierbei ist es wichtig eine zweite Sicherung mit Hilfe eines Saftys anzubringen. Sollte die normale Halterung versagen, dürfen die Besucher nicht in Gefahr gebracht werden.

Computer einrichten

Für die Ausstellung selbst sollen alle Computer möglichst nur noch ein- und ausgeschaltet werden, ohne eine Maus oder Tastatur zu brauchen. Dies hilft dabei die Computer an einen Ort zustellen, an dem sie von Besuchern nicht gesehen werden können. Zudem ermöglicht es einen schnellen Neustart, falls es Probleme mit einem Programm geben sollte. Zusätzlich kann die Einrichtung eines Fernzugangs nützlich sein, wenn man doch während der Ausstellung schnell auf einen der Computer zugreifen muss.

Openbox

Unter Linux steht für solche Anwendungsfälle Openbox zur Verfügung. Openbox ist ein Fenstermanager, der sich auf die nötigsten Funktionen beschränkt.[6] Es wird eine Autostart Datei anlegen, in der konfiguriert wird, welche Funktionen beim Hochfahren des Rechners ausgeführt werden. In unserem Fall werden unsere Menü-Programme automatisch gestartet. Für alle weiteren Einstellungen gibt es eine Config-Datei im XML Format. Darin wird eingestellt, dass Programme im Vollbild starten sollen und ohne Fensterrahmen angezeigt werden. Dies ist bei uns sehr wichtig, da die pseudoholographische Darstellung sonst nicht glaubhaft vermittelt wird. Ein weiterer Punkt ist der Mauszeiger, der immer in der Mitte des Bildschirms angezeigt wird. Mit Hilfe der kleinen Linux Erweiterung „Unclutter“, welche den Mauszeiger automatisch ausblendet, solange dieser nicht bewegt wird.[7] Nach den finalen Tests der Programme in der Ausstellung, ergab sich nach einem Neustart das Problem, dass die Bildschirmauflösung nicht mehr richtig eingestellt war. Um dieses Problem sicher in den Griff zu bekommen, muss die Auflösung fest eingestellt werden. Dafür nutzen wir das Hilfsprogramm „xrandr“, mit dem eine feste Ausgabeauflösung eingestellt werden kann.[8] Mit diesen Einstellungen können die Computer per Ein-Ausschalt-Knopf sowohl Hoch-, als auch Heruntergefahren werden.

Einrichtung OS X

Die Einrichtung der MacBooks unter OS X musste schnell erfolgen, weil wir diese erst einen Tag vor Ausstellungsbeginn erhalten haben. Das MacBook für das Kinect-Menü muss komplett neu aufgesetzt werden. Dafür wurde das neuste Betriebsystem OS X 10.11 installiert. Weiter wird ein Benutzer nur für die Ausstellung erstellt, bei dem alle benötigten Programme automatisch starten. Außerdem wurde für diesen Benutzer ein Fernzugriff eingerichtet, sodass bei Bedarf von einem anderen Mac darauf zugegriffen werden kann. Das MacBook für die Todesstern-Steuerung kann nicht komplett neu aufgesetzt werden. Aus diesem Grund ist nicht das neueste OS X installiert, was zur Folge hat, dass Xcode, die Entwicklungsumgebung von Apple, nicht aus dem Mac App Store installiert werden kann. Daher können hier nur die fertigen Programme von uns gestartet und keine kurzfristigen Änderungen mehr gemacht werden. Das automatische Starten der Programme ist dennoch eingerichtet. So muss der Computer ebenfalls nur hochgefahren werden.

Weblinks

Downloads

Quellcode

Bildmaterial

Einzelnachweise

  1. http://fxpo.de/uber-uns, FXpo Homepage
  2. http://fxpo.de/spenden, FXpo Homepage
  3. https://www.netzwelt.de/gaming/microsoft-kinect.html, netzwelt
  4. http://openframeworks.cc/about, openFrameworks
  5. https://developer.leapmotion.com/documentation/csharp/devguide/Leap_Gestures.html, Leap Motion Dokumentation
  6. http://openbox.org/wiki/Main_Page, Openbox
  7. https://wiki.archlinux.org/index.php/unclutter, Archlinux, Unclutter
  8. https://wiki.archlinux.org/index.php/xrandr, Archlinux, xrandr