FORUM

Aus toolbox_interaktion
Wechseln zu: Navigation, Suche
Logo der Projektgruppe

Forum - Shaping our Future ist ein Konzept für das Deutsche Museum in Nürnberg und wurde im Rahmen einer zehnköpfigen Projektgruppe im Wintersemester 2018/2019 verwirklicht.


Inhaltsverzeichnis

Einleitung

Nahezu fünf Monate sind vergangen, seitdem sich die „deutsches Museum interaktiv“ Gruppe zusammengefunden und angefangen hat, gemeinsam an dem Ziel zu arbeiten, einen Teil zu dem, in Nürnberg entstehenden, Ableger des Deutschen Museums in München beizutragen. Im Folgenden wird das bis dato Geschaffene aufgeschlüsselt und in seine jeweiligen Schaffensebenen zerlegt. Beginnend mit der intensiven Konzeptphase, die etwa die Hälfte der Zeit in Anspruch genommen hat, über das Forum, das Zentrum des neu entstehenden Zukunftsmuseums, bis hin zu Programmierung und Erstellung eines ersten Prototypen.

Das erste Projektsemester

Konzeptionsphase

Nach der Festlegung der Projektgruppe auf die Forumsgestaltung stand fest, dass die Gruppe die Spielauswertung mit einbeziehen möchte. Die Idee unter den Stelen einen LED-Boden anzubringen, um beim Einlesen des RFID-Chips einen Effekt zu erzeugen, der sich von dem Boden aus über die Stelen ausbreitet, sollte nun weiter Gestalt annehmen. Hierzu beschäftigte man sich in einer verkleinerten Runde um die Konzeption der Spielauswertung und im Anschluss, die passende Visualisierung auf den Stelen.


LED Leitsystem

LED-Leitsystem
LED-Leitsystem

Wie auch in einer anderen, hier nicht näher erläuterten Idee von Fritz Lenssen handelt es sich hierbei, um eine lichtbasierte Installation. Wobei der Nutzen dieser größer gewesen wäre, als eine reine Installation. Wie in jedem größeren Museum auch, wird der Besucher durch große Räume, lange Gänge und einige Stockwerke geleitet. Als Orientierungshilfe dienen meist nur große Schildertafeln, auf denen aufwändig und verwirrend in verschiedenen Sprachen geschrieben steht, wo die nächste Ausstellung zu finden ist.

Durch das Installieren eines LED Leitsystems hätte eben genanntes Problem umgangen werden können. Entweder in die Wände oder den Boden eingelassen, hätten die LED Lichtstreifen nicht nur zur Orientierung beigetragen, sondern dem Zukunftsmuseum einen futuristischen Anstrich verpasst. Derartige Systeme werden vermehrt auch in öffentlichen Verkehrsmitteln verwendet, um die Menschen schneller und sicherer von Ort zu Ort bewegen zu können. Beispielsweise an U-Bahn-Stationen, in öffentlichen Gebäuden oder Flugzeugen, in denen in möglichem Notfallsituationen LED Leitsysteme zusätzlich Leben retten könnten. Wie sich im späteren Projektverlauf herausgestellt hatte, war die Anbringung eines aus LEDs bestehenden „Grids“ in Planung, welches sich sehr gut mit dem Leitsystem hätte verbinden lassen können. Das Museum hat sich ebenfalls als Ziel gesetzt, für alle Altersgruppen etwas bieten zu können. Diese Voraussetzung wäre durch diese Idee abgedeckt gewesen, sowohl für die jüngere Generation, bei denen der Erlebnis- und Staunfaktor im Vordergrund gestanden hätte, als auch bei der älteren Generation, die durch das LED Leitsystem möglichen Sehschwierigkeiten aus dem Weg hätten gehen können.



Interaktiv warten

Was ein Museumsbesuch stets auch mit sich bringt, sind durchaus längere Wartezeiten. Entweder vor dem Ticketverkauf, aber auch vor Exponaten und Installationen. Ein sich durch das gesamte Museum ziehendes, interaktives System könnte längere Wartezeiten spielerisch spannender gestalten und zusätzlich zu Dokumentationszwecken dienen. Gerade Kinder oder Schulklassen sind oft ungeduldig und das lange Anstehen fällt ihnen schwer. So brachte Fritz Lenssen die Idee auf, die Besucherzahlen in physischer Form zu visualisieren und für alle Besucher zugänglich zu machen, wobei hier keine Grenzen gesetzt gewesen wären. Seien es Steine, Quader, bunte Kugeln oder gar Wasser, welches in Behälter tropft, fällt oder fließt.

Eine solche Installation hätte sich gut im Eingangsbereich einbinden lassen, da hierfür kaum Platz benötigt wird. So hätten beispielsweise Besucher, die sich an der Kasse ihr Ticket geholt hätten, direkt im Hintergrund erfahren können, was ihr Kauf des Tickets bewirkt hat. Ausweitbar wäre das System in jeglicher Form gewesen, beispielsweise hätten zu bestimmten Zeitpunkten oder ab gewissen Füllmengen Effekte ausgelöst werden können.

Mosaik als das große Ganze

FORUM - Mosaik

Es gab eine Problematik, mit der sich die Projektgruppe, aber auch das Museum hat auseinandersetzen müssen. Der Besucher sollte das Gefühl haben, eine bedeutende Rolle in der Gestaltung der Zukunft zu spielen, da alle Menschen Teil dieser Zukunft sind und sie verändern, gestalten und zum Positiven wenden können. So entstand auch der Name der Gruppe „Forum – Shaping our Future“. Da es die Zukunft aller ist und die Welt nur funktionieren kann, wenn auch alle gemeinsam diesem Leitspruch folgen, etwas gemeinsam zu erschaffen.

Es wurden sich viele Gedanken gemacht, wie die Idee eines großen Ganzen umgesetzt werden könnte. Hierbei hatte Fritz Lenssen die Idee, ein Mosaik zu schaffen. Dieses Mosaik würde aus allen Typen der Besucher geformt werden, sodass jeder zum einen als Individuum, zum anderen als Teil eines großen Ganzen erkennbar ist.

In folgender Abbildung ist gut zu erkennen, wie das große Ganze, also das Mosaik, auf den Stelen des Forums aussehen könnte.



Augmented Reality Sandbox

Eine Idee von Daniel Mehlhorn, beruht auf einem kurzen Video-Clip, in welchem sich Personen um einen Sandkasten befinden und darin graben. Die Besonderheit liegt darin, dass es sich um einen Augmented-Reality Sandkasten handelt. Es wird interaktiv eine Landschaft geschaffen, die Berge, Täler, Flüsse und Seen darstellt. Anhand von verschiedensten Formen, die in den Sand gezeichnet werden, entsteht so die Topographie einer virtuellen Welt. Eine Verlinkung in dem Video führt zum Aufbau und der Umsetzung einer solchen Sandbox. Im Detail sieht dies folgendermaßen aus. Ein Holzkasten beliebiger Größe wird mit einer großen Menge feinem, sauberen Sand gefüllt. Über der Sandbox hängt ein lichtstarker Projektor, der die einzelnen topographischen Schichten von oben auf den Sand strahlt. Daneben ist eine Xbox Kinect. Diese ist ausgestattet mit zwei Tiefensensoren. Der linke Tiefensensor strahlt großflächig Infrarotwellen aus. Der rechte Tiefensensor fängt diese Wellen wieder ein, die von Personen, Objekten oder in diesem Fall, dem Sand, reflektiert werden. So ist es möglich die Höhe und Tiefe des Sandkastens zu ermitteln. Mit einem Computerprogramm wird nun die topographische Welt berechnet und als Bildausgabe visualisiert. So entsteht der Effekt, als könnte man mit seinen eigenen Händen eine ganze Welt schaffen und diese verändern. Besonders von Kindern würde diese Installation im Museum Anerkennung finden. Diese könnten mit einer spielerischen Herangehensweise, futuristische Innovationen zum Zwecke der Bildung nutzen. Bei intensiveren Recherchen über eine solche Augmented Reality Sandbox fällt jedoch schnell auf, dass es solche Installationen bereits massenhaft gibt. Nicht zuletzt wurde ein solches Projekt bereits von dem Studiengang Media Engineering selbst implementiert, was schnell zum Verwurf dieser Idee geführt hat.

RFID

Das museums-eigene Spiel zieht sich durch den kompletten Aufenthalt des Besuchers im Museum. Start und Ende des Spieles finden im Forum statt und ist somit Hauptgegenstand unseres Projekts. Wie das Spiel im Detail aussieht ist noch ungewiss. Bereits bekannt ist aber, dass der Besucher sich ein RFID-Armband für den Besuch holen kann. Dieses Armband dient zur Identifizierung der einzelnen Personen. Somit kann ermittelt werden, wo sich der Besucher wie lange aufgehalten hat, welche Fragen er beantwortet hat und auch wie er zu bestimmten Themen eingestellt ist. An jeder Station, die eine Interaktion mit dem Besucher erfordert, sind folglich RFID-Geräte, an denen man sich über das Armband „einloggen“ kann. Die Spielauswertung am Ende im Forum ist also abhängig von der Identifizierung über einen RFID-Chip. Die Umsetzung der Auswertung eines solchen Chips wurde verschoben auf den zweiten Abschnitt des Projekts. Dennoch wurden bereits einige Recherchen von Daniel Mehlhorn durchgeführt.


Arduino

Um nun für unseren Fall mit den Daten zu arbeiten, ist es wohl eine sehr angemessene Methode den Reader an einem Arduino-Gerät anzuschließen. Der Arduino ist eine kleine Platine mit einem Minicontroller darauf. Neben der Hardwarekomponente bietet Arduino aber auch eine Software-Komponente, mit der Programme für das Arduino-Gerät geschrieben werden können. Es handelt sich hierbei also um eine Plattform, die es ermöglichen soll, technische Projekte umzusetzen. Dabei kann Arduino verwendet werden, um interaktive Systeme zu steuern oder mit Computerprogrammen zu interagieren. An den kleinen Platinen können zahlreiche Sensoren, Lampen und Motoren verbunden werden und über ein Programm angesteuert werden, welches mittels USB auf die Platine übertragen wird. Es handelt sich hierbei um ein Quelloffenes Open Source Projekt und ist somit auf allen Betriebssystemen verfügbar. Die benötigte Programmiersprache ist C++. Es gibt auch bereits eine Vielzahl an Umsetzungen, wie ein RFID an einem Arduino ausgelesen wird. Eine sehr elegante Variante, die auch gleich den nötigen Source Code liefert, ist das Tutorial von makerblog.at vom 27.11.2017. Hier wird mit einem MFRC-522 Card Reader Module gearbeitet. Dieser beinhaltet eine RFID Karte mit unterschiedlichen UIDs und ist auch sehr kostengünstig erwerbbar. Einer der größten Vorteile der Benutzung von Arduino ist, dass es eine bereits vordefinierte Klasse ofArduino bei OpenFrameworks gibt. Daher war es die Idee von Daniel Mehlhorn, diese Technologie im Projekt mit Einfließen zu lassen.


Avatare

In einem der ersten persönlichen Treffen mit einem Vertreter des Deutschen Museums (Herr Gundelwein – Projektleiter), wurde unteranderem die Idee eines eigenen Avatars, von Daniel Mehlhorn, vorgestellt. Die Besucher des Museums könnten sich dabei zu Beginn ihres Aufenthalts einen eigenen Avatar erstellen und individuell gestalten. In einem der ersten Räume würden die Besucher getrackt und durch ihren Avatar an einem Projektionsbild an der Wand dargestellt werden. Durch Bewegungen und Gesten könnte man so seinen eigenen Avatar steuern. Die Idee wäre noch erweiterbar gewesen, indem man den Avatar immer wieder an verschiedenen Stationen im Laufe des Besuches antrifft, und so sein eigenes Profil während des Besuches füllt. Die Idee hatte den Hintergedanken, dass interessierte Studenten aus der Design Fakultät sich der Gestaltung der Avatare annehmen können und die Media Engineering Studenten könnten das Tracking umsetzen. Auch von Seiten des Museums war diese Idee positiv behaftet, es gäbe jedoch bereits ein sehr ähnliches Konzept. Die Besucher sollen durch ein gewisses Spiel während ihres Aufenthaltes begleitet werden und an verschiedenen Stationen, ihren eigenen Eingaben zufolge, den Besuch individuell gestalten. Dies ist jedoch ein äußerst zentraler Leitfaden, der sich durch das gesamte Museum zieht und somit wohl besser in Händen des Museums liegt. Es sei an dieser Stelle erwähnt, dass die Instandhaltung der Exponate einer außerordentlichen Bedeutsamkeit zuteil ist. Daher muss jede Installation vom Museum, beziehungsweise dessen beauftragten Agenturen, regelmäßig gewartet werden. Daher dienen die Ergebnisse aus der gesamten Projektarbeit lediglich zur Vorlage für spätere Umsetzungen, welche von den Verantwortlichen selbst durchgeführt wird. Mit diesem und vielen weiteren Umständen, wie der Abnahme und Genehmigung durch den TÜV und der Zugänglichkeit für alle Personengruppen, erfolgten noch weitere Treffen.


LED Tunnel

Konzept LED-Tunnel

Die Überlegung eines LED-Tunnels stammt von Tobias Lindner und Sebastian Holzki. Ursprünglich war der LED Tunnel als freistehender Aufbau mehrerer LED Panels hintereinander gedacht. Die Lichteffekte sollten steuerbar über eine Konsole mit Touch Oberfläche sein. Das Konzept wurde für das Museum angepasst. Flure und Durchgänge im Museum sollten auf allen Flächen mit Lichtstreifen ausgestattet werden. Auf diese sollte dann ein Effekt erscheinen, wenn ein Besucher hindurchläuft.



Der LED Tunnel als verbindendes Element

Bei den ersten Überlegungen und ersten Ideen, wurde viel über die Einsatzmöglichkeiten von LEDs gesprochen. So kam es dazu, dass Tobias Lindner den Einfall hatte, einen „LED-Tunnel“ installieren zu wollen. Im Grunde handelt es sich hierbei um eine Lichtinstallation, die sich tunnelförmig in allen vorstellbaren Variationen durch den Raum erstrecken könnte. Nach den Absprachen, geleitet durch Herrn Brünig und die beiden Laboringenieure, welche die ersten Wochen im Abstand von jeweils einer Woche stattgefunden haben, wurde allerdings schnell klar, dass Ähnliches so schon oft eingesetzt wird und nicht als einziges Projektergebnis am Ende stehen hätte können. Fritz Lenssen brachte folgend die Idee auf, dass es sinnvoll wäre, eine solche Installation nicht als alleinstehendes Exponat, sondern als Verbindung der einzelnen Bereiche im Museum zu nutzen. Oft sind Übergänge träge, ziehen sich lange durch verwinkelte Flure und es müssen häufig Treppen hinter sich gebracht werden. Sein Einfall hätten längere, unspektakuläre Bereichsverbindungen zu einem weiteren erinnerungswürdigen Erlebnis während des Besuches gemacht.

Gut zu verbinden wäre das mit Daniel Mehlhorns Idee gewesen, dass sich jeder Besucher vor seinem Besuch einen personalisierten Avatar erstellt, der auch die favorisierte Farbe eines jeden hätte speichern können. Somit wäre es für Sensoren an und in jedem Tunnel möglich gewesen, die individuelle Farbe des Besuchers zu erkennen und durch die LEDs wiederzugeben. Der hierdurch entstehende spielerische Aspekt, hätte vor allem für die Hauptzielgruppe, der jüngeren Generation, ein spannendes Extra sein können. Hierfür wurde von Fritz Lenssen in Kooperation mit Daniel Mehlhorn eine Idee für eine „InterApp“ entworfen, die es jedem Besucher vereinfacht hätte, sich seinen individuellen Avatar zu erstellen. In folgender Abbildung ist die Idee dargestellt, die mit Hilfe von Adobe Experience Design von Fritz Lenssen erstellt worden ist. Selbige ist ebenso im Anhang unter „InterApp“ zu finden.

InterApp

Kinetische Lichter

Messestände mit Lichtkugeln waren die Inspiration für die kinetischen Lichter. Das sind Lichtkugeln, die an einer Seilwinde befestigt sind und hoch- und runtergefahren werden können. Eine solche Lichtinstallation war auch für das Museum vorstellbar. Dabei wurden auch Erweiterungen vorgeschlagen. Neben Kugeln können auch Neon Röhren verwendet werden, oder Lichtkugeln die mit einem Laser verfolgt werden und so abstrakte Formen bilden. Sebastian Holzki und Tobias Lindner formulierten diesen Einfall.


Energy-Harvesting Boden

Die Idee für einen Strom erzeugenden Boden, ebenfalls von Tobias Lindner und Sebastian Holzki, entstand während der Vorstellung der zwei vorangehenden Konzepte. Als Erweiterung für einen LED Tunnel soll eine Energy-Harvesting Boden die benötigte Energie liefern. Besucher haben somit die Möglichkeit durch das Betreten des Tunnels einen Effekt auszulösen. Hierbei wurde auch ein didaktischer Hintergrund mit einbezogen. Indem man dem Besucher anzeigt, wie viel Energie er gerade durch das Betreten erzeugt.


Build your own city

Katharina Ott beschäftigte sich schwerpunktmäßig mit dem Bereich „Urbanes Leben“. Sie hatte die Idee ein Exponat in Form einer Stadt auszustellen. Der Wunsch hierbei war, dass die Besucher/-innen schnell und anschaulich sehen, welche Auswirkungen selbst kleinste Veränderung im Aufbau der Stadt nach sich ziehen. Diese Umgestaltungen des Stadtbildes würden durch die Besucher/-innen selbst, mit Hilfe von Virtuelle Reality, Augmented Reality oder sogar eines Multitouch-Tisches vornehmen. Würden sie zum Beispiel ein Stromkraftwerk vollständig abschalten, dann wäre am nächsten Tag nicht genügend Strom für alle Bewohner der Stadt vorhanden (Straßenbeleuchtung fällt aus).


Augmented Reality

Für Agathe Gnus war es wichtig, eine Technologie zu finden, die zum Zukunftsmuseum passt, weshalb sie sich für Augmented Reality (kurz „AR“) entschied. Gerade durch den technischen Fortschritt, immer leistungsfähiger werdenden Smartphones, wurde diese Technologie für den Endnutzer ohne Zusatzanschaffungen immer greifbarer.

Moodboard - Build your own City

Das Konzept, die Technologie auf dem Smartphone zu nutzen, löste einen Hype rund um AR aus. Durch Pokémon Go und Snapchat beschäftigten sich vor Allem Heranwachsende mit AR, kennen sich sehr gut damit aus und verstehen, dass man die Realität dadurch mit dem Smartphone erweitern und digitale Objekte im Raum visualisieren kann. So könnte man beispielsweise für die Ausstellung ein vollständig eingerichtetes Wohnzimmer, in dem man sich frei bewegen und mit dem Smartphone umsehen kann, nachstellen, um so dem Besucher die Möglichkeiten dieser Technologie aufzuzeigen.

AR - Ausstellung

Als Inhalte für die so erweiterte Realität könnten auch neue Technologien gezeigt werden, die in der Zukunft alltäglich geworden wären. Beispielsweise könnte man dafür anstatt einem TV, über ein Hologramm fernsehen. Alle technischen Geräte sowie Lampen, Türen und die Heizung wären über dieses Hologramm steuerbar. Auch gut vorstellbar wäre, dass beispielsweise, sobald sich ein Besucher auf ein Sofa setzt, automatisch eine Leselampe anginge. So würde der Besucher noch mehr Einfluss auf die Darstellungen der AR nehmen können, anstatt die Szenerie nur durch ein Smartphone zu betrachten. Alles in Allem könnte man dem Besucher durch eine AR das Leben in der Zukunft fast hautnah erleben lassen und ihm Impulse zum Beschäftigen mit dem Alltag oder den Problemen der Zukunft geben. Vor Allem Kinder und Jugendliche können durch diese Art der Darstellung einer modernen Einrichtung fasziniert werden. Diese Idee wurde letztendlich in Absprache mit Frau Saverimuthu aber verworfen, da verhindert werden soll, dass sich Besucher mit den Smartphones mehr beschäftigen als mit den Ausstellungen an sich.



Laser Audiovisualisierung

Laser Audiovisualisierung


Die Inspiration stammte von der Automarke Lexus. Für einen Stunt wurde eine Strecke gebaut, bei der die Autos des Herstellers über Lichtpunkte fahren mussten, damit eine fortlaufende Melodie abgespielt wird. Am Start wurden Laser kreisförmig um die Fahrzeuge auf den Boden projiziert, sobald ein Klang wahrgenommen wurde, ändert sich die Struktur des Kreises und wird dann in Wellen dargestellt. Sobald die Fahrzeuge die Lichtschranke überquerten, begann das Spiel.

Audio Input + Laser

Kevin Frania hatte die Idee, eine Art Tour Guide für das Deutsche Museum zu erstellen. An bestimmten Punkten in der Ausstellung sollte durch Tracking, ein Abbild des Benutzers per Laser auf die Wand gestrahlt werden. Wenn dem Besucher etwas zu einem Exponat erzählt wird, ändert sich die getrackte Silhouette des Benutzers anhand der Audio Schwingungen. Der Audio Guide und somit das Tracking, sollten durch eine Lichtschranke ausgelöst werden. Somit wäre es dem Anwesenden selbst überlassen, ob er eine Information zu der Ausstellung hören möchte, oder nicht.



Interaktives (pseudo) Hologramm

Die Idee stammt von Kevin Frania und war als Ausstellungsstück angedacht. Es handelte sich dabei um ein interaktives Spiel, bei dem der Besucher mithilfe von Gesten eine Figur steuern kann. Das sollte so funktionieren, dass der Gast sich vor das Exponat stellt, seine Bewegungen zur Steuerung getrackt werden und das Spiel dreidimensional als pseudo Hologramm dargestellt wird. Dabei gebe es auch die Möglichkeit, eine Art Multiplayer Spiel zu gestalten, bei dem mehrere Besucher teilhaben können.

Entwurf

Das Forum

Vorstellung

Mit seinen 128m2 stellt das Forum den Dreh- und Angelpunkt des gesamten Museums dar. Hier sollte sich jeder Besucher mindestens zweimal aufgehalten haben, bevor man das Museum wieder verlässt. Des Weiteren werden sich in der Mitte des Raumes sechs kreisförmig angeordnete Stelen befinden. Über jede der insgesamt 7,5m hohen und einen Meter breiten Stelen soll sich jeweils eine Bildschirmfläche von 6,5m erstrecken. Auf der Rückseite waren zu Beginn der Konzeptphase noch Spiegelflächen angedacht, die zum jetzigen Zeitpunkt (Februar 2019) allerdings schon nicht mehr aktuell sind und noch überdacht werden. Weiterführend war die Installation von GoBo Lights geplant, die Anregungen, Wünsche und Gedanken der Besucher an die Wände des Forums hätten strahlen sollen.

Sowohl die Projektgruppe, als auch Prof. Dr. Heinz Brünig und die beiden Laboringenieure Daniel Baer und Johannes Brendel hatten ihre Bedenken, ob dieses Vorhaben so auch umsetzbar ist.

Das Forum sollte nicht nur als Ort der Zusammenkunft dienen, sondern auch zentraler Teil des sich durch das Museum ziehenden Spiels sein. Das Spiel, gekoppelt mit dem Forum, nutzte die Projektgruppe, um konzeptionell arbeiten zu können. Es entstanden folgend erste konkretere Ideen, wie eine Visualisierung der gesammelten Spieldaten im Forum hätte aussehen können. Das Problem hierbei war und ist es nach wie vor, dass die Zuständigen selbst noch rein konzeptionell arbeiten und es kaum tatsächliche Vorstellungen gab. So waren der Gruppe vorerst jedoch keine Grenzen gesetzt. In einem weiteren Treffen mit den Verantwortlichen, an dem auch die Architektinnen des Gebäudes teilnahmen, stellte Fritz Lenssen die Herausforderungen dar, die durch verspiegelte Rückseiten der Stelen und die GoBo Lights entstehen könnten (vgl. „Herausforderungen_Präsentation“ im Dateianhang). Unter anderem sind hier die drei auffällig großen Wandfenster problematisch, die zusätzlich auch noch zur Südseite ausgerichtet sind und das Forum somit den ganzen Tag mit Tageslicht durchfluten. Daher müssten die Projektoren besonders lichtstark sein, was wiederum den Preis deutlich in die Höhe getrieben hätte.

Die Gruppe wollte die Visualisierung der Spieldaten mit Hilfe von Partikelsystemen verwirklichen, die sowohl auf den Stelen, als auch auf dem, von Herrn Frieder Weiss ins Spiel gebrachten, LED-Boden in Mitten der Stelen stattfinden soll. Die Präsentation der Idee traf allgemein auf positive Resonanz und die gemeinsame Arbeit konnte fortgesetzt werden. Das Museum soll in fünf unterschiedliche Themengebiete unterteilt werden, welche die Besucher/-innen, während des Besuches im Museum, durchlaufen und erleben sollen.

Die Themengebietet lauten:

a. Urbanes Leben

b. System Erde

c. Raum und Zeit

d. Körper und Geist

e. Arbeit und Alltag

Diese fünf Bereiche sind wiederum durch ein öffentliches Forum verbunden. In diesem Forum können sich sämtliche Besucher/-innen treffen, um sich über Erlebtes auszutauschen, aber auch um über die eigenen Erfahrungen im jeweiligen Themengebiet in Ruhe nachzudenken und auf sie sich wirken zu lassen. Ein herausstehendes Merkmal unseres Projektes ist es, dass wir erst einmal unsere Ideen frei entfalten durften, da es keine Einschränkungen von Seiten der Projektinitiatoren gab. So entstanden über Wochen hinweg mehrere Ideen, wie wir für das Deutsche Museum einen Beitrag leisten können. Diese konnten wir dann in mehreren Treffen mit Herrn Gundelwein, Frau Saverimuthu und anderen Kollegen des Deutschen Museums vorstellen und ausführlich besprechen.

Entwurf der Spielauswertung

Im Zuge der Konzeptphase für das Forum hatte sich die eine Untergruppe, die sich mit der Spielauswertung auf den Stelen beschäftigt haben, gebildet. Die während den regelmäßigen Besprechungen der Teilgruppe gefassten Beschlüsse wurden von Agathe Gnus schriftlich festgehalten und im Nachhinein zu einem Bericht zusammengefasst, sodass alle auf dem neuesten Stand waren.

Daniel Mehlhorn und Jana Gumbert entwickelten hierfür eine Möglichkeit für die Spielauswertung.

Das Deutsche Museum kommunizierte bereits Überlegungen zum Thema „Spiel/ Tool“. Bekannt ist, dass in jedem der fünf Themenbereiche ein bis zwei Spielstationen existieren, die alle zur Auswertung genutzt werden können. Die Idee des Deutschen Museums war es, den Besucher anhand seiner Entscheidungen in drei verschiedene Typen einzuteilen. „Technik“ wäre ein neutraler Besucher, dessen Interesse in die Richtung Science ginge. Für eine Einschätzung der „Utopie“ stellt sich der Besucher seine Zukunft positiv vor. Die „Dystopie“ hingegen erhält man bei negativer Zukunftsvision. Basis dessen ist die Beantwortung von JA/NEIN/NEUTRAL –Fragen bzw. sollen Aufgaben oder Probleme dem Spielenden präsentiert werden. Die Kritik hierbei war, dass eine dystopische Einordnung auch einen negativen Eindruck bei jenem Besucher hinterlässt. Daher war die Idee interessant, mit Farben zu arbeiten, die jeweils einen Themenbereich symbolisieren.

Je nach Einordnung des Besuchers für einen Themenbereich in „interessiert“ bzw. „nicht interessiert“ wird die Themenfarbe durch die Partikel nun stark und hoch saturiert bzw. schwach und verblasst dargestellt. Positiv wäre hierbei, dass dem Besucher kein negativer Eindruck vermittelt wird. Problematisch könnte hierbei sein, dass der Besucher kein eindeutiges Ergebnis für sich herauslesen kann. Möglich wäre eine Einordnung zu lediglich einem Themenbereich als Typus des Besuchers, oder das Anzeigen aller Farben der Themenbereiche. Das Auftreten der roten Partikel repräsentiert dann das prozentuale Interesse des Besuchers für den roten Themenbereich. Zusätzlich zu der Farbe, soll auch ein Bild oder ein Symbol durch die Partikel gebildet werden. Dies soll ein Wiederfinden des Besuchers garantieren und für einen Überraschungseffekt sorgen. Die Idee ein Symbol je Themenbereich auszugeben, wirft das Problem auf, dass aufeinanderfolgendes Einlesen das gleiche Symbol auslösen können, da nur fünf verschiedene Möglichkeiten existieren. Daher kam der Lösungsansatz wie bei der Farbdarstellung den Besucher als interessiert oder nicht interessiert einzustufen. Hierdurch ergeben sich zwei Optionen je fünf Themenbereiche. Mathematisch ausgedrückt:

2 Einordnungen 5 Themenbereiche

25 = 32 Optionen.

Für die Visualisierung der Spielauswertung war angedacht, ein Partikelsystem zu benutzen, mit dem sowohl Symbole als auch schöne Effekte erzeugt werden können. Mit diesem Partikelsystem wurde ein Ablauf definiert, nach dem sich jede Spielauswertung richtet:

1. Nachdem Daten über ein RFID Armband eingelesen wurden, lösen diese eine Farbexplosion, die auf dem LED-Boden simuliert wird, aus. Die von dort ausgehende Welle setzt sich auf den Stelen-Monitoren fort. Wir beschlossen die Farbmischungen wie folgt auszuwählen:

Körper & Geist: #FF00FF

Urbanes Leben: #848484, #2ECCFA

System Erde: #3ADF00, #704828

Arbeit & Alltag: #FFFF00

Raum & Zeit: #890085

2. Alle Partikel bewegen sich zu einer Stele und bilden die Kontur eines Symboles. Welche Farben und Symbole verwendet werden sollen, kann das Programm anhand der Informationen auf dem Besucher-RFID-Chip des Armbandes erkennen.

Die Kontur löst sich schließlich nach oben auf, die einzelnen farbigen Partikel steigen in die Höhe und bilden mit Anderen einen Teil eines Partikelwirbels (siehe unten). Dadurch können alle Spielergebnisse, z.B. der vergangenen Tage, durch dieses farbcodierte Gebilde dargestellt werden.


Entwurf des Großen Ganzen

Partikelsystem

Für die Konzeption des Großen Ganzen, wurde folgende Überlegung von Jana Gumbert entwickelt. Zu erwähnen ist, dass die Idee aus Gesprächen mit dem Deutschen Museum entsprang. So wurde erwähnt, dass das Forum ein wichtiger Teil sei um den einzelnen Besucher mit einzubeziehen und ihn an der Gestaltung der Zukunft teilhaben zu lassen. Dazu passend entstand die Idee der schwebenden Wolke für die Visualisierung des Großen Ganzen in das sich das typisierte Bild jedes Besuchers auflöst. Die Zukunft ist nicht für jeden gleich darstellbar und ist in seiner Gänze nur wage zu erahnen.

Die Wolke soll in ständiger Bewegung sein und pulsieren um zu zeigen, dass unsere Zukunft sich durch die Entscheidungen im Hier und Jetzt verändert und anpasst. Wie der Besucher im gegenwärtigen Museumsspiel entscheidet, trägt zur Gestaltung der Wolke und damit der Zukunft bei. Außerdem symbolisiert die Wolke eine nicht greifbare Form, die jeden Gast zu Eigeninterpretationen anregt. Dies ist passend, da es der Wunsch des Museums war keine eindeutige Zukunftsversion zu präsentieren, da schließlich keine existiert. Die bereits erwähnten Symbole werden durch die Partikel gebildet. Dabei hat Agathe Gnus sich überlegt, ob es nicht interessant wäre, die Symbole so zu bilden, dass Partikel, die zu dem Symbol gehören, sich mittels Linien verbinden. Doch es wurde erst einmal entschieden, die Partikel nicht zu verbinden. Jedoch hier zwei Beispiele, wie diese Idee aussehen könnte.

Mögliche Erweiterung des Partikelsystems

Bei der Überlegung, wie die Darstellung des Gesamtergebnisses aussehen soll, einigte sich die Teilgruppe uns auf zwei Möglichkeiten: Es sollte auf die Stadt Nürnberg eingegangen werden und so sollten sich die Partikel die Skyline Nürnbergs in der Zukunft abbilden oder sich zu einem Wirbel formen.

Es wurde sich dazu entschieden, die Partikel in einen Wirbel in den oberen Drittel der Monitore der Stelen darzustellen, da die Darstellung der Skyline schwer umsetzbar ist, wenn zu wenige Partikel vorhanden sind.

Der Wirbel ist leichter umzusetzen, da dieser sowohl mit wenigen als auch mit vielen Partikeln machbar ist. Zudem kommt die Mischung der einzelnen Partikelfarben besser zur Geltung.

Entwurf für die Stelen

Die Untergruppe „Spielauswertung auf den Stelen“ wurde weiter unterteilt in „Animation“ und „Spielauswertung“. Das gesamte Projektteam entwickelte zunächst ein Partikelsystem, welches innerhalb eines vorgegebenen Frame-Zeitfensters eine fest definierte Anzahl an farbigen Partikeln instanziiert. Durch Realisierung einer fiktiven Anziehungskraft werden diese Partikel in Richtung des Zentrums des Mauszeigers angezogen, sobald sich dieser in unmittelbarer Nähe befindet. Hiermit wurde über die Nutzerinteraktion eine visuelle Veränderung des zugrundeliegenden Bildmaterials umgesetzt. Partikel sollen bereits auf den Stelen existieren und in Bewegung sein. Kommt nun ein Besucher und liest seinen Chip ein, formatieren sich die Pixel zu einem Bild. Der Besucher wird typisiert und ein Bild entsprechend seines Typus auf den Stelen ausgegeben. Der obere Teil der Stelen, in etwa 1/3, soll permanent eine Version des Großen Ganzen zeigen. 2/3 sind daher für die Darstellung eines Bildes für den Besucher zu verwenden. Das Bild löst sich nach kurzer Zeit (etwa 10 sec) in seine Partikel/ Einzelteile auf und schwebt nach oben.

Partikelansammlungen

Obige Illustration zeigt die Ansammlung der Partikel zu einem farbigen Bild und das Wandern nach oben ohne die Berücksichtigung des Großen Ganzen und wurde von Jana Gumbert angefertigt. Dies diente als Vorlage für die anschließende Programmierung des Partikelsystems.

Bevor das Team „Spielauswertung“ mit der Entwicklung begonnen hat, machte sich jedes Teammitglied Gedanken über das Design der Spielauswertung. Um den Teammitgliedern das Design präsentieren zu können erstellte Katharina Ott Grafiken, welche die Vorstellungen über das Design visualisiert.

Möglicher Ablauf von Spielauswertungen

Agathe Gnus arbeitete zusätzlich noch an der Idee mit der Skyline weiter.

Spielauswertung mit Erweiterung des Großen Ganzen als Stadt

Die Abbildungen zeigen die von uns visualisierte Spielauswertung. Im ersten Bild sieht man die Explosion der Partikel, sobald ein RFID Armband eingelesen wird. In den darauffolgenden beiden Bildern erkennt man wie die Symbole aus den Partikeln gebildet werden. Die nächsten zwei Bilder zeigen wie sich die Symbole wieder in Partikel auflösen und in die Skyline (in der Endumsetzung Wirbel) ziehen. Im letzten Bild wird die Skyline detailliert dargestellt. Analog dazu zeigen die folgenden Bilder die Explosion und den Aufbau von anderen Symbolen.

Design - Symbolbildung

Entwurf des Tornadoeffekts

Das Konzept sieht vor, dass die Partikelsysteme des Bodens und der Stelen in einer noch nicht definierten Art und Weise miteinander agieren sollten. Da die Stelen kreisförmig angeordnet sind, bot es sich an, die gesamte zylinderartige Fläche zu nutzen. Um die gesamte Höhe der Stelen ausnutzen zu können, hatte Fritz Lenssen die Idee, die Partikel am oberen Rand des Fensters entstehen und schneefallartig fallen zu lassen. Des Weiteren sollte sich die Bewegungsrichtung der Partikel ab einem bestimmten Zeitpunkt ändern und somit die Partikel zur oberen Kante zurückkehren. Da sich die Bewegungsrichtung sowohl in x, als auch y-Richtung verändern soll, entsteht durch die kreisförmige Anordnung der Stelen ein selbsternannter „Tornado“ – Effekt. Hintergrund der Überlegung war es, dass sich am Ende des Spielauswertungsprozesses ein großes Ganzes, dessen Form zu diesem Zeitpunkt noch unklar war, formen sollte.

Ein grob skizzierter Ablauf des Effekts ist den nachfolgenden Abbildungen zu entnehmen.

Entwurf des Besuchertrackings

Da das Museum und die Gruppe besonders viel Wert auf Interaktivität legen wollten, entstand die Idee des Besuchertrackings. So sollte es dem Besucher möglich sein, mit den Partikelsystemen sowohl auf dem LED-Boden, als auch auf den Stelen zu interagieren. Das Konzept sah vor, dass Besucher, die sich über den Boden bewegen, getrackt werden und die Partikel fußspurenartig den Besuchern folgen. Weiterführend sollte möglich gemacht werden, dass sich jeder Besucher an einer RFID Station einlesen kann, damit die individuellen Daten ausgelesen werden können. Nach dem Auslesen der Daten soll eine Art Typisierung auf den Stelen stattfinden, damit sich jeder Besucher mit seiner persönlichen Vorstellung der Zukunft auseinandersetzen kann. Hierbei sollten sich ab dem Punkt des Einlesens, Partikel in allen erdenklichen Farben, über den Boden hinweg die Stelen hinaufbewegen.

Programmierung

Das Partikelsystem allgemein

Die Projektgruppe hatte sich relativ früh schon darauf geeinigt, die Visualisierung der Spieldaten mit Hilfe von Partikelsystemen realisieren zu wollen. Da es das Ziel der Gruppe war, zum größten Teil die eigene Arbeit in den Prototypen mit einfließen zu lassen, wurde nahezu vollständig auf fertigen Code verzichtet. Unter Leitung von Herrn Brendel entstand ein erstes Partikelsystem, an dem vorerst die gesamte Gruppe mitwirkte. Vorteil hierbei war es, dass sich alle von Grund auf mit dem Partikelsystem auseinandergesetzt haben, was essentiell für die weiteren Arbeitsschritte war. Grundsätzlich ging es zu Beginn vor allem darum, die Funktionsweise der Partikel, den Aufbau des Systems nachvollziehen zu können und sich in das System einzuarbeiten. Zu diesem Zeitpunkt wurde entschieden, inwiefern jeder am Projekt mitwirken möchte. Es entstanden somit kleine Teilgruppen, die jeweils an einem Thema gemeinsam gearbeitet haben. Eine Gruppe setze sich weiterhin mit dem „Counter Finder“ basiertem Programm auseinander, welches im weiteren Verlauf die Grundlage für das Trackingsystem bildete. An sich besteht das Partikelsystem aus einem Emitter, der in regelmäßigen Abständen neue, in der eigens erstellten Partikel Klasse definierten, Partikel entstehen lässt. Grundsätzlich werden hierbei neue Partikel in einem dynamischen Vektor gespeichert („.push_back“) und durch den „.back“ - Befehl kann dann auf das letzte neu hinzugefügte Element zugegriffen werden. Durch den eben genannten Befehl und den Verweis auf die setup()-Methode durch einen „Pointer“ kommt es zum Entstehen der Partikel in der Mitte des vordefinierten Fensters.

system.push_back (new thParticle);
system.back()->setup(ofVec2f(ofGetWidth()*0.5, ofGetHeight()*0.5));

In der eben angesprochenen Partikel Klasse wird beispielsweise festgelegt, welche Form die einzelnen Partikeln haben sollen. Ein Partikel hat folgende Eigenschaften: Position (pos), Geschwindigkeit (vel), Alter (age), maximale Lebensdauer (maxLife), Farbe (color), Größe (size) und Gewicht (mass). Die Werte der Parameter sind durch Testreihen mehrerer Einstellungen entstanden. Diese waren abhängig von der definierten Auflösung und der zur Verfügung stehenden Rechenleistung.

this->position = _position;   
vel.set(ofRandom(-3.0, 3.0), ofRandom(-3.0, 3.0));  
age = 0.0;  
maxLife = 12.0;  
color.set(250, 250, 250);
size = ofRandom(1.0, 0.01);  
mass = ofRandom(100, 250);

In diesem Fall wurde durchgehend ein „ofDrawCircle (pos, size)“, also ein gefüllter Kreis mit einer festgelegten Position und Größe gezeichnet. Eine Bewegung entstand durch ein stetiges Addieren der „velocity“ (zweidimensionaler Richtungsvektor) auf die aktuelle Position des Partikels.

Partikelsystem LED-Boden

Zu Beginn der Programmierarbeit war die Konzeptphase noch nicht weiter vorangeschritten. Somit entschied sich die Gruppe vorerst für ein einziges Partikelsystem, an dem Fritz Lenssen und Tobias Lindner gleichzeitig mitwirkten. Eine der ersten Veränderungen war es, den von sich aus weißen Partikeln eine andere Farbe zu verleihen. Zusätzlich wird die Transparenz mit voranschreitender Lebensdauer verringert, bis die Partikel schließlich verblassen. Des Weiteren fügte Fritz Lenssen einen visuell deutlich ansprechenderen Farbverlauf hinzu, dessen Transparenz langsam weniger wurde.

Möglich gemacht wurde das mit Hilfe der ofMap (value, inputMin, inputMax, ouputMin, outputMax) – Funktion, die einen selbstbestimmten Farbverlauf auf die Farbe der Partikel überträgt.

ofColor color = ofColor::red;
float hue = ofMap( age, 100, maxLife, 128, 255 ); 
color.setHue( hue );
ofSetColor(color, (1 - age/maxLife)*255 );

Da das Konzept für den LED-Boden vorsah, die Besucher zu tracken und ihnen die Möglichkeit zu geben mit dem Boden interagieren zu können, wurde zusätzlich eine Anziehungskraft hinzugefügt. So war es nun möglich, dass wenn sich etwas über den Boden bewegt, Partikel in einem festgelegten Radius angezogen und gebündelt werden. Hierbei wurden Partikel, die sich weiter weg befunden haben, schneller angezogen, als welche, die sich näher am sich bewegenden Objekt befanden. Als Zusatz, der so auch im finalen Code übernommen wurde, fügte Fritz Lenssen eine Addition zur Größe des Partikels in Abhängigkeit der Anziehungskraft hinzu. Mit voranschreitender Konzept- und Entwicklungsphase kam die Projektgruppe zu dem Schluss, dass es sinnvoll wäre, ein weiteres unabhängiges Partikelsystem aufzusetzen, dass alleine für die Stelen entwickelt werden sollte. Fritz Lenssen hatte sich folgend dazu entschieden, das System für die Stelen aufzusetzen und das System für den Boden an Tobias Lindner abzugeben, der mit ihm gemeinsam an dem Bodensystem gearbeitet hatte. Der bis zu diesem Zeitpunkt entstandene Code (particleSystem_01) ist der beigefügten Datei zu entnehmen.

Erste Effekte für Partikel

Zu diesem Zweck übernahm Tobias Lindner die Aufgabe, alleine an dem Partikelsystems des LED-Bodens weiter zu wirken. Das Partikelsystem besteht aus Kreisen ofCircle. Ohne Änderungen bewegen sich nur Kreise auf dem Bildschirm. Zu Beginn hat jeder Partikel eine vorgegebene Farbe color. In der draw() Methode der Klasse particle wird die Farbe und die Transparenz basierend auf dem Alter des Partikels verändert. Über getAgeNorm()wird das aktuelle Alter in normalisierter Form eines Partikels abgefragt. Hiermit können RGB Farbwerte zwischen 0 und 255 erzeugt werden. Die Partikel alternieren in ihrer ersten Lebenshälfte zwischen einem Cyan und Dunkelblau. Wenn sie von einem Attraktor angezogen werden ändert sich die Farbe in einen violetten Farbton. Ebenso können mit dieser Methode Partikel mit einem Alpha Wert ausgeblendet werden.

color.set(getAgeNorm() * 241,241/ getAgeNorm() ,219);  
ofSetColor(color, (1 - getAgeNorm()) * 255);  
ofDrawCircle(position,size);

Attraktoren, Tracking und Kommunikation zwischen Programmen

Das Partikelsystem am Boden braucht Koordinaten, um Attraktoren auf dem Boden setzen zu können. Dazu ist eine Kommunikation zwischen dem Tracking und dem System auf dem Boden notwendig. In Zusammenarbeit mit Sebastian Holzki wurde die Klasse Attraktor und die zugehörige OSC Kommunikation umgesetzt. Dabei wurde die Software Entwicklungs Strategie Pair Programming eingesetzt.

Erstellung der Klasse Attractor

Es sollen mehrere Personen gleichzeitig getrackt werden können. Deswegen ist es notwendig mehrere Attraktoren gleichzeitig aktiv laufen zulassen. Eine Klasse attractor ermöglicht es mehrere Instanzen eines Attraktors anzulegen attractors.at(index)->setup(xPosition,yPosition). Zunächst werden acht Attraktoren ohne Koordinaten angelegt. Diese werden mit den Mittelpunkten aus dem Tracking gefüllt und aktiviert.

Anziehung der Partikel an Attraktoren

Attraktoren ziehen Partikel innerhalb eines Radius von 150 Pixeln an. Der Abstand force eines Partikels errechnet sich aus der Differenz zwischen der x und y Position des Attraktors und der Position des Partikels. Anschließend wird definiert mit welcher Kraft der Attraktor einen Partikel zu sich zieht. Da nun die Kraft bestimmt ist, muss sie noch auf die aktuelle Geschwindigkeit vel addiert werden. Dabei muss auch das Gewicht mass des Partikels mitberücksichtigt werden. Wird ein Teilchen angezogen vergrößert sich auch seine Größe size mit einem zufälligen Wert pro Update. So werden angezogene Teilchen größer. Befindet sich ein Partikel nicht in der Nähe eines Attraktors, wird die aktuelle Position, bei gleichbleibender Geschwindigkeit, aktualisiert und das Alter age erhöht.

force.set(attractors->at(i)->getX() - position.x, attractors->at(i)->getY() - position.y);  
       if (force.length() < 150) {  
           force = 60 * force.getNormalized();  
           size = size + ofRandom(.01, 0.01);  
           vel += force;  
           vel = mass * vel.getNormalized();  
       }  
       else {  
           force = 0 * force.getNormalized();  
           vel += force;  
           vel = mass * vel.getNormalized();  
       }  
   }  
   age += deltaT * .5;  
   position += (vel * deltaT);

Partikelsystem Stelen

Umsetzung und Herausforderungen - Tornadoeffekt

Ausgangslage für das Partikelsystem der Stelen war das System der Bodeninstallation. Nun ging es darum, die Idee des „Tornado“ – Effekts in die Realität umzusetzen. Federführend, war hierbei Fritz Lenssen. Grundsätzlich war klar, dass die Partikel stets fallen, irgendwann aufhören neu zu entstehen und daraufhin ihre Bewegungsrichtung umkehren sollten. Gesteuert werden sollte der Ablauf durch den Einsatz der „keyReleased“ – Methode, die sowohl das Entstehen der Partikel, als auch die Richtungsumkehrung steuert. Wie im obigen Teil bereits erwähnt, entstehen die Partikel an der x-Achse, während der y-Wert gleich 0 ist. Jeder einzelne Partikel hat hierbei eine unterschiedliche positive Bewegungsrichtung, damit sie alle eine grundsätzliche Fallrichtung besitzen. Solange der Benutzer, in diesem Fall, der, der Befehle per Tastendruck erteilt, nicht eingreift, passiert vorerst weiter nichts mit den Partikeln. Besonders wichtig für den Effekt des Tornados ist es, dass die Partikel nach einer gewissen Zeit oder eben durch einen Tastaturbefehl aufhören zu entstehen. Denn falls die Partikel weiter entstehen würden, hätten sich die bereits umgekehrten Partikel mit den noch fallenden, überlagert und es wäre nicht zu dem Eindruck eines Wirbels gekommen. Folgend konnte die Methode, die neue Partikel entstehen hat lassen, durch einen boolean (life) gesteuert und per Drücken der Taste ’l‘ ein und ausgeschalten werden. Weiterführend beschäftigten sich Danial Eshete und Fritz Lenssen damit, eine Methode zu entwickeln die für das Umkehren der Bewegungsrichtung (velocity) verantwortlich ist und diese dann wiederum durch ein boolean (tornado) und die Taste ’t‘ hat gesteuert werden kann. Die Idee war es, dass sich die velocity ab einem vordefinierten Vektor (grenze) umkehrt und sich die Partikel zurück nach oben bewegen. Das Umkehren übernahm hierbei eine Addition eines neu definierten Vektors bei jedem Aufruf der update() – Methode auf die bestehende velocity.

partikel->vel += ofVec2f(ofRandom (1.5,2), ofRandom (0.5, 0.8)*(-1));

Besonders wichtig war es hierbei, den y-Wert zu negieren. Hinzuzufügen war noch, dass Partikel, die den rechten Rand verlassen am linken Rand wiedererscheinen. Möglich gemacht wurde das durch eine Abfrage der x Position eines jeden Partikels. Zu Testzwecken und zur Aufwertung des Systems wurden an jener Grenze neue Farbwerte definiert.

Der bereits erwähnte Wunsch von Fritz Lenssen war es, den Tornado nicht als reinen Block aufsteigen, sondern ab einer weiteren vordefinierten Grenze in eine Sinusbewegung übergehen zu lassen. Vorerst sollte hierzu eine Farbänderung der Partikel an „grenze2“ stattfinden, um auf dieser Basis weiterarbeiten zu können. Es entstanden jedoch mehrere Problematiken, derer sich die beiden hatten annehmen müssen. Zum einen erkannten beide, dass wenn die Partikel nicht aufhörten zu entstehen und der Tornado – Befehl bereits ausgeführt worden ist, die Partikel bereits auf die Funktionsinhalte ab „grenze2“ hörten, statt zuerst die erste Grenze zu passieren und im Anschluss die zweite. Nach einigen Tests und Versuchen, ist festgestellt worden, dass der auslösende Befehl auf das gesamte System ausgeübt worden ist, statt die einzelnen Partikel anzusprechen. Zum anderen stellte die Wandlung in eine sinusartige Bewegung eine deutlich höhere Herausforderung dar, als angenommen. Fritz Lenssen hatte zunächst versucht durch die Veränderung der Position der Partikel, einen Sinuseffekt zu erwirken. Im Anschluss daran versuchte er es über die Formel y = sin(x) erreichen zu können und wollte den y-Wert der velocity verändern. Weder das eine, noch das andere klappte. So entschieden sich Danial Eshete und Fritz Lenssen für dieses Semester auf einen derartigen Effekt zu verzichten und das bestehende System reibungsloser und funktionstüchtiger zu gestalten. Den Stand bis zu diesem Zeitpunkt ist dem „ParticleSystem02“ zu entnehmen.

Als folgenden Schritt machte es sich Fritz Lenssen zur Aufgabe, den Code übersichtlicher und leichter nachzuvollziehen zu machen und ihn aufzuwerten. Im Vergleich zum vorangegangenen Code hatte sich vorerst, bis auf ein kleines Detail, dass die Größe der Partikel etwas variabler ist, nicht viel verändert. Die Partikel entstanden nach wie vor an der oberen Kante und fielen schneefallartig. Auffällig beim veränderten Code ist es vor allem, dass überflüssige Codeabschnitte weggelassen worden sind und grundsätzlich umstrukturiert wurde. So wurde beispielsweise die Methode zur Tornadoentwicklung in mehrere Teilschritte aufgeteilt. Die neue Idee war es, dass sich die Partikel zu Beginn des Effekts erst bündeln sollten und sich im Anschluss daran die Richtung umkehren sollte. Gleichgeblieben ist hierbei, dass die Partikel den rechten Rand der Applikation verlassen und am linken Rand wiederauftauchen.

Für das Bündeln der Partikel ist folgender Codeauszug wichtig. Hierbei werden die Partikel zu jenem festgelegten Part im Fenster, durch das Neusetzen der velocity (vel), gezogen und gebündelt.

void particle02::startTornado() {
   int distance = pos.y - ofGetHeight()/3.5*3;
   vel.y = -distance/2;

Im Anschluss werden die Partikel zu einem etwas breiterem Balken aufgespannt, die Bewegung wird umgekehrt und der eigentliche Tornadoeffekt beginnt. Hierbei, wird wie im vorangegangenen Code, ebenso eine veränderte velocity zu der Bestehenden dazu addiert und die Partikel werden beschleunigt. Es ist zusätzlich noch ein Timer von 15 Sekunden eingestellt, der bei Beginn des Tornados das zählen beginnt und nach Ablauf des Timers, nachdem der Tornado bereits die Applikation wieder verlassen hat, zurück zur Ausgangslage kehrt. Der für diesen Effekt vorerst finale Code ist unter dem Namen „ParticleSwitch“ zu finden.

Umsetzung und Herausforderungen - Spielauswertung

Das Partikelsystem, welches zu Beginn vom gesamten Team mit Hilfe von Herrn Brendel entwickelt wurde, diente dem Team „Spielauswertung“ als Basis für ihre Implementierung. Für die eigentliche Spielauswertung sollten die Partikel jedoch nicht mehr von einem Mauszeiger angezogen werden, sondern sollten sich mittels neuer Attraktoren zu einem Symbol formen. Dies wurde von Agathe Gnus, Jana Gumbert und Daniel Mehlhorn gemeinsam mit Herrn Brendel realisiert. Zunächst werden die Bilder, die dargestellt werden sollen, in dem bin/data Ordner abgelegt. Wichtig ist, sich im Vorfeld zu vergewissern, ob die richtige Größe bereits existiert bzw. sie anzupassen, damit sie zu der Bildschirmgröße passt. In unserem Falle sollte das Bild ca. zwischen 400 und 500 Pixel groß sein (z.B. 450x450).

void ofApp::setup() {
  ofSetBackgroundColor(0, 0, 0);
  ofSetFrameRate(60);
  maxParticle = 50;
  fileImage.load("Ohm.png");
  attractors = pixelInVector(fileImage);
}

In der setup-Methode in ofApp.cpp wird das Bild hochgeladen. Das Problem, dass sich zunächst die Partikel nur um die Kontur des Bildes formatierten, wurde im Folgenden gelöst. Ein Vektor zur Speicherung der Bildpixel bot sich an, da er dynamisch ist. Zunächst greift man auf das Bild zu und schreibt die Breite bzw. die Höhe in zwei Integer. Außerdem holt man sich die Pixelanzahl des Bildes. Wichtig hierbei ist, dass das Bild einen transparenten Hintergrund besitzt, ansonsten würde auch der Hintergrund gezeichnet werden. Anschließend in einer for-Schleife geht man die Pixel durch und prüft in der if-Abfrage, ob überhaupt ein Pixel vorhanden ist. Um die y und x Werte herauszurechnen teilt man durch den Wert Vier um die Informationen von R,G,B und die Transparenzinformation herauszurechnen, da sie nicht benötigt wird. Für int y wird durch die Breite geteilt und int x erhält man durch Modulo 4.

vector<ofVec2f> ofApp::pixelInVector(ofImage a) {
  int picWidth = a.getWidth(); 
  int picHeight = a.getHeight();
  ofPixels pix;
  pix = a.getPixels();
  vector<ofVec2f> pxPos;
   for (int i = 3; i <= pix.size(); i += 4) {
    if (pix[i] > 0) {
     int width = pix.getWidth();
     int y = i / 4 / width;
     int x = i / 4 % width;
     ofVec2f vec;
     vec.set(x + ((ofGetWidth() / 2) - picWidth / 2), y + ((ofGetHeight() /2) - picHeight / 2));
     pxPos.push_back(vec);
     picPix++;
     }
 }
  return pxPos;
}

Durch den dynamischen Vector, kann jedes beliebige Bild eingelesen werden. Dieser Code wurde gemeinsam mit Daniel Mehlhorn erarbeitet.

void theParticle::update(float deltaT, ofVec2f attractor, bool deleteAttractor, bool noAttractor){
  age += deltaT;
  ofVec2f force = attractor - position; 
   if (force.length() < 200) {   
    force = 30 * force
   }else {
   force = 10 * force.getNormalized(); 
   }
}

In der particle.cpp Datei wird festgelegt wie stark die Partikel zum Attraktor gezogen werden sollen und welchen Abstand zwischen Attraktor und Partikeln existieren soll, wie oben abgebildet, die „force.length“. Die Anziehungskraft wird force bezeichnet. DeltaT ist das Zeitintervall seit dem letzten Update. Die zwei booleans deleteAttractor und noAttractor sind in der particle.h Datei initiiert.

if (deleteAttractor == true){
  attractor.set((ofRandom(0, ofGetWidth())), ofRandom(0, ofGetHeight() / 8));
  ofVec2f force2 = attractor - position;	
  velocity2 += force2 / 50;  
  velocity2 = (mass / 12)* velocity2.getNormalized
  position += (velocity2)*2
}

Wenn der boolean deleteAttractor auf true gesetzt wird, wird der Attraktor neu gesetzt und die velocity2 regelt die Bewegungsgeschwindigkeit zum Attraktor. Durch position ist es möglich, dass die Partikel nicht statisch an ihrem Attraktor kleben bleiben, sondern der Effekt des umher schwirrens entsteht.

Sobald die Partikel ein gewisses Alter erreicht haben, sollten sich diese wieder von dem Attraktor des Symbols lösen und eine Wolke am oberen Fensterrand bilden. Damit soll sowohl die Zukunft der Gesamtheit der Besucher/-innen dargestellt, aber auch gezeigt werden, dass jedes Individuum Einfluss auf die Entwicklung der Erde hat. Katharina Ott gelang die Realisierung der Wolke durch die Neuplatzierung des Attraktors am oberen Rand des Anwendungsfensters.


Ablauf - Spielauswertung

Um die visuelle Darstellung aufzuwerten, entschieden Agathe Gnus und Katharina Ott der Wolke einen neuen Farbwert zuzuordnen. Nach einigen Herausforderungen den Code für jedes Teammitglied zugänglich zu machen entschied sich die Gruppe „Stelen“ im Rahmen der Projektarbeit für die Verwendung eines Git-Repositories auf Github. Die Gruppe „Spielauswertung“ entschied sich für Github, da Katharina Ott in ihrem Praxissemester mit Git schon einige gute Erfahrungen gemacht hatte. Durch dessen Verwendung konnten die Mitglieder remote an einer gemeinsamen Code-Basis arbeiten. Die Git eigene Versionskontrolle ermöglichte darüber hinaus selektive Rücksprünge auf vorherige Programmversionen, um ungewünscht auftretende Fehler bei der Programmierung rückgängig machen zu können. Durch Git wurde auch ermöglicht, Änderungen an Dateien der jeweiligen Person zuordnen zu können. Jegliche Änderungen, die während der Projektdauer an den Branches des Projekts getätigt wurden, sind bis zur initialen Erstellung des Repositories nachvollziehbar und transparent. Um die Funktionalitäten von Github innerhalb der Programmierumgebung Visual Studio verwenden zu können, wurde von Katharina Ott eine Github Extension installiert. Somit kann unter Angabe der Accountdaten Visual Studio mit dem Github Backend verbunden werden. Des Weiteren unterstützt Git einen Vorgang namens Merging. Führen zwei oder mehrere Personen Änderungen am gleichen Programmmodul durch, kann es zu sich überlagernden Änderungen und daraus resultierenden Versionskonflikten kommen. Merging ermöglicht, diese Änderungen auf eine gemeinsame Basis zu bringen, bevor sie Änderungen auf den Remote Server gepushed werden. Nach erfolgreicher Implementierung der Wolke, lag der Schwerpunkt weiterer Arbeiten auf der Optimierung der visuellen Darstellung. Agathe Gnus und Katharina Ott entwickelten eine Funktion, welche sämtliche Partikel der Wolke nach dem Ablauf ihres maximalen Alters transparent werden lässt. Dies führte zu einem restlosen Auflösen der Wolke. Allerdings sollte sich die Wolke nicht komplett auflösen. Sie sollte lediglich durch eine geringere Anzahl von Partikeln dargestellt werden. Das Verringern der Partikelanzahl konnten Agathe Gnus und Katharina Ott stattdessen durch die Implementierung einer Funktion, die Partikel per Knopfdruck löscht, erreichen.

Um die Wolke und das Symbol unabhängig von der Zeitkomponente zu erstellen, wurde von Katharina Ott eine Nutzerinteraktion (Tastendruck) eingeführt. Bei Tastendruck wird der jeweilige Boolean auf „true“ gesetzt und bei der update-Methode der Partikel-Klasse übergeben. Dadurch kann in der Partikel-Klasse der Boolean abgefragt werden und die Bewegung der Partikel zu den Attraktoren gesteuert werden. Falls kein Tastendruck erfolgt, bewegen sich die Partikel frei im Fenster.

Des weiteren gelang es Katharina Ott durch eine kleine Änderung im Programm (Typanpassung), das System macOS kompatibel zu machen. Das Team „Spielauswertung“ musste sich für die nächste Entwicklungsphase im nächsten Semester detaillierter mit der Auswertung und den verschiedenen Symbolen befassen. Das Team beschloss für jeden Themenbereich zwei Bewertungen zu bestimmen (Pro oder Contra des jeweiligen Themenbereiches). Das bedeutete, dass insgesamt 32 verschiedene Typisierungen entstehen können. Um hierfür die Symbole suchen oder erstellen zu können entwarf das Team ein Excel-Sheet. Die verschiedenen Typisierungsmöglichkeiten wurden dann unter den Teammitgliedern aufgeteilt, somit kann jedes Mitglied passende Symbole für nächstes Semester heraussuchen.

Verbindung von Spielauswertung und Animation

Für die Projektpräsentation im Februar mussten das Team „Spielauswertung“ und das Team „Animation“, bestehend aus Fritz und Danial, ihre Partikelsysteme zusammenfügen. Da Danial und Fritz auf einem macOS Gerät arbeiteten und das Programm für die Präsentation auf Windows laufen muss, entschied sich das Team „Stelen“ das Programm auf dem Windows Laptop von Katharina Ott zusammenzusetzen. Anschließend wurden von beiden Teams die ofApp-Dateien beider Systeme zusammengefügt und erstmals die beiden Partikel-Klassen in ein gemeinsames Projekt geladen. Die Partikel-Klasse des Teams „Spieleauswertung“ wurde nach und nach in die Partikel-Klasse des Teams „Animation“ eingearbeitet. Das stellte das Team vor die Herausforderung die Setups und Updates für beide Systeme anzupassen und Namensgebungen von einem ins andere System zu übernehmen. Die Update-Methode der Spielauswertung konnte problemlos in die Methode der Animation übernommen werden. Nach umfangreichem Testen fand Katharina Ott heraus, dass die Setup-Methode der Spielauswertung auch für die Animation auf den Stelen übernommen werden konnte. Dem Team „Stelen“ gelang es so eine Codegrundlage zu schaffen, welche es ermöglichte das Programm in Visual Studio zu bauen. Um die Funktionsfähigkeit beider Systeme zu gewährleisten, mussten von Katharina Ott zusätzliche Tasten in das System der Stelen-Animation eingefügt werden, um bei der Präsentation die jeweiligen Effekte unabhängig von Zeitfaktoren ablaufen zu lassen. Nachdem beide Codeteile für die Stelen erfolgreich zusammengefügt wurden, führte Katharina Ott zudem noch ein Coderefactoring durch. Katharina Ott gelang es erfolgreich die Partikelanzahl individuell anzupassen, um bei Bedarf überschüssige Partikel zu löschen und fehlende zu erstellen. Fritz Lenssen und Katharina Ott beschlossen gemeinsam für die Präsentation mehrere Bilder in das Programm einzufügen. Dazu suchten sie drei Bilder heraus und entschieden sich für das Ohm-Logo, das Projekt Forum-Logo und einen „Danke“ Schriftzug.

Partikelsystem

Um die Bilder präsentieren zu können musste noch eine Lösung gefunden werden, wie mehrere Bilder eingelesen und gleichzeitig die Attraktoren für die Partikel gesetzten werden können. Lösungsweg von Fritz Lenssen und Katharina Ott: Im Setup werden die Bilder in das Programm geladen.

void ofApp::setup(){
  ofSetBackgroundColor(0,0,0);	
  ofSetFrameRate(60);
  maxParticle = 50;
  fileImage1.loadImage(“Ohm.png”);
  fileImage2.loadImage(“FINAL_Logo.png”);
  fileImage3.loadImage(“Danke_40470_2.png”);
}

Danach kann bei Knopfdruck der jeweilige Attraktor gesetzt werden.

void ofApp::keyReleased(int key){
  switch (key) {
  …
  //---------// ab hier laden der unterschiedlichen Bilder
  case '1':						//Bild 1: Ohm
    attractors = pixelInVector(fileImage1);
    symbolAttractorIsSet = true;
    cloudAttractorIsSet = false;
    tornadoIsFinished = true;
    drawAllPixel = false;
    break;
  case '2':						//Bild 2: Forum-Logo
    attractors = pixelInVector(fileImage2);
    symbolAttractorIsSet = true;
    cloudAttractorIsSet = false;
    tornadoIsFinished = true;
    drawAllPixel = false;
    break;
  case '5':						//Bild 3: Danke
    attractors = pixelInVector(fileImage3);
    symbolAttractorIsSet = true;
    cloudAttractorIsSet = false;
    tornadoIsFinished = true;
    drawAllPixel = true;
    break;
    }
}

Da die Pixelanzahl der Bilder variiert und dadurch unterschiedlich viele Partikel benötigt werden, kümmerten Fritz Lenssen, Jana Gumbert, Agathe Gnus und Katharina Ott sich darum, die Pixel je nach Bedarf automatisch zu erstellen oder zu löschen. Vorgehensweise: • Es wird pro Frame eine bestimmte Anzahl an Partikeln erstellt. Diese Partikel entstehen am oberen Rand des Fensters. Das geschieht so oft, bis der Status geändert wird, oder sich ein Symbol bilden soll • Wenn die Stelen-Animation abgelaufen ist, und für das jeweilige Symbol nicht genügend Partikel vorhanden sind, werden automatisch Partikel an beliebiger Stelle im Fenster generiert • Falls zu viele Partikel für dieses Symbol vorhanden sind, werden die überflüssigen Partikel gelöscht

time += deltaT;
  if((birthCnt >=0) && (status == -1) && (tornadoFinished == false)){
   for(int i = 0; i < paramount; i++){
    system.push_back(new particle02);
    system.back()->setup(ofVec2f(ofRandom(0,ofGetWidth()),0),20);
  }	
  birthCnt = 0;
  }
   else if ((tornadoFinished == true) && (system.size() < picPix / 7)){
    int newPix = (system.size() - picPix / 7);
    for (int i = 1; I <= newPix; i++){
    system.push_back(new particle02);
    int y = ofRandomHeight();
    int x = ofRandomWidth();
    system.back()->setup(ofVec2f(x, y),20);
    }	
  }
  else if ((tornadoFinished == true) && (system.size() > picPix / 7)){
   int newPix = (picPix / 7) – system.size();
   for (int i = 0; I <= newPix; i++){
   delete sytem.at(i);
   sytem.erase(system.begin() + i);
  }	
}

Auch nach dieser längeren Coding-Phase führte Katharina Ott ein weiteres Coderefactoring durch, um den Code wieder auf einheitlichen und korrekten Stand zu bringen. Dies bezog sich vor allem auf überschüssige Leerzeichen oder Absätze, Namensgebung und auch auf das Schreiben von Kommentaren. Für die Präsentation musste der Quellcode anschließend in das Mapping-Programm von Herrn Brendel auf einen der Hochschulrechner eingefügt werden. Hierbei stellte sich heraus, dass die Addons, welche das Team verwendete (ofxCv und ofxOpenCv), noch nicht mit in das Programm eingebunden worden waren. Diese fügte Katharina Ott nachträglich hinzu, wobei beim Einbinden von ofxCv ein Fehler auftrat. Eine Header-Datei konnte nicht gefunden werden. Diese fehlte im Addon-Verzeichnis. Um den Fehler zu beheben kopierte Katharina Ott den ofxCV Ordner von ihrem Laptop auf den Hochschulrechner. Anschließend kümmerten Fritz und Katharina Ott sich darum, dass die Bilder die richtige Größe für das Modell haben und an der richtigen Stelle angezeigt werden. Bei der Positionierung und dem Setzen der Attraktoren griff das Team auf „getWidth“ zu. Da man hierbei auf den gemappten Bereich zugreifen wollte, mussten Fritz und Katharina Ott dies durch die „sceneSize“ austauschen. Auf die „sceneSize“ musste ebenfalls bei allen Abfragen zugegriffen werden. Des Weiteren haben Fritz und Katharina Ott noch einmal die Anzahl der Partikel für die kleinere Modellgröße angepasst. Die Kommentare wurden abschließend von Agathe Gnus und Katharina Ott ein letztes Mal bezüglich der Änderungen angepasst. Zum Ende unserer Codearbeiten sieht unser Partikelsystem mit seinen Animationen wie folgt aus:

Partikelsystem

OSC-Kommunikation

Die OSC-Kommunikation wurde von Sebastian Holzki, Kevin Frania und Tobias Lindner umgesetzt.

OSC-Sender

Grundsätzlich stellt sich bei interaktiven Systemen die Frage, wie Sensor-, Kamera- oder allgemein Inputdaten an das verarbeitende System gelangen, wenn keine unmittelbare Verbindung über ein Kabel besteht. Auf unterschiedlichen Gebieten der Mediensteuerung hat sich OSC (kurz für Open Sound Control) bewährt. Es handelt sich um ein Netzwerkprotokoll, das folglich voraussetzt, dass kommunizierende Systeme sich im selben Netzwerk befinden müssen, was meist über WLAN oder Ethernet realisiert wird. Schließlich kann über die Definition von Ports und klaren Bezeichnungen der OSC-Nachrichten garantiert werden, dass die richtigen Daten vom richtigen System interpretiert werden. Beispielhaft soll im Codeauszug auf der folgenden Seite das Packen der OSC-Nachricht im behandelten Trackingsystem betrachtet werden.

if (cam.isFrameNew()){
       if(contourFinder.nBlobs){
           oscMessageAttractors.clear();
           oscMessageAttractors.setAddress("/centroidsOfBlob");
           if(contourFinder.nBlobs >= 8){  
               contourFinder.nBlobs = 8;
           }
           oscMessageAttractors.addIntArg(contourFinder.nBlobs);
           for(int i = 0; i < contourFinder.nBlobs ; i++){
           oscMessageAttractors.addFloatArg(contourFinder.blobs.at(i).centroid.x / WIDTH);
           oscMessageAttractors.addFloatArg(contourFinder.blobs.at(i).centroid.y / HEIGHT);
           }
           if(stopOSC == false){  
               sender.sendMessage(oscMessageAttractors);
           } else {
               stopOSCTimer += 1;
               if(stopOSCTimer > 100){
                   stopOSC = false;
                   stopOSCTimer = 0;
               }
           }
           oscMessageAsString = ofToString(oscMessageAttractors);
       }

}

Um performanter zu arbeiten, packen wir nur dann Nachrichten, wenn zum einen ein neues Kamerabild vorliegt, zum anderen muss gewährleistet sein, dass es überhaupt erkannte Konturen gibt, also getrackte Objekte (Besucher auf dem LED-Boden). „contourFinder.nBlobs“ ist äquivalent zu „contourFinder.nBlobs > 0“. Anschließend wird die OSC-Nachricht benannt, damit der OSC-Receiver (OSC-Empfänger) später die korrekte Nachricht ausliest. Für das Forum wurde die maximale Anzahl an Konturen auf 8 gesetzt, wobei dieser Wert nach oben skalierbar ist. Den Aufbau einer OSC-Nachricht kann man sich wie folgt vorstellen:

Verpacken von fünf erkannten Konturmittelpunkten in eine OSC-Nachricht

Noch vor Iteration durch die Koordinatenpaare der Konturmittelpunkte wird die Anzahl der Blobs an Stelle 0 der OSC-Nachricht gespeichert. Anhand dieses Werts weiß später der Empfänger, wie viele Koordinatenpaare er zu erwarten hat. Der Nachricht werden für jede erkannte Kontur Wertepaare von floats hinzugefügt, welche in Bezug zu Auflösung des Kamerabildes auf einen Wert zwischen 0 und 1 normalisiert werden, um in der Zielanwendung unabhängig auf andere Dimensionen skaliert werden zu können. Die übrigen Zeilen stellen die erste Implementierung des RFID Konzepts dar, indem die OSC-Nachricht nur geschickt wird, wenn stopOSC == false gilt, was auch der default-Einstellung entspricht. Per Tastendruck am Trackingsystem (später RFID-Checkin) wird diese boolean auf true gesetzt, woraufhin ein Timer hochzuzählen beginnt. Erreicht dieser einen Wert über 100 wird der Timer auf 0 und stopOSC wieder auf false gesetzt. Dadurch die Sendeblockade aufgehoben und für den nächsten Checkin vorbereitet.

OSC-Receiver

Auf der Empfängerseite, die für das LED-Boden-Partikelsystem zuständig ist, findet ein ähnlicher Prozess, nur in umgekehrter Reihenfolge statt. Für das Verständnis des folgenden Codeexzerpts genügt es, zu verstehen, dass es sich bei attractors in der letzten Codezeile (ungeachtet die letzten schließenden Klammern) um eine Art Container handelt, in welchen eine variable Anzahl an Koordinatenpaaren gepackt werden können und dessen Größe sich in Echtzeit an seiner Befüllung orientiert. Jedes Partikel zieht sich dann in jedem update()-Durchlauf alle nötigen Informationen über die übergebenen Koordinatenpaare, welche als Attraktoren, also Anziehungspunkte arbeiten.

while(receiver.hasWaitingMessages())
   {
       
       ofxOscMessage contourCentroids;
       receiver.getNextMessage(contourCentroids);
       if(contourCentroids.getAddress() == "/centroidsOfBlob")
       {
           
           nBlobs = contourCentroids.getArgAsInt(0);
    
           for(int i = 1; i < nBlobs; i++){
           
               xOfCentroid = contourCentroids.getArgAsFloat(i*2 - 1) * ofGetWindowWidth();
               yOfCentroid = contourCentroids.getArgAsFloat(i*2) * ofGetWindowHeight();
           
               attractors.at(i-1)->setup(xOfCentroid, yOfCentroid);
           
           }
       }
   }

Das Auslesen einer Nachricht findet nur dann statt, wenn am Receiver-Eingang auch Nachrichten „warten“. Es wird eine OSC-Nachricht erstellt, um die kommenden Informationen speichern zu können. Daraufhin wird die Adresse der Nachricht auf Übereinstimmung mit der im Sender definierten Adresse überprüft. Der Receiver merkt sich nun, wie bereits angekündigt die Anzahl der empfangenen Blobs, um die kommende for-Schleife korrekt abarbeiten zu können. Das Zwischenspeichern der Koordinaten in xOfCentroid und yOfCentroid dient der besseren Lesbarkeit des Codes. Da das Argument an Stelle 0 der OSC-Nachricht von der Information über die Anzahl an Konturen belegt war, rutschten die Koordinatenpaare jeweils auf Position 1 und 2, 3 und 4, usw. Daraus resultieren die auf den ersten Blick „wilden“ Positionsangaben (i*2-1) und (i*2) für getArgAsFloat.

Mit diesem aussichtsreichen Kommunikationszwischenstand soll nun weitergearbeitet werden, um das Partikelsystem auch sinnvoll auf in dieser Form erstellte Informationen reagieren zu lassen.

Tracking eines Farbpunktes

Zu Beginn sollte grundsätzliches Basiswissen zu Tracking und Bildverarbeitung im Allgemeinen geschaffen werden. Diese Einarbeitung erfolgte unter Zuhilfenahme eines ausführlichen openFrameworks-Leitfadens in die Thematik der Bildverarbeitung. Erstes Ziel war das erfolgreiche Bestimmen eines einzelnen Punktes in einem in Echtzeit aktualisierenden Kamerabild. Dies wurde von Sebastian Holzki durchgeführt. Das Ansteuern einer externen Kamera und das Einstellen selbiger, sowie das Kennenlernen verschiedener openFramework-Addons, waren wichtige Lernerfolge für unser Forumsprojekt. Eine der einfachsten Methoden zur Bestimmung eines Punktes ließ sich schließlich mithilfe eines Farbtrackers realisieren.

widthOfImage = img.getWidth();
       heightOfImage = img.getHeight();
       leastDistance = 255;
       xOfPixelWithClosestColor = 0;
       yOfPixelWithClosestColor = 0;
       for(int i=0; i<widthOfImage; i++)
       {
           for(int j=0; j<heightOfImage;j++)
           {
               ofColor colorAtXY = img.getColor(i, j);
               float rAtXY = colorAtXY.r; //schreibe R-Wert aus Color in rAtXY
               float gAtXY = colorAtXY.g;
               float bAtXY = colorAtXY.b;
               
               //Distanz der Farbwerte
               
               float rDif = rAtXY - rTarget;
               float gDif = gAtXY - gTarget;
               float bDif = bAtXY - bTarget;
               float colorDistance = sqrt(rDif*rDif + gDif*gDif + bDif*bDif);                
               if(colorDistance < leastDistance){
                   leastDistance = colorDistance;
                   xOfPixelWithClosestColor = i;
                   yOfPixelWithClosestColor = j;
               }
           }
       }

Hierbei wird das Bild in x- und y-Ausbreitung (widthOfImage und heightOfImage) Pixel für Pixel durchgeprüft und der RGB-Wert an jedem so getesteten Koordinatenpaar mit dem von Grün (RGB(0,255,0)) verglichen. Begonnen wird mit dem ersten Pixel, was auch direkt als „ähnlichstes“ gespeichert wird, da noch kein weiterer Bildpunkt geprüft wurde und die Variable „leastDistance“ noch den Wert 255 hat. Jedes Mal, wenn der Farbwert eines Pixels ähnlicher ist, als der aktuell gespeicherte Wert für „leastDistance“, wird dieser überschrieben. Nach kompletter Iteration durch alle Bildpunkte bleibt im Speicher das Koordinatenpaar (xOfPixelWithClosestColor, yOfPixelWithClosestColor) welches den „grünsten“ Farbwert enthält. An diese Koordinaten kann nun in der draw-Methode beispielsweise ein ofCircle (eine Kreistextur aus openFrameworks) gezeichnet werden.

Über das Pixel mit dem Farbwert, der RGB(0,255,0) am ähnlichsten ist, wird ein weißer Kreis gemalt

Über diese Art zu tracken, lässt sich wiederum nur ein Punkt bestimmen und auch dieser liegt nicht ruhig im Bild, sondern zittert, in Abhängigkeit von Lichtverhältnissen und Größe der grünen, zu erkennenden Fläche.

Die Hintergrund Subtraktion

Um Besucher tracken zu können, wurde von Kevin Frania und Sebastian Holzki, eine neue Methode implementiert: die Hintergrund-Substraktion. Das ContourFinder Beispiel aus openFrameworks hat eine gute Grundlage für das Trackingsystem geschaffen. Allerdings war dabei das Problem, dass mehr Konturen in einem Bild erkannt worden sind, als erwünscht. Somit wäre es unmöglich eine gute Qualität zu erreichen.

Um dieses Problem zu lösen, muss eine Hintergrundsubtraktion stattfinden. Die Funktioniert so, dass ein Standbild aufgenommen wird, indem sich keine bewegenden Objekte befinden. Wenn jetzt eine Veränderung im Bild geschieht, wird das Grauwertbild der originalen Aufnahme vom Screenshot abgezogen. Dadurch werden zuerst nur weiße Pixel erkannt. Aus der Ansammlung der weißen Pixel, werden im nächsten Schritt die Konturen gebildet.

       grayImage = colorImg;
       if (bLearnBackground == true){
           grayBg = grayImage;
           bLearnBackground = false;
       }
       grayDiff.absDiff(grayBg, grayImage);
       grayDiff.threshold(threshold);
       contourFinder.findContours(grayDiff, minArea, maxArea, threshold, false);

Mit grayImage = colorImg; wird das Grauwertbild (2) des live Bildes (1) erstellt. Durch die if-Abfrage kann ein Screenshot dann gespeichert werden (3). Um jetzt eine Differenz aus dem live Bild und dem erstellten Bild machen zu können, wird die Funktion grayDiff.absDiff(grayBg, grayImage); abgerufen. Hier wird das live Bild, das als Grauwertbild dargestellt wird, von dem aufgenommenen Graustufenbild subtrahiert (4). Im letzten Punkt (5) werden jetzt die erkannten Konturen dargestellt. Über den threshold wird jetzt die Empfindlichkeit definiert. Damit lässt sich einstellen, ab welchem Punkt ein weißer Pixel erkannt werden soll.

Hintergrundsubtraktion

RFID mit Mikrocontroller

Wie schon einleitend erwähnt, plant das Museum ein Spiel für den Rundgang durch das Museum. Im Forum soll sich der Besucher mit einem RFID Armband einchecken können und so einen Effekt auf dem Boden und Stelen auslösen. Ebenso soll dieser Effekt als Spielauswertung dienen. Da schon viel in der eigenen Freizeit, von Tobias Lindner, mit Mikrocontrollern experimentiert wurde, waren die benötigten Komponenten für eine RFID Station bereits vorhanden. Diese konnten für das Projekt Forum angepasst werden. Im späteren Verlauf entschloss sich das Team nur ein Prototyp in kleineren Maßstab zu bauen. Deshalb wurde die weitere Entwicklung der RFID Komponente in den zweiten Projektabschnitt verlegt.

Hardware Aufbau mit Arduino

Der Aufbau der RFID Station besteht aus einem esp8226 Mikrocontroller Board und einem mfrc522 Reader Modul. Beide wurden mithilfe von Jumper Kabeln verbunden. Der blaue RFID Chip soll das Armband im Museum simulieren. Der Chip kann in einen Abstand von maximal 5 cm eingelesen werden.

Hardwareaufbau RFID mit esp8226 und mfrc522

Senden einer OSC Nachricht bei einlesen

Mit dem RFID Chip soll der Effekt auf LED Boden und den Stelen ausgelöst werden. Dafür ist eine Kommunikation zwischen der einlese Station und dem Partikelsystem notwendig. Da schon Tracking und LED Boden über OSC kommunizieren, wurde auch hier OSC verwendet. Hierzu war es zunächst notwendig den esp8226 über Wlan mit dem Netz zu verbinden und den mfrc522 Chip zu initialisieren. Wenn ein Chip in der Nähe ist mfrc522.PICC_IsNewCardPresent()sendet die einlese Station eine OSC Nachricht mit der Adresse /checkin an die definierte IP-Adresse des LED Boden Systems.

void loop() {  
   if (mfrc522.PICC_IsNewCardPresent()) {  
     OSCMessage msg("/checkin");  
     Udp.beginPacket(outIp, outPort);  
     msg.send(Udp);  
     Udp.endPacket();  
     msg.empty();  
     delay(500);  
   }  
} 

Prototypenbau

Für die Projekt Präsentationen der Projektgruppe wurde ein Prototyp gebaut, der den Stand des Projekts repräsentieren und außerdem das Potenzial der Technik aufzeigen sollte.

Planung

Bei der Planung für den angedachten Prototypen, kam Sebastian Holzki und Stefan Maurer, unter Abstimmung mit Herrn Brendel, schnell der Gedanke auf, die original Maße des Forums zu reduzieren und ein abstraktes Modell des Forums nachzubauen. Entschieden wurde sich für eine groben Maßstab 1:11. Der Led-Boden konnte im Modell ohne größere Probleme durch einen von der Hochschule zur Verfügung gestellten Bildschirm simuliert werden. Die Stelen wurden ebenfalls im Maßstab 1:11 umgesetzt. Jedoch bat sich eine Reduktion der Anzahl der Stelen, von sieben auf nur drei, an. Diese Anzahl reichte vollkommen aus, um das Potenzial der Videostelen ausreichend zu demonstrieren. Ebenso änderte sich die Anordnung der Stelen. Statt sie im Kreis um den LED-Boden anzuordnen entschied man sich für eine lineare Anordnung an einer der Seiten des Led-Bodens. Somit war das Bespielen der „Videostelen“ mittels eines einzelnen Beamers zu bewerkstelligen und es musste nicht jede Stele mit einem eigenen Gerät bestrahlt werden, was den Aufwand erheblich reduzierte, jedoch keinen Einfluss auf den gewünschten Präsentationszweck hatte.

Der Aufbau der Prototypen sollte sich wie folgt darstellen. Auf einem Tisch sollte der Bildschirm flach, mit dem Bildschirm nach oben und waagerecht, gelagert werden. Auf diesen Monitor sollte dann eine Holzkonstruktion aufgelegt werden, auf der eine Plexiglasscheibe ein Zerkratzen des Bildschirms, im Ausschnitt des LED-Bodens, verhindern sollte. Im späteren Verlauf des Aufbaus wurde entschieden, die Plexiglasscheibe aufgrund der geringen Materialstärke direkt auf dem Fernseher zu anzubringen und die Holzkonstruktion darüber aufzulegen. Um ein Verrutschen zu vermeiden, wurden alle aufgelagerten Teile auf dem Monitor mit Klebeband temporär zusammengefügt. Die Holzkonstruktion hatte die Aufgabe, sowohl den Bildschirmbereich so zu begrenzen, dass nur der für die Präsentation relevante Bereich sichtbar ist, als auch die drei hölzernen Stelen zu tragen. Diese Konstruktion wurde abermals mit Klebeband, gegen ein verrutschen gesichert. Die Maße des Prototyps waren vom Maßstab und der Bildschirmhöhe des Monitors angegeben. So wurde der LED-Boden auf dem Prototyp mit einer quadratischen Fläche mit je 47cm Länge präsentiert. Die Stelen wiesen eine Breite von 10cm auf und eine Höhe von 44cm. Angesetzt wurden sie in einer Entfernung von 5cm vom Rand des „Led-Bodens“, mit einem gleichmäßigen Abstand.

Baumarkteinkauf

Nachdem die erste Planung abgeschlossen war, war es Zeit das benötigte Material einzukaufen. Hierzu fuhren Kevin Frania und Stefan Maurer zu einem Baumarkt, um dort alles nötige zu beschaffen.

Erster Prototyp

Der erste Aufsatz, der für den Monitor entstand, war eine 90x90cm und 1cm starke verleimte Pressspanplatte. In der elterlichen Werkstatt von Stefan Maurer wurde dann zentral, mit Hilfe von Kevin Frania, ein quadratisches Loch in die Platte eingesägt mit den Abmessungen 47x47cm. Die Platten für die Modelle der Videostelen, bestanden aus weiß laminierten matten MDF- Platten, die für den Zweck des Bespielens durch einen Beamer eine ideale Oberfläche boten. Die Stelen wurden mit Halbrundhölzern verklebt, um sie auf der Trägerplatte aufbringen zu können. Um eine möglichst effektive Verbringung auf der Trägerplatte zu ermöglichen wurden die Halbrundhölzer im unteren freien Bereich abermals mit Halbrundhölzern verklebt, sodass einen kreisrunde Trägersäule für die Modelle der Stelen entstand, da die benötigten Löcher in der Trägerplatte so deutlich einfacher zu bohren waren. Die Träger der Stelen wiesen einen Durchmesser von 1cm auf. Bei der Sägung des quadratischen Ausschnitts, zeigte sich aber schnell, dass das falsche Material bei der Platte gewählt worden war. Durch die Sägung mit einer Stichsäge entlang der Holzmaserung, war es im Schnittverlauf immer wieder zu unschönen Absplitterungen des Holzes gekommen. Auch ein weiteres Behandeln der Stellen, mit Schleifpapier brachte keine signifikante Verbesserung.

Zweiter Prototyp

So wurde die Entscheidung von Stefan Maurer getroffen eine neue zweite Trägerplatte zu konstruieren, bei der vier einzelne Platten, so miteinander verklebt werden sollten, dass sie in der Mitte ein Quadrat mit Maße 47x47cm aufwiesen, um die Notwendigkeit des Sägens und dem damit verbundenen Risiko von unsauberen Schnittkanten zu verhindern. Die abermals im Baumarkt erworbenen Platten sollten die gleichen Grundabmessungen haben, wie die erste Trägerplatte und zusammen an der äußeren Kante wieder ein Quadrat von 90x90cm ergeben. Mit der Prämisse, dass das innere Quadrat wieder die Abmessung 47x47cm haben sollte, ergaben sich je zwei Platten mit den Abmessungen 47x21,5cm und zwei mit den Abmessungen 90x21,5cm. Da die verleimte Pressspanplatte im ersten Versuch sich als nicht ideales Material erwiesen hatte, wurden die neuen Platten aus 1cm starken MDF-Platten vom Baumarkt zugesägt. Die MDF-Platten hatten zumal den Vorteil, dass sie hundertprozentig eben und nicht verzogen waren. Der Zuschnitt im Baumarkt war auf Anfrage Millimetergenau präzise, so dass es möglich war durch Verleimung der Stöße mit einem entsprechenden Kleber, ein nahezu perfektes Ergebnis bei den Abmessungen zu erhalten. Zuerst war die Frage offen, ob eine Verleimung an den Stößen der Platten, mit einer Stärke von 1cm genügend Stabilität aufweisen würden, um die nötige Stärke in der Bindung zu erzeugen, jedoch erwies sich der verwendete Kleber, mit dem Regale und Möbeln an Wänden verklebt werden, als äußerst stark und so war keine weitere zusätzliche Verstärkung der Verleimung an den Stößen nötig. Danach wurden die Bohrungen, zum Verbinden der Stelen in der Trägerplatte mit einem Lochschneider mit Durchmesser 1cm in die Trägerplatte eingesägt. Der ursprüngliche Plan sah es vor, die Stelen fest mit der Trägerplatte zu verkleben, dieser Plan wurde allerdings verworfen, um ein leichteres Transportieren zu ermöglichen. Außerdem erwiesen sich die eingesägten Löcher für die Stelen als so präzise, dass mit Hilfe eines Mantels aus Isolierband ein Stecken möglich war, das trotz der fehlenden Verleimung ausreichend Festigkeit aufwies, um die Stelen zu tragen und fest in Position zu halten.

Aufbau in der TH

Der Aufbau des Prototyps in den Räumen der Technischen Hochschule erwies sich dank der vorangegangenen Planung als nahezu problemlos, brauchte aber dennoch Zeit und wurde von der ganzen Projektgruppe gemeinschaftlich durchgeführt. Der Aufbau der Monitor-Trägerplattenkonstruktion ging schnell von statten und wurde wie schon erwähnt unter Verwendung von Klebeband, um ein verrutschen auf dem Tisch zu verhindern, schnell umgesetzt. Die Einrichtung des Tracking-Systems wurde von Sebastian Holzki und Kevin Frania umgesetzt. Dazu wurden unteranderem verschiedene Kamerapositionen und Kameraeinstellungen, für ein sauberes Tracking, ausprobiert. Bei ersten Versuchen hatte die Gruppe Probleme mit dem Infrarotlicht, da Spiegelungen über den Bildschirm entstanden sind. Diese Spiegelung hat uns zusätzliche Punkte generiert, weshalb Partikel zu einem Punkt angezogen wurden, der eigentlich nicht als Objekt zählte. Zur Lösung wurde das Licht etwas seitlich aufgehängt, dadurch wurde die Fläche gleichmäßiger beleuchtet. Die Kamera selbst hingegen, musste so positioniert werden, dass nur der LED Boden, bzw. der Bildschirmausschnitt im sichtbaren Bereich für die Kamera liegt. Desweitern wurde ein Beamer installiert, um dem Aufbau entsprechend, die Holz-Stelen zu bespielen. Über ein Mapping-System, welches speziell für die Projektgruppe, von Herrn Brendel entwickelt worden ist, wurde das Partikelsystem der Stelen ausgespielt. Am Tag vor der Präsentation erhielt der Prototyp noch ein schwarzes Stoffkleid von Tobias Lindner, um die hölzerne Konstruktion und alle Technik verschwinden zu lassen.


Projektmanagement

Ab dem 10. Dezember 2018 erhielt Stefan Maurer die verantwortungsvolle Aufgabe, die Gruppe als Projektmanager zu leiten und löste Tobias Lindner als Vorgänger ab.

PM-Management Tool

Eine der ersten Aufgaben als Projektmanager war es, ein geeignetes Management-Tool zu finden, über das die Gruppenmitglieder kommunizieren konnten, aber auch zeitliche Absprachen erfolgen konnten und natürlich auch Aufgaben verteilt werden konnten. Zu Beginn stand hierfür, dass für die Studenten über eine Hochschul-Lizenz kostenlos zur Verfügung stehende Projektmanagement-Tool „Microsoft Planner“ zur Diskussion und wurde auch als solches verwendet. Allerdings stieß man bei der Bedienung und bei der Konnektivität mit der nötigen Lizenz schnell auf Herausforderungen. So konnten nicht alle Projektmitglieder problemlos hinzugefügt werden und außerdem war es nicht möglich Herrn Brünig zum Projektboard hinzuzufügen. Aufgrund dieser Problematiken wurde beschlossen, ein neues Management-Tool für die Projektgruppe aufzusetzen. Es gab diverse Alternativen zu dem „Microsoft Planner“, die auch frei verfügbar waren, jedoch meist in den frei verfügbaren Versionen nicht die nötigen Teilnehmerplätze unterstützen. Häufig mussten hierbei für Gruppen über fünf Personen Lizenzen, basierend auf einem monatlichen Bezahlmodell, erworben werden. Da es keine Option war, für ein Projektmanagement-Tool einen monatlichen Betrag zu zahlen, fiel die Wahl letztendlich auf den Branchenklassiker Asana. Asana ist eine Webanwendung die im Browser läuft, was äußerst praktisch ist, da so auf jedem Gerät, das über Internet und einen Browser verfügt auf das Tool zugegriffen werden kann. Zusätzlich gibt es auch noch eine App für Smartphones, die alle Funktionen von Asana unterstützt. Asana stellt in der frei verfügbaren Version 15 Plätze innerhalb eines Projekts zur Verfügung und genügte somit in voller Weise den Ansprüchen. Außerdem konnten so sowohl Herr Brünig, als auch Herr Baer und Herr Brendel, als begleitende Laboringenieure, zum Projektboard hinzugefügt werden. Asana stellt außerdem sehr viele weitere nützliche Tools zum Verwalten eines Projekts zur Verfügung. Mit Asana ist es möglich ein Projekt professionell zu verwalten. Aufgaben können als Task an ein oder mehrere Gruppenmitglieder zugewiesen werden. Außerdem können Aufgaben in Unteraufgaben aufgeteilt werden, die wiederum jemandem anderen, als dem Hauptaufgabenbesitzer zugeteilt werden kann. Desweitern besitzt jede Aufgabe und jede Unteraufgabe über eine eigene Kommentarfunktion. Dies ermöglicht eine äußerst einfache und aufgabenspezifische Kommunikation über die jeweiligen Aufgaben. Jeder Nutzer besitzt seine eigene Inbox, in der die zu erledigenden Aufgaben und auch Unteraufgaben aufgelistet werden. Wird dem Task ein Timing mitgegeben, so wird dem zugewiesenen Nutzer oder der Gruppe zusätzlich in seiner jeweiligen Inbox eine entsprechende Notiz angezeigt, bis wann dieser zu erledigen ist. Ergänzt werden diese Tasks, die ein Timing haben außerdem in einem Kalender, der für alle Gruppenmitglieder einheitlich ist, somit können gemeinschaftliche Termine, die die ganze Gruppe betreffen, übersichtlich dargestellt werden. Der Kalender erleichtert die Projektplanung um ein Vielfaches, da er einem eine gute Gesamtübersicht über die zur Verfügung stehenden Zeit in dem Bezug auf die zu erledigenden Aufgaben gibt. Die Tasks werden übersichtlich auf einem Projektboard angezeigt, was eine weitere praktische Funktion von Asana darstellt. Die Tasks können hier in Spalten sortiert werden. Für die Projektgruppe entschied sich Stefan Maurer für vier Unterteilungen der erstellten Aufgaben. Als Erstes das „Backlog“. Hier sind alle gruppenrelevanten Aufgaben hinterlegt oder Aufgaben, die noch nicht zugeteilt wurden. Als Zweites die Spalte „Tasks zugewiesen“ Wie der Name schon sagt befinden sich hier die Aufgaben, die an einzelne oder mehrere Mitglieder zugeteilt wurden. Das gibt einem eine gute Übersicht darüber, wer zurzeit eine Aufgabe hat oder nicht. Den Mitgliedern, die keine Aufgabe zugewiesen haben, kann dann eine aus dem Backlog zugeteilt werden. So ist es möglich, auf eine gleichmäßige Aufgabenverteilung innerhalb der Projektgruppe zu achten. Als dritte Spalte wurde „Tasks in Bearbeitung“ erstellt. Auch hier ist der Name der Spalte gleichzeitig die Erklärung. Hier befinden sich alle Aufgaben, die sich zum aktuellen Zeitpunkt in der Umsetzung befinden. Diese Spalte ist essentiell, da hier jeder Teilnehmer nachvollziehen kann, wer gerade im Moment an welcher Aufgabe arbeitet. Letztendlich gibt es noch die Spalte „Tasks abgeschlossen“. Auch diese Spalte ist selbsterklärend. Hier liegen die erledigten Aufgaben ab. Hier kann einfach nachvollzogen werden wer wann was umgesetzt hat. Diese Spalte ersetzte ab Einführung von Asana, in das Projekt, gewissermaßen die Protokolle. Mit Hilfe dieser vier Spalten war es möglich stets eine gute Übersicht über das Projekt zu gewährleisten.

Kommunikation

Eine der wichtigsten Aufgaben, die Stefan Maurer in seiner Funktion als Projektmanager zu Teil wurde, war es stets die Kommunikation zwischen Projektgruppe, leitendem Professor, Laboringenieuren und dem Deutschen Museum herzustellen, aufrechtzuerhalten und Nachrichten weiterzuleiten. Dies war und ist stets die Hauptaufgabe eines Projektmanagers, damit alle Beteiligten vom gleichen Nachrichten- und Wissensstand ausgehen und jeder weiß, was der andere gerade tut, um zu gewährleisten, dass die investierte Zeit möglichst effektiv genutzt werden kann. Hierzu zählen natürlich sämtliche Kommunikationswege, wie Email, Asana, Whatsapp, oder geführte Gespräche. In diesem Bereich zählt zum Beispiel auch die immer wieder kehrende Problematik der Terminfindung, unter Berücksichtigung der Zeitpläne aller Gruppenteilnehmer. Hierbei war es von Vorteil, dass es einen Termin gab, der sich von Anfang bis Ende des Semesters etabliert hatte, nämlich der Montagvormittag bis Nachmittag. In diesem Zeitraum fand ein Großteil der Projekttreffen statt, jedoch gab es auch etliche Treffen und Besprechungen außerhalb dieses Zeitraums, die immer wieder zu Herausforderungen bei der Planung führten.

Planungsgremiensitzung

Als Leiter der Projektgruppe, war es auch Teil der Aufgabe von Stefan Maurer sich an dem generellen Geschehen im Planungsgremium für den Ablauf der Projektpräsentationen zu beteiligen, hierzu besuchte er die nötigen Treffen und erarbeitete mit den anderen Projektleitern, des Jahrganges den Ablaufplan für die Präsentationen. Insbesondere die Videodokumentation der einzelnen Projektpräsentationen wurde durch Stefan Maurer geplant und umgesetzt, durch Tobias Lindner.


Design

Tobias Lindner arbeitete im Laufe des Projektes an verschiedenen Designherausforderungen. Neben Namensfindung war es wichtig ein einheitliches Bild nach außen hin zu präsentieren. Besonders die Wirkung auf das Museum soll professionell und ernst wirken. Darunter viel neben der Namensgebung auch die Erstellung eines Logos und Styleguides. Gearbeitet wurde mit folgenden Programmen aus der Adobe Cloud: Photoshop, Illustrator und After Effects

Namensfindung und Claim

Das Projekt war lange ohne Namen. Als das Forum zentraler Ort für das Vorhaben wurde, einigte sich das Team auf den Vorschlag „Forum“. Andere vorgeschlagene Namen klangen zwar nach Zukunft, aber hatten keinen direkten Bezug zu dem Projekt. Der Claim orientiert sich am Leitzitat des deutschen Museums: "Der beste Weg, die Zukunft vorauszusagen, ist, sie zu gestalten" Da das Museum auch internationales Publikum ansprechen möchte fiel die Wahl auf einen Englischen Claim: Shaping our Futre Damit soll zum Ausdruck gebracht werden, dass die Menschen im Forum die Möglichkeit gemeinsam an einem Entwurf der Zukunft zu arbeiten.

Corporate Idendity

Nachdem der Name festgelegt wurde, brauchte das Projekt ein einheitliches Erscheinungsbild nach Außen hin. Hierfür wurde, von Tobias Lindner, eine Corporate Idendity (CI) erstellt. Diese CI besteht aus fest definierten Merkmalen, anhand deren ein Unternehmen (in diesem Fall das Projekt Forum) erkannt werden kann. Merkmale sind das Logo, Farben und Schriften. In den folgenden Punkten wird erläutert, wie die CI für das Projekt Forum entwickelt wurde. Dabei wird auf die einzelnen Merkmale eingegangen.

Zunächst hatte das Projekt nur eine Wortmarke als Logo. Diese Art Logo hat bedeutende Nachteile. Außer dem Namen, hatte das Logo nichts mit dem Projekt zu tun. Deshalb orientiert sich, Tobias Lindner, an einem RGB Split bzw. ein Glitch Effekt. Dadurch standen zunächst die zwei Grundfarben Cyan und Rot fest. Ein Logo muss auch in allen Größen lesbar und erkennbar bleiben. Bei Text ist das nicht gegeben. Deshalb fiel die Wahl auf eine abstrakte geometrische Form. Orientiert wurde sich an einem kontrastreichen minimalistischen Stil. Das finale Logo entstand bei einer Versuchsreihe mit sich überschneidenden Formen. Die hochkant gestellten Rechtecke erinnern an die Form der Stelen. Spiegelt man diese Form erhält man die schemenhafte Anordnung der Stelen im Forum. So ist der Bezug zwischen Logo und dem Projekt geben.

Forum Logo Entwicklung

Außerdem wurde für das Logo ein Entwurf von Danial Eshete angefertigt, dieser wurde allerdings nicht als finales Design ausgewählt, soll aber hier der Vollständigkeit halber aufgeführt werden:

Logoentwurf

Styleguide

Nachdem nun Name, Claim und Logo feststehen, braucht es noch ein Regelwerk für die Benutzung des Logos in verschiedenen Kontexten. Hierfür wurde, von Tobias Lindner, ein Styleguide erstellt. Dieser stellt sicher, dass alle Dokumente, die zu dem Projekt gehören, einen einheitlichen Look haben. Der Guide enthält das Logo, wie es auf den zwei erlaubten Hintergründen erscheinen muss. Auf weißen Hintergrund sind die überlappenden Flächen schwarz. Auf schwarzem Hintergrund weiß. Die genaue Farbgebung ist auch als Hex Code hinterlegt. Das Cyan und Rot stehen im komplementär Kontrast zusammen und bilden die Akzentfarben im Rahmen des Projektes. Die zu verwendeten Schriftarten sind auch definiert für Wortlaut, Überschrift und Fließtext.

Styleguide Forum CI


Augmented Reality Plakat

In den Designaufgabenbereich viel auch der Entwurf eines Plakates. Anforderungen an das Plakat ist die Beschreibung des Projektes und Werbung für die Projektpräsentationen. Neben den Eckdaten der Präsentation sind auch alle beteiligten Institutionen aufgeführt. Im Hintergrund sind Partikel zu sehen, welche eine Sphäre bilden. Das stellt das Große und Ganze aus dem Konzept der Stelen dar.

Plakatentwurf links und Augmented Reality Plakat rechts

Das von Tobias Lindner ertstellte Plakat bot eine Möglichkeit die Idee eines animierten Posters umzusetzen. Inspiriert durch die bewegten Zeitungsartikel aus Harry Potter wurde recherchiert, wie ein bewegtes Poster realisiert werden kann. Ein Blog Eintrag auf medium.com lieferte die nötigen Informationen. Zuerst musste eine animierte Version des Plakates mit Adobe After Effects erstellt werden (../materialien/videos/plakat_animation.mp4). In der Unity Engine wurde unter der Verwendung des Vuforia Frameworks das Plakat als Marker definiert. Auf diesen Marker wurde ein Videoplayer gelegt, der mit Hilfe des Markers passgenau auf das Referenzbild platziert werden kann. Um dieses Augmented Reality Feature des Plakates nutzen zu können, wird eine App auf dem Smartphone benötigt. Die exportierte App aus Unity konnte nicht in den Appstores der populären Anbieter bereitgestellt werden, weshalb auf die bereits verfügbare App HP Reveal zurückgegriffen wurde. Zwar war die geleistete Programmierarbeit zunichtegemacht, aber wichtige Erkenntnisse aus Funktionsweise und Methodik gewonnen. Über den QR-Code können sich Betrachter des Plakates die App herunterladen. Der Code erkennt das Betriebssystem des einlesenden Gerätes und verweist auf die entsprechende App im Store.

T-Shirts

Ein professionelles Auftreten sollte sowohl bei der Projektpräsentation und vor dem Museum gesichert sein. So entschied sich das Team T-Shirts anzuschaffen. Hierfür wurden, von Tobias Lindner, zwei Entwürfe gefertigt:

T-Shirt Mockup Forum

Aufkleber

Aufkleber Design

Im Zuge der Marketing Maßnahmen wurden von Tobias Lindner auch Aufkleber entworfen. Der Hintergedanke dabei ist, den Besuchern am Tag der Präsentationen ein kleines Erinnerungsstück an das Projekt mitzugeben. Es gibt vier verschiedene Aufkleber. Logo und Claim auf Weiß und auf Schwarz.

LaTeX Vorlage

Der einheitliche Look sollte ich auch im Projektbericht wiederspiegeln. Deshalb wurde, von Tobias Lindner, eine LaTeX Vorlage anhand des Styleguides erstellt. Die fertige Vorlage fand jedoch keine Verwendung, da das Team keine Erfahrung mit LaTeX hat und keinen extra Aufwand betreiben wollte.

Präsentation

Während der Vorbereitung für die Projektpräsentation in der Hochschule und für die Projektpräsentation bei einer Tagung des deutschen Museums, wurde eine gemeinsame Präsentation erstellt. Als Vorlage dieser, diente eine vorangegangene Präsentation von Sebastian Holzki und Fritz Lenssen. Um diese vorzubereiten erstellte jeder Vortragende, seine eigenen Folien. Mit Hilfe von Tobias Lindner und Sebastian Holzki wurden die jeweiligen Präsentationen final überarbeitet.

Fazit der Präsentationen

Bei der Projektpräsenation innerhalb der Hochschule zeigte sich das große Potential der entwickelten Ideen und des Konzepts. Die allgemeine Begeisterung im Umgang mit dem Prototypen, sowohl der Besucher, als auch der Hochschulanghörigen, war stets zum Ausdruck gekommen. In vielen Gesprächen, wurde die Begeisterung für den Prototypen immer wieder bestärkt.

Bei der zweiten Präsentation bei einer Tagung des Deutschen Museums in Nürnberg, hatte die Projektgruppe noch einmal die Chance, beim Museum mit den bisher erarbeiteten Ergebnissen, vorstellig zu werden. Ziel der Gruppe, war es bei diesem Termin vor allem, die Repräsentanten, des Museums, von dem Konzept des LED-Bodens zu überzeugen, um auf dieser Grundlage weiterarbeiten zu können. In den Gesprächen direkt nach der Präsenation, wurde rege diskutiert und beratschlagt. Seitens des Museum wurde das Konzept sehr gut aufgenommen und auch hier war die Begeisterung für das erarbeitete Konzept spürbar. Es wurden außerdem seitens des Museums, viele neue Aspekte zur Berücksichtigung und zur Umsetzung angesprochen und in die Zielsetzung der Projektgruppe, für den weiteren Projektverlauf aufgenommen.

Reflexion

Der Start in das Projektsemester begann etwas durcheinander, da keine klaren Ziele definiert wurden und jedes Gruppenmitglied eine andere Vorstellung vom Projekt hatte. Außerdem wurde dies nochmal dadurch bestärkt, dass viele Vorgaben Seitens des Museums nicht definiert wurden, da sie sich selbst in der Konzeptphase und in der Planung befanden. Dies hatte zur Folge, dass das Projekt großen Raum für Kreativität bot. Die Konzeptphase zog sich bis kurz vor Weihnachten, da viele Absprachen mit dem Museum gehalten werden mussten. Anfängliche Ideen, die entweder aufgrund von fehlenden Informationen, technischer Umsetzbarkeit oder aus Sicherheitsaspekten verworfen werden mussten, kosteten Zeit für die Fertigstellung. Zum Beispiel ist die geplante Zusammenarbeit mit Herrn Triendl zu nennen. Die Unterstützung durch ein Team von Design-Studenten wurde unserer Gruppe zunächst zugesagt, jedoch im Laufe der Besprechungen nach einigem Hin und Her wieder abgesagt. Nach einer relativ kurzen, aber produktiven Entwicklungsphase können wir nun einen funktionsfähigen Prototypen aufweisen. Zwar wurden nicht alle gewünschten Ziele in diesem Semester erreicht, wie zum Beispiel die Verbindung des LED Bodens mit den Stelen. Das Ziel für das nächste Semester, ist es die beiden Systeme zusammenzuführen um durch das Einlesen des Besuchers das synchrone Ausbreiten auf beiden Systemen zu gewährleisten. Auch das Einbauen von OSC Nachrichten, zur Übermittlung der Besuchertypisierung, war im Rahmen des 5. Semesters noch nicht möglich.

Zukunftsausblick für das Projekt

Bei dem letzten Treffen mit dem gesamten Team des Deutschen Museums, bei dem die Gruppe die Gelegenheit hatte, den aktuellen Stand des Projekts zu präsentieren, ergaben sich neue Erkenntnisse, die den Anforderungskatalog des Museums an das Forum betreffen. Für das nächste Semester gibt es drei vorrangige Zielsetzungen, die auf jeden Fall bis zum Ende der Projektphase umgesetzt werden sollen. Der Prototyp soll um die Möglichkeit erweitert werde, tatsächlich mit einem RFID-Chip angesteuert zu werden und spezifische Effekte, nach den jeweiligen Daten auf dem Chip abspielen lassen. Die Partikelsysteme sollen kontinuierlich weiterentwickelt werden, und sowohl auf dem Boden, als auch auf den Stelen optisch überarbeitet werden, um visuell aufregender zu werden. Außerdem soll es mehrere Effekte und Modi zur Präsentation der Spieldaten geben. Der größte Punkt, der im neuen Semester angegangen werden soll, ist den Prototyp um die Fähigkeit zu erweitern mit User-Input, in Form von Text oder Bild umgehen zu können. Dieses Thema kristallisierte sich bei dem Präsentationstermin in der anschließenden Diskussionsrunde heraus und wurde vom Museum gefordert. Hier soll nach aktueller Planung, wohl die meiste Zeit investiert werden, aufgrund des Interesses des Museums. Zurzeit prüft das Museum die voraussichtlichen Kosten, die für eine tatsächliche Umsetzung unseres Projekts, eingeplant werden müssen. Beispielsweise würde ein erhöhter Kostenaufwand für das Deutsche Museum durch die Installation eines LED-Bodens entstehen. Auch die Präsentation innerhalb der technischen Hochschule, bei der Besucher die ersten Berührungspunkte mit dem Konzept und dem Prototypen hatten, war uneingeschränkt positiv. Die Technik lief zu jedem Zeitpunkt einwandfrei und zeigte keine Anfälligkeit, für Störungen.

Das zweite Projektsemester

Konzeption

Das System wird aktualisiert

Zu Beginn des sechsten und damit letzten Projektsemesters stand auf der Agenda, sich mit der abgeschlossenen ersten Hälfte auseinander zu setzen. Beim Prototyp des letzten Semesters gab es zwei in sich geschlossene, nicht gekoppelte Partikelsysteme, die per Tastensteuerung den Anschein erweckten ein geschlossenes System zu ergeben. Das Trackingsystem war nebenbei ebenfalls ausgelagert, dass jedoch per OSC mit dem Partikelsystem des Bodens kommunizierte. Der Anspruch der Gruppe war es jedoch in der zweiten Phase der Projektarbeit ein einziges System aufzusetzen, das lediglich per OSC Informationen von außerhalb erhält, ansonsten in sich geschlossen ist.

Darstellung für Berechnung

Wie der obigen Abbildung zu entnehmen ist, war es die Idee, die beiden Partikelsysteme zu einer großen 2D Szene zusammenzuführen. Hierbei war anfangs angedacht, verschiedene Bereiche zu definieren. Der pinke Bereich stand für die Stelen, der Türkise für den Boden und der schwarze Bereich für den Zwischenraum, welcher zwar durchlaufen werden kann, am Ende aber nicht ersichtlich sein sollte. So war es möglich Partikeln einen natürlichen Bewegungsverlauf zu übergeben, ohne dass die Räume zwischen den Stelen hätten übersprungen werden müssen. Fritz Lenssen brachte in dieser Konzeptphase die Idee eines ersten Ablaufs auf. Der Kreis (Boden) und die Stelen agieren getrennt voneinander, bis es zum Einlesen der RFID-Daten kommt. Sobald sich der Besucher mit seinem RFID Armband eingecheckt hat, wird die imaginäre Barriere (der Schwarze Bereich) zwischen dem Boden und den Stelen durchbrochen und sie agieren als ein gekoppeltes System. Im Kollektiv entstanden auch die ersten Ideen für einen neuen Prototyp und die Abschlusspräsentation. Hierfür sollte sich das gekoppelte neue Partikelsystem auf Boden und Stelen erstrecken. Anders als beim letzten Prototyp sollte der Boden, ebenso wie die Stelen, projiziert werden, um tatsächlich als Person damit interagieren zu können. Besser wären jedoch wieder mehrere Bildschirme, die dann durch eine Plexiglas Konstruktion geschützt werden, um einerseits Schattenwürfen aus dem Weg zu gehen, andererseits aber auch das Museum abermals von der Installation eines LED-Bodens überzeugen zu können. Die einzelnen Stelen sollten diesmal, um eine bessere Wirksamkeit zu erzielen, in einem größeren Maßstab aufgebaut werden. Des Weiteren wurden erste Überlegungen gemacht, wie sich Untergruppen bilden könnten, damit nicht alle gleichzeitig an einer Sache arbeiten müssen. So musste die Codearchitektur überarbeitet, RFID überdacht, Personas mussten sich überlegt und ein zweites visuelles Konzept musste aufgestellt werden (vgl. PDF/Anforderungsdefinition im Anhang).

Die Projektfahrt - Berchtesgaden

Nach den ersten Überlegungen ging es für weitere Konkretisierungen nach Bertechsgarden in eine Jugendherberge, damit jede Gruppe an ihren Projekten weiterarbeiten konnte. Zu Beginn wurde eine grobe Roadmap definiert, wie sich das Projektteam durch das Semester arbeiten wird. Vor allem wurde viel über ein Refactoring der bestehenden Systeme diskutiert und konzeptualisiert. Ebenso wurden neue Konzepte für das große Ganze, Styleguides für die Spielertypen und das Verhalten der Partikel am Boden und auf den Stelen erstellt. Des Weiteren wurde sich Gedanken gemacht, wie die später einmal im Museum erhaltenen Daten aussehen könnten. Wie bereits weiter vorne schon erwähnt, hatte das Team keine Einschränkungen durch das Museum und konnte frei konzeptualisieren. Zusammengefasst sind die Errungenschaften in einem PDF (vgl. Anhang: Präsentation/Projektfahrt).

Git-Workshop

Am dritten Tag der Projektfahrt, wurde von Herr Professor Hopf ein Git-Workshop angeboten, an dem Kevin Frania teilgenommen hat. Hier bestand die Möglichkeit einen Einblick und Kenntnisse über das Versionsverwaltungs-Programm Git zu bekommen. Der Umgang mit Repositories, also Verzeichnissen, wurde gut erklärt. Außerdem wurde gezeigt, wie man mehrere Branches durch das mergen zusammenführt.

Die erste neue Code-Architektur Idee

Wie bereits erwähnt wollte die Gruppe von den zwei getrennten Systemen abrücken und sie zu einem System vereinen. Kurz gesagt sollte das Gesamtsystem ein Interface - genannt PhysicsObjects -, ein oder mehrere Partikelsysteme, die sich bewegenden/getrackten Besucher/Visitor und Avatare, die durch das Einlesen entstehen, beinhalten. Dies wurde in einem Klassendiagramm festgehalten.

Klassendiagramm des Gesamtsystems

An sich sollte sowohl der Boden als auch die Stelen ein oder mehrere Partikelsysteme besitzen, die wiederum ein Emitter oder auch ein Attraktor hätten sein können. Neue, sich auf den Boden zubewegenden, Besucher hätten ebenso ein weiteres Partikelsystem zugewiesen bekommen, dass sich im sogenannten Default Modus befunden hätte. Das System hätte erstmals nur Partikel emitten lassen, ohne sich zu verändern. Nach dem Einchecken des Besuchers, hätte das Partikelsystem dann eine eigene ID erhalten. Denn auf dem RFID-Armband sind die Daten des Besuchers gespeichert, die dann wiederum das erhaltene Partikelsystem in Form, Farbe und Verhalten verändert hätte. Nach vielen Diskussionen innerhalb der Gruppe, entschied sich das Team allerdings auf den Gebrauch mehrerer Partikelsysteme zu verzichten, sowie das personalisierte Zuweisen auf die Besucher. Das hätte den Rahmen gesprengt und somit plante die Gruppe vorerst mit der Verwendung eines einzigen Partikelsystems. Das Gesamtsystem sollte dynamisch aufgebaut werden, daher auch die Verwendung eines Interfaces. Interfaces ermöglichten der Gruppe flexibler arbeiten zu können, ohne sich weiter konkretisieren zu müssen. Diese beinhalten eine beliebige Anzahl an Emittern und Attraktoren, die sich verwalten und zuweisen lassen. So ist es nach wie vor möglich, die getrackten Besucher zu Attraktoren werden zu lassen, damit diese Partikel anziehen können. Weiterhin war es die Idee über XML Dateien Daten einlesen zu lassen. Da das Gesamtsystem stets auf seine vordefinierten Settings zugreifen kann, können diese beliebig in XML Dateien verändert werden, um so unterschiedliche Looks erzeugen zu können. So muss nicht jedes Design vorher im System eingetragen und aufgerufen werden, sondern kann direkt aus der richtigen XML geladen werden. Das verwendete Partikelsystem verfügt über eine Partikelklasse, in der, wie auch schon im vergangenen Semester, die Eigenschaften (position, age, velocity, ...) eines jeden Partikel vordefiniert sind. Auch hier ist es möglich XML Dateien zu laden, die vorgefertigte Partikeleigenschaften gespeichert haben. Ebenso war angedacht dem Partikelsystem (PS) verschiedene Spielertypen, bzw. Systemtypen zu übergeben, sodass das PS auf verschiedene Logiken reagieren kann, die ebenfalls vordefiniert sind. Auch die Partikelklasse enthält verschiedene Modi, die die Eigenschaften und das Verhalten der Partikel verändern. Des Weiteren enthält das Gesamtsystem eine Besucherklasse. In dieser Besucherklasse sind die sich eincheckenden Visitor definiert. Je nach Spielertyp, werden hier Bilder geladen und auf den Stelen ausgegeben. So erfolgt die Spielerdatenauslesung visuell. Ebenso sind hier weitere Effekte, die beim „Auslesen der Daten“ entstehen sollen, festgelegt. Wie beispielsweise die emittierenden Partikel, die sich an die geladenen Spielertypen (Images) heften und den Bildern nach oben folgen. Das war zu diesem Zeitpunkt die erste Idee, die das Projektteam grundsätzlich auch beibehalten hat, allerdings sind Passagen verändert und optimiert worden.

Ausarbeitung des neuen Konzepts

Um den eben erläuterten Ansprüchen gerecht werden zu können wurden unterschiedliche Grundstrukturen unter Einsatz von einer Art Pseudo-Klassendiagramm für das System besprochen und diskutiert. Teile dieses Prozesses fanden schon während der Projektfahrt statt, wobei die wirklich durchdachte Ausarbeitung erst später erfolgte. Folgendes Diagramm veranschaulicht den finalen Aufbau.

UML-Diagramm der finalen Architektur

An oberster Stelle steht das Gesamtsystem, welches sowohl die Besucher im Museum (Klasse Visitor), als auch die schon eingecheckten Besucher (Klasse CheckedInVisitor) direkt verwaltet. Diese Hierarchie erlaubt es, die Informationen über visitors und checkedInVisitors direkt im System zu nutzen und weiterzugeben. So können Objekte in Abhängigkeit vom Besucheraufgebot erzeugt, verwaltet oder gelöscht werden. Zudem wurde der Aufzählungstyp enum particleMode (kurz für Enumeration (dt. Aufzählung)) definiert, der den Zustand eines Partikelsystems angibt.

     enum particleMode {  
           PARTICLE_MODE_DEFAULT,        
           PARTICLE_MODE_POLYMESH,  
           PARTICLE_MODE_RFID  
     } 

Das Gesamtsystem gibt die Information über den aktuellen Modus weiter ans Partikelsystem und dieses wiederum an seine eigenen Partikel. So ist gewährleistet, dass in den Klassen getrennt voneinander auf eine Änderung des Modus reagiert werden kann. Außerdem lässt sich das System spielend einfach um weitere Modi erweitern.

Die Spielertypen

Das wichtigste Ziel der Spielauswertung ist die leichte Verständlichkeit für die Museumsbesucher. Da wir erwarten, dass die Museumsbesucher aus vielen verschiedenen Teilen unserer Gesellschaft stammen und sich auch in anderen Merkmalen wie Alter, Geschlecht oder Psychologie unterscheiden werden, müssen wir Personas erstellen. Personas sind fiktive Personen und ihre Cha¬rak¬teris¬ti¬ka von potentiellen Museumsbesuchern. Diese helfen uns dabei einige der erwarteten Merkmale der zukünftigen Besucher sozusagen unter einen Hut zu bringen und uns so diese besser vorstellen zu können. So bilden diese Personas die Grundlage für verschiedene Facetten unseres Interfaces. Deshalb haben Katharina Ott, Jana Gumbert und Agathe Gnus jeweils eine Persona erstellt. Die Datei der Persona von Agathe Gnus ist im Anhang zu finden. Damit für die Besucher alles auf Anhieb leicht verständlich ist, haben Katharina Ott und Agathe Gnus an der Erstellung und Gestaltung von Symbolen gearbeitet, die ohne Text (anders als anfangs angedacht, damit auch An¬al¬pha¬beten und Kinder inkludiert werden können) die erspielte Zukunft des Besuchers widerspiegeln sollen. Durch das Spiel, welches die Besucher in den verschiedenen Themenbereichen des Museums spielen werden, werden unterschiedliche Teilaussagen (je nach Themenbereich) über die jeweilige Zukunft des Besuchers getroffen. Um diese dem Besucher anschaulich zu vermitteln, empfiehlt es sich, individuell für jedes Gesamtergebnis des Spieles ein Symbol zu kreieren, welches diese Teilergebnisse in einem Bild vereint. Denn nicht jeder Besucher wird eindeutig nur einem der fünf Themenbereiche („System Erde“, „Körper und Geist“, „Urbanes Leben“, „Arbeit und Alltag“ sowie „Raum und Zeit“) des Museums zugeordnet werden können. Für unsere Persona „Miriam“ hat Agathe Gnus ein Symbol erstellt, das zu ihren Interessen, und so dem erwarteten Spielergebnis passt. Dieses Symbol besteht aus Hochhäusern und Windrädern, die die Teilgebiete des Zukunftsmuseums „Urbanes Leben“ (verkörpert durch das Hochhaus) und „System Erde“ (Windräder) verdeutlichen.

Verworfenes Symboldesign

Dieses Symbol sollte nicht, wie die anderen Symbole in früheren Versionen unserer Projektarbeit, durch Partikel entstehen, sondern als farbiges Icon angezeigt werden und nur das umrandende Hexagon sollte durch Partikel nachgezeichnet werden. Letztendlich entschied sich die Gruppe für die einfacheren Symbole, erstellt von Katharina Ott (siehe 4.3. Symbole). Agathe Gnus hat in dem Stil dieser Symbole ein weiteres erstellt (das dritte Symbol von links im nachfolgenden Bild) und alle Symbole in passenden Farben eingefärbt damit diese optisch ansprechender sind.

Ablauf Spielauswertung

Auch der Ablauf der Spielauswertung soll für die Besucher intuitiv sein, weswegen Katharina Ott und Agathe Gnus zusammen einen Ablaufplan schrieben, in dem festgelegt wird, was passieren soll, wenn die Besucher Teilergebnisse des Spieles auf ihrem RFID Armband gesammelt haben und im Forum ankommen:

1. Der Besucher läuft auf dem LED Boden und wird durch das Tracking System zum Attraktor für das, auf dem Boden projizierte Partikelsystem (siehe unten). Er zieht die Partikel auf dem LED Boden an und diese folgen auch seinen Schritten. 2. Der Besucher hält das RFID Band an die Einlesestation. Die Daten aus der Datenbank werden ausgelesen und analysiert. Je nach Auswertung der Daten wird das entsprechende Symbol konstruiert und die Bildpunkte der Symbole werden als Attraktoren für die Effekte des Partikelsystems gesetzt. 3. Der Besucher sieht sein Symbol auf einer der Stelen und kann beobachten wie die Partikel in einer Tornadoformation nach oben fliegen. 4. Im oberen Drittel der Stelen angekommen, gehen die Partikel in das „Große Ganze“ über (siehe nächste Seite). 5. Der Besucher kann nun seine eigene Zukunft im „Großen Ganzen“ identifizieren. 6. Zusammen mit anderen Besuchern kann dieser dann weiter den Boden beobachten oder sich über die Zukunft austauschen.

Ablauf der Stelen Animation

Das überarbeitete "Große Ganze"

Um dem Besucher verständlich aufzuzeigen, dass seine individuelle Zukunft ein Teil der gesamtheitlichen Zukunft unserer Gesellschaft ist, überlegte sich unter anderem Agathe Gnus das Konzept des sogenannten „Großen Ganzen“. Das „Große Ganze“ ist ein Zusammenschluss aus Symbolen vorangegangener Spielergebnisse anderer Besucher, welcher im oberen Drittel der Monitore waagrecht in die gleiche Richtung über die Stelen vorüberziehen. Nun blieb die Frage offen, ob man die Symbole untereinander interagieren lassen möchte und wie dies aussehen soll. Dafür gibt es einige Möglichkeiten: Zum einen kann man die Linien der Hexagone mit Partikeln nachzeichnen lassen (Bild 1, 2, 3). Diese folgen dann dieser Linie und bilden kleine Brücken mit anderen Hexagonen, sofern diese sich in unmittelbarer Nähe befinden (Bild 2). Diese Verbindung kann auch über Linien zwischen Partikeln zweier Hexagone dargestellt werden (Bild 3). Es bietet sich aber auch die Möglichkeit an, ganze Hexagone Grenzlinie an Grenzlinie miteinander zu verbinden (Siehe Gruppierung in Bild 1). Eine andere Möglichkeit ist es, die Linie der Hexagone nicht durch Partikel nachzuzeichnen, sondern die Symbole über glatte Hexagone zu begrenzen. Die Verbindungen entstehen beim gegenseitigen Berühren der Hexagone, die sich nach einer bestimmten Zeit oder wenn sich die Hexagone gegenseitig abstoßen, auflösen (Bild 4). Auch bei dieser Variante ist eine Verbindung zwischen zwei Hexagonen mittels Linien möglich (Bild 5). Alle Überlegungen hat Agathe Gnus mit der iPad App Pixelmator visualisiert und das Team hat sich dann für das vierte Konzept entschieden (Bild 4). Zudem wurde der oben beschriebene Ablaufplan insofern verändert, dass es nun doch keinen Tornadoeffekt mehr geben wird.

Bild 1 - Möglichkeit der Darstellung - Symbolbildung
Bild 2 - Möglichkeit der Darstellung - Symbolbildung
Bild 3 - Möglichkeit der Darstellung - Symbolbildung
Bild 4 - Möglichkeit der Darstellung - Symbolbildung
Bild 5 - Möglichkeit der Darstellung - Symbolbildung

Konzeptplan

Mit der Zeit wurden die Ideen und Konzepte für den finalen Prototyp immer komplexer. Mit Unterstützung von Stefan Maurer machten es sich Daniel Mehlhorn und Fritz Lenssen zur Aufgabe für den Ablauf einen konkreten Plan zu entwerfen und die Ideen zu bündeln. Dieser wurde im weiteren Arbeitsprozess als Grundlage verwendet. Der Plan legte fest, wann sich das System wie verhält und was genau ausgegeben wird. Angefangen im Default Modus des Bodens – Was passiert, wenn sich keiner einliest und sich kein Besucher auf dem Boden bewegt. Das Partikelsystem ist default geschalten, es gibt einen Emitter, der Partikel mit einer zufälligen velocity und position entstehen lässt und es sind keine Attraktoren gesetzt. Für die Stelen war zu Beginn angedacht, dass weitere Emitter an dessen Unterkante Partikel entstehen lassen. Als mögliche Erweiterung wären für die unterschiedlichen Stelen, unterschiedliche Looks vorstellbar gewesen. Zu diesem Zeitpunkt war weiterhin in Planung, dass der Boden und die Stelen zwar ein System ergeben, allerdings vor dem Einchecken noch den Schein zweier unterschiedlicher Systeme machen. Das Besuchertracking unterschied sich grundsätzlich nicht wirklich von dem vom letzten Semester. Allerdings stand zur Debatte, ob getrackte Besucher ein eigenes Partikelsystem zugewiesen bekommen sollten und somit auch zu möglichen Emittern werden oder wie schon letztes Semester „nur“ zu Attraktoren werden. Die Partikelsysteme sollten auch ein Verhalten zugewiesen bekommen. Beispielsweise wenn sich ein Benutzer einliest oder wenn sich zwei Besucher nähern. Die Systeme könnten Verbindungslinien zwischen den einzelnen Partikeln herstellen oder bei Annäherung mehrerer Systeme, hätten diese zu einem Effekt verschmelzen können. Anfangs war noch der Plan, RFID mit einzubauen, womit jeder Besucher eine persönliche ID erhalten hätte. Auf diese ID und die gesammelten Daten, hätte das Projektteam dann zugreifen können und beispielweise Partikelsysteme personalisieren können. Die gesammelten Daten müssen dann auch noch ausgelesen werden, was direkt an den Stelen angedacht war. Die Daten beeinflussen das Partikelsystem und es geht über zur Spielauswertung. Der Fokus wird dabei auf die Stelen gelenkt, denn die imaginäre Barriere zwischen dem Boden und den Stelen würde durchbrochen werden. Die sich auf dem Boden befindenden Partikel würden sich zur Stele bewegen und der Stelen Emitter würde aufhören neue Partikel zu generieren. Währenddessen erscheint das, an die Daten angepasste, Symbol in Form eines Icons. Die übrigen Partikel von Boden und Stele formen im Anschluss ein Hexagon um das Symbol. Das Icon, gefolgt von Partikeln, wandert daraufhin an die Oberkante der Stelen und bildet mit den anderen bereits ausgelesenen Spielertypen eine Art Wabe, die sich kreisförmig an der Spitze der Stele bewegt. Innerhalb der Wabe können sich die Icons abstoßen oder anziehen. Der Plan diente lediglich der Orientierung und wurde so Größtenteils in die Realität umgesetzt. Das Projektteam hatte aber nun einen roten Faden, an dem sich alle orientieren konnten (vgl. Präsentation/FORUM_Konzept.pdf im Anhang).

Der Museumsbesuch

Während Fritz Lenssen und Daniel Mehlhorn noch an der Anfertigung eines Konzeptplans arbeiteten, kam Fritz Lenssen bereits die erste Idee eines kleinen Schauspiels, bzw. einer größeren Demonstration des Prototyps. Bei der letzten Präsentation übernahmen bereits Sebastian Holzki und Fritz Lenssen die Demonstration des kleineren Prototyps. Damals allerdings noch mit Hilfe von kleinen Papp Konstrukten und benötigter Vorstellungskraft auf Seiten der Zuhörer. Bei der Präsentation im sechsten Semester sollte aber der Prototyp an sich für sich selbst sprechen können. Den möglichen Nutzen der Stelen, des Bodens und der visuellen Spielauswertung sollte dann durch das Schauspiel deutlicher werden. Zu Beginn stand ein Brainstorming auf der Agenda. Hier machte sich Fritz Lenssen Gedanken, in welcher Form und in welchem Ausmaß die Demonstration stattfinden könnte. An sich sollte der Museumsbesuch und die damit verbundene Spielauswertung spielerisch an die Zuhörer gebracht werden. Als nächstes musste entschieden werden, ob bei der Vorführung zufällige Testpersonen ausgewählt werden sollten oder ob die Gruppe zwei Teammitglieder auswählt, die sich der Sache annehmen. Für eine zufällige Testperson hätte der auftretende „Wow-Effekt“ gesprochen, sowie das tatsächliche Erleben des Besuchers beim Interagieren mit dem System. Dagegen sprachen allerdings Erfahrungen bei den letzten Präsentationen anderer Gruppen, da es hier schnell zu Komplikationen führen kann. Zusammen mit seinem Team entschied sich Fritz Lenssen daraufhin dafür, dass zwei aus der Gruppe ausgewählt werden, die die Zuschauer durch die Installation führen sollten. Das Schauspiel sollte, ähnlich wie letztes Semester, durch eine Erzählstimme begleitet werden. Fritz Lenssen war es dabei besonders wichtig, dass ein gesamter Museumsbesuch simuliert wird, um den Nutzen des Prototyps klar deutlich zu machen. Denn aus den Gesprächen nach der letzten Präsentation ging des Öfteren hervor, dass sich die Zuschauer nicht genau vorstellen könnten, was sie in dem Forum machen können. So sollte die Vorführung mit dem Betreten des Museums beginnen, an den fünf verschiedenen Bereichen vorbeiführen und schlussendlich im Forum mit der visuellen Spielauswertung enden. Die ersten Ideen hierfür sind nochmals im Anhang in Form einer Präsentation zu entnehmen (vgl. Präsentation/Der_Museumsbesuch.pdf).

Skriptausarbeitung

Nachdem die Idee vom gesamten Team sehr positiv aufgefasst wurde, begann Fritz Lenssen mit der Ausarbeitung eines Skripts. In diesem sollte klar definiert sein, wann welcher Protagonist welchen Einsatz hat, was der Sprecher genau zu erzählen hat und was das System währenddessen macht. Eine erste Ausarbeitung erfolgte in Form einer Tabelle, um einen Überblick über die Vorführung zu erhalten (vgl. PNG/Schauspiel_Tabelle.png). Als beschlossen war, dass Sebastian Holzki und Fritz Lenssen den spielerischen Part und Stefan Maurer den Part des Erzählers übernehmen werden, folgte die Ausarbeitung eines Skripts. In diesem war zu jedem Zeitpunkt des Schauspiels genau festgelegt, was Sebastian Holzki und Fritz Lenssen zu spielen hatten, während Stefan Maurer den Sprecher gab. Ebenso war festgelegt, wie sich das System jeweils verhielt. Fritz Lenssen schrieb hierfür eine Art Drehbuch, samt zu erzählendem Text für Stefan Maurer. Das Skript ist ebenfalls im Anhang hinterlegt (vgl. PDF/SKRIPT.pdf)

Abschlusspräsentation

Für die bevorstehenden Abschlusspräsentationen im Juli mussten auch noch einige Aufgaben erledigt werden. So war es notwendig einen kurzen Videoclip zu drehen, welcher als Teaser für das Projekt fungierte. Plakate, die sowohl die Besucher anlocken als auch technisch aufklären sollten, mussten erstellt werden. Zusätzlich war der gesamte Aufbau für die Präsentation des Prototyps zu bewältigen. Da dieser im 6.Semester deutlich an Größe zulegen sollte war neben dem Aufwand für den Zusammenbau auch eine Vorstellung angedacht. Diese sollte in einer Art Schauspiel durchgeführt werden, um den Zuhörern im Raum den Ablauf des Museumsbesuch zu verdeutlichen. Die gemeinsam erarbeiteten Ziele, sowie mögliche Ansätze zur Umsetzung wurden in Form eines PDF-Dokumentes zusammengetragen und sind dem Bericht unter A2 Anforderungsdefinition angehängt.

Design

Persona Template

Durch das Aufzeigen der verschiedenen Museumsbesucher ergeben sich Möglichkeiten für die Effekte nach dem Einlesen mittels RFID-Chip. Sie sollen damit eine Orientierung für die Symboldarstellung liefern. Das Template diente der einheitlichen Präsentation der Personas.

Template Persona

Personas repräsentieren Ziele und Bedürfnisse der Zielgruppe und machen es möglich, von Beginn an fundierte Entscheidungen bei der Entwicklung nutzerfreundlicher Produkte zu treffen. Durch ein Zitat ist es möglich einer Persona Leben einzuhauchen und den Kern der Persönlichkeit in einem Satz zusammenzufassen. Auch Herausforderungen sind ein gutes Mittel um zu prüfen, ob man mit seinem Produkt auf dem richtigen Weg ist, um möglichst viele Besucher zu begeistern. Auch Platz für ein Bild ist in dem Template gegeben. Anhand von Bildern bleiben sie im Gedächtnis und stellen den Menschen in den Fokus. Das besondere war wohl auch an diesem Projekt, dass durch das Museum eine breite Zielgruppe angesprochen werden sollte. So werden die Museumsbesucher sich sowohl aus Schulklassen und jungen Technikbegeisterten, als auch aus technikversierten oder schlichtweg interessierten Erwachsenen zusammensetzen. Zu erwähnen ist, dass zwischen diesen eben genannten Stereotypen noch sehr viele weitere Charaktere zu der Zielgruppe gehören. Eine komplette Abdeckung war daher schlichtweg nicht möglich bzw. nicht gewünscht, da lediglich ein Überblick geschaffen werden sollte.

Personas

Persona Patrick Seeberger

Folgende Persona, welche von Jana Gumbert entworfen worden ist, fällt in die Gruppe eines erwachsenen Technikaffinen. Patrick Seeberger, der selbst beruflich in der Software Entwicklung tätig ist, kennst sich bestens mit aktuellen und zukünftigen Technologien aus. Die Bedienung von Installationen im Museum wird ihm wohl sehr leicht von der Hand gehen. Durch sein Ziel immer neue Technik ausprobieren zu wollen, lässt sich auch ableiten, was das Produkt dafür bieten muss. Auch diese Persona birgt eine Herausforderung oder mögliche Probleme für das Projekt. Nämlich wird sie durch überholte Technik schwer zu beeindrucken sein.

Persona Patrick Seeberger

Nach dem Aufstellen der Persona lässt sich anschließend analysieren, ob Patrick Seeberger durch unsere Interaktion für das Forum begeistert werden kann. Positiv anzuführen ist, dass im Forum eine starke Einbeziehung des Besuchers in die Technik stattfindet. Auch der LED-Boden der unter jedem reagiert, fördert die Interaktion. Durch die 7-8 m hohen Stelen, auf denen der persönliche Bezug zum Besucher durch die Symbolsymbiose, entsteht, war sich die Projektgruppe einig, könne man Herrn Seeberger imponieren.

Persona Maria Edwardson

Die von Katharina Ott entworfene Persona war weiblich, Masterstudentin, allerdings mit noch ungenau definierten Interessen. Nach dem OK der Projektgruppe wurde diese Persona von Katharina Ott noch genauer definiert. Sie erhielt einen Namen, sie erhielt eine Nationalität, sie schloss ihren Bachelor erfolgreich ab, sie befindet sich im Masterstudium in Deutschland und interessiert sich außerdem für Umweltschutz, Nachhaltigkeit und technischem Fortschritt. Folgende Abbildung zeigt die fertiggestellte Persona:

Persona Maria Edwardson

Symbol

Bereits im ersten Semester entwarf das Projektteam eine Vielzahl von Möglichen Symboldarstellungen, die jedoch wieder verworfen wurden. Die Gruppe einigte sich auf eine einfache Darstellung des „Ohm“-, des „Forum“- Logos und auf einen „Danke“-Screen. Zur Intensivierung der bisherigen Projektergebnisse begab sich das Team im zweiten Projektsemesters auf eine Projektfahrt nach Berchtesgaden. Hier wurden unter anderem bestehende Symbole bezüglich der Kompaktheit diskutiert. In diesem Zusammenhang verfeinerten Agathe Gnus und Katharina Ott die bestehenden Symbole und entwarfen geeignete Beispiele. Zusätzlich hierzu erkannte Katharina Ott, dass eine Reduktion des Detaillierungsgrades der Symbole eine wesentliche effizientere Wirkung auf den Museumsbesucher erzielt. Auf Basis dieser Erkenntnis überarbeitete sie die vorhandenen Symbole mittels Adobe Illustrator 2019. Die hierbei erzielten Ergebnisse wurden vom Team aufgrund der Konformität mit der Projektvision als sehr geeignet eingestuft und sollen langfristig für die geplante Spielauswertung genutzt werden. Um im weiteren Verlauf technische Widerstände bei der Bearbeitung der Symbole zu beseitigen, wandelte Katharina Ott diese mittels Adobe Photoshop CC 2019 in das PNG Format um. Um dem Nutzer die Möglichkeit zu bieten Symbole individuell einfärben zu könne, wurden diese vorerst im „schwarz-weiß-Stil“ erstellt.

Design der Symbole

Da sich dies in Kombination mit dem Partikelsystem negativ auf die Rechenleistung auswirkt, wurden die Symbole dennoch eingefärbt. Im weiteren Verlauf des Semesters konnten diese Symbole in ihre einzelnen Komponenten zerteilt und daraus durch Neukombination neue Symbole erstellt werden.

Farbdesign der Symbole

Design und Grafik

Für das Design und die zu erstellenden Grafiken, waren in diesem Semester vor allem Sebastian Holzki und Fritz Lenssen verantwortlich. Neben dem Veranstaltungsplakat, sollte diesmal ebenso ein Technikplakat erstellt werden, dass deutlich werden lassen soll, wie das Projekt aufgebaut ist und welche Technik dafür verwendet wurde.

Technikplakat

Sebastian und Fritz hielten sich dabei optisch an das Styleguide vom letzten Semester. Die hauptsächlich verwendete Grundfarbe war dabei Cyan (#05f1db), die sich auch im Logo der Forumsgruppe wiederfinden lässt. Der Hintergrund war ein sattes Schwarz, das so den Blick auf das Wesentliche lenken lässt. An den Seiten sind Partikel in den Farben des Zukunftsmuseums platziert, um so eine Brücke zum Veranstaltungsplakat herstellen zu können. In dessen Zentrum findet sich ein, aus Partikeln bestehender, Kreis wiederfindet. In der Mitte des Technikplakats ist das Forum oder der Aufbau des Prototyps zu finden, das sowohl Herzstück des Museums als auch des Projekts ist. Um das Abbild des Aufbaus herum befinden sich die verwendeten Techniken, wie die Projektoren, das Trackingsystem oder auch das Partikelsystem. Durch die weißen kontrastreichen Linien werden die in Verbindung stehenden Techniken deutlich. Ebenso wird klar, dass zur Realisierung OpenFrameworks verwendet wurde. Ein kurzer prägnanter Textpart wurde ebenso eingefügt, der zur Erklärung der Funktionsweise des Systems dienen soll. Neben dem Technikplakat arbeitete Fritz Lenssen zusätzlich noch an Grafiken für die Abschlusspräsentation, unter anderem an der Aufbau Grafik. Des Weiteren kümmerte sich, wie auch schon im vergangenen Semester, um den Druck der Plakate und der Aufkleber, die jedoch gleichblieben und sich nicht veränderten. Die verwendeten Grafiken sind im Anhang hinterlegt (vgl. Druck).

Trailer für Projektgruppe Forum

Allgemeiner Vorspann

Wie jede andere Gruppe auch musste ein Trailer erstellt werden. Dieser stellt das Projekt vor und soll für die Projektpräsentation werben. Hierfür erstellen Tobias Lindner und Sebastian Holzki ein Konzept. Berücksichtigt dabei wurde vor allem die Aufteilung des Inhaltes auf 4 Bildschirme. Anhand dieser Vorgabe wurde ein Trailer aus Videos des ersten Projektabschnitts und neuen Animationen erstellt.

Programmierung

Neue Codearchitektur

Klasse Particle

Um die genaue Funktionsweise eines Partikels zu verstehen, soll im Folgenden noch einmal etwas tiefer in die Klasse eingetaucht werden. Beginnend mit der überarbeiteten setup(...)-Methode, bis zu Auszügen aus der update(...)-Methode.

       void Particle::setup(ofVec2f _position, float sceneHeight){  
       position = _position;  
       velocity.set(0,0);  
       age = 0.0;  
       maxLife = 11.0;  
       color.set(ofRandom(100,150),ofRandom(100,150),ofRandom(20,255));  
       size = 1.5;  
       mass = 100;  
 
       activeSlowingDown = 0;  
       factorOfSlowingDown = 0.3;  
       activeSpeedingUp = factorOfSlowingDown;  
       factorOfSpeedingUp = 1;  
       scaleFactorPerDeltaT = 0.002;  
       distanceToCenter = 0;  
       angleToCenter = 0;  
       aging = true;  
     
       particleIsOnGround = isTheSetupPositionOnTheGround(position, sceneHeight);  
       } 

Bei der Erzeugung eines Partikels werden dessen Variablen mit Basiswerten gefüllt. Eigentlich sollte dieser Vorgang auch über eine externe XML-Datei realisiert werden, jedoch fanden wir keine ressourcenschonende Lösung für das Problem. Im Nachhinein kam die Idee auf, die XML bei Erzeugung des Partikelsystems in der Klasse ParticleSystem zu laden und dann als Übergabeparameter an jedes Partikel weiterzugeben, was tatsächlich auch keinen großen Aufwand bedeuten würde. Wie schon im Code des ersten Prototyp, kriegen Partikel im Moment ihrer Entstehung eine Position übergeben. In der Regel ist das die Position des Emitters, welcher das Partikel erzeugt. Anders als in Prototyp 1 wird der velocity (Bewegungsrichtung und Geschwindigkeit) während des setup vorerst nur ein festes Wertepaar (0,0) zugewiesen, da es unterschiedliche Szenarien gibt. In Abhängigkeit von Modus und Art des Emitters können unterschiedliche Regeln zur Definition der Partikelbewegung greifen. Ein Beispiel hierzu ist die Unterscheidung, ob es sich beim Emitter um einen CheckedInVisitor handelt oder um einen herkömmlichen Emitter.

       	if( objectPhysics->at(i)->emitting == true){ 
     
       	    this->particles.push_back(new Particle);  
     
       	       particles.back()->setup(objectPhysics->at(i)->getPosition(), sceneHeight);  
       	       if(objectPhysics->at(i)->type == "emitterOnStele"){  
       	           particles.back()->setRandomVelocityOnlyGoingDown();  
       	       }else{  
       	           particles.back()->setRandomVelocity();  
       	       }  
       	}  

Emittierende ObjectPhysics, welche sich auf einer Stele befinden geben ihren Partikeln Geschwindigkeiten, die sich nur nach unten ausbreiten. Diese Methode wurde genutzt, um den Raketeneffekt etwas authentischer darzustellen. Die Methode isTheSetupPositionOnTheGround(...), zur Festlegung des boolean particleIsOnGround, wird in Kapitel 2.5.1. zusammen mit den weiteren für das Mapping relevanten Methoden besprochen. Eine weitere interessante Methode ist die attractParticle(...)-Methode, welche sich zum Beispiel im Codeauszug in Kapitel 2.2.3. im Modus PARTICLE_MODE_DEFAULT wiederfindet. Die Methode wird dann aufgerufen, wenn ein Partikel von den aktiven Attraktoren der Szene angezogen werden soll. Die Art, wie sich die Anziehung berechnet ist abhängig davon, ob sich ein Partikel am Boden oder auf den Stelen befindet. Es ist wichtig, dass Partikel, welche sich auf den Stelen bewegen nicht von Attraktoren beeinflusst werden können, die sich in Wirklichkeit nicht in ihrer Nähe befinden und nur im Programm – dem Aufbau der gerenderten Szene geschuldet - so interpretiert werden.

Die erste Hälfte der Methode beschäftigt sich mit der Anziehung auf Partikel, die sich am Boden befinden. Für jedes ObjectPhysics wird überprüft ob es sowohl attractor, als auch attracting ist. Ist beides der Fall wird ein Vektor mit dem Namen force erzeugt, der die auf das Partikel wirkende Kraft darstellt. Nach einfacher Überlegung soll ein Partikel in die Richtung eines Attraktors angezogen werden. Um diesen Richtungsvektor zu erhalten muss also die eigene Position von der Zielposition abgezogen werden. Je kleiner der ermittelte Vektor force ist, desto näher befindet sich das Partikel am entsprechenden Attraktor. In unserem Fall addieren wir zur velocity, der aktuellen Bewegungsrichtung- und geschwindigkeit, bestimmte Längen des auf Länge 1 normalisierten force-Vektors auf. Ein Attraktor, dessen Abstand zum Partikel beispielsweise unter 50 liegt, zieht das Partikel mit 60facher (40+20) normalisierter force an. Für Partikel auf den Stelen kam die Überlegung auf, die Avatare der eingecheckten Besucher als Attraktoren zu nutzen, wobei deren Anziehungskraft mit der Zeit abnehmen sollte, sodass Partikel nur von neueren CheckedInVisitor-Instanzen angezogen werden. Um dies zu realisieren, iteriert jedes Partikel durch alle aktiven eingecheckten Besucher durch und überprüft deren Alter. Immer wenn ein CheckedInVisitor jünger als 30 Sekunden ist, wird für ihn – vorausgesetzt er befindet sich ausreichend nah am Partikel - eine force zur velocity addiert, die mit zunehmendem Alter abnimmt.

       	void Particle::attractParticle(vector<ObjectPhysics*>* objectPhysics, vector<CheckedInVisitor*>* checkedInVisitors){  
       	  
       	if(particleIsOnGround == true){  
       	  for(int i = 0; i < objectPhysics->size(); i++){  
       	     if(( (*objectPhysics).at(i)->type == "attraktor" ) && (objectPhysics->at(i)->attracting ==  true)){  
       	ofVec2f force;  
       	force.set(objectPhysics->at(i)->getPosition() - position);  
       	if(force.length() < 150){  
       	   velocity += force.getNormalized() * 40;  
       	}  
       	if(force.length() < 50){  
       	   velocity -= force.getNormalized() * 20;  
       	}  
       	    }  
       	  }  
       	}  
       	if(particleIsOnGround == false){          
       	   for(int i = 0; i < checkedInVisitors->size(); i++){  
       	     float ageOfCheckedInVisitor = checkedInVisitors->at(i)->getAge();  
       	     if(( ageOfCheckedInVisitor < 30.0 )){  
       	ofVec2f force;  
       	force.set(checkedInVisitors->at(i)->getBottom() - position);  
       	float forceLength = force.length();  
       	        if(forceLength < 250){  
       	   force = force.getNormalized() * ( 100 / ageOfCheckedInVisitor );  
       	   velocity += force;  
       	       }  
       	    }  
       	  }  
       	}}  

particleMode und Switch-Anweisungen

Das wahrscheinlich wichtigste Element des neuen Systems ist der sogenannte particleMode, der Modus, in welchem sich das (Partikel-)System befindet. Durch Definition eines solchen Modus, ist es jetzt möglich dem System an nur einer einzigen Stelle mitzuteilen, dass sich der Modus geändert hat und alle anderen Komponenten reagieren direkt entsprechend darauf. Realisiert wurde diese Mechanik schließlich durch Switch-Anweisungen, welche sich in den verschiedenen Klassen wiederfinden. Diese Komponente entstand in Zusammenarbeit mit Tobias Lindner. Die Applikation selbst, die Partikelsysteme und jedes Partikel wissen über den aktuellen Zustand des Systems Bescheid und rufen dementsprechende Methoden und Abläufe auf. Die Mechanik kann nach Belieben um weitere switch-cases erweitert werden. In den folgenden Kapiteln wird anschaulich erklärt, wie diese Switch-Anweisung in den einzelnen Klassen implementiert wurde und was die Besonderheiten sind. Der Inhalt der jeweiligen Switch-Anweisungen wurde auf die zwei wichtigsten cases, nämlich den Default-Modus PARTICLE_MODE_DEFAULT und den Besucher-hat-sich-eingecheckt-Modus PARTICLE_MODE_POLYMESH reduziert. Der folgende Code-Ausschnitt geht der Switch-Anweisung innerhalb der Klasse ofApp voraus.

     if (currentMode != lastMode) {  
           
           currentModeHasChanged = true;   
     	  
     }        
     if (currentModeHasChanged == true){  
     		      
           switch(currentMode){ ... }
     
     }  

Durch Definition eines particleMode lastMode zusätzlich zum particleMode currentMode kann das System feststellen, ob sich der Modus in dem es sich befindet geändert hat. Durch diese Mechanik wird garantiert, dass Veränderungen an den ObjectPhysics nur einmal ausgeführt werden, obwohl das System ständig wieder in die update-Methode springt. So lassen sich einmalige Veränderungen getrennt von dauerhaften, modusbedingten Abläufen behandeln.

In Klasse ofApp

Folgendes Codebeispiel zeigt Teile der Switch-Anweisung aus der c++ Datei ofApp.cpp.

     for(int i = 0; i < objectPhysics.size(); i++){  
            if ( (objectPhysics).at(i)->type == "emitter" ){                          
                 (objectPhysics).at(i)->setEmitting(true);                          
            }  
     }                  
     currentModeHasChanged = false;  
     break;                  
     }  
     
     case PARTICLE_MODE_POLYMESH: {          
         
      for(int i = 0; i < objectPhysics.size(); i++){                      
           if ( (objectPhysics).at(i)->type == "emitter" ){                          
                 (objectPhysics).at(i)->setEmitting(false);                          
           }  
     }                               
     currentModeHasChanged = false;                  
     break;                
     }  
     	  
     default:{}  

Es wird durch alle ObjectPhysics durchiteriert, die sich im Vektor befinden und dann kann nach Belieben manipuliert werden: Im PARTICLE_MODE_DEFAULT sollen alle vorhandenen Emitter neue Partikel emittieren können, deshalb wird bei jenen ObjectPhysics des Typs „emitter“ die in Kapitel 1.2. erwähnte boolean emitting auf true gesetzt. Im PARTICLE_MODE_POLYMESH wiederum sollen alle Emitter deaktiviert werden. Wenn die update-Methode der ObjectPhysics noch implementiert werden soll, müsste man entweder noch eine zweite Switch-Anweisung bauen, die nicht nur dann ausgeführt wird, wenn sich der Modus ändert, oder man zieht die kurze Anweisung zur Überprüfung in jeden Switch-case und macht die Überprüfung, welche Zeilen ausgeführt werden sollen dort.

In Klasse ParticleSystem

Folgendes Codebeispiel zeigt Teile der Switch-Anweisung aus der c++ Datei particleSystem.cpp.

     case PARTICLE_MODE_DEFAULT: {  
     
     PARTICLESYSTEM_BIRTHRATE = 1;  
     break;  
     }  
     
     case PARTICLE_MODE_POLYMESH: {  
     
           PARTICLESYSTEM_BIRTHRATE = 0;  
           updateLines(currentMode, objectPhysics);  
                 
           int PARTICLESYSTEM_BIRTHRATE_CHECKEDINVISITORS = 4;              
           while (PRODUCED_PER_EMITTER < PARTICLESYSTEM_BIRTHRATE_CHECKEDINVISITORS){  
                 for(int i = 0; i < checkedInVisitors->size(); i++){  
                       if( checkedInVisitors->at(i)->getAge() <= 7){  
                             this->particles.push_back(new Particle);  
                             particles.back()->setup(checkedInVisitors->at(i)->getBottom(), sceneHeight);  
                             particles.back()->setRandomVelocityOnlyGoingUp();  
                       }  
                 }                 
                 PRODUCED_PER_EMITTER++;  
           }  
           PRODUCED_PER_EMITTER = 0;  
           break;  
     }  
     
     default:{}  

Jedes Partikelsystem verwaltet „seine“ Partikel. Deshalb ist der richtige Ort um Effekte zu generieren, die eine Interaktion der Partikel erfordern hier. Das Partikelsystem überwacht und kontrolliert all seine Partikel von hier aus, vom Erzeugen neuer bis zum Löschen alter Partikeln. In diesem Fall wird im jeweiligen case die Birthrate festgelegt, mit welcher das Partikelsystem im Anschluss an die Switch-Anweisung Partikel an den Positionen aller aktiven Emittern erzeugt. Der PARTICLE_MODE_POLYMESH hat zusätzlich noch andere Funktionen: Die while-Schleife sorgt dafür, dass neu eingecheckte Besucher das Verhalten von Emittern imitieren. An der Mitte der unteren Bildkante des neuen CheckedInVisitor werden ab seiner Entstehung für eine festgelegte Zeit neue Partikel erzeugt, deren Bewegungsrichtung ausschließlich nach unten gerichtet ist. Folgende, aufgerufene Methoden aus den Klassen Particle und CheckedInVisitor sind für diesen Effekt erwähnenswert:

     ofVec2f CheckedInVisitor::getBottom(){  
           ofVec2f bottom = this->position;  
           bottom.x += hexagon.getWidth()/2;  
           bottom.y += hexagon.getHeight()*0.99;  
           return bottom;  
     }  
      
     void Particle::setRandomVelocityOnlyGoingUp(){  
           velocity.set(ofRandom(-50,50), ofRandom(-50,-1));  
     }  

In der Methode updateLines(...) wird das Liniennetz erzeugt, welches sich zwischen Besucher und nahen Partikeln sowie deren nächsten Nachbarn aufspannt. Das Partikelsystem hat wie bereits in der Architektur erwähnt einen Vektor aus einer variablen Anzahl an Objekten der Klasse Line. Dieser Vektor wird wie folgt mit Linien gefüllt:

     void ParticleSystem::updateLines(particleMode currentMode, vector<ObjectPhysics*>* objectPhysics){  
           lines.clear();  	
           for(int i = 0; i < objectPhysics->size(); i++){  
     
                 if((objectPhysics->at(i)->type == "attraktor")&&(objectPhysics->at(i)->attracting == true)){  
     
                       for(int p = 0; p < particles.size(); p++){  
     
                             if(particles.at(p)->particleIsOnGround == true){  
                                   ofVec2f distance = particles.at(p)->getPosition()-objectPhysics->at(i)->getPosition();  
                                         if(distance.length() < 150){  
                                               lines.push_back(new Line(particles.at(p)->getPosition(), objectPhysics->at(i)->getPosition()));  
     
                                               for(int p2 = 0; p2 < particles.size(); p2++){  
                                                     ofVec2f distance = particles.at(p)->getPosition() - particles.at(p2)->getPosition();  
                                                           if(distance.length() < 50){  
                                                                 lines.push_back(new  Line(particles.at(p)->getPosition(),particles.at(p2)->getPosition()));  
                                                           }  
                                                           p2 += 4;        
     }}}}}}}  

Auf den ersten Blick erscheint die Methode kompliziert, bei genauerem Betrachten aber wird die Vorgehensweise klar: Zuerst werden alle ObjectPhysics auf type und attracting überprüft. Für alle aktiven Attraktoren iteriert die Methode nun durch alle Partikel innerhalb des Partikelsystems und sucht sich jene, welche sich auf dem LED-Boden befinden, also particleIsOnGround == true ist. Woher diese Information kommt wird in Kapitel 2.5.1. näher erläutert. Als nächstes wird überprüft wie weit vom Attraktor sich das Partikel entfernt befindet. Fällt die Distanz unter einen bestimmten Schwellwert, in unserem Fall 150, wird dem Vektor lines eine neue Instanz der Klasse Line mit den Koordinatenpaaren von Partikel und Attraktor hinzugefügt. Außerdem überprüfen jene Partikel, deren Distanz zum Attraktor unter dem Schwellwert liegen noch, ob sich andere Partikel in einem noch kleineren Radius (hier 50) um sie selbst herum befinden. Für diese Partikel werden weitere Linien erzeugt und dem Vektor hinzugefügt, diesmal mit Koordinatenpaaren des Partikels und seinen nächsten Nachbarn. Da der Rechenaufwand dieser Methode exponentiell mit der Partikelanzahl in der Szene wächst, wurde die letzte for-Schleife etwas entschlackt, so dass ein Partikel nur noch jedes fünfte weitere auf seine Distanz überprüft. Die Übergabe des particleMode currentMode könnte für mögliche Varianten des Effekts nützlich werden. Der Aufruf der draw(...)-Methode innerhalb des Partikelsystems sieht jetzt wie folgt aus und berücksichtigt in Abhängigkeit vom Modus den Vektor lines:

     void ParticleSystem::draw(typeOfView activeTypeOfView){  
           for(int i = 0; i < particles.size(); i++){    
                 particles.at(i)->draw(activeTypeOfView);  
           }  
           if( currentMode == PARTICLE_MODE_POLYMESH){  
                 for(int i = 0; i < lines.size(); i++){  
                       ofDrawLine(lines.at(i)->point1, lines.at(i)->point2);  
                 }     
           }  
     }  

Unter der Bedingung, dass gilt currentMode == PARTICLE_MODE_POLYMESH werden durch Verwendung der openFrameworks-Methode ofDrawLine alle Linien mit ihren gespeicherten Punkten aus dem Vektor lines in die Szene gezeichnet. Dieser Effekt wird im Prototypen immer dann ausgelöst, wenn ein CheckedInVisitor erzeugt wird, sich also ein Besucher an einer Einlesestation eincheckt.

In Klasse Particle

Folgendes Codebeispiel zeigt Teile der Switch-Anweisung aus der c++ Datei particle.cpp.

     case PARTICLE_MODE_DEFAULT: {  
           if(currentMode != lastMode && lastMode == PARTICLE_MODE_POLYMESH){  
                 activeSpeedUpFactor = activeSlowDownFactor;  
           }  
           if(activeSpeedUpFactor < maximumSpeedUpFactor){  
                 activeSpeedUpFactor = activeSpeedUpFactor + deltaT;  
           }else{  
                 activeSpeedUpFactor = maximumSpeedUpFactor;  
           }  
     
           attractParticle(objectPhysics, checkedInVisitors);  
     
           position += activeSpeedUpFactor * (velocity * deltaT);  
           aging = true;  
     
     break;  
     }  
     case PARTICLE_MODE_POLYMESH: {  
     
           if(currentMode != lastMode){  
                 activeSlowDownFactor = 1;  
           }  
           if(activeSlowDownFactor > maximumSlowDownFactor){  
                 activeSlowDownFactor = activeSlowDownFactor - deltaT;  
           }else{  
                 activeSlowDownFactor = maximumSlowDownFactor;  
           } 
     
           position += activeSlowDownFactor * (velocity * deltaT);  
                 aging = true;  
                 break;      
           }
           default: {}  

In der Klasse Particle wird hauptsächlich die Bewegung und das Verhalten eines Partikels berechnet. Beim Durchschalten von verschiedenen Modi läuft man schnell Gefahr, dass eine Veränderung in z.B. Geschwindigkeit oder Richtung abgehakt und ruckelig wirken, da man von einer Formel für die Berechnung der Geschwindigkeit in eine andere „springt“. Da eine solche Veränderung in der Geschwindigkeit beim Wechsel zwischen PARTICLE_MODE_DEFAULT und PARTICLE_MODE_POLYMESH erwünscht ist, wurden ein paar Zeilen Code eingebaut, die garantieren, dass sich die Geschwindigkeitsberechnung nicht direkt ändert, sondern sich gekoppelt an die vergangene Zeit, langsam an die gewünschte Berechnung annähert. Wechselt ein Partikel beispielsweise von einem schnellen (DEFAULT) in einen langsamen (POLYMESH) Modus, so wird seine Geschwindigkeit anfangs noch mit dem „Bremsfaktor“ 1.00 multipliziert. Dieser Bremsfaktor, im Code als activeSlowDownFactor bezeichnet, wird nun mit jeder Iteration um deltaT gesenkt, bis es den Zielwert maximumSlowDownFactor erreicht. Dieser ist wiederum extern definiert und kann nach Belieben verändert werden. Dieses Vorgehen sorgt dafür, dass das Partikel allmählich langsamer wird und nicht plötzlich eine neue Geschwindigkeit zugewiesen bekommt. Darüber hinaus können in der Switch-Anweisung der Partikel Eigenschaften wie das aging oder die Berechnung der Anziehungskräfte durch aktive Attraktoren verwaltet und reguliert werden. Auf die Methode attractParticle(...) wird im Folgenden Kapitel 2.3. genauer eingegangen.

Das Interface ObjectPhysics

Nach aktuellem Stand werden in unserem System zwei Kindklassen des Interfaces benutzt, die Attraktoren und die Emitter. Während die Unterschiede dieser Klassen bereits erläutert wurden – mehr zur Relevanz dieser Unterschiede in 2.2.2. – sollen hier die Gemeinsamkeiten dargestellt werden.

     class ObjectPhysics {  
     
           public:  
     
                 ObjectPhysics();  
                 ~ObjectPhysics();  
     
                 void update(float deltaT);  
        
                 void setPosition(float x, float y);  
                 void setPosition(ofVec2f position);  
                 ofVec2f getPosition(); 
     
                 void setEmitting(bool emitting);  
                 void setAttracting(bool attracting); 
     
                 void setIsVisitor(bool isVisitor);  
                 bool getIsVisitorObject();  
                 float getAge();  
                 void aging(float deltaT);  
     
                 string type;  
                 ofVec2f position;  
                 bool emitting;          //if true: Particles will emit from the position  
                 bool attracting;        //if true: Particles will be attracted to the position  
                 bool agingEnabled;  
                 bool isAVisitorObject;  
                 float age;  
                 float force;  
                 float vel;  
     
           };  

All jene Variablen und Eigenschaften hat jede Instanz der Kindklassen des Interfaces. Hervorzuheben ist, dass anhand der Methoden setEmitting() und setAttracting() auch zur Laufzeit die Funktionalität von ObjectPhysics verändert werden kann. Zudem kann definiert werden, ob es sich bei einer Instanz um einen Besucher im Raum handelt oder nicht. So kann in Effekten zwischen System-OPs und Besucher-OPs unterschieden werden, um Beispielsweise im System verankerte Emitter unabhängig von besuchergesteuerten Emittern anzusprechen. ObjectPhysics haben außerdem ein Alter, wobei je nach Art und Verwendung des OPs festgelegt werden kann, ob es altern kann oder nicht. Es ist nicht sehr sinnvoll den Attraktor eines Besuchers im Raum altern zu lassen, da seine Bewegungen und Interaktionsdauer willkürlich und nicht vorhersehbar sind. Sinnvoller wird diese Mechanik beispielsweise bei eingecheckten Besuchern, wenn Instanzen der Klasse CheckedInVisitor entsprechende ObjectPhysics generieren und diese nur eine gewisse Zeit als Emitter oder Attraktoren aktiv sein sollen. Um dieses Altern zu ermöglichen, wurde auch für alle ObjectPhysics eine klassische update-Methode geschrieben. Will man später noch andere Methoden implementieren, durch die ObjectPhysics in Laufzeit beeinflusst werden, können diese dann hier aufgerufen werden. Geplant ist beispielsweise eine move(...)-Methode für einen zukünftigen Effekt, bei dem eine gewisse Anzahl an Emittern an den Spitzen der Stelen Kreise um die Besucher ziehen und dabei Partikel emittieren, welche dann wie leicht seitlich fallende Schneeflocken in die Szene fallen. Auch hier wäre wiederum möglich beispielsweise die Farbe der emittierten Partikel mit dem Alter der Emitter zu koppeln. Im alten System gab es lediglich eine Art von Objekten, welche Einfluss auf die Partikel hatten: die Attraktoren. Das waren Punkte, welche eine gewisse Anziehung auf die Partikel haben, zu denen sich die Partikel also bewegen. Die Attraktoren wurden direkt in der Klasse des Gesamtsystems durch Informationen aus dem Tracking erzeugt und von dort an die Partikel übergeben. Diese Vorgehensweise mag für die damaligen Ansprüche ausgereicht haben, jedoch ist die Mechanik und Steuerung dadurch sehr beschränkt und kaum in Echtzeit modifizierbar. Die Idee im neuen Konzept war, Attraktoren mit Emittern in einem Interface zusammenzufassen und die Möglichkeit offenzuhalten, diesem Interface später noch andere Klassen hinzufügen zu können. Außerdem wurde für weitreichendere Kontrolle hierarchisch noch eine Klasse zwischen ofApp und Particle gebaut, die Klasse ParticleSystem.

           class ofApp {  
                 ...  
                 vector<ObjectPhysics*>* objectPhysics;  
                 ...  
           }  
     
           class Particle {  
           ...  
           update(..., vector<ObjectPhysics*>* objectPhysics, ...);  
           ...  
           }  
     
           class ParticleSystem {  
                 ...  
                 update(..., vector<ObjectPhysics*>* objectPhysics, ...);  
                 ...  
           }  

Im Kern handelt es sich bei Objekten des Interface ObjectPhysics um einen zweidimensionalen Vektor der Klasse ofVec2f, ausgestattet mit einigen Eigenschaften und Methoden, die beim späteren Einsatz helfen. Die drei wichtigsten Eigenschaften sollen hier kurz ausgeführt werden: bool emitting; Mithilfe dieses boolean kann ein Partikelsystem später feststellen, ob an der Position des überprüften ObjectPhysics Partikel erzeugt werden sollen. bool attracting; Mithilfe dieses boolean kann ein Partikel später feststellen, ob es an der Position des überprüften ObjectPhysics angezogen werden soll. string type; Anhand des Typs erkennen Partikel und Partikelsysteme wie sie sich bezüglich der Position des ObjectPhysics zu verhalten haben. Diese Eigenschaften lassen sich auch in Laufzeit bearbeiten, um beispielsweise auch ObjectPhysics vom Typ Emitter für gewisse Zeit deaktivieren zu können. In diesem Kapitel soll lediglich der Aufbau und die Funktionsweise des neuen Systems erläutert werden, weshalb sich weitere Ausführungen dazu, wie Partikel und Partikelsysteme diese ObjectPhysics verarbeiten in Kapitel 2 wiederfinden.

Attraktoren

Die Klasse der Attraktoren ist gewissermaßen ein Erbstück aus der ersten Projekthälfte. Sie wurde jedoch grundlegend überarbeitet und mit einigen neuen Eigenschaften ausgestattet, die größtenteils in das Interface eingepflegt wurden, auf welches der Attraktor aufbaut. Es gibt mehrere Konstruktoren, mit welchen Attraktoren erzeugt werden können, wobei direkt alle Eigenschaften wie booleans und type Attraktor-spezifisch festgelegt werden.

Emitter

Der Emitter unterscheidet sich vom Attraktor hauptsächlich im Namen und seinem gesetzten Typen. Zudem werden Eigenschaften, wie attracting/emitting, im Konstruktor anders gesetzt als beim Attraktor.

Visitors

In der neuen Architektur werden die Informationen, welche das Trackingsystem per OSC liefert nicht mehr direkt an die Partikel weitergegeben. Für bessere Übersichtlichkeit sowie Kontrolle sollen jegliche Informationen über Besucher im Raum in Instanzen einer eigenständigen Klasse gespeichert werden, auf welche dann von anderen Seiten zugegriffen werden kann. So besteht die Möglichkeit je nach aktivem Modus anders mit den visitor-Informationen umzugehen. Während die Besucher im einen Modus noch als Attraktoren über den Boden wandern, können sie in der nächsten Sekunde zum Mittelpunkt eines komplexen Liniennetzes werden oder selber Partikel emittieren.

CheckedInVisitors

Die Idee, dass Besucher sich nach dem Museumsbesuch in der Installation „verewigen“ können, wurde aus der ersten Projekthälfte übernommen und weitergeführt. Zur Realisierung wurde die Klasse des CheckedInVisitor konzipiert. Instanzen dieser Klasse repräsentieren eingecheckte Besucher anhand eines Avatars, der aus einer Sammlung individueller Daten generiert wird, die während des Aufenthalts gesammelt wurden. Ein CheckedInVisitor wird dann erzeugt, wenn sich ein Besucher per RFID – in unserem Prototypen per TouchOSC - an einer Einlesestation einliest. Diese Instanz der Klasse selbst lässt sich bewegen und kann so in die Spitzen der Stelen überführt werden, wo sie sich fortan mit weiteren CheckedInVisitor-Objekten über die Stelen bewegt. Gemeinsam bilden die Besucher eine wachsende Ansammlung von individuellen Zukunftstypen. Für maximale Individualisierung kann eine Kamera in die Einlesestation integriert werden. Der Besucher kann nun zusätzlich frei entscheiden, ob er zur Generierung seines Avatars noch ein Bild bereitstellen will. Informationen über alle checkedInVisitors werden ebenfalls im Hauptsystem verwaltet, wodurch anderen Klassen wiederum die Verarbeitung der Informationen ermöglicht wird. So können anhand der eingecheckten Besucher direkt Instanzen des Interfaces ObjectPhysics erzeugt werden.

Neue Stelen Code Architektur - Spielauswertung

Nach dem Design-Abschnitt beschäftigte sich Katharina Ott intensiv damit, die Darstellung der neu gestalteten Symbole in das Gesamtsystem einzuarbeiten, und die Spieleauswertung auf den Stelen zu entwickeln. Anfänglich wurde von Sebastian Holzki die Gesamtarchitektur des Systems entwickelt. Parallel hierzu implementierte Katharina Ott Bestandteile und Komponenten des Einzelsystems der Stelen. Nachdem sie aus dem Dateisystem die alten Symbole gelöscht hatte, fügte sie die von ihr entwickelten neuen Symbol PNG-Dateien ein um diese auch im Programmcode verfügbar zu machen. Das Hexagon wurde von Katharina Ott getrennt von den Symbolen eingelesen. Das Hexagon selbst soll zu Beginn als Partikelwolke angezeigt werden. Um die Partikel in Form eines Hexagons anzuordnen, wird über alle Pixel der Hexagon PNG-Datei iteriert. Für jeden Pixel wird geprüft ob dieser nicht transparent ist, da alle transparenten Pixel den Hintergrund darstellen. Alle nicht transparenten Pixel werden in einer Vektor Datenstruktur gespeichert. Dieser Vektor wird anschließend genutzt um jedem Partikel eine Koordinate der Punkte aus dem Vektor als Attraktor (Anziehungspunkt) zuzuweisen. Für die Positionierung des Symbols und des Hexagons konnte Katharina Ott auf bestehenden Code zurückgreifen. In diesem mussten die verwendeten Koordinaten geringfügig angepasst werden.

Planung

Um die Zuständigkeiten der Klassen besser Aufteilen zu können und das System der Stelen weiter zu modularisieren, entschied Katharina Ott das bisherige System (ofApp und Partikel Klasse) in mehr als zwei Klassen aufzuteilen. Dadurch erzeugte sie eine bessere Wart- und Lesbarkeit und vermied darüber hinaus Codeduplizierungen. Ein Weiterer Vorteil hierbei war, dass hierbei mehrere Symbole eingelesen und angezeigt werden konnten.

Komponenten

Folgende Systemkomponenten wurden von Katharina Ott identifiziert.

ofApp: Diese Klasse verwaltet die *-Partikel-Systeme und gibt vor, welches Bild verwendet wird.

Bild: Ein Objekt dieser Klasse repräsentiert ein darzustellendes Symbol. Es verwaltet seine aktuelle Position und stellt eine Referenz auf das darzustellende Bild (Pfad zur Bilddatei) dar. Es zeichnet ebenfalls ein Hexagon um das Bild. Zudem steuert es, wie sich die Position des Bildes während seiner Lebenszeit verändert.

Partikel: Objekte dieser Klasse repräsentieren einen einzelnen Partikel. Hier wird die Zeichnung und Positionsverschiebung eines einzelnen Partikels anhand eines übergebenen Attraktors realisiert.

Bild-Partikel-System: Ein Objekt der Klasse Bild-Partikel-System verwaltet einen Attraktor und übergibt diesen dem Partikel und setzt Referenzen auf ein Objekt der Bild Klasse und einen Vektor aus Partikeln.

Regen-Partikel- System: Diese Klasse setzt Referenzen auf einen Vektor aus Partikeln und setzen des Attraktors.

Ablauf

Nach Identifizierung der möglichen Komponenten des Stelen-Systems konzipierte Katharina Ott den Ablauf und das Zusammenspiel der einzelnen Komponenten. Die Einstiegsstelle des Stelen-Systems bildet die ofApp Klasse. Sie ist für die zentrale Verwaltung des Ablaufs zuständig. Solange kein Datensatz eingelesen wird, soll ein Regen von Partikeln dargestellt werden. Um das zu realisieren erstellt die ofApp Klasse nach Start des Systems ein Regen-Partikel-System. Wird ein neuer Datensatz eingelesen (bisher realisiert über die Eingabe einer Zahl) soll in der ofApp Klasse ein neues Bild-Partikel-System mit dem passenden Symbol erstellt werden. Das erstellte Bild-Partikel-System erstellt anschließend die sich um das Bild bewegenden Partikel sowie das eigentliche Bild selbst. Die Partikel und das Bild kümmern sich dann um die Bewegungen auf dem Bildschirm.

Umsetzung des geplanten Konzepts

Um den in Kapitel 4.2.1.2 genannten Ablauf mit den jeweiligen Komponenten umzusetzen wurden von Katharina Ott die Klassen Image, ImageParticleSystem und RainParticleSystem mit den notwendigen Attributen erstellt und die Attribute der bestehenden Klassen (ofApp und Particle) angepasst.

Anpassung in der ofApp Klasse

Beim Start des Stelen Systems wird die Setup() Methode der ofApp Klasse aufgerufen. In dieser wird nun ein Objekt der Klasse RainParticleSystem erstellt. In diese Klasse wurde von Katharina Ott die bisherige Logik für das Darstellen eines Regens mit Partikeln eingefügt.

           rainIsActive = true;  
           int particleSystems = 7;    //number of rainparticlesystems (one for single stele)  
           
           //calculate the width for every single rainparticlesystem  
           float sceneSizeForSingleParticleSystem = sceneSize.x / particleSystems;   
       
           //create all rainparticlesystem  
           for (int i = 0; i <= particleSystems - 1; i++) {   
           rainParticleSyst.push_back(new RainParticleSystem(i * sceneSizeForSingleParticleSystem, sceneSizeForSingleParticleSystem, sceneSize.y));  
           }  

Wenn ein Datensatz eingelesen wird, muss ein ImageParticleSystem erstellt werden. Da es möglich sein soll, mehrere Datensätze gleichzeitig auf dem Bildschirm anzuzeigen, wurde von Katharina Ott ein Vector, der ImageParticleSystem verwaltet, eingefügt. Bei Einlesen eines Datensatzes wird zu diesem Vector ein neu erstelltes ImageParticleSystem-Objekt hinzugefügt. Anschließend hat Katharina Ott die Update() Methode der ofApp Klasse dahingehend angepasst, dass lediglich die Update() Methode des erzeugten RainParticleSystems aufgerufen wird, sollte vorher kein Datensatz eingelesen werden. Sobald ein Datensatz eingelesen wird, wird über die ImageParticleSystem Objekte des oben genannten Vektors iteriert und für jedes System die Update() Methode aufgerufen.

     void ofApp::update() {  
           if (rainIsActive) {           
           //Movement of the particles of rainparticlesystems  
                 for (int i = 0; i < rainParticleSyst.size(); i++) {  
                       rainParticleSyst.at(i)->updateParticleSystem();  
                 }  
           }  
           else {    
                 //Movement of Imageparticlesystems and symbols when rain is false  
                 for (int i = 0; i < imageParticleSystems.size(); i++) {  
                       imageParticleSystems.at(i)->updateParticleSystem();  
                 }  
           }  
     } 

Implementierung der RainParticleSystem Klasse

Im System sind zwei unterschiedliche Anordnungsformen von Partikeln vorhanden. Einerseits sollen, solange kein Datensatz eingelesen wird, die Partikel in Form eines Regens dargestellt werden. Andererseits sollen die Partikel den dargestellten Symbolen bei Einlesen eines Datensatzes folgen, um das visuelle Erlebnis aufzuwerten. Die Logik der beiden Anordnungsformen unterscheidet sich deutlich voneinander. Infolgedessen wurde die Implementierung in zwei unabhängige Klassen aufgeteilt. Die Klasse RainParticleSystem ist zuständig für die Darstellen der Partikel als Regen. Bei der Implementierung wurde der bestehende Code für die Darstellung des Regens wiederverwendet und in diese Klasse verschoben. Um die Partikel zu steuern, werden die Attraktoren, sowie die Partikel selbst in jeweils einer Vektor Datenstruktur verwaltet. Die RainParticleSystem Klasse erstellt bei Bedarf die nötigen Partikel für den Regen und befüllt damit den Vektor.

     void RainParticleSystem::createParticlesForRain()  
     {  
           for (int i = 0; i < parAmount; i++) { 
     
                 particles.push_back(new Particle);  	
                 int rgen = ofRandom(startSceneX, startSceneX + sceneSizeX);  
     
                 particles.back()->setup(ofVec2f(rgen, sceneSizeY), 20);  
           }  
           birthCnt = 0;  
     }  

Ähnlich des Ablaufs im Grundsystem müssen die Partikel bei Bedarf geupdatet (bewegt) und in jedem Frame gezeichnet werden. Die RainParticleSystem Klasse iteriert dafür über alle Partikel im Vektor und ruft für jeden Partikel dessen Update()- und Draw()-Methode auf.

===== Implementierung der ImageParticleSystem Klasse

Wie bereits im RainParticleSystem werden die Partikel im ImageParticleSystem erstellt, aktualisiert und gezeichnet. Der Unterschied hier ist jedoch, dass die Partikel in verschiedenen Formen, um ein Bild angeordnet werden müssen. Diese Klasse benötigt dementsprechend Zugriff auf das zu zeichnende Symbol, sowie auf die Partikel, die um das Symbol dargestellt werden sollen. Das zu zeichnende Bild wird in einem ofImage Objekt aus der OpenFrameworks Bibliothek gespeichert. Da jedes Bild mit einem Hexagon umrahmt wird, wird auch das Bild für das Hexagon in einem ofImage Objekt gespeichert. Diese beiden ofImage Objekte werden später von Katharina Ott in der DrawableImage Klasse zusammengeführt (siehe nächster Abschnitt). Auf diese Objekte setzt das ImageParticleSystem eine Referenz. Diese Referenz repräsentiert das zu zeichnende Bild. Die Partikel und Attraktoren, die benötigt werden, um die Darstellung des Symbols aufzuwerten, werden von Katharina Ott wie bereits im RainParticleSystem in zwei Vektor Datenstrukturen gespeichert. Da sich die Darstellungsformen der Partikel während der Darstellung eines Symbols ändern können, gibt es verschiedene Create() und Delete() Methoden, welche die korrekte Anzahl von Partikeln zum jeweiligen Zeitpunkt sicherstellen. Bei der Implementierung dieser Methoden griff Katharina Ott auf bestehenden Code zurück, reduzierte die Methodenfunktionalitäten um nicht benötigte Features, um Rechenleistung einzusparen und die Ausführungszeit zu optimieren. Die Darstellung eines Symbols hat den folgenden Ablauf: 1. Darstellung des Symbols in einem Hexagon 2. Anordnung der Partikel in Form eines Hexagons 3. Bewegung des Bildes nach oben 4. Anordnung der Partikel in Form eines Antriebs einer Rakete unter dem Symbol 5. Bewegung des Bildes nach rechts 6. Bewegung der Partikel hinter dem Bild 7. Nach Verlassen des rechten Randes: Darstellung des Symbols am linken Bildrand Die Realisierung dieser Abläufe wurde in der updateParticleSystem() Methode implementiert. Hier werden mit Countern die Dauer bzw. durch Positionsüberprüfung die Maximalposition der jeweiligen Phasen gesteuert. Vor bzw. nach jeder Phase wird die Anzahl der Partikel durch die Create() und Delete() Methoden gesteuert.

     void ImageParticleSystem::createParticlesForHexagonInSymbol()  
     {  
           int newPix = (picPix / 7) - particles.size();  
           for (int i = 1; i <= newPix; i++) {                          //Go through pixel i = 1 (there is no pixel 0)  
           particles.push_back(new Particle);  
     
           int x = sceneSizeX / 2;  
           int y = sceneSizeY; 
     
           particles.back()->setup(ofVec2f(x, y), 20);  
           }  
     }  

Die ImageParticleSystem Klasse steuert diese Phasen und teilt dem Symbol inklusive des Hexagons (DrawableImage) und den Partikeln mit, sich upzudaten. Die ersten beiden Phasen waren bereits im bestehenden Code vorhanden. Wurde modifiziert und in die updateParticleSystem() Methode eingefügt. Die restlichen Phasen wurden von Katharina Ott neu implementiert . Bei der Bewegung nach oben wird in jedem Frame überprüft, ob das Symbol und die Partikel bereits an der Zielposition (z.B.: „nahe dem oberen Rand“) sind. Ist dies nicht der Fall, wird der DrawableImage- und der Partikel-Klasse mitgeteilt, ein Update innerhalb dieser Phase durchzuführen und die Phase nicht zu wechseln.

Implementierung der DrawableImage Klasse

Die DrawableImage Klasse vereint wie bereits oben beschrieben, das darzustellende Symbol, sowie das umgebene Hexagon. Sie ist für die Bewegung und für das Zeichnen der beiden Bilder (pro Datensatz) zuständig. Beide Bilder werden jeweils in ofImage Objekten gespeichert. In den Phasen des ImageParticleSystem teilt dieses seinem DrawableImage mit, wie es sich bewegen muss. Anschließend werden die jeweiligen X und Y Positionswerte in der DrawableImage Klasse angepasst. Ist die Zielposition des Symbols noch nicht erreicht wird die Y-Position des DrawableImage (Symbol + Hexagon) erhöht.

     //y-Movement to cloud  
     if (pastMaxYInWave) {  
           yToMoveIntoCloud += newCloudVelY;               //y up  
     }  
     else {  
           yToMoveIntoCloud -= newCloudVelY;               //y down  	
     }  

Hat das Bild seine Zielposition erreicht, beginnt die Phase, welche das Bild am oberen Rand nach rechts bewegt. Hier wird in jedem Frame geprüft ob das Symbol bereits den rechten Bildrand erreicht hat. Solange der Rand noch nicht erreicht wurde, wird die Y-Position des DrawableImage inkrementiert. Wenn der Rand erreicht wurde, wird das Bild neu am linken Bildrand dargestellt. Bei der Neupositionierung des Symbols am linken Bildrand entstanden anfangs Probleme, da die Partikel durch das gesamte Bild flogen, um wieder ihre Position hinter dem Symbol einzunehmen. Dieses Problem konnte dadurch gelöst werden, dass die Partikel gelöscht werden und neu am linken Rand erzeugt werden. Eine weitere Aufgabe, die diese Klasse übernimmt, ist das Anpassen der Farbe des Symbols und des Hexagons. Hierfür wurden von Katharina Ott zwei verschachtelte For-Schleifen implementiert, die über die Pixel der Einzelbilder iterieren. Die äußere Schleife durchläuft eine Zeile von Pixeln des Bildes. Die Innere iteriert über die Spalten. Pro Pixel des Bildes werden Informationen über den Rot-Wert, den Grün-Wert, den Blau-Wert und die Transparenz des Pixels gespeichert. Da durch den vollständigen Informationsbestand iteriert wird, wird die aktuelle Position vor Zugriff auf den Wert mit vier multipliziert.

     for (int x = 0; x < picWidth; x++) {  
           for (int y = 0; y < picHeight; y++)  
           {  
                 int index = (x + y * picWidth) * 4; 
     
                 if (imageToDraw.getPixelsRef()[index + 3] >= threshold) {  
     
                       imageToDraw.getPixelsRef()[index] = r;  
                       imageToDraw.getPixelsRef()[index + 1] = g;  
                       imageToDraw.getPixelsRef()[index + 2] = b;  
                 }  
           }  
     }  

Ist der Transparenz-Wert des Pixels über einem bestimmten Schwellwert, wird der Pixel neu eingefärbt. Liegt der Wert unter dem Schwellwert, ist ein Einfärben nicht notwendig, da der Pixel nicht dargestellt wird. Die DrawableImage Klasse ist letztendlich auch die Klasse die das Symbol und das Hexagon auf den Bildschirm zeichnet. Hierfür wird auf beiden Bildern jeweils die Draw() Methode aus OpenFrameworks aufgerufen.

Anpassung der Particle Klasse

Bei der Anpassung der Particle Klasse wurden bestehende Code Abschnitte zusammenhängend mit der Partikelbewegung angepasst und zu neuen Methoden zusammengefügt. In den Phasen des ImageParticleSystem, teilt dieses dem jeweiligen Partikel mit, wie es sich bewegen muss. Anschließend wurden die jeweiligen X und Y Positionswerte in des Attraktors angepasst. Ist die Zielposition des Attraktors noch nicht erreicht, wird die Position weiter in jedem Frame erhöht.

Verfeinerung des Designs der Stelen

Nachdem das Stelen System von Katharina Ott an die neue Architektur angepasst wurde, nahm sie gemeinsam mit Agathe Gnus weitere Design-Änderungen vor. In der DrawableImage Klasse passten sie den Schwellwert an, welcher für die Bewegung des Symbols zu dem maximalen Wert an der oberen Kante zuständig ist. Sie entschieden sich dafür, einen Vektor aus bestimmten Y-Werten zu erstellen, aus dem ein zufälliger Wert als Schwellwert für die Bewegung des Symbols nach oben in der Setup() Methode bei Erstellung eines Symbols genutzt wird. Die Wahl dieses Vektors ist notwendig, da die Symbole nach einiger Zeit in einer Honigwabenstruktur angeordnet werden sollen. Mit Verwendung der zufälligen Y-Werte als Schwellwerte wird eine korrekte vertikale Koordinate für die Wabenstruktur genutzt. Nach einer gewissen Zeit muss nun noch der X-Wert des Symbols angepasst werden, um die Wabenstruktur zu erhalten.

"Großes Ganzes"

Ein weiteres Projektziel war, einen sogenannten „Raketeneffekt“ in das „Große Ganze“ umzusetzen. Geplant war, dass die Partikel, welche um das Symbol als Hexagon schweben sich zunächst am unteren Rand verdichten. Danach sollten sie einen Feuersschweif bilden, den das sich nach oben bewegende Symbol nach sich zieht. Dieses Nachziehen der Partikel wurde vom Team als „Raketeneffekt“ betitelt. Sobald der Effekt getriggert worden ist, wird ein Counter nach oben gezählt und die Y-Koordinate des Bildes verringert sich in jedem Frame. Des Weiteren definierte Katharina Ott einen Schwellwert für die maximale Y-Position. Durch diesen verhinderte sie, dass das Symbol über die obere Kante des gemappten Bereiches verschwindet.

     bool DrawableImage::imageIsOnTop(float sceneSizeY) {              
     //see if symbol and particles reached cloud  
     	  
     return yToMoveIntoCloud >= maxYpositionForPicture;  
     }  

Im Verlauf des Projekts stellte sich heraus, dass die Anzeige von mehreren Symbolen nur durch Codeduplizierung möglich war. Deswegen entschied Katharina Ott die Architektur des Systems anzupassen. Das Team hat sich für diesen Ablauf des „Großen Ganzen“ entschieden:

Ablaufplan des "Großen Ganzen"

Wabenstruktur

Für die Gestaltung des „Großen Ganzen“ gab es zudem eine zweite Überlegung, welche aber schlussendlich auf Grund von Zeitmangel nicht umgesetzt werden konnte. Dennoch soll sie hier vollständigkeitshalber Erwähnung finden. Anders als oben beschrieben sollen sich die einzelnen Hexagone aneinander angliedern, Grenzlinie an Grenzlinie, ohne dass dazwischen noch freie Abstände bestehen. Auch findet in dieser Überlegung die sinusoide Bewegung keinen Platz mehr. Diese Wabenstruktur sollte entstehen, indem die neu hinzukommenden Symbole die Position des vorherigen Symbols erfragen und dementsprechend an dieses andocken, sobald sie oben angekommen sind. Diese Positionsabfrage würde sich aber äußerst kompliziert gestalten, da sich die gesamte Wabenstruktur nach rechts bewegen sollte. Ein anderer Ansatz um das selbe Ergebnis zu erzielen wäre das Addon „ofXBox2d“ zu verwenden, doch auch das wäre ein zusätzlicher Zeitaufwand. Mit diesem Addon kann man die Position anderer Objekte abfragen und so auch zum Beispiel ein Abstoßen der Gegenstände untereinander simulieren. Da die Umbauarbeiten an unserm Code für diese andere Wabenstruktur sehr viel Zeit gebraucht hätten, einigten wir uns drauf unseren oben beschriebenen Ansatz mit der sinusoiden Bewegung unserer Symbolcluster weiter zu verfolgen.


Code Refactoring

Nach der vollständigen Implementierung der Funktionalitäten passte Katharina Ott den Code an gegebene Code Conventions an. Hierdurch verbesserte sie die Wartbarkeit und Lesbarkeit des Codes erheblich. Dafür ging sie sukzessive alle Methoden und Variablen des Codes durch, um diese auf richtige Benennung zu überprüfen. Falls dies nicht der Fall war, passte sie Variablen- und Methodennamen so an, dass diese repräsentativ für den Aufgabenbereich bzw. den Wertebereich stehen. Bei Abschnitten, die ohne Kommentare nur schwer verständlich waren, fügte sie passende Kommentare ein. Anschließend passte Katharina Ott noch die Klassennamen entsprechend der Code Convention an die Großschreibung an. Das Team beschloss die Kommentare in Englisch zu verfassen, dies übernahmen Agathe Gnus und Katharina Ott.


Gesamtsystem

Nachdem von Sebastian Holzki die erste Version des Gesamtsystems auf Git hochgeladen wurde, testete Katharina Ott die Integration des Stelen-Systems. Bei der Realisierung der Kompilierung des Gesamtsystems traten lediglich unwesentliche Probleme auf. Durch Umwandlung von .hpp-Dateien zu .h-Dateien wurden die Probleme behoben. Nach Anpassung der Dateien konnte das Gesamtsystem mit Hilfe von VisualStudio erfolgreich kompiliert werden. Das testweise Einfügen führte jedoch wie erwartet nur zu einer kompilierbaren Lösung, die vollständige Funktionalität konnte noch nicht sichergestellt werden. Denn Boden und Stelen arbeiteten im selben Fenster übereinander. Nach dem das Gesamtsystem von Sebastian Holzki fertig gestellt worden war, halfen Agathe Gnus und Katharina Ott das System der Stelen in dieses einzubauen. Zuerst bauten sie das Einlesen der Symbole in das Gesamtsystem ein. Danach erarbeiteten sie den „Raketeneffekt“. Hierbei machten sie weitere Anpassungen, damit die Bewegungen noch flüssiger wirken. Abschließend wurde von ihnen die Bewegung nach rechts im Gesamtsystem übernommen.


Zusammführung beider Codes

Der letzte große Abschnitt dieses Semesters beinhaltete die Zusammenführung der zwei verschiedenen Codes, die unsere Gruppe programmiert hatte. Der erste Code beinhaltet das Tracking der Besucher, das Partikelsystem, das auf dem Boden projiziert werden soll und XML Dateien. Der zweite Code beinhaltet die Partikelsysteme, die auf den Stelen angezeigt werden sollen und den Ablauf der Symbole. Sobald die beiden Codes zusammengeführt werden, soll es ein zusammenhängendes Partikelsystem (Boden und Stelen) geben, das über die XML Dateien sein Aussehen und seine Eigenschaften ändern kann. Während der Zusammenführung haben Sebastian Holzki und Agathe Gnus ein Coderefactoring durchgeführt und einige Funktionen des zweiten Codes neu geschrieben. Zu Beginn war die Szene in die benötigten Ausschnitte unterteilt (eine runde Fläche für den Boden und 6 Balken für die Stelen). Dabei achteten Sebastian Holzki und Agathe Gnus darauf die Stelen so im Programm zu hinterlegen, dass sie genau so angeordnet sind wie dann auch im Museum, sodass das Verschwinden der Symbole an der letzten Stele ganz rechts und das Neueinführen des selben Symbols am einen Monitorrand der ersten Stele stattfindet. Da die Stelen im Zukunftsmuseum dann in einem geschlossenen Kreis stehen werden, wird es dadurch so aussehen, dass die Formation des „Großen Ganzen“ ebenfalls in einer geschlossenen Bahn um den Mittelpunkt kreist.

Im Bild unten stehen die grauen Flächen für die Abstände zwischen den Stelen.

Aufteilung des Gesamtsystems

Symbole Stelen

Ablauf der Symboldarstellung

In der Entwicklungsphase haben Katharina Ott und Agathe Gnus den Ablauf der Darstellung des Symboles auf den Stelen verändert. Bisher sind die Symbole und der dazugehörige Attrakor mit den Partikeln mittig im unteren Bildschirmdrittel entstanden, haben sich dann senkrecht nach oben bewegt, bis sie eine festgesetzte Höhe erreichten und bewegten sich dann weiter horizontal nach rechts. Beim Erreichen des rechten Bildschirmrandes sind diese dann wieder auf dem linken Bildschirmrand entstanden, sodass ein Gefühl entsteht, dass die Symbole auf dem Bildschirm kreisen. Da sich alle Symbole mit der gleichen Geschwindigkeit und auf einem Y-Wert bewegt haben, kam es vor, dass es unter den Symbolen zu Überschneidungen kam und diese ein Konglomerat bildeten (siehe Bild).

Überschneidung der Symbole

Um das zu verhindern haben Katharina Ott und Agathe Gnus beschlossen vier unterschiedliche Ebenen einzuziehen, auf denen sich die Symbole, am Ende ihres Aufstieges in das obere Bildschirmdrittel bewegen können. So wurden vier maximale Y-Positionswerte festgelegt, die die Symbole erreichen können. Dafür verwendeten sie ein Array in dem vier verschiedene Y-Positionen gespeichert sind und rufen diese dann random auf.

Die vier Positionen wurden so gewählt, dass genau ein halbes Symbol dazwischen passt, sodass im späteren Verlauf die Symbole sich zu einer Wabenstruktur („Großes Ganzes“) zusammensetzen lassen könnten.

     int drawableImage::setMaxHeightPosition(float sceneSizeY){      // Array für maximale Y-Werte  
     
           for (float i = 0; i <= 4; i++) {         //setzten der gewünschten Werte  
                 newMaxHeight -= imageHeight / 2;  
                 maxHeightPositions.push_back(newMaxHeight);  
           }  
           int rgen = ofRandom(0, 4);                                        
           return (int)maxHeightPositions.at(rgen);            //random Arrayposition   
     }  

Da dies aber noch nicht ausreichte, die Bildung eines Konglomerats aus mehreren Symbolen zu vermeiden, randomisierte Agathe Gnus die Geschwindigkeit der Symbole in X-Richtung. In diesem Schritt wurde auch die Geschwindigkeit durch 0.0015*sceneSizeX, 0.004 * sceneSizeX definiert. Das bewirkt, dass die Geschwindigkeit der Symbole an verschiedene Bildschirme mit verschiedenen Auflösungen angepasst wird.

     int DrawableImage::setSpeedAtCloud(float sceneSizeX) {  
           for (int i = 0; i <= 10; i++) {                                      //number of different velocities in x dircetion  
           newXToMoveInCloud = ofRandom(0.0015*sceneSizeX, 0.004 * sceneSizeX);  
           cloudVelX.push_back(newXToMoveInCloud);  
     }  
     int rgen = ofRandom(0, 9);  
     return (float)cloudVelX.at(rgen);  
     }   

Symbole in Bewegung im "Großen Ganzen"

Die Symbole schweben im „Großen Ganzen“ nun waagrecht mit unterschiedlichen Geschwindigkeiten auf vier verschiedenen Ebenen. Da dies optisch nicht besonders „anregend“ für den Besucher ist, hat Agathe Gnus sich überlegt, wie man die Gestaltung verbessern kann. Ihre Idee war es nun die Symbole nicht nur waagrecht vorbeiziehen zu lassen, sondern auf einer Art sinusoiden Bahn. Die Sinusbewegung realisierte sie, indem sie den Symbolen eine zusätzliche Y-Richtung gegeben hat und diese sich nun diagonal über den Bildschirm bewegen. Dabei entstand aber das Problem, dass obwohl man für die Symbole einen maximalen Wert definiert hatte, diese sich trotzdem aus dem Anzeigebereich des Bildschirmes bewegten.

Herausforderung bei der Bewegung in Y-Richtung

Das Problem versuchten Jana Gumbert, Danial Eshete, Stefan Maurer, Katharina Ott und Agathe Gnus wie folgt zu lösen:

     if (pastMiddle) {      
           xToMoveInCloud += newCloudVelX;  
     
           if (yToMoveIntoCloud >= sceneSizeY/8) {  
                 yToMoveIntoCloud += newCloudVelY;           //y up  
           }  
     }else{ xToMoveInCloud -= newCloudVelX;  
     
     if (yToMoveIntoCloud <= sceneSizeY/4) {  
     
           yToMoveIntoCloud += newCloudVelY;                       //y up  
     } else {  
           yToMoveIntoCloud -= newCloudVelY;           //y down  
     }  

} . . .

     if (yToMoveIntoCloud <= maxYpositionForPicture) {        //y-Movement into cloud  
           if (ofGetLastFrameTime() > frameTime) {  
     
                 yToMoveIntoCloud += (0.005*sceneSizeY) * 2; //y-Movement *2, if the frameTime is over 0.03  
           }  
           else {  
                 yToMoveIntoCloud += 0.005*sceneSizeY;  
           }  
     }  

Jedoch konnte das Problem erst gelöst werden, indem zunächst die Höhe des Symbols, während es nach oben in Y-Richtung schwebt, abgefragt wird und mit der maximalen Höhe (maxYpositionForPicture) (circa an der Grenze zum obersten Bildschirmviertel) verglichen wird. Sobald es diese Höhe erreicht hat, bekommt das Symbol zusätzlich eine X-Richtung, wodurch es nun diagonal nach oben schwebt. Dies passiert so lange bis das Symbol den nächsten Grenzwert erreicht hat (pastMaxYInWave). Danach bewegt es sich nach unten, bis es auch hier einen Grenzwert erreicht hat. Von dort ab soll sich das Symbol wieder diagonal nach oben bewegen und so eine fortlaufende Zickzackbewegung entstehen, die einer Sinuskurve gleichen soll.

Der Wert pastMaxYInWave definiert also die maximal erreichbare Höhe, die ein Symbol erreichen kann. Zusätzlich zu der randomisierten Geschwindigkeit in X-Richtung (Bewegung nach rechts), haben Stefan Maurer und Agathe Gnus die Geschwindigkeit in Y-Richtung random (Bewegung nach oben bzw. unten) gesetzt. Nun fliegen die Symbole in unterschiedlichen Winkeln und Geschwindigkeiten, sodass kein ungewolltes Konglomerat aus Symbolüberschneidungen mehr entstehen kann und die Symbole unterschiedlich geformten Sinusbahnen folgen.

     int DrawableImage::setYAtCloud(float sceneSizeY) {  
           for (int i = 0; i <= 10; i++) {                                  //number of different velocities in y dircetion  
           newYToMoveInCloud = ofRandom(0.0012*sceneSizeY, 0.0015 * sceneSizeY);  
           cloudVelY.push_back(newYToMoveInCloud);  
     }  
     int rgen = ofRandom(1, 9);  
     return (float)cloudVelY.at(rgen);  
     }  

Ausrichtung der Symbole in "Großen Ganzen"

Bis die Symbole sich in einer Art Sinuskurve bewegten, gab es mehrere Herausforderungen, die äußerst zeitintensiv bearbeitet werden mussten. Allgemein wird die Bewegung derzeit über das Addieren oder Subtrahieren von verschiedenen Positionswerten zu der aktuellen Position definiert. So können die Symbole in verschiedene Richtungen bewegt werden, jedoch ist es nicht möglich die Bewegung in Form einer Sinuskurve zu definieren, da man die X- und die Y-Werte getrennt berechnet. Deswegen haben Sebastian Holzki und Agathe Gnus die Bewegung beim Zusammenführen beider Codes über die Velocity definiert, was nun die Kodierung einer Sinuskurvenbewegung ermöglicht und gleichzeitig die die Form der Sinuskurve glatter zu gestalten, sodass sie weniger einer Zickzackbewegung gleicht.

Zum anderen war die Logik hinter den Abläufen sehr verschachtelt, wodurch es schwierig wurde sich in dem Code zurechtzufinden und weitere Logik hinzuzufügen. Beispielsweise gab es durch zusätzlichen Code, der in keiner Verbindung mit der Anziehung der Partikel stand, einen Fehler, dass das Hexagon keine Partikel mehr angezogen hat, sobald es oben angekommen ist. Den Fehler konnten Katharina Ott und Agathe Gnus in der unten gezeigten Reihenfolge der if-Bedingungen finden und diesen beheben, indem sie die Reihenfolge änderten:

     void particle::updateParticle(double deltaT, ofVec2f attractor, bool cloudAttractorIsSet, bool imageIsOnTop, bool tornadoIsFinished, int imageHeight, int imageWidth, float sceneSizeX, float sceneSizeY) {  
     
     //Bewegung der Partikel in den unterschiedlichen Einstellungen  
     
     doMovementOfParticlesAtRain(tornadoIsFinished, deltaT, sceneSizeX);  
     
     if (cloudAttractorIsSet == true) {  
           doMovementOfParticlesAtRocketEffect(sceneSizeY, imageHeight, imageWidth, sceneSizeX, attractor, deltaT);  
     }  
     	  
     if (tornadoIsFinished == true && cloudAttractorIsSet == false) {  
           doMovementOfParticlesAtSymbols(deltaT, attractor);  
     }  
     
     if (imageIsOnTop == true) {  
           doMovementOfHexagonOnTheTop(attractor, sceneSizeX, deltaT);  
     }  
     }  

Um die Logik hinter dem Ablauf zu vereinfachen und so ein Coderefactoring durchzuführen, haben Stefan Mauer und Agathe Gnus den Ablauf in mehrere Status unterteilt:

Status 1: Raketeneffekt Symbol und Hexagon entstehen unten im Anzeigebereich. Das Hexagon wird von Partikeln umrandet. Danach bewegen sich diese nach oben zu einer random definierten Höhe. Die Partikel folgen dabei dem Hexagon. Oben angelangt umranden die Partikel wieder das Hexagon.

Status 2: „Großes Ganzes“ Die Symbole bewegen sich nach rechts in einer random Wellenbewegung. Die Symbole überschneiden sich zwar noch kurzzeitig, was leider nicht vollständig vermeidbar ist, bleiben aber nicht aneinander hängen und bilden so kein Konglomerat.

Status 3: Symbole sterben Nach einer gewissen Zeit sollen die ältesten Symbole und die dazugehörigen Partikel verschwinden, damit das „Große Ganze“ übersichtlich bleibt. Die Symbole „sterben“ außerhalb des Bildschirmes, wenn sie am rechten Bildschirmrand aus dem Anzeigebereich gerückt sind und bevor sie normalerweise am linken wieder neu erscheinen würden.

Status 4: Rain Sollten keine Symbole zu sehen sein, beispielsweise wenn länger keine neuen Spielergebnisse mehr eingelesen wurden, zeigt das System den sogenannten Rain Effekt an. Dieser besteht aus vielen Partikeln, die am unteren Bildschirmrand entstehen und sich langsam nach oben bewegen (wie ein, nach oben fallender Regenschauer). Die oben genannten vier Status wurden nicht im Code übernommen und nur als Checkliste für die spätere Codezusammenführung durch Sebastian Holzki und Agathe Gnus verwendet. Danach hat Agathe Gnus ein Coderefactoring durchgenommen, indem sie Kommentare hinzugefügt und aussagekräftigere Namen eingeführt hat, sodass der Code für Außenstehende verständlicher wurde. Als nächstes fiel Agathe Gnus auf, dass sobald Partikel rechts aus dem Anzeigebereich heraustreten und links wieder auftauchen, diese sich in der linken oberen Ecke bündeln, bevor das dazugehörige Symbol auftaucht. In der folgenden Abbildung ist der Problemfall rot umkreist zu sehen. Das Symbol entsteht weiter unten und die dazugehörigen Partikel sammeln sich zunächst etwas weiter oben und werden dann von dem Symbol angezogen.

Neuerstellung der Partikel

Diesen Fehler konnte sie lösen, indem sie die random Position mit der Höhe (Y-Position), die das Symbol hat und einer X-Position, die sich weit außerhalb des Bildschirmrandes befindet, neu definiert hat.

     if (particleToDelete) {  
     
           delete particles.at(0);         //löschen des Partikel Obj.  
           particles.erase(particles.begin());     //löschen der Pointer   
     
           //Durchgehen ab Partikel i = 1 da es kein Pixel 0 gibt  
           particles.push_back(new particle);  
     
           int x = -50;  
           int y = imageToDraw->getHeight(); // kein Random !        
     
           particles.back()->setup(ofVec2f(x, y), 20);  
     
     }  

Bewegungsrichtungen

Solange der Wert startingAnimationIsFinished nicht true ist (siehe letzten Code-Ausschnitt), bewegen sich die Symbole, wie schon gesagt, nur in Y-Richtung. Sobald der Wert true ist, in einer random Sinuskurve mit random k1 Wert für das Ausmaß der Amplitude und k2 für die Veränderung der Periode. Der random k3 Wert gibt die Geschwindigkeit der Symbole an. Zum Schluss schicken wir die Icons, wie auch im ursprünglichen Code, zurück zum Anfang der ersten Stele, wenn diese am rechten Bildrand angelangt sind.

     k1 = ofRandom(0.3,0.5); // random value for k1*sin(...)+...  
     k2 = ofRandom(0.3,1.2); // random value for ...*sin(k2*age)+....  
     k3 = ofRandom(0.8, 1.2);// random value for velocity  
     .  
     .  
     .  
     void CheckedInVisitor::move(float deltaT, float sceneWidth, float sceneHeight){  
           int startingSpeed = 65;  
           if(startingAnimationIsFinished != true){  
                 startingAnimation(startingSpeed, sceneWidth, sceneHeight);  
                 position += velocity * startingSpeed * deltaT;  
           }  
           if(startingAnimationIsFinished == true){  
                 position.y += k1*sin(age*k2);  
                 position += velocity * startingSpeed * deltaT * k3;  
           }  
     
           //jump from right to left  
           if(position.x > (sceneWidth - (sceneWidth - 0.5*sceneHeight)/36 )){  
                 position.x = sceneHeight;  
           }  
     }  

Attrkatoren der Symbole

Da es im neuen System nicht mehrere, sondern nur ein gemeinsames Partikelsystem gibt, das sowohl auf den Stelen als auch auf dem Boden verwendet wird, muss die Art wie die Attraktoren gesetzt werden, verändert werden. Zudem haben Sebastian Holzki und Agathe Gnus sich entschieden, nur einen Attraktor pro Icon zu setzen, um so die Berechnungen nicht zusätzlich zu verlangsamen. Die Position des Attraktor wird bestimmt, indem man den Mittelpunkt der Breite des Hexagons berechnet. Nun wird der Attraktor ein paar Pixel unter dem unteren Rand des Hexagons auf Höhe des Mittelpunktes gesetzt, damit die Partikel, die von dem Attraktor angezogen werden, nicht das Hexagon und das Symbol darin verdecken. Zudem wurde sichergestellt, dass Attraktoren auf den Stelen die Partikel auf dem Boden nicht beeinflussen können und andersrum. Um herauszufinden ob sich ein Partikel gerade auf dem Boden oder auf einer der Stelen befindet, wurde ermittelt ob sich dieser in einer geringeren Entfernung vom Mittelpunkt des Kreises befindet als die Länge des Radius (sceneHeight geteilt durch 2).

     bool Particle::isTheSetupPositionOnTheGround(ofVec2f _position, float sceneHeight){  
           ofVec2f centerOfFloor(sceneHeight/2, sceneHeight/2);  
           distanceToCenter = _position.distance(centerOfFloor);  
           if(distanceToCenter > (sceneHeight/2)){  
                 return false;  
           }else{  
                 return true;  
           }    
     }  

So kann ein Partikel, der sich auf der Stele befindet, nur von dem AttrakorStele angezogen werden und dieser Attraktor ist nur 30 Sekunden lang aktiv, spricht solange der Wert des ages des checkedInVisitors unter 30.0 ist. Dies wurde deshalb so definiert, damit die Symbole, sobald diese im „Großen Ganzen“ angekommen sind, keine Partikel mehr anziehen. Dies verbessert die Übersichtlichkeit für den Beobachter.

Feinjustierung der Effekte

Damit die Variante mit der Sinuskurve noch eindrucksvoller wirkt hat sich Agathe Gnus mit den Feineinstellungen des Ablaufes beschäftigt. Zunächst hat sie den Raketeneffekt verbessert, indem sie das Hexagon als Attraktor für Partikel verwendet hat, wenn das Symbol nach oben fliegt. So hat der aus Partikeln bestehende „Schweif“ eine bessere Form bekommen (vergleiche hierzu Bild 1 und 4). Als nächstes kam das Problem auf, dass sobald mehr als ein Symbol eingelesen wird, die Partikel, die den Symbolen eigentlich folgen sollten, diese Symbole einholen (siehe Bilder 2 und 3).

Dies ist ein unerwünschter Effekt, der durch die verringerten Frames per Second (genannt FrameTime im unterstehenden Code (erhöhte FrameTime entspricht verringerten FPS)) entsteht, die direkten Einfluss auf die Geschwindigkeit der Symbole hat. Die FrameTime steigt, weil durch die Darstellung mehrerer Symbole das Programm mehr Ressourcen benötigt und so insgesamt die neuen Frames nur noch langsamer berechnen kann. Je höher nämlich die FPS sind (geringere FrameTime), desto schneller bewegt sich das Symbol über den Anzeigebereich. Man konnte beobachten, dass die FrameTime von ca. 0,01 auf bis zu 0,04 steigt, wenn zu viele Symbole und Partikel gleichzeitig dargestellt werden; Dies bedingt, wie oben erklärt, eine Verlangsamung der Symbolbewegung ohne Beeinflussung der Partikel-Bewegungsgeschwindigkeit. Deshalb legte Agathe Gnus im Code fest, dass wenn die FrameTime über den Wert 0,03 steigt, die Geschwindigkeit der Symbole sowohl beim Hochfliegen, als auch bei der Bewegung im „Großen Ganzen“ verdoppelt wird und so dadurch verhindert wird, dass die Symbole von ihren begleitenden Partikeln überholt werden können.

Bild 1
Bild 2
Bild 3
Bild 4


     if (yToMoveIntoCloud <= maxYpositionForPicture) {        //y-Movement into cloud  
           if (ofGetLastFrameTime() > frameTime) {  
     
                 yToMoveIntoCloud += (0.005*sceneSizeY) * 2; //y-Movement *2  
     
           }else {  
                 yToMoveIntoCloud += 0.005*sceneSizeY;  
           }  
     }  
     
     if (pastMiddle) {  
           if (ofGetLastFrameTime() > frameTime) {//from the middle to right                xToMoveInCloud += newCloudVelX;  
     
                 if (min < yToMoveIntoCloud <= max) {  
                       std::cout << yToMoveIntoCloud << endl;  
                       yToMoveIntoCloud += newCloudVelY;       //y up  
                 }  
           }  
           else {  
                 xToMoveInCloud += newCloudVelX;  
     
     
           if (min < yToMoveIntoCloud <= max) {  
                 std::cout << yToMoveIntoCloud << endl;  
                 yToMoveIntoCloud += newCloudVelY;       //y up  
           }  
     }  	  
     }  
     else {  //From left to the middle  
           if (ofGetLastFrameTime() > frameTime) {  
                 xToMoveInCloud -= newCloudVelX;  
                 if (yToMoveIntoCloud <= sceneSizeY / 4) {  
                       yToMoveIntoCloud += newCloudVelY;           //y up  
                 }  
                 else {  
                       yToMoveIntoCloud -= newCloudVelY;       //y down  
                 }  
           }  
           else {  
                 xToMoveInCloud -= newCloudVelX;  
     
                 if (yToMoveIntoCloud <= sceneSizeY / 4) {  
                       yToMoveIntoCloud += newCloudVelY;        //y up  
                 }  
                 else {  
                       yToMoveIntoCloud -= newCloudVelY;       //y down  
                 }  
           }  
     }  
     }  

XML

Bisher waren die Effekte anhand von Parametern im Code gesetzt. Dadurch war eine Veränderung während des laufenden Programms nicht möglich. Um Effekte in Echtzeit ohne Neustart realisieren zu können, müssen die Parameter veränderbar sein. Hierzu entschieden wir uns auf Raten von Herrn Brendel die Parameter für Effekte über XML Files in das laufende Programm zu laden. Der folgende Abschnitt beschreibt welche Schritte nötig waren, um das zu realisieren.

Laden von Parameter aus XML Datei

Das laden aus einer XML Datei ermöglicht es Parameter des Partikelsystems im laufenden Betrieb zu ändern. Dazu kam das Addon ofxXmlSettings zum Einsatz. In einer XML Datei können Werte in Form von Tags abgelegt werden.

     <default>  
           <velMin>-60</velMin>  
           <velMax>60</velMax>  
     </default> 

Unter Berücksichtigung der Tag Struktur können nun Werte aus dem XML File geladen werden.

</code>

     effect.loadFile("xml/default.xml");  
     int velMin = effect.getValue("default:velMin", 0);  
     int velMax = effect.getValue("default:velMax", 0);  
     setVel(velMin, velMax);  

</code>

Settings des Partikelsystems aus XML laden

Mit dem Begriff Settings ist im Falle unseres Systems keine Klasse an sich gemeint, sondern eher das Kollektiv aller flexiblen Bestandteile des Codes. Das Tracking und Einchecken der Besucher sowie Faktoren wie der Zeitverlauf als Indikatoren für bestimmte Einstellungen wurden noch um kleinere XML-Dateien erweitert. XML steht für Extensible Markup Language, wobei Dateien dieses Datentyps kurzgesagt eine kompakte Sammlung von Werten unterschiedlicher Attribute darstellen. Anstatt Variablen im Quellcode zu definieren, werden sie im XML-Dokument festgehalten und bei Programmstart oder Aufruf einer entsprechenden Methode geladen. Diese Funktionalität nutzten wir in erster Linie, um das System in Abhängigkeit der gewünschten Fenstergröße zu starten. So wurden alle definierten Punkte innerhalb der Szene in Abhängigkeit der Fensterhöhe berechnet und als floats zwischen 0 und 1 in einer XML-Datei gespeichert. Die Berechnung der entsprechenden Werte erfolgte über Vektorberechnungen und trigonometrische Basisfunktionen. Die folgende Abbildungen veranschaulicht auf einen Blick Aufbau und Funktionsweise von XML-Dateien. Die Variablen lassen sich durch sogenannte „Tags“ gliedern. Beispielsweise findet sich die x-Koordinate des Kreismittelpunktes in der Tag-Struktur unter <setup>""<cnter><x>value<...>". Das openFrameworks-Addon ofxXmlSettings bietet mit der Methode getValue(...) eine Möglichkeit die Tags bis zur gewünschten Variable durch zu navigieren. Dazu genügt die einfache Auflösung der Tag-Struktur durch den Pfad (in unserem Beispiel) „setup:center:x“. Auf diese Weise könnten in der Zukunft beispielsweise auch verschiedene Variablen in Abhängigkeit eines eingecheckten Spielertyps oder nach vergangener Zeit geladen werden.

Übergang zwischen eines Auszugs aus der XML-Datei setup.xml eines älteren Branches und einem aus der c++ Datei ofApp.cpp

Gleichermaßen lassen sich in Laufzeit modifizierte Werte auch in XML-Dateien abspeichern und überschreiben. Der Vorteil besteht darin, dass diese XML-Dateien unabhängig vom Quellcode sind, weshalb Werte dann bei einem späteren Programmstart noch so vorliegen, wie sie beim Beenden gespeichert wurden. Zu dieser Vorgehensweise mehr im Kapitel 2.5.2.

Effekte

Zusätzlich machten wir es uns zur Aufgabe einige Effekte funktional umzusetzen. Nicht nur um die große Anzahl der Möglichkeiten, die ein Partikelsystem bietet, auszutesten, auch um bei der Präsentation am Ende des Semesters für ein Staunen zu sorgen. Solche Effekte wurden unter Anderem benötigt für das Einlesen des RFID Armbandes und dem Standardverhalten des Partikelsystems auf den Stelen, wenn gerade keine Auswertung stattfindet.

Effektverwaltung

Um überhaupt mehrere Effekte abspielen zu können, braucht es eine Art „Effektverwaltung“. Zugrunde liegt eine Liste von Effekten enum particleMode, in welcher alle Effekte namentlich aufgeführt sind. Nun kann jederzeit über die Variable currentMode der aktuelle Mode des Partikelsystems abgefragt und geändert werden. Über den Effektnamen lädt das System aus der zugehörigen XML Datei die zugehörigen Variablen.

     enum particleMode{
     PARTICLE_MODE_DEFAULT,
     PARTICLE_MODE_ATTRACTOR,
     PARTICLE_MODE_RAIN,
     PARTICLE_MODE_RADIAL,
     PARTICLE_MODE_DETRACTOR,
     PARTICLE_MODE_POLY,
     };

Der Schweif (Trail) Effekt

Ende vergangenen Semesters hatte Fritz Lenssen die Idee, dass Partikel Schweife ziehen lassen können. Als Vorlage dienten damals zwei Effekte aus der „Gravity“ App.

Effekt 1 & 2 aus der "Gravity"-App

In eine der beiden „Coding Nights“, kamen Tobias Lindner, Daniel Mehlhorn und Fritz Lenssen zusammen, um gemeinsam an einem solchen Effekt zu arbeiten.

Trail Effekt im Partikelsystem

Der Effekt hat es leider nicht in den finalen Prototyp geschafft. Da wir eingeschränkt in der Rechenleistung waren. Ebenso war das Rendern in einen Frame Buffer nötig. Der Schweif besteht aus vorherigen Versionen eines Partikels. Diese werden von der Dauer über die history angegeben. Dazu wird im Framebuffer fbo ein schwarzes Rechteck als Art Schablone über alles gelegt. Über den alpha Wert sind die Partikel durch das AlphaBlending sichtbar.

    history = 0.94;  
    fbo.allocate(ofGetWidth(), ofGetHeight(), GL_RGBA);  
    
    [...]  
    
    fbo.begin();  
         ofEnableAlphaBlending();          
    
         float alpha = (1 - history) * 255;  
         ofSetColor(0, 0, 0, alpha);  
         ofFill();  
         ofRect(0, 0, ofGetWidth(), ofGetHeight());  
    
         ofDisableAlphaBlending();          
         //Draw particle system  
         for (int p = 0; p < system.size(); p++) {  
              system.at(p)->draw(currentMode);  
         }  
    fbo.end(); 

Kommunikation

Nachdem die Kommunikation von Tracking- und Hauptsystem über OSC für den ersten Prototyp einwandfrei funktionierte, blieben wir der Technik treu, erweiterten deren Einsatz aber noch. Während es anfangs nur einen Sender gab, haben wir im neu aufgesetzten System noch einen Zweiten. Das Hauptsystem, der OSC-Receiver, wird jetzt von zwei OSC-Sendern bedient: Dem Trackingsystem und der Einlesestation. Die Folgenden Abschnitte beschäftigen sich zum einen mit TouchOSC und dem verwendeten User Interface, zum anderen mit Aufbau der eingehenden Nachrichten beider Sender und der Verarbeitung im Receiver.

TouchOSC

TouchOSC Code

Für die Präsentation in der Hochschule sollte das Einlesen durch den RFID-Chip möglichst Usability-freundlich durch TouchOSC realisiert werden. Für die Demo hat der Proband die Möglichkeit, gewisse Einstellungen zu übernehmen, die beim RFID-Einlesen normalerweise automatisch passieren. TouchOSC ist eine OSC und MIDI Steuerungsapp für Touchscreens. Die vollständig modulare Bedienoberfläche läuft sowohl auf IOS- als auch auf Android-Geräten. Dadurch können Open Sound Control- oder MIDI-Nachrichten über WLAN gesendet und empfangen werden, um alle kompatiblen Software- und Hardwarekomponenten zu steuern. Ein Smartphone mit Android-Software stand uns dank Herrn Eshete für die Demo zur Verfügung. Somit wurde die TouchOSC-Applikation auf dem Smartphone gemeinsam mit Danial Eshete für 4,99€ erworben und installiert. Auf dem eigenen Rechner konnte der TouchOSC Editor eingerichtet werden, auf dem die Bedienoberfläche der App gestaltet werden kann. Auch TouchOSC Bridge ist über hexler.net verfügbar, dies war für unser Projekt allerdings nicht von Relevanz.

Somit wurden die keyReleased-Events durch TouchOSC ersetzt. OfxOSC ist dabei das benötigte Addon. Dann definiert man einen Port, damit Rechner und Smartphone miteinander kommunizieren können.

     #define PORT 12345  
     
     string oscMsg;   
     ofxOscReceiver receiver;      
     receiver.setup(PORT);   

„define Port“ stellt den Port auf, damit Rechner und Smartphone in der Lage sind zu kommunizieren. Der String enthält die Nachricht, die der Receiver empfängt und der ofxOscReceiver bekommt die Nachricht von Smartphone. Mit receiver.setup (PORT) kann unser Receiver nun die Nachricht von unserem definierten Port empfangen.

Im Menü “OSC” wird die IP-Adresse des Rechners in “Host” eingegeben. In Outgoing Port wird der vordefinierte Port angegeben. Somit ist die Kommunikation der beiden gewährleistet. In diesem Fall soll TouchOSC am Smartphone nur senden und keine Nachrichten empfangen, daher wird kein Incoming Port verwendet. Da wir keine TouchOSC Bridge benötigen, erscheint hier im Menü „not configured“.

TouchOSC Setting
TouchOSC OSC Einstellung

     while(receiver.hasWaitingMessages()){  
     
           ofxOscMessage checkinInformations;  
           receiver.getNextMessage(&checkinInformations);  
           oscMsg = ofToString(checkinInformations);  

Solange der Receiver nun Nachrichten erhält, wird der die Messages in oscMsg als String speichern.

     if(checkinInformations.getAddress() == "/players"){ stele=getSteleForCheckin(checkinInformations.getArgAsFloat(0))+2;  
           playerType=getTypeForCheckin(checkinInformations.getArgAsFloat(1));  
     }  

Wenn die übergebene Adresse „/players“ entspricht, wird bei den Argumenten zwischen Stele und PlayerType unterschieden mit „(checkinInformations.getArgAsFloat(0))+2“ für die Stele und mit „(checkinInformations.getArgAsFloat(1))“ für die SpielerTypen. Eine Message könnte beispielsweise ungefähr so aussehen „/players 0.5 0.4“. In diesem Beispiel repräsentiert 0.5 den Spielertyp und 0.4 die Stele.

    if(checkinInformations.getAddress() == "/go"){  
         checkedInVisitors.emplace_back(new CheckedInVisitor());  
         checkedInVisitors.back()->setup(playerType , stele , sceneWidth, sceneHeight);  
    }  

Wenn der Button „go“ gedrückt wird, wird ein neuer CheckedInVisitor erstellt, mit den Variablen playerType und Stele.

</code>

     if (currentMode != PARTICLE_MODE_POLYMESH){               
           std::cout << "change of mode to DEFAULT" << std::endl;  
           currentMode = PARTICLE_MODE_POLYMESH;  
           currentModeHasChanged = true;         
           }  
     }  

</code>

Wenn in dem Moment der Default-Modus auf dem Boden läuft, ändert sich der Mode zu PARTICLE_MODE_POLYMESH der zu der Explosion führt.

TouchOSC Editor

Nun werden die verschiedenen Varianten und der Prozess der Gestaltung einer Bedienoberfläche für die TouchOSC-Applikation auf dem Smartphone erläutert. Wie bereits erwähnt, kann der TouchOSC Editor auf hexler.net kostenlos gedownloadet werden. Die Installation der App auf dem Smartphone allerdings ist kostenpflichtig. Zur Verfügung stehen z.B. Buttons, Textfelder oder X-Y-Pads.

TouchOSC Editorenansicht

Durch betätigen des Sync-Buttons in der Menüleiste, wird der Editor mit der Smartphone-App synchronisiert und das aktuelle UI auf das Smartphone übertragen. Das erste Interface bildete im Prinzip genau die keyReleased-Events aus dem vorangegangenen Code ab.

TouchOSC erster Editor

Da der Code noch keinen Initialzustand hatte, gab es in der ersten Version einen Default-Button, der später allerdings nicht mehr nötig war. Die Buttons 2 bis 7 erzeugten Symbole, bisher allerdings auf random gesetzten Stelen. Die Taste „R“ war dabei noch der Debugger und die Explosion wurde durch den dementsprechenden Button ausgelöst. Dieser erste Frame wirkt für Besucher allerdings sehr unübersichtlich und eine gute User Experience kann nicht gewährleistet werden.

TouchOSC zweiter Editor

Der zweite Editor besitzt bereits eine intuitivere Oberfläche. Insgesamt neun Buttons repräsentieren die neun Möglichkeiten drei verschiedene Symbole auf unseren drei prototypischen Stelen auszuwählen. Allerdings ist die Bedienung wenig spannend für die Probanden. Somit entstanden zwei mögliche User Interfaces, die durch eine Testperson vergleichend getestet wurden.

TouchOSV dritter Editor

Somit fiel die Entscheidung zwischen dem dritten und dem vierten Editor.

TouchOSC vierter Editor

Durch das X-Y-Pad des vierten Editors ist es möglich mit nur einem Schieberegler und einem „Check-In RFID“ Button das Einlesen so logisch wie möglich zu gestalten. Auch im kurzen Usability Test mit der Testperson, sprach diese sich für die letzte Version aus.

TouchOSC als Stellvertreter für RFID

Für die finale Umsetzung und den Aufbau im deutschen Museum soll RFID-Technik verwendet werden, um Besuchern die Möglichkeit zu geben, sich kontaktlos und mit einer eindeutigen ID mit dem System zu verbinden. Für unseren zweiten Prototyp wurde vorerst wieder OSC-Technik verwendet, deren Umgang einigen Teammitgliedern bereits vertraut war. Für die Anforderungen, einen ausgewählten Spielertypen auf einer ebenfalls ausgewählten Stele zu erzeugen reichte OSC aus. Erst wenn der Spielauswertung eine komplexe Datensammlung vorausgeht, muss dieser Teil des Systems umstrukturiert werden. Als Einlesestation diente ein älteres Smartphone, auf dem TouchOSC installiert wurde. Zudem wurde das Programm auch noch käuflich erworben, damit zuhause unabhängig selber weiter damit gearbeitet werden konnte. Der nächste Schritt war, die bereits auf Tastendruck implementierte Logik der CheckedInVisitor-Erzeugung in den OSC-Receiver auszulagern. Die in der CheckedInVisitor::setup(...)-Methode definierten Variablen waren zum einen der Spielertyp, zum anderen die gewünschte Stele, auf welcher das Avatar erscheinen soll. Bei drei Stelen und vier Spielertypen ergaben sich zwölf verschiedene Varianten, wie ein „CheckIn-Event“ aussehen kann. Über mehrere Layouts mit beispielsweise 12 einzelnen Buttons oder 2 Buttons und je zwei Slidern entwickelte sich schließlich das in der Demonstration verwendete User Interface.

Das User Interface der Einlesestation

Eine elegante Lösung für das Erzeugen eines gekoppelten Wertepaares war ein zweidimensionales Koordinatensystem. Auf der x-Achse konnte die gewünschte Stele, auf der y-Achse der Spielertyp gewählt werden. Der Besucher selbst konnte jetzt einen Punkt verschieben, dessen Position im Netz dann die Information von gewählter Stele und zugehörigem Typen jeweils als float zwischen 0 und 1 verpackte. TouchOSC verpackte die zwei Werte gebündelt in eine OSC-Nachricht und versendete diese an den OSC-Receiver des Hauptsystems. Bei Klick auf den roten Button wurde eine Nachricht versendet, die dem System mitteilt, dass es das aktuellste Datenpaar verarbeiten soll. Wie das Entpacken und die Interpretation der Daten implementiert wurde, wird in Kapitel 2.4.3. ausgeführt.

Receiver für Tracking und die Klasse Visitor

Der Programmteil, der sich mit der Interpretation der gepackten Besucherinformationen aus dem Trackingsystem beschäftigt, hat einige Modifikationen über sich ergehen lassen müssen. Da die Informationen jetzt nichtmehr direkt an die Partikel übergeben werden, werden sie in Instanzen der Klasse Visitor zwischengelagert und im <vector> visitors verwaltet.

     if(checkinInformations.getAddress() == "/centroidsOfBlob") {  
           if(COUNT_VISITORS_LASTFRAME != COUNT_VISITORS){  
                 if(COUNT_VISITORS_LASTFRAME < COUNT_VISITORS){  
                       for(int i = 0; i < COUNT_VISITORS - COUNT_VISITORS_LASTFRAME; i++){  
                             visitors.emplace_back(new Visitor);  
                             objectPhysics.emplace_back(new Attraktor(visitors.back()->getPosition()));  
                             objectPhysics.back()->setIsVisitor(true);  
                       }              
                 }else{  
                       for(int i = 0; i < COUNT_VISITORS_LASTFRAME - COUNT_VISITORS; i++){  
                             delete visitors.back();  
                             visitors.pop_back();  
                             delete objectPhysics.back();  
                             objectPhysics.pop_back();  
                       }  
                 }  
           }  
           for(int i = 1; i < visitors.size() +1; i++){  
                 float xOfVisitor = checkinInformations.getArgAsFloat(i * 2 - 1);  
                 float yOfVisitor = checkinInformations.getArgAsFloat(i * 2) ;  
                 visitors.at( i - 1 )->setPosition(xOfVisitor, yOfVisitor);  
            }  
     }   

Das Verarbeiten der Trackinginformationen wurde in zwei Phasen aufgeteilt, wobei die erste bläulich, die zweite rötlich unterlegt ist: Erst wird der visitor-Vektor, der die Informationen speichert, an die Anzahl der übermittelten Koordinatenpaare, also Besucher in der Szene, angepasst. Das vorderste Argument innerhalb jeder OSC-Nachricht die das Tracking übermittelt, gibt die Anzahl der gefundenen Konturen (Besucher) an. Immer, wenn sich die aktuelle Anzahl der Besucher zu der des vorigen Programmdurchlaufs unterscheidet, überprüft das System, ob neue Besucher dazugekommen oder ob weniger Konturen erkannt worden sind. Abhängig davon werden jetzt der visitors- sowie der objectPhysics-Vektor angepasst. Wie schon erwähnt, ist es für die Partikel wichtig zu wissen, ob ObjectPhysics-Objekte Besucher repräsentieren, deshalb wird für die hier erzeugten Attraktoren die boolean isVisitorObject = true gesetzt. Im zweiten Teil wird der eben angepasste visitor-Vektor aktualisiert, die vorhandenen Visitor-Objekte also mit den aktuellen Besucher-Koordinaten befüllt. Wenn jetzt verschiedene ObjectPhysics im Speicher liegen, muss das System erkennen können, wann es sich um Besucher, wann um andere Objekte handelt. Dafür wurde eine Funktion implementiert, die ermittelt, an welcher Stelle im ObjectPhysics-Vektor die visitors beginnen. Nach aktueller Architektur bleiben die von der Szene fest verwalteten Instanzen der Klasse ObjectPhysics immer im Vektor und werden nicht gelöscht oder neu instanziiert, die der Klasse Visitor hingegen schon.

     void ofApp::refreshCoordinatesOfVisitorAttraktors(int beginOfVisitorsInObjectPhysicsVector, float sceneHeight){  
     
     for(int i = 0; i < visitors.size(); i++){  
           float x = visitors.at(i)->getPosition().x * sceneHeight;  
           float y = visitors.at(i)->getPosition().y * sceneHeight;  
           objectPhysics.at(beginOfVisitorsInObjectPhysicsVector + i)->setPosition(x,y);  
           }  
     }  
     //--------------------------------------------------------------  
     int ofApp::getBeginOfVisitorsInObjectPhysics(){  
           for(int i = 0; i < objectPhysics.size(); i++){   
                 if(objectPhysics.at(i)->getIsVisitorObject() == true){  
                       return i;  
                 }  
           }  
     }  

Durch diese zwei „Sicherungsmethoden“ wird garantiert, dass Wertepaare aus OSC-Nachrichten nicht den falschen Objekten zugeordnet werden. Die Methode getBeginOfVisitorsInObjectPhysics() wird nur einmal ausgeführt, bevor refreshCoordinatesOfVisitorAttraktors() ausgeführt wird, um Performance einzusparen.

Receiver für TouchOSC und die Klasse CheckedInVisitor

Über den zweiten OSC-Sender, die Einlesestation, sollen jetzt in Laufzeit Instanzen der Klasse CheckedInVisitor erzeugt werden können. Im Folgenden soll zuerst erläutert werden, wie die Nachricht aufgebaut ist, die dieses Event auslöst, um anschließend zu zeigen, was genau ab diesem Moment im System, besonders in der Klasse CheckedInVisitor passiert.

     if(checkinInformations.getAddress() == "/steleAndType"){    
     
           stele = getSteleForCheckin(checkinInformations.getArgAsFloat(0)) + 2;  
           playerType = getTypeForCheckin(checkinInformations.getArgAsFloat(1));  
     }  
     
     if(checkinInformations.getAddress() == "/go"){  
     
           checkedInVisitors.emplace_back(new CheckedInVisitor());  
           checkedInVisitors.back()->setup(playerType , stele , sceneWidth, sceneHeight);  
     
           if(currentMode != PARTICLE_MODE_POLYMESH){  
                 currentMode = PARTICLE_MODE_POLYMESH;  
                 currentModeHasChanged = true;  
           }  
     }  

Nachrichten der Adresse „/steleAndType“ werden ständig gesendet und empfangen. In ofApp bekommen die zwei Integers stele und playerType somit ständig den aktuellen Stand übermittelt. Leider sind die Gestaltungsmöglichkeit von Nachrichten in TouchOSC sehr limitiert, ansonsten hätte man auch einen Sender entwickeln können, der nur bei Veränderungen sendet oder beide Nachrichten in eine packt, also das Koordinatenpaar immer genau dann sendet, wenn sich jemand eincheckt. Über die Methoden getSteleForCheckin(...) und getTypeForCheckin(...) wandelt das System die übermittelten Float-Werte zwischen 0 und 1 in Ganzzahlen um. Das erste übermittelte Argument (getArgAsFloat(0) ) gibt die Stele, das zweite (getArgAsFloat(1)) den Spielertypen an. Zur Stele wird schließlich noch eine 2 addiert, da die Stelen eins bis drei im Prototypen durch die Stelen drei bis fünf aus der gerenderten Szene dargestellt werden. Nachdem jetzt einen neuer CheckedInVisitor hinzugefügt wurde, wird dessen setup()-Methode mit den übergebenen Werten für stele und type aufgerufen.

     void CheckedInVisitor::setup(int _playerType, int _checkedInStele, float sceneWidth, float sceneHeight){  
           k1 = ofRandom(0.3,0.5);     
           k2 = ofRandom(0.3,1.2);     
           k3 = ofRandom(0.8, 1.2);  
           checkedInStele = _checkedInStele;  
           playerType = _playerType;  
           switch ( playerType ){  
     
           case 1: {  
                 imageOfType.load("images/image1_color.png");  
                 hexagon.load("images/hexagon_1.png");  
                 break;  
           }  
           case 2: {  
                 imageOfType.load("images/image2_color.png");  
                 hexagon.load("images/hexagon_2.png");  
                 break;  
           }  
     
           [... case 3 & case 4 ... ]  
     
           default:{  
                 imageOfType.load("images/noplayertype.png");  
           }  
     }   
     setupPosition(sceneWidth, sceneHeight, checkedInStele);  
     imageOfType.resize(imageOfType.getWidth()*0.5, imageOfType.getHeight()*0.5);  
     hexagon.resize(hexagon.getWidth()*0.5, hexagon.getHeight()*0.5);  

}

Die drei Werte k1, k2 und k3 werden später bei der Bewegung relevant. Jeder CheckedInVisitor besteht aus zwei ofImages, für den Bildinhalt und das zugehörige Hexagon. In Zukunft können diese Bilddateien auch wieder in einem Bild vereint werden, die Trennung rührt in diesem Falle noch daher, dass ursprünglich alle farbigen Pixel des Hexagons als Attraktoren dienen sollten. Der Effekt sah aber ruckelig aus und sprengte die Rechenleistung. In Abhängigkeit vom übergebenen Spielertypen werden jetzt die passenden Bilder geladen und in den ofImages abgespeichert. Nachdem das passende Bildmaterial geladen wurde, wird nun die Startposition in der Szene ermittelt, an der der Avatar erstmalig gezeichnet werden soll. Dafür übergeben wir die Informationen über Szenenbreite und –höhe und die ausgewählte Stele an die Methode setupPosition(...). Um den Moment des Eincheckens auch am Boden sichtbar zu machen, wird der particleMode PARTICLE_MODE_POLYMESH aktiviert. Dieser erzeugt einen Effekt, der aussieht, als seien die Personen auf dem Boden Zentrum von Explosionen eines Netzes aus Linien. Wie der Effekt funktioniert und aufgebaut ist, wurde in Kapitel 2.2.2. erklärt.

Bodeneffekt "Netzexplosion" beim Einchecken. Zeitlicher Ablauf von links nach rechts

Nach Aufruf der draw(...)-Methode erscheint jetzt auf der gewählten Stele der CheckedInVisitor mit dem passenden Spielertypen. Dieser muss sich jetzt noch in Richtung „Großes Ganzes“ an die Spitzen der Stele bewegen, um schließlich seine Kreisbahnen um die Besucher zu ziehen.

     void CheckedInVisitor::move(float deltaT, float sceneWidth, float sceneHeight){  
     
           if(startingAnimationIsFinished != true){  
                 startingAnimation(startingSpeed, sceneWidth, sceneHeight);  
                 position += velocity * startingSpeed * deltaT;  
           }else{  
                 position.y += k1*sin(age*k2);  
                 position += velocity * startingSpeed * deltaT * k3;  
           }  
     
          if(position.x > (sceneWidth - (sceneWidth - 0.5*sceneHeight)/36 )){  
                 position.x = sceneHeight;  
           }  
     }  

Die boolean startingAnimationIsFinished ist anfangs für jeden CheckedInVisitor false. Deshalb wird die Bewegung anfangs hauptsächlich in der ersten if-Abfrage, in der Methode startingAnimation(...) stattfinden.

     void CheckedInVisitor::startingAnimation(float startingSpeed, float sceneWidth, float sceneHeight){  
           if(position.y < sceneHeight*0.4){  
                 velocity.y *= 0.985 ;  
           }  
     
           if(position.y < sceneHeight*0.6 && startedMovingToTheRight == false){  
                 velocity.x = 0.1;  
                 startedMovingToTheRight = true;   
           }  
     
           if(velocity.x < xVelocityMax){  
                 velocity.x *= 1.02;  
           }  
     
           if(   (((xVelocityMax - velocity.x) < 0.0001)) && ((velocity.y < 0.0001))){  
                 velocity.x = xVelocityMax;  
                 velocity.y = 0;  
                 startingAnimationIsFinished = true;  
           }  
     }  

Der Avatar wird ab einer bestimmten Höhe in seiner y-Bewegung allmählich abgebremst. Noch ein bisschen tiefer auf den Stelen beginnt die Bewegung in x-Richtung, indem velocity.x einen Wert größer null zugewiesen kriegt. Ab diesem Moment beschleunigt der CheckedInVisitor in x-Richtung, bis er seine vorher definierte, maximale Geschwindigkeit nach rechts – xVelocityMax – erreicht hat. Sobald der Avatar sich seinen Zielgeschwindigkeiten, nämlich xVelocityMax in x- und 0 in y-Richtung ausreichend angenähert hat, werden diese übernommen und startingAnimationIsFinished = true gesetzt. Von nun an bewegt sich das Objekt in einer individuellen Sinuskurve, deren Amplitude, Geschwindigkeit und Frequenz von den im setup(...) festgelegten Zufallszahlen k1, k2 und k3 abhängig sind.

System nach Einchecken eines Spielertypen auf Stele2

Mapping

Auf dem Weg zum finalen Mapping wurde viele Wege ausprobiert und einige Addons getestet. Beispielsweise wurde versucht über ofGLProgrammableRenderer das komplette System in zwei Szenen aufzuteilen und nur jeweils den gewünschten Bereich anzuzeigen. Ähnliches wurde mit ofTexture versucht. Jedoch wurde schnell klar, dass einige Wege irreführend waren, um letztendlich ein funktionales Mapping auf die Beine zu stellen.

Warping

Das Addon ofxGLWarper versprach bereits etwas mehr. Ein Addon, dass sogenannte „Warps“ für ein Bild erzeugt, mit denen es möglich war dieses zu transformieren. Die Warps werden in einem Vector gespeichert und konnten so angesprochen werden. Aufgesetzt war das ganze auf der openGL API. Diese ist jedoch sehr umfangreich und überwiegend für die Benutzung der GPU gedacht. Daher haben wir uns final für das Addon ofxWarp entschieden. Ein erster Versuch für das Mapping eines Partikelsystems liegt dem Bericht unter „Code\Mapping_ofxWarp\Particle_Mapping“ bei. Zum Verständnis werden jedoch die grundlegenden Vorgehensweisen beschrieben. Zuerst muss der Begriff des Framebuffers definiert werden. Die Klasse ofFbo ist grundlegend ein Container für Texturen, 3D- oder 2D-Objekte oder die Ansicht von Kameras. Eben genauso wie bei einem Framebuffer. Generell kann vieles gleichzeitig innerhalb der ofFbo Klasse gezeichnet werden. Die Besonderheit daran ist, dass es nur ein einziges Objekt ist, das von der Grafikkarte gezeichnet werden muss. Es handelt sich also sinngemäß um einen Renderer in den geschrieben werden kann. Um einen Framebuffer zu benutzen muss er zunächst in der Setup Methode mittels der allocate()-Funktion instanziiert werden.

     ofVec2f sceneSize;  
     ofFbo fbo;  
     sceneSize.set(1920, 1080);  
     fbo.allocate(sceneSize.x, sceneSize.y, GL_RGBA);  
     fbo.begin();  
           ofClear(0);  
     fbo.end();  

Als nächstes muss der WarpController implementiert werden. Dieser wird in der dem OfxWarp Addon deklariert und bildet das Grundgrüßt für die Transformation. Es gibt drei verschiedene Arten von Warpcontroller. Die perspektivische Verzerrung eignet sich für rechteckige Ebenen an einer Wand. Die Korrektur für die Projektion kann unabhängig davon wie der Projektor eingerichtet ist durchgeführt werden. Unabhängig davon, in welchem Winkel auf die Fläche projiziert wird, können die vier Ecken des Bildes an die gewünschte Stelle gezogen werden. Diese Art von WarpController wurde auch in unseren Fall verwendet. Die bilineare Verzerrung ermöglicht das Transformieren auf gekrümmten Oberflächen. Über zusätzliche Kontrollpunkte kann eine Krümmung ausgerichtet werden. Diese beiden Arten der Verzerrung können auch kombiniert werden. Im Addon ist dies als „perspective-bilinear warp“ zu finden. Erst wird über die vier Eckpunkt das Bild an die gewünschte Stelle geschoben, über die zusätzlichen Kontrollpunkte kann eine Verzerrung eingerichtet werden. Ein WarpController wird wie folgt implementiert.

     ofxWarpController warpController;  
     if (this->warpController.getWarps().empty())  
           {  
                 std::shared_ptr<ofxWarpBase> warp;  
     
                 warp = this->warpController.buildWarp<ofxWarpPerspective>();  
                 warp->setSize(sceneSize.x, sceneSize.y);  
                 warp->setControlPoint(0, glm::vec2(0.0f, 0.0f));  
                 warp->setControlPoint(1, glm::vec2(0.5f, 0.0f));  
                 warp->setControlPoint(2, glm::vec2(0.5f, 0.5f));  
                 warp->setControlPoint(3, glm::vec2(0.0f, 0.5f));  
           }  

Der WarpController erstreckt sich über die komplette Größe der Szene. Da wir jedoch die Szene in unterschiedliche Bereiche aufteilen möchten, müssen mehrere WarpController implementiert werden. Die einzelnen Ecken werden über setControlPoint an die jeweilige Position in der Szene gesetzt. Hier bilden die Ecken des WarpControllers das obere, linke Viertel der Szene. In der draw()-Methode wird nun das komplette System innerhalb des Framebuffers gezeichnet.

     fbo_circle.begin();  
           ofClear(0, 0, 0);  
           …  //your code goes here  
     fbo_circle.end();  

Außerhalb des Framebuffers wird nun für jeden WarpController der zu transformierende Bereich aus dem Framebuffer ausgewählt und in einer Subsection ausgegeben.

     warpController.getWarp(0)->begin();  
           fbo.getTexture().drawSubsection(0, 0, 1920, 1080, 0, 0, 960, 540);  
     warpController.getWarp(0)->end(); 

Da der Framebuffer zu Beginn die komplette Fenstergröße zugeteilt bekommt, wird auch hier die gesamte Größe des Fensters ausgewählt. Wenn in HD dargestellt werden soll von der Stelle (0,0) 1920 Pixel breite und 1080 Pixel Höhe. Die Werte des zweiten Teils der drawSubsection()-Methode beziehen sich auf den Teilbereich, der durch den WarpController verändert werden soll. Idealerweise erstreckt er sich über dieselbe Fläche, die zuvor mit setControlPoint() bestimmt wurde. Also wieder das obere, linke Viertel der Szene. In unserem Fall von der Stelle (0,0) 960 Pixel nach rechts und 540 Pixel nach unten. Somit wird nun genau der Bereich der Szene gezeichnet, der auch mit dem WarpController verzerrt werden kann. Um das Transformieren zu ermöglichen wird der Boolean setEditing() noch auf true gesetzt. Wichtig ist, dass nach jeder Transformation der Boolean für den ausgewählten WarpController auch wieder auf false gesetzt wird, damit er nicht bei der Veränderung eines anderen WarpControllers mit verzerrt wird.

     boolean editingWarp = false;  
     void ofApp::keyReleased(int key){  
           if (key == '1') {     
                 editingWarp = !editingWarp;                           
                 warpController.getWarp(0)->setEditing(editingWarp);  
           }  

Damit beim Editieren auch Angriffspunkte in den Ecken angezeigt werden, muss der Ordner „shaders/ofxWarp“ in dem „bin/data“ Verzeichnis des Projektes abgelegt werden. Dieser beinhaltet die notwendigen .frag und .vert Dateien, um die Angriffspunkte darzustellen. Der Ordner ist aus dem „example“ des ofxWarp Addons zu entnehmen.

Zustand und Bewegung der Partikel

Für einen reibungslosen Ablauf und erfolgreiches Mapping der Partikel von Boden auf Stelen hat das Partikel in der neuen Implementierung die boolean particleIsOnGround erhalten, damit schnell festgestellt werden kann, welchen Regeln dieses zu folgen hat. Mit folgender Methode isSetupPositionOnTheGround(...) wird direkt bei Geburt überprüft, ob sich das Partikel auf dem Boden befindet.

     bool Particle::isTheSetupPositionOnTheGround(ofVec2f _position, float sceneHeight){  
           ofVec2f centerOfFloor(sceneHeight/2, sceneHeight/2);  
           distanceToCenter = _position.distance(centerOfFloor);  
           if(distanceToCenter > (sceneHeight/2)){  
                 return false;    
           }else{  
                 return true;  
           } 

So wie die Szene aufgebaut ist, verlässt ein Partikel immer dann den kreisförmigen Boden, wenn seine Distanz zu dessen Mittelpunkt den Kreisradius übersteigt. Der Kreisradius wiederum wird durch die Höhe der gerenderten Szene definiert und kann mit sceneHeight/2 ausgeschrieben werden, da der Kreis die Szene immer in der gesamten Höhe ausfüllt. Wenn also der Abstand eines Partikels zum Kreismittelpunkt den Radius übersteigt, wird particleIsOnGround auf false gesetzt. Später in der update(...)-Methode wird diese Distanz immer aktualisiert. Von jetzt an wird in der Berechnung immer berücksichtigt, ob ein Partikel sich auf den Stelen befindet oder nicht.

     void Particle::updateDistanceToCenter(float centerX, float centerY, float sceneHeight){  
                 
           distanceToCenterLastFrame = distanceToCenter;   
     
           if(particleIsOnGround == true){  
                 ofVec2f centerOfFloor(centerX, centerY);  
                 distanceToCenter = position.distance(centerOfFloor);  
           }  
           if(particleIsOnGround == false){  
                 distanceToCenter = sceneHeight/2 + sceneHeight - position.y;  
           }  
           if(distanceToCenterLastFrame <= sceneHeight/2 && distanceToCenter > sceneHeight/2){  
                 particleJumpedOffGround = true;  
           }  
     }  

Die Distanz zum Mittelpunkt setzt sich also für Partikel abseits des Bodens aus dem Radius und der eigenen Höhe auf den Stelen zusammen. Mit einer weiteren Methode kann nun festgestellt werden, ob ein Sprung über den Kreisradius stattgefunden hat, der wiederum das Mapping aktiviert. Über die Distanz weiß das Partikel „Wann“ es gemapped wird. Das „Wohin“ wird anhand des Winkels zum Kreismittelpunkt festgestellt. Stellt man sich die Kante des gesamten 360°-Kreises des Bodens als Linie vor, erhält die Unterkante aller 6 Stelen und den entsprechenden Zwischenräumen. In folgender Abbildung wird dieser Zusammenhang verdeutlicht.

Vereinfachte Visualisierung der gerenderten Szene des Projekts

Um das Mapping, also den „Sprung“ eines Partikels vollständig, inklusive „Wann“, „Wie“ und „Wohin“ auszuführen, benötigen wir noch die Information über den Winkel, den ein Partikel zum Kreismittelpunkt hat.

     void Particle::updateAngleToCenter(float centerX, float centerY){  
     
           ofVec2f center(centerX, centerY);  
           ofVec2f particleToCenter = position - center;  
           ofVec2f referenceVector(0, 0.5);  
     
           angleToCenter = particleToCenter.getNormalized().angle(referenceVector.getNormalized());  
           angleToCenter = angleToCenter + 180;  
     
     }  

Der Winkel eines Partikels zur Mitte wird über den Winkel zwischen zwei Vektoren berechnet. Das Partikel spannt einen Vektor von Kreismittelpunkt zu sich selbst auf. Dieser berechnet sich also durch die Differenz der eigenen Position mit der des Zentrums der Szene. Der zweite Vektor ist ein Referenzvektor, der senkrecht nach oben gerichtet ist. Anschließend bietet openFrameworks die Methode angle(...), um den Winkel zwischen zwei Vektoren als float ausgeben zu lassen. Da das Ergebnis dieser Berechnung einen Wert zwischen -180 und 180 liefert, werden weitere 180 dazu addiert, um später nur positive Werte von 0 bis 360 verarbeiten zu müssen. Mit Wissen über Distanz und Winkel zum Mittelpunkt lässt sich jetzt ermitteln wann das Partikel wohin übergeht.

     void Particle::mapParticle(float sceneWidth, float sceneHeight){  
     
           if(particleJumpedOffGround == true){  
     
                 position.y = sceneHeight - 20;  
                 position.x =  (sceneHeight + angleToCenter / 360 * (sceneWidth - sceneHeight));  
     
                 if(position.x > sceneWidth){  
                       float difference = position.x - sceneWidth;  
                       position.x = sceneHeight + difference;  
                  }  
           float k = velocity.length();  
           velocity.set(0, -k);  
           particleJumpedOffGround = false;  
           }  
     }  

In dem Moment, in dem ein Partikel den Boden verlässt wird seine neue Position in der gerenderten Szene berechnet. Zum einen wird es an die untere Szenenkante gezeichnet, zum anderen auf bzw. neben die passende Stele, in Abhängigkeit vom Austrittswinkel.Man erkennt, dass die neue x-Position eines Partikels sich immer zusammensetzt aus der sceneHeight plus einen Anteil der Differenz (sceneWidth – sceneHeight). Dieser Anteil kann alle Werte zwischen 0 und 1 annehmen. Um den passenden Wert zu finden wird der Winkel des Partikels zum Mittelpunkt durch 360° geteilt. Da die Länge des Vektors velocity als wirkliche Geschwindigkeit interpretiert werden kann, wird der Wert velocity.length() gespeichert, um die neue Bewegungsrichtung (0, -1) mit der passenden Geschwindigkeit auszustatten. Ein Partikel, das den Kreis verlässt, erscheint jetzt mit derselben Geschwindigkeit auf den Stelen.

Zusammenspiel von Soft- und Hardware für Projektion

Nachdem sich die letzten Kapitel mit den relevantesten Komponenten der dem System zugrundeliegenden Software beschäftigten, soll nun abschließend der Hardware-Aufbau dargestellt werden sowie das sogenannte Warping, also Verziehen und Verzerren der projizierten Fläche. Um diese 3600x1200 Pixel große Fläche über zwei Beamer unverzerrt in mehreren Dimensionen darzustellen, wurde die gerenderte Szene in einen Framebuffer geladen, der dann zur Ausgabe auf die Beamer verteilt wurde. Die einzelnen relevanten Bildteile wurden im Framebuffer definiert und jeweils in einem eigenen Warp abgespeichert. Anschließend konnten die Eckpunkte der vier zur Projektion verwendeten Bildteile verschoben werden. Folgende Abbildungen sollen die Funktionsweise verständlicher zu machen. Alles, was in der draw()-Methode gezeichnet wird, wird in den Framebuffer gezeichnet, also die gesamte Szene:

Framebuffer des kompletten Fensters

Als nächstes definieren wir vier voneinander getrennte Warps für die zu projizierenden Bildanteile:

Relevante Bildanteile für die Projektion

Die definierten Bereiche sollen in der Projektion jederzeit verschoben und verzerrt werden können, weshalb wir Kontrollpunkte an den Ecken erzeugen. Durch bestimmte Split-Screen Einstellungen kann die Szene, das breite Fenster, zwischen die Bildschirme, in diesem Fall Projektoren gelegt werden. So erscheint der linke Teil des Fensters auf einem anderen Ausgabegerät als der rechte.

Die Kontrollpunkte wurden an die Ecken der Warps gesetzt. Oben: Die Szene wurde zwischen zwei Monitore gezogen. Unten: Die Monitore werden auf verschiedenen Ausgabegeräten dargestellt.

Die ausgewählten Teile des Framebuffers sind jetzt getrennt voneinander auf Boden und Stelen zu sehen. Die Kontrollpunkte regeln, wie die Bildinhalte dargestellt werden. Durch anfassen und verschieben der Kontrollpunkte transformiert sich der Inhalt des entsprechenden Warps, also der Bildinhalt, welcher von den Kontrollpunkten behandelt wird.

Der Framebuffer nach Anpassung der Kontrollpunkte an die Szene
Partikelsystem wird in Fenster mit Größe 380x1200 gerendert

Die Koordinaten der Kontrollpunkte werden in einer externen XML bereitgestellt.

     xmlWarp.load("xml/warp.xml");  
     
           c_1_x = xmlWarp.getValue("circle:x1", 0.0);  
           c_1_y = xmlWarp.getValue("circle:y1", 0.0);  
           c_2_x = xmlWarp.getValue("circle:x2", 1.0);  
           c_2_y = xmlWarp.getValue("circle:y2", 0.0);  
           c_3_x = xmlWarp.getValue("circle:x3", 1.0);  
           c_3_y = xmlWarp.getValue("circle:y3", 1.0);  
           c_4_x = xmlWarp.getValue("circle:x4", 0.0);  
           c_4_y = xmlWarp.getValue("circle:y4", 1.0);  
           ...  

Der Aufruf der XML-Datei funktioniert nach dem altbekannten Muster. Innerhalb der Header-Datei der Applikation wurden für jede nötige Koordinate zwei floats angelegt, von c_1_x (circle, erster Kontrollpunkt, x-Koordinate) bis s3_4_y (stele3, vierter Kontrollpunkt, y-Koordinate). Die Werte aus der XML-Datei werden jetzt gelesen und die Szene entsprechend gezeichnet.

     if (key == 's') {                              
     warpControllerCircle.getWarp(0)->setEditing(false);  
     
           float circle_1_x = warpCircle->getControlPoint(0).x;  
           float circle_1_y = warpCircle->getControlPoint(0).y;  
           float circle_2_x = warpCircle->getControlPoint(1).x;  
           float circle_2_y = warpCircle->getControlPoint(1).y;  
           float circle_3_x = warpCircle->getControlPoint(2).x;  
           float circle_3_y = warpCircle->getControlPoint(2).y;  
           float circle_4_x = warpCircle->getControlPoint(3).x;  
           float circle_4_y = warpCircle->getControlPoint(3).y;  
     
           xmlWarp.setValue("circle:x1", circle_1_x);  
           xmlWarp.setValue("circle:y1", circle_1_y);  
           xmlWarp.setValue("circle:x2", circle_2_x);  
           xmlWarp.setValue("circle:y2", circle_2_y);  
           xmlWarp.setValue("circle:x3", circle_3_x);  
           xmlWarp.setValue("circle:y3", circle_3_y);  
           xmlWarp.setValue("circle:x4", circle_4_x);  
           xmlWarp.setValue("circle:y4", circle_4_y);  
     }  

Werden jetzt Kontrollpunkte während Programmausführung verändert, lassen sich diese in der XML abspeichern und der alte Wert überschreiben. Auf diese Weise muss die Projektion nur einmalig auf die Szene angepasst werden, da die Einstellungen gespeichert und beim nächsten Programmstart wieder aufgerufen werden kann. Die Ausarbeitung des Warpings erfolgte in erster Linie durch Fritz Lenssen, Tobias Lindner und Daniel Mehlhorn. Die Integration ins Gesamtsystem und Erweiterung durch XML dann in Zusammenarbeit.

Multiple Windows

Eine weitere Herausforderung stellte die Aufteilung des Programmes auf zwei Fenster dar. Da dasselbe Programm über zwei unterschiedliche Projektoren dargestellt werden musste, erschien dies als notwendig. Ein erster Versuch liegt dem Bericht unter „Code\TwoWindows\Mapping_Example“ bei. Hierbei wurde über die Klasse „ofGLFWWindowSettings“ ein zweiter Monitor definiert. Dies lief auch problemlos, jedoch wurden zwei voneinander komplett unabhängige Fenster geöffnet. Das Problem konnte behoben werden, indem dieselbe ofRunApp in zwei separaten Fenstern ausgegeben wurde. Auch dies zeigte ein ordentliches Ergebnis auf, jedoch war es äußerst umständlich genau die gewünschten Bereiche des Programms in dem dafür vorgesehenen Fenster auszugeben. Das war notwendig damit nicht dasselbe Programm zweimal komplett ausgeführt wird, da sonst die doppelte Rechenleistung erforderlich ist. Hierfür konnte das Addon „ofxSecondWindow“ Abhilfe schaffen. Mittels des Addon war es möglich ein zweites Fenster zu deklarieren. ofxSecondWindow secondWindow; Die Größe, sowie die Position werden bei der Initialisierung angegeben. Zudem kann die Fensterdekoration ein- und ausgeblendet werden. secondWindow.setup("second window", 0, 0, 1000, 1000, true); Um nun den gewünschten Bereich in das zweite Fenster zu zeichnen wird ähnlich wie beim WarpController einfach die Subsequenz des Framebuffers innerhalb des zweiten Fensters gezeichnet. In unserem Fall sollte der Boden von den Stelen getrennt werden. Daher war es notwendig die obere linke Ecke der Szene in ein separates Fenster auszugeben.

     secondWindow.begin();  
           ofClear(0, 0, 0);  
           warpController.getWarp(0)->begin();  
                 fbo_warp.getTexture().drawSubsection(0, 0, 1920, 1080, 0, 0, 500, 500);  
           warpController.getWarp(0)->end();  
     secondWindow.end();  

Die Anwendung des Addon ist unter „Code\ofxSecondWindow\Particle_Architecture_2“ zu finden. Diese Variante zur Aufteilung auf zwei Fenster funktionierte einwandfrei. Letztendlich war es dann aber ein kleiner Trick, der uns die Aufteilung auf zwei Projektoren ohne jegliches Addon ermöglichte. Wenn beide Beamer am ausführenden Computer angeschlossen sind, ist es ganz einfach möglich zwei Bereiche des Programms auf zwei verschiedene Beamer zu verteilen, indem man die Fensterbreite über zwei Bildschirme erstreckt. Dieser einfache Trick ermöglichte es uns ein System in einem einzigen Fenster auf zwei Beamer abzuspielen, unterteilt in die linke und rechte Hälfte des Programms. Wichtig war hierbei die Höhe der Szene beizubehalten und die Breite zu verdoppeln, damit das gerenderte Bild am Ende nicht gestreckt wirkt. Die größte Herausforderung hierbei war, dass Geräte vom Hersteller Apple automatisch das Fenster auf Fullscreen anpassen, sobald es über den Bildschirmrand hinaus geht. Daher musste der Code komplett auf einen Windows Rechner übertragen werden.

Mapping - XML

Bei der Übertragung des Codes wurde noch ein weiteres Problem, zusammen mit der Lösung klar. Die Position der Ecken und Angriffspunkte jeder WarpController mussten bei jedem Start des Systems neu eingestellt werden. Das ist natürlich sehr aufwendig und für den Fall eines Absturzes während der Präsentation auch Abbruchkriterium. Daher machten wir es uns zur Aufgabe die einzelnen Werte in einer XML-Datei zu speichern, und daraus die Eckpunkte zu setzen.

     xmlWarp.load("xml/warp.xml");  
     s1_1_x = xmlWarp.getValue("stele1:x1", 0.0);  
     s1_1_y = xmlWarp.getValue("Stele1:y1", 0.0);  
     s1_2_x = xmlWarp.getValue("stele1:x2", 1.0);  

Die XML-Datei beinhaltet Werte für den Boden und jede der drei Stelen. Dazu jeweils die X- und Y-Koordinaten der vier Eckpunkte. Insgesamt also 32 Werte. Diese Werte werden aus der XML gelesen und in Variablen abgespeichert. Sollte in der XML-Datei noch kein Wert vorhanden sein, wird ein Default-Wert genommen, der den unverzerrten Eckpunkten entspricht. Um nun die Verzerrung an den richtigen Stellen zu haben, wird wieder, wie oben bereits beschrieben jeder WarpController mit den dazu gehörigen ControlPoints versehen.

     if (this->warpControllerCircle.getWarps().empty())  
           {  
     
                 warpCircle = this->warpControllerCircle.buildWarp<ofxWarpPerspective>();  
                 warpCircle->setSize(sceneSizeWarp.x, sceneSizeWarp.y);  
                 warpCircle->setControlPoint(0, glm::vec2(c_1_x, c_1_y));  
           …  

In der draw()-Methode werden wieder die einzelnen Subsections des Framebuffers gezeichnet. Diese decken sich mit den gesetzten ControlPoints.

     // FIRST WARP  
     warpControllerCircle.getWarp(0)->begin();  
           fbo_warp.getTexture().drawSubsection(0, 0, 3840, 1200, 0, 0, 1200, 1200);  
     warpControllerCircle.getWarp(0)->end();  

Die Besonderheit liegt nun darin, dass jede Veränderung während der Laufzeit abgefragt und die XML-Datei damit überschrieben werden kann. Dies ist besonders hilfreich, damit beim erneuten Systemstart alle Ausrichtungen erhalten bleiben.

     if (key == 's') {                            //SAVE warpController  
           warpControllerCircle.getWarp(0)->setEditing(false);  
           float circle_1_x = warpCircle->getControlPoint(0).x;  
           float circle_1_y = warpCircle->getControlPoint(0).y;  
           float circle_2_x = warpCircle->getControlPoint(1).x;  
           …  
     
           xmlWarp.setValue("circle:x1", circle_1_x);  
           xmlWarp.setValue("circle:y1", circle_1_y);  
           xmlWarp.setValue("circle:x2", circle_2_x);  

Dazu wird mit Tastendruck der setEditing-Boolean wieder auf false gesetzt. Also ist es nun nicht mehr möglich diesen WarpController zu verändern. Zusätzlich wird die aktuelle X- und Y-Koordinate der jeweiligen ControlPoints in einer Variablen gespeichert. Diese überschreibt die zugehörige Stelle in der XML-Datei und ist für den nächsten Systemstart abrufbar. Die ausführliche Umsetzung der Integration von XML-Dateien, sowie das finale Mapping ist dem Bericht beigelegt unter „Code\Code“. Dies spiegelt auch die komplette Software des Prototyps wider.

Projektmanagement

Wie auch schon im Vorsemester übernahm Stefan Maurer die Tätigkeit als Projektmanager.

Zeitplan

Zu Beginn des zweiten Projektabschnitts verschaffte sich Katharina Ott einen Überblick über die anstehenden Deadlines im Projekt. Diese waren schon zu Projektbeginn festgelegt worden. Um die Terminsituation visuell darzustellen erstellte Katharina Ott einen Zeitstrahl mit allen wichtigen Endterminen. Nachdem dieser von Katharina Ott den Gruppenmitgliedern vorgestellt worden ist, definierte die Gruppe die für die Einhaltung aller Deadlines notwendigen Aufgaben und teilte diese auf die Teammitglieder auf.

Zeitplan mit allen Projektdeadlines

Projekt Roadmap

Mit Entwicklung einer Roadmap zu Beginn des Semesters wurden von Ihm Meilensteine für das Projekt definiert. Anhand dieser sollte es erleichtert werden, den Projektfortschritt zu überwachen und zu gewährleisten.

Kommunikation

Mit der größte Teil der geleisteten Arbeit im Bereich des Projektmanagements war es, die Kommunikation mit der Gruppe, dem Deutschen Museum, dem leitenden Professor Herrn Professor Brünig und den Laboringenieuren Herrn Brendel und Herrn Baer herzustellen und zu bewahren. Des Weiteren galt es die zahlreichen Aufgaben zu erstellen und an die Gruppe zu koordinieren und dabei den Projektfortschritt zu überwachen. Außerdem fertigte Stefan Maurer bei den Terminen immer wieder Mitschriften an, um Besprochenes festzuhalten.

PM Tool (Agantty)

Für diese Aufgabe der Koordination der Aufgaben verwendete die Gruppe bis kurz nach Semesterbeginn das PM-Tool „Asana“. Auf Wunsch von Sebastian Holzki wurde dann hin zu „Agantty“ gewechselt, das in großen Teilen die gleiche Funktionsweise aufwies, aber im Gegensatz zu „Asana“, seine webbasierte Anwendung um eine übersichtliche Timeline ergänzte auf der der Projektfortschritt sehr gut verfolgt werden konnte. Katharina Ott identifizierte die zur Realisierung der Projektziele notwendigen Aufgaben und fasste diese in einer Liste zusammen. Diese Liste stellte sicher, dass bei der Planung der Tasks keine Lücken entstanden und somit Meilensteine im Laufe des Projekts barrierefrei erreicht wurden.

Agantty Dashboard

Bei Einführung des neuen Tools wurden gleich alle bestehenden Tasks überführt und somit konnte Stefan Maurer diese dann ohne weitere Probleme an die entsprechenden Gruppenmitglieder verteilen. Fortan wurde hier immer wieder von Stefan Maurer neue Aufgaben eingepflegt, Zeitrahmen und Meilensteine definiert und an die entsprechenden Personen weitergegeben.

Planungsgremiensitzung

Stefan Maurer nahm in seiner Funktion als Projektmanager auch an den projektübergreifenden Planungsgremiensitzungen teil. Hierbei wurden vor allem die Zeitabläufe der Präsentationen am Tag der Abschlusspräsentation festgelegt, sowie die entsprechenden Räume an die Gruppen vergeben. Außerdem war die größte Aufgabe in diesem Semester bei den Sitzungen, die Feier nach den abschließenden Präsentationen zu planen und den Auf- und Abbau davon zu koordinieren. Weiterhin wurden kleinere Aufgaben, wie Plakaterstellung und andere organisatorische Dinge besprochen und definiert.

Präsentation

Abschlusspräsentation

Stefan Maurer war maßgeblich an der Erstellung und Planung der Abschlusspräsentation beteiligt. Immer wieder unterstützt wurde er von Agathe Gnus, Katharina Ott, Fritz Lenssen, Sebastian Holzki und Kevin Frania. Zusammen erarbeiteten Sie unter Leitung von Stefan Maurer den neuen Aufbau, der Präsentation und bauten die Keynote-Präsentation. Als Styleguide wurde die Präsentation vom Vorjahr gewählt, jedoch wurde im Vergleich zum Vorjahr deutlich mehr Wert auf die Logik innerhalb der Präsentation gelegt und einige Design Elemente, vor allem die immer wiederkehrenden Hexagon-Formen, quasi das Leitsymbol der Projektarbeit, neu implementiert. Um die Präsentation für den Zuschauer logisch aufzubauen wurde entschieden die Präsentation anhand des Prototypenaufbaus zu strukturieren, immer wieder auf diese Folie zurückzukehren, mit dem jeweilig erklärten Bereich im Fokus, um maximale Transparenz für den Zuschauer zu schaffen was man denn gerade erklärt. Der Zuschauer sollte seine Aufmerksamkeit stets auf dem Redner haben und nur in wichtigen, zum Verständnis beitragenden Momenten, auf die Präsentationen lenken. Deswegen entschied Stefan Maurer nahezu sämtliche Text-Folien zu entfernen. Durch die freie Redeweise aller Vortragenden und die auf das Nötigste reduzierten Folien führte dies bei der Präsentation genau zum gewünschten Ergebnis. Die Zuschauer folgten den Worten des Vortragenden und wurden in entscheidenden Momenten durch Animationen in den Grafiken und Folien wieder zur Betrachtung der Präsentation abgeholt. Die Präsentation wurde zudem unterteilt in fünf Themen. Stefan Maurer übernahm die Rolle für den einleitenden Teil, stellte das Team, das Deutsche Museum und die Präsentation in seinem Aufbau kurz vor und übernahm darüber hinaus die Rolle des Sprechers, während des von Fritz Lenssen konzipierten Schauspiels, mit dem der Prototyp demonstriert wurde. Abschließend moderierte er die Präsentation ab. Die Vorstellung des Konzeptes des Projekts, mit der Einführung in das Projekt, sowie die Vorstellung des Forums des Deutschen Museums wurde von Daniel Mehlhorn präsentiert. Zudem gab es noch einige Informationen zu dem Aufbau des Prototyps, sowie zu Partikelsystemen allgemein. Einblicke in die Funktionsweise des Trackings und der Code Architektur waren ebenso gegeben. Abgerundet wurde das Ganze noch durch das geplante Schauspiel. Dieses machte allen im Raum anwesenden Teilnehmern verständlich, wie der Entwurf der Studenten eines Tages im Museum integriert werden könnte. Fritz Lenssen übernahm den Part des Aufbaus und demonstrierte zusammen mit Sebastian Holzki, das von Stefan Maurer als Erzähler begleitete, anhand eines kleinen Schauspiels die Funktionsweise des Projekts. Im Folgenden sind einige exemplarische Folien dargestellt:

Präsentationsfolien

Der Prototyp - Planung und Installation

Letztes Jahr noch mit Bildschirm als Boden und drei kleinen parallel angeordneten Stelen, sollte der Prototyp zum Abschluss des Projekts deutlich interaktiver und maßstabsgetreuer werden. Schon zu Beginn des zweiten Projektsemesters saßen Teile des Projektteams, und überlegten gemeinsam an einem möglichen Aufbau. Grundsätzlich sollten diesmal sowohl der Boden, als auch die Stelen mit jeweils einem Projektor angestrahlt werden. Anfangs war für den Boden noch angedacht, dass dieser mit drei Projektoren bestrahlt wird, um die Schattenwürfe zu eliminieren. Schlussendlich entschied sich die Gruppe dann für jeweils einen Hochleistungsbeamer. Zu den beiden Projektoren kam noch das Gesamtsystem, das die beiden Projektoren bedient und das System für das Tracking. Für jenes waren noch sowohl ein Infrarotstrahler, als auch eine Kamera mit Infrarotfilter notwendig. Zusammen sah der Aufbau dann folgendermaßen aus.

Ablauf

Holzstelen

Für den neuen Prototypen im neuen, größeren Maßstab, entschied sich die Gruppe dafür drei eigenständige Holzstelen zu verwenden, die dann mit einem Beamer bespielt werden sollten. Die Aufgabe diese Stelen zu entwerfen und zu bauen übernahm Stefan Maurer.

Stelen Moodboard

Die Stelen wurden zunächst mit dem 3D-Modellierungsprogramm SketchUp von Ihm geplant und mit der Gruppe diskutiert, um eine Vorstellung von den Dimensionen zu bekommen. In der Gruppe wurde die Entscheidung getroffen die Stelen so groß wie möglich zu bauen, so dass sie noch in den Raum der Präsentation passen würden. Die Projektionsfläche belief sich somit letztendlich auf 2,8 Meter auf 80 Zentimeter, pro jeweilige Stele.

Stele Front
Stele Rückseite

Prototypenbau

Stelen

Die Holzstelen, die Abschlusspräsentation benötigt wurden, um sie mit einem Beamer zu bespielen, wurden von Stefan Maurer angefertigt und zu dem Raum der Projektpräsentation gebracht. Mit Hilfe von Agathe Gnus und Katharina Ott wurden die von Stefan Maurer vormontierten Elemente endmontiert und an ihren Bestimmungsort verbracht.

Aufgebaute Holzstelen
Einlesestation

Einlesestation wurde benötigt, um ein Handy als Display prominent in der Mitte des Prototyps platzieren zu können. Auf dem Handy, das von Danial Eshete zur Verfügung gestellt wurde, konnten per TouchOSC die Icons auf den Stelen angesteuert, beziehungsweise ihr Erscheinen ausgelöst werden. Für den Bau der Einlesestation verwendeten Stefan Maurer, Agathe Gnus und Katharina Ott unterschiedlichste Materialien, die sie an der Hochschule zur Verfügung hatten. So wurde aus Hartschaumplatten eine Verkleidung für das Handy gebaut, die auf einer Stele aus Karton ruhte. Da das Handy in die Verkleidung eingearbeitet war und somit nur noch der Touchscreen zu sehen war, wurde von Stefan Maurer noch zwei Öffnungen in die Verkleidung eingebohrt, um zum einen ein Stromkabel zum Handy zu verlegen, das es mit Hilfe einer Powerbank laden sollte und zum anderen, um einen kleinen Holzstift einzustecken, mit dem der Powerbutton des Handys bedient werden konnte. Um dem ganzen Aufbau der Einlesestation eine gewisse Stabilität zu geben, wurde in die Kartonsäule ein Holzstab eingefügt, um Gewicht und Stabilität zu fördern. Außerdem wurde die Säule auf eine Holzplatte aufgeklebt, um ihr mehr Standfläche zu geben. Abschließend wurde die Einlesestation noch komplett schwarz lackiert und mit Projektlogo-Aufklebern gebrandet.

Einlesestation im Ruhezustand
Einlesestation im fertigen Zustand

Fertiger Prototyp

Die beiden Systeme (Tracking und Partikel) kommunizierten per OSC. Das Partikelsystem erhält zusätzlich noch Informationen über TouchOSC, womit die Spielertypen und der Ort des Entstehens (an einer der drei Stelen) ausgewählt werden können. Die Einlesestation wurde durch TouchOSC ersetzt, da kein RFID verwendet wurde.

Aufbau in hel und ihne Bespielung und dunkel mit Bespielung

Um eine bessere Vorstellung für den tatsächlichen Aufbau zu erhalten sind oben die drei 2,80m hohen und 0,80m breiten Stelen zu sehen. Davor is die Einlesestation für die Spielauswertung zu sehen. Der LED-Boden wurde dann kreisförmig, an die Anordnung der Stelen angepasst, projiziert. Am Aufbau des Prototyps arbeitete nahezu das gesamte Projektteam, wobei die Stelen von Stefan Maurer gefertigt wurden. Das Trackingsystem brachten dann Sebastian Holzki und Fritz Lenssen wieder zum Laufen. Die dafür vorgesehene Technik musste wieder neu angepasst und platziert werden. Die beschränkte Reichweite des trackbaren Bereichs bereitete anfangs Schwierigkeiten, konnte aber an das System angepasst werden.

Aufbau

Auch beim Aufbau für die Präsentation übernahm Stefan Maurer eine führende Rolle. So koordinierte er mit den Laboringenieuren die benötigte Projektionstechnik und baute diese zusammen mit ihnen auf. Auch den Aufbau des Infrarot-Trackings, samt dem benötigten Rechner und die erstmalige Justierung übernahm er zusammen mit Kevin Frania. Final initialisiert und eingestellt wurde es dann von Sebastian Holzki und Fritz Lennsen. Überdies bereitet er mit einigen anderen zusammen den Raum auf die Abschlusspräsentation vor, da in dem Laborraum erst einmal Platz für den Aufbau des Prototyps geschaffen werden musste.

Aftermovie FORUM - Shaping our future

Planung

Um die Präsentation in der Hochschule mit der anschließenden Demo zu dokumentieren, kam die Idee auf den Tag zu filmen, um anschließend ein Aftermovie dem Museum präsentieren zu können. Da der Prototyp im 6. Semester aus drei fast deckenhohen Holzgerüsten bestand, wäre eine Live-Demo im Museum schwer möglich gewesen. Aus diesem Grund war es das Ziel den Prototypen in Aktion mit Besuchern zu zeigen und auch gleich positive Emotionen einzufangen. Dazu stellte Tobias Lindner seine Kamera und ein Gimbal zur Verfügung. Eine Planung des Videos stellte sich als sehr hilfreich heraus, da so Aufnahmen nicht willkürlich entstanden, sondern planbar waren. So ließen sich unnötig viele Aufnahmen vermeiden. Hierzu war die Erfahrung aus dem Teilmodul Videojournalismus bei Malte Burdekat sehr hilfreich. Folgender Auszug aus der Planung wurde an seine Empfehlungen angelehnt.

Videoplanung

Nahaufnahmen der Präsentierenden wurden bereits während der Generalprobe am selben Tag aufgezeichnet, um die Sicht der Zusehenden nicht zu stören. Zu erwähnen ist, dass die Lichtverhältnisse während der Präsentation und Demonstration stets sehr dunkel und damit nicht optimal waren. Dies war allerdings nötig, um die Projektion des Prototypen am intensivsten zu zeigen. Nichtsdestotrotz entstanden gute Aufnahmen, die trotz des dunklen Raums einen lebendigen Einblick in die Endpräsentation liefern.

Schnitt

Der Schnitt erfolgte mit dem Programm Adobe Premiere Pro. Der Film ist 2,06 Minuten lang und beinhaltet die Präsentation bis hin zur offenen Demo des Prototyps. Die Entscheidung fiel auf einen Song von frametraxx anstelle des Originaltons, mit dem Titel „Anywhere“. Durch die Hintergrundmusik wirkt das Video dynamischer und ermöglichte in zwei Minuten gebündelt eine Vielzahl an Eindrücken zu vermitteln. Das Video ist dem beigelegten Datenträger zu entnehmen („Aftermovie_FORUM.mp4“).

Reflexion

Das Ziel der Projektgruppe „Forum – Shaping our future“ war es von Anfang an ein Konzept für das Forum in dem Zukunftsmuseum des Deutschen Museums zu erarbeiten und einen Prototyp für die Veranschaulichung herzustellen. Zum Projektende steht die Projektgruppe mit einem erfüllten Aufgabenkatalog am Ende Ihres Weges. Die definierten Ziele wurden ausgearbeitet und realisiert.

Zusammenfassend kann man Folgendes sagen: Für das Deutsche Museum wurde ein interaktives System erdacht, das aufbauend auf den vorgegebenen Stelen im Forum konzeptionell um einen LED-Boden erweitert wurde. Es wurde ein interaktives System mit OpenFrameworks entwickelt, das mit Hilfe von OSC Nachrichten ein Infrarot-Tracking der Besucher auf dem LED-Boden ermöglicht und somit ein Steuern des Partikelsystems des Bodens möglich macht. Außerdem wurde eine Einlesestation für die vom Museum angedachten RFID-Bänder mit Hilfe einer Touch-Steuerung, die per TouchOSC mit dem Partikelsystem der Stelen und des Bodens verbunden war, simuliert. Die Partikelsysteme von Boden und Stelen wurden, unter Zuhilfenahme von Mapping verbunden, um die unterschiedlichen Bereiche korrekt einteilen zu können und somit eine 2D-Szene in einer 3D-Szene anzeigen zu können. Desweitern wurde dem Deutschen Museum mit der konzeptionellen Arbeit der Projektgruppe eine umfassende Möglichkeit der Auswertung ihres, seitens des Museums noch nicht genauer definierten, Spieles ausgearbeitet. Hierzu fanden umfassende Design- und Konzeptions-arbeiten, sowie Effektentwicklungen für die Partikel statt. Außerdem wurden für die Zwischen- und Abschlusspräsentation jeweils ein voll funktionsfähiger Prototyp entwickelt, der das Konzept und die Technik wiederspiegelte, die für einen reellen Einsatz im Museum benötigt werden würden, wobei die Bildschirmflächen durch Projektionen ersetzt wurden. Rückblickend war der Weg dorthin mit Nichten immer einfach und oft hatten wir Frust oder waren mit unserem Latein am Ende. Teilweise gab es Schwierigkeiten in der Kommunikation oder mit der Planung. Ab und zu fehlte es auch mal am Ehrgeiz und der Ausdauer und manchmal gab es auch Streitereien zwischen den Mitgliedern über Entscheidungen. Letzten Endes hatten wir aber auch genauso viel Freude an der gemeinsamen Arbeit, die teils bis spät in die Nacht ging. Wir sind als Gruppe zusammengewachsen, haben Stärken und Schwächen voneinander kennengelernt und uns entsprechend gegenseitig unterstützt. Wir hatten erfolgreiche Präsentationen, begeisterte Zuschauer, die uns mit Fragen und Anregungen überhäuften und haben vor Freude gejubelt, wenn ein Problem nach langem Kampf endlich gelöst war. Ich glaube jedes Gruppenmitglied kann sagen, dass es an dieser Projektarbeit gewachsen ist. Wir haben vor zehn Monaten als zusammengewürfelter Haufen ein abstraktes Projekt begonnen und jetzt als Gruppe ein echtes Ergebnis abgegeben. Abschließend kann die Projektgruppe stolz auf die geleistete Arbeit sein und muss sich damit keinesfalls verstecken. Mit unserer Arbeit haben wir dem Museum und uns selbst bewiesen, dass Partikelsysteme, das Forum und unser Konzept für die Spielauswertung gut zusammen-passen und funktionieren. Wir hoffen das Museum von unserer Arbeit genauso überzeugt zu haben, wie uns selbst und wünschen uns, wenn auch nur anteilig, damit tatsächlich im Museum vertreten zu sein.