CO/OP TREE

Aus toolbox_interaktion
Wechseln zu: Navigation, Suche

Im Rahmen des Studiengangs Media Engineering findet eine semesterübergreifende Projektarbeit in Form eines Gruppenprojektes statt. Der vorliegende Wiki Eintrag behandelt den Projektabschluss der interaktiven Medieninstallation „CO/OP TREE“. Dabei wird nach einleitender Erläuterung der Projektthematik das Konzept vorgestellt. Anschließend werden die Organisationsarbeiten und die Aufgaben der einzelnen Untergruppen aufgezählt. Diese umfassen den Input, OSC, das Brain, die LEDs, das Partikelsystem und die Game Engine. Darauffolgend wird auf die Umsetzung des Design und der Präsentation eingegangen. Abschließend wird als Fazit ein Rückblick auf das Projekt, die Teamarbeit und ein Ausblick für zukünftige Erweiterungen gegeben.

Einführung

Bei dem durch Professor Brünig, sowie von Herrn Baer und Herrn Brendel, betreuten Projekt handelt es sich um eine interaktive Medieninstallation, die die Studenten nach eigenen Vorstellungen entwerfen können. Bei dieser Aufgabenstellung steht im Vordergrund, eine Installation zu kreieren, mit dem der Besucher interagieren kann. Die Grenze zwischen Mensch und Technik soll überbrückt werden, indem der Interagierende selbst Reaktionen auslösen, beziehungsweise die Technik steuern kann. Das zehnköpfige Projektteam wählte im fünften Semester als Thema einen sogenannten „interaktiven Baum“ namens CO/OP TREE, der sich bewusst von der Natur distanzieren und die Technik als Thematik mehr in den Vordergrund rücken soll. Im fünften Semester plante das Team die Umsetzung des gesamten Baums, fand geeignete Materialien und fertigte Prototypen vom Partikelsystem und der Bodenplatte an. Zu Beginn des sechsten Semesters wurde klar, dass aufgrund Covid-19 und den damit einhergehenden Kontaktbeschränkungen der Baum nicht real umgesetzt werden kann. Daher musste das Konzept in der zweiten Projektphase überarbeitet werden. Der Baum musste virtuell erstellt werden, sodass die Aufgabe des Bauens mit der des digitalen Modellierens ersetzt wurde. Es wurde gemeinschaftlich beschlossen, die Programmierung des Baumes so vorzunehmen, dass eine reale Umsetzung jederzeit möglich wäre, sollte man sich wieder in der Hochschule treffen dürfen. Um trotz diesen Einschränkungen ein vorzeigbares Ergebnis zu haben, entschied sich das Team dafür, neben einer 2D-Simulation auch eine 3D-Simulation in Erwägung zu ziehen. Als ersten Schritt fertigte jedes Teammitglied ein Vernetzungskonzept an, wie er sich die gegenseitigen Einflüsse der unterschiedlichen Komponenten vorstellt. Aufgrund der Teamgröße und der Menge an zu bewältigenden Aufgaben teilte sich das Team mithilfe der Vernetzungskonzepte in mehrere kleine Untergruppen auf.
Input:

  • Sensorwerteingabe und Sensorsimulation
  • Aktionen vom Benutzer erkennen/Empfangen der eintreffenden Daten

OSC:

  • Übertragen von Werten zwischen den verschiedenen Programmen/Teilen der Installation

Brain:

  • Verarbeiten von Inputwerten, erzeugen von Effekten basierend auf Werten und Usereingaben, Setup der Installation

LED:

  • Ausgabe einer 2D Simulation der LED-Stripes anhand der vom Brain bestimmten Effekte
  • Feedback zum Nutzer

Partikelsystem:

  • Ausgabe eines Partikelsystems anhand der vom Brain bestimmten Parameter
  • Feedback zum Nutzer

Game Engine:

  • Umsetzung der Gruppen Input und LED in einem dreidimensionalen Umfeld – reale Installation repräsentierend

Nur durch eine strukturierte Arbeitsverteilung war es möglich, dieses umfangreiche Projekt effizient umzusetzen. Das Ziel der einzelnen Teams war es, bis zur Projektpräsentation am 15.07.2020 den fertigen, virtuellen CO/OP TREE präsentieren zu können.

Konzept

Trotz der nur virtuellen Umsetzung des Projektes soll das Grundkonzept beibehalten werden. Zur Erinnerung an dieses Konzept hier ein kurzer Auszug daraus:
„The interactor is playing nature. The trees life is dependent on the small actions of many individuals, bringing them together in a Co-Operation. Individuals can influence or represent the factors of nature which are important for the tree: water, soil | temperature | sound/wind | „energy“ By adjusting these factors, the tree responds accordingly. If the factors are correctly adjusted, the user gets a positive feedback through audiovisuals. If they are incorrectly adjusted, the user gets a negative feedback.“

Der Interagierende soll also die Rolle der Natur übernehmen und den Baum mit den lebensnotwendigen Faktoren versorgen. Ursprünglich entworfen wurde ein Baum, der optisch stark abstrahiert wurde. Dieser sollte übereinandergestapelten Plexiglaswürfeln bestehen, welche je eine eigene Interaktionsmöglichkeit bereitstellen, platziert auf einer Bodenplatte mit leuchtendem Wurzelgeflecht, welches ebenfalls auf den Besucher reagiert. Dabei konnten in diesem Semester nicht alle Faktoren umgesetzt werden, da der Temperaturwürfel sowie der Windwürfel aufgrund von Corona nicht umgesetzt werden konnten (durch keine reale Umsetzung als auch durch Corona-Probleme bei einer realen Umsetzung (u.a. Kontaktflächen)). Jedoch wurde die „Meta-Energie“ weiterhin durch das Partikelsystem verfolgt und die Nährstoffquelle als Wasser/Erde durch die LED-Wurzeln mit virtuellen Sensoren ins Auge gefasst. Bei der digitalen Umsetzung des Projektes stand immer im Vordergrund, dass diese auch noch im realen physisch aufgebaut werden konnte. Deswegen wurde z.B. das Projekt nicht komplett in einer Game Engine simuliert, sondern die Einzelkomponenten bilden eigene Programme, welche über das Netzwerk kommunizieren. Somit ist eine größtmögliche Flexibilität für eine reale Umsetzung gegeben.


Organisation

Durch das Online-Semester ergaben sich deutlich mehr organisatorische Aufgaben und auch die Kommunikation musste sehr klar und strukturiert sein. Daher geht es in diesem Abschnitt um die Kommunikation, die Teamstruktur, den Datenaustausch, den Zeitplan und die Aufgabenverteilung.

Kommunikation

Da in diesem Semester kein reales Treffen der Teammitglieder stattfinden konnte, wurden verschiedene Tools zum Online-Treffen probiert. Jitsi, Hangouts und Discord wurde getestet. Hierbei stellte sich heraus, dass Discord die geeignetste Plattform darstellt. Bei Discord wurde ein eigener Channel mit dauerhaften Chats erstellt. Einmal die Woche fand ein gemeinsames Teamtreffen mit den Projektleitern statt, zudem wurde später ein zweites Teamtreffen in der Woche hinzugefügt. Die einzelnen Teams trafen sich die Woche über selbstständig und teilten die Informationen bei den gemeinsamen Treffen. Zu jedem Treffen wurde auch immer ein Protokoll angefertigt, damit jederzeit von allen nachvollzogen werden konnte was besprochen wurde. Hierbei durften die einzelnen Teams kleine Entscheidungen selbst treffen und größere wurden im gesamten Team besprochen. Zusätzlich wurden Online-Coding-Days veranstaltet an denen alle Teammitglieder teilnahmen, um gemeinsam zu arbeiten und sich auszutauschen. Um gemeinsame Termine zu finden, wurde ein Google Kalender geführt, in den individuelle Termine eingetragen werden konnten. Zum schnellen Austausch diente zusätzlich weiterhin die WhatsApp-Gruppe. Außerdem trafen sich alle zwei Wochen alle Projektleiter der weiteren Projekte mit Herrn Prof. Röttger, um die Projekt-Präsentationen zu besprechen und Fragen zu klären. Natürlich wurden auch diese Treffen immer vor und nachbereitet, um eine klare Struktur und Ablauf zu gewährleisten.

Input

Da zu Beginn des Semesters nicht klar war, inwieweit der reale Bau eingeschränkt wird und ob somit überhaupt ein realer Input durch den Interakteur möglich sein wird, entschied sich das Team, einen 2D-Input zu programmieren. Dieser sollte das Betreten der Bodenplatte und das Aktivieren der Sensoren in den einzelnen Würfeln im realen Leben simulieren. Im realen Leben würde der Interakteuer durch Betreten der Sensoren auf der Bodenplatte die LED’s aktivieren. Die einzelnen Würfel würden ebenfalls durch Berühren der jeweiligen Sensoren aktiviert werden. Im Code der 2D-Animation findet dies durch manuelles ‚Aktivieren‘ von verschiedenen Slidern statt. Es gibt also keine realen Sensoren mehr, sondern nur virtuell erzeugte Werte. Während in der realen Umsetzung die Daten der Sensoren an einen Arduino weitergeleitet werden, werden in der 2D-Umsetzung die Daten an OSC weitergeleitet. OSC verarbeitet diese Daten und leitet sie an das Brain weiter. Das Brain wiederum leitet diese Werte abschließend an die einzelnen Komponenten des Baums weiter.


Abbildung 1: Weiterleitung des Inputs


Um dies umzusetzen wurde mittels Visual Studio Code ein User Interface erstellt. Es wurde eine Vektorliste programmiert, welche die jeweilige SensorID für die Würfel und den aktuellen Wert der Slider an OSC weiterleitet. Für jeden Würfel gibt es einen extra Slider – Temperaturwürfel, Partikelwürfel und für die LED’s. Zusätzlich zu den einzelnen Slidern wurde eine Art Abstandscountdown programmiert. Dieser simuliert einen variierenden Abstand zu einem beliebigem Sensor. Bei diesem Countdown ist es zudem möglich, die Geschwindigkeit manuell einzustellen. Je niedriger man den Wert setzt, desto schneller bewegt sich der Countdown. Desto schneller bewegt sich also der Interakteur auf den Sensor zu.


Abbildung 2: Finales Ergebnis des Inputs


Aufbau der Klassen

Die Klassen des Inputs erfüllen folgende Funktionen:

  • ofApp: Es werden die Methoden setup(), update(), draw() von der Klasse InputGroup aufgerufen.
  • «abstract» Sensor: Ist allgemeiner Sensortyp und abstract durch ofAbstractParameter & getParam(), welche in der Klasse GenericFloatSensor neu definiert wird. Bei abstrakten Klassen werden Typen nicht instanziiert, aber können als Basisklasse verwendet werden. Virtuell, dass sie in abgeleiteter Klasse (GenericFloatSensor) neu definiert werden. Ansonsten wird hier noch „id= idcounter++“ (in Sensor.cpp) festgelegt, sodass für jeden hinzukommenden Sensor die ID steigt und jeder möglicherweise zugefügte Sensor somit eine andere ID hat.


Abbildung 3: Sensor.h


  • GenericFloatSensor: Generischer Sensor, der Datentyp festlegt als float (ofParameter _ param), Name der Variable wird als Referenz übergeben. Es werden Grenzen 0-40 und Startwert von 20 im Konstruktor festgelegt, die für den Abstand der Sensoren stehen. Ich habe mich hierbei an dem Abstandssensor HC-SR04 vom vergangenen Semester orientiert, der bis 40 cm ging. Die Funktion „calibrate“ wird nicht verwendend, der Ansatz ist jedoch vorhanden, sodass man bei einer Umsetzung mit tatsächlichen Sensoren, diese noch kalibrieren könnte.


Abbildung 4: GenericFloatSensor.cpp


  • InputGroup: In InputGroup::setup() wird die Liste mit Hilfsfunktion addfloatSensor erzeugt. OSCElement elementSender wird in der updateMethode aufgerufen und mit elementSender.sendValue(s->getId(), s->getCurrentValue()) wird Sensorliste durchgegangen (Zeile 29-31 in InputGroup.cpp). In der folgenden Abbildung ist das Inputsystem in der Anwendung zu sehen.


Abbildung 5: Ausgabefenster OSC und Input Gui
Abbildung 6: InputGroup.cpp


OSC

OSC ist die Abkürzung für Open Sound Control und beschreibt ein nachrichtenbasiertes Netzwerkprotokoll, welches überwiegend für die Echtzeitverarbeitung von Daten über Netzwerke verwendet wird. Es lassen sich damit auch integer- oder float-Werte übersenden, was sich zunutze gemacht wurde. Es fanden wöchentliche Treffen statt, bei denen programmiert oder über den aktuellen Codestand informiert wurde.

Bedeutung der OSC-Gruppe für das Gesamtkonzept

Die Hauptaufgabe des Teams war es, die Kommunikation zwischen den einzelnen Elementen (z.B. Sensoren, LED oder Partikelsystemwürfel) und dem Zentralrechner (Brain) herzustellen. Ein Überblick hierzu ist auf folgendem Systemplan dargestellt:


Abbildung 7: OSC Systemplan


Die Grundlage der OSC Kommunikation sind ein Sender, ein Receiver und eine Nachricht. Sender und Receiver müssen hierbei über einen gemeinsamen Port und eine identische IP-Adresse miteinander kommunizieren. Der Nachricht muss zusätzlich eine feste Adresse gegeben werden, damit sie beim Receiver auch richtig empfangen werden kann.

Umsetzung

Als ersten Schritt wurde das Addon ofxOsc zum Projekt hinzugefügt. Im Anschluss wurde über das Plugin „Live-Share“ in Visual Studio 2017 ein inputseitiger Sender, ein brainseitiger Empfänger und eine Nachricht kreiert, welche die simulierten Sensorwerte des Inputs enthielt. Die korrekte Übertragung wurde in den Konsolenfenstern der Programme ausgegeben. Damit war eine erste Übertragung zwischen zwei Systemen geschaffen.


Abbildung 8: Codeausschnitt - Kommunikation zweier Systeme
Abbildung 9: OSC Übertragung zwischen zwei Systemen


Nach einigen Absprachen entschied man sich im nächsten Schritt für einen Login Prozess. Hierbei meldet sich jedes Element mittels seiner ID beim Brain an und bekommt seinem Typ entsprechend passende Werte zurückgeliefert. Zusätzlich werde in diesem Prozess alle Konfigurationen für den nachfolgenden Loopprozess vorgenommen, über welchen stetig Werte zwischen Element und Brain übersendet bzw. empfangen werden. Dies gilt analog für alle In- oder Output-Elemente. Hierfür steht folgende Abbildung, wobei zu erwähnen ist, dass die calibrateValue() und valueWasSet()-Methoden keine Umsetzung fanden.


Abbildung 10: OSC Sequenzdiagramm


Außerdem wurde die Basis des Setupprozesses in Rücksprache mit Herrn Brendel programmiert. Wie auf dem nächsten Schaubild zu erkennen ist, wurde zunächst geplant den OSC-Code in den Klassen der jeweiligen Elemente zu implementieren.


Abbildung 11: OSC Implementierungsübersicht


Der in Abbildung 12 angefügte Code bildet den Prototyp des Setup-Prozesses ab. Mittels einer Switch-Anweisung springen die Programmteile zwischen verschiedenen Anweisungen hin und her. Diese Anweisungen rufen zum Teil eigene Methoden auf. Auf Basis des bereits oben erklärten Funktionsweise von Sender und Receiver wurde so eine wechselartige Kommunikation realisiert. Für den Fall einer verlorenen Nachricht oder einer Nachricht, die zu schnell übertragen wurde und somit verpasst werden kann, kann mit Hilfe der Anweisung "!setupCubeReceiver.hasWaitingMessages()" ein Schritt zurückgesprungen und die Nachricht erneut versendet werden. Auf diese Weise kann eine Übermittlung garantiert und gesichert werden.


Abbildung 12: Codeausschnitt Setup-Prototyp


OSC-Handler

Mit dem Voranschreiten des Projektes wurde allerdings deutlich, dass es sinnvoll ist, eigene Klassen für die OSC-Verbindung zu integrieren. So ist das Konzept des OSC-Handlers entstanden, welches vorsah, eine elementseitige und eine brainseitige OSC-Klasse zu schreiben. Diese Klassen sollten alle In- und Output relevanten Methoden beinhalten, welche für den Setup- und den Loopvorgang notwendig sind. Hierzu wurden folgende grobe Klassendiagramme angefertigt:


Abbildung 13: Klassendiagramme OSC


Die Erstellung der Klassen war ein langer Prozess, welcher einiges an Feedback erforderte. Ergänzend wurden Meetings mit den anderen Untergruppen organisiert, um die Methoden richtig für den Code der einzelnen Elemente anzupassen, also z.B. dem Input oder dem LED-Output. Sieht man sich den Code der OSCElement-Klasse in der Anlage an, ist zu erkennen, dass zur Unterscheidung der Elemente versucht wurde, die Präprozessor Direktive #ifndef zu verwenden. Dies funktionierte leider nicht immer einwandfrei, deshalb wurden im OSCBrain Unterklassen für Input, LED und Partikelsystem erstellt (SensOSCBrain, LEDOSCBrain & ParticleOSCBrain). Der „LOGINSENDPORT“ wurde auf 50000 und der „LOGINRECEIVEPORT“ auf 50001 gelegt. Die jeweils passenden Ports für den Loop-Prozess, werden im OSCBrain berechnet und dem Element während des Setupvorgangs mitgeteilt. Mit dem isInitialized Boolean wird geprüft, ob ein Element bereits den Setupvorgang abgeschlossen hat. Falls nicht, werden die Methoden des Setupprozesses in einer Switch-Anweisung durchlaufen (initializeUpdate(), login(), reveiceLoginConfirmation(), sendLoopPortConfirmation(), receiveInfos(), sendInfoConfirmation()). Diese entsprechen einer wechselseitigen Kommunikation zwischen OSCElement und OSCBrain. Anschließend wird die Methode loopSenderReceiverSetup() aufgerufen, um die Verbindung über den Loopport zu gewährleisten. Direkt danach wird der isInitialized Boolean auf „true“ gesetzt, um zu kennzeichnen, dass dieses Element das Setup bereits abgeschlossen hat. Falls eine Nachricht nicht beim Empfänger ankommen sollte, wird der initStatus mithilfe der if-Anweisung und der hasWaitingMessages()-Methode einen Schritt zurückgesetzt und die vorherige Methode erneut ausgeführt. Die OSCBrain Klasse fängt die Nachrichten des Elementsetups mit folgenden Methoden ab: receiveLoginData(); SendLoginConfirmation(loopSendPort, loopReceivePort); sendInfos(); , receiveLoopPortConfirmation();closeSetup(). Für die weitere Übertragung wurden, abhängig vom Typ des Elements, passende Methoden entwickelt.


Abbildung 14: OSC Methode


Zusätzlich wurden noch viele weitere Methoden entwickelt, um den Code lauffähig zu machen, wie beispielsweise die LED-Output Methoden getNetworkEffect(), getStrandEffects() und getLocalEffects() aus der OSCElement-Klasse.


Brain

Das Team Brain hatte die Aufgabe den Zentralrechner, das Brain unseres Baumes, zu programmieren. Es sollte so gestaltet werden, dass alle Werte die es geliefert bekommt, verarbeitet werden und anhand dieser Werte entschieden wird, was für eine Ausgabe auf unserer Installation gezeigt werden soll. Zudem verwaltet das Brain die Positionen und Eigenschaften der Module (z.B. Würfel), Elemente (z.B. Arduino für Sensoren) und Childelemente (z.B. Sensoren, LED-Strips). Es ist somit auch für den Setup der gesamten Installation verantwortlich. Im Folgenden findet sich eine Übersicht und das Klassendiagramm.


Abbildung 15: Übersicht Brain
Abbildung 16: Klassendiagramm Brain


XML-Handler

Das Brain übt das gesamte Setup der Installation aus. Dafür werden die Eigenschaften der Module in – anfangs nur einer – später in mehreren XML-Dateien mit jeweils unterschiedlichen enthaltenen Merkmalen gespeichert. Um das Setup auszuführen muss also die XML-Datei ausgelesen, die Eigenschaften in Variablen gespeichert werden und diese dann den Modulen, Elementen und Child-Elementen zugewiesen werden. OpenFrameworks bietet hierzu das nützliche Addon ofxXMLSettings. Das Addon war zum damaligen Zeitpunkt leider nicht besonders ausführlich dokumentiert. Deshalb wurde ein kleines Testprogramm geschrieben, in dem die für das Projekt benötigten Funktionalitäten in einem kleineren Rahmen ausprobiert wurden. Zu den getesteten Funktionalitäten gehörten das Erstellen einer XML-Datei, sowie das Speichern dieser, das Ändern von Werten zwischen den XML-Tags und das Ändern der Werte von Attributen im XML-Tag. Letzteres war besonders wichtig, da die Eigenschaften unserer Module und Elemente als Attribute von Tags gespeichert werden. Die Verwendung von verschiedenen Methoden des Addons in einer for-Schleife wurde ebenfalls getestet. Mit den Erkenntnissen aus diesem Test Programm konnten der XML-Handler aufgesetzt werden. Die erste XML-Handler Klasse war zwar XMLHandler, allerdings sind diese Funktionalitäten jetzt in der Klasse InstallationXMLHandler zu finden. Der Installation XML-Handler enthält folgende Methoden:

Installation* setup_installation();
Module* setup_module(int current_Module, ofMatrix4x4 parent_Matrix);
Element* setup_element(int current_Element, ofMatrix4x4 parent_Matrix);
ChildElement* setup_childElement(int current_ChildElement, ofMatrix4x4 parent_Matrix);


Die Methoden funktionieren alle ähnlich. Die hinterlegte XML-Datei wird nach bestimmten Tag-Namen abgesucht. Die Anzahl der Tags mit den richtigen Namen wird gespeichert und pro Tag wird ein Objekt erstellt. Die Methode setup_installation() wird zuerst aufgerufen, da das Tag installation alle anderen Elemente enthält.


Abbildung 17: Beispiel Setup XML


Sobald ein Tag mit dem Namen Installation gefunden wird, wird der Konstruktor der Klasse Installation aufgerufen und ein Objekt dieser Klasse erstellt. Danach werden die Tags mit dem Namen Module gesucht und pro Tag die Methode setup_module(…) aufgerufen. In dieser Methode passiert wieder das gleiche. Pro Funktionsaufruf wird der Konstruktor der Klasse Module aufgerufen und ein Objekt davon mit den zugehörigen Eigenschaften erstellt. Danach wird pro Element innerhalb des Module-Tags wieder die Methode setup_elements(…) aufgerufen. Mit dem letzten Aufruf der Methode setup_childelements(…) wurden dann alle Objekte erzeugt und die Installation wurde vollständig aufgesetzt.


Abbildung 18: Beispielkonfiguration XML-Datei


LED

Die LED Stripes gehören zum visuellen Output des CO/OP TREEs. Zuerst wurde ein 2D Output generiert, der dann in der Game Engine in 3D übersetzt wurde. Die LEDs sind ein drei Gruppen unterteilt. Das Network beschreibt das gesamte Netz der LED Stripes im Baum, die Strands stellen einen direkten Weg von einem Sensor bis zur Baumkrone dar. Ein Link ist ein Abschnitt zwischen zwei Verzweigungen, einem Sensor und einer Verzweigung oder einer Verzweigung und der Baumkrone.


Abbildung 19: Network, Strand und Link Darstellung LED


Die Setupinformationen für jeden einzelnen Link werden vom Brain über OSC an die LED-Komponente übermittelt. Das Network erstellt anhand dieser Informationen die Links und Strands. Das Brain teilt dem Network, und dieses dann den Links die aktuellen Leuchteffekte und Parameter mit. Die Effekte werden vom LED Output durch verschiedene mathematische Funktionen berechnet. Das Brain teilt dem Output lediglich die Entscheidung über die Effekttypen und die benötigten Parameter mit. Neben verschiedenen Effekttypen unterteilen sich die Effekte in unterschiedliche Gattungen, die den Geltungsbereich des jeweiligen Effekts definieren. Die wichtigste Gattung bildet hierbei der sogenannte StrandEffect: dieser gilt nur auf einem Strand. Zusätzlich kann ein NetworkEffect, welcher die gesamte Installation beeinflusst, sowie beliebig viele LocalEffects, welche an einer bestimmten dreidimensionalen Position vorherrschen angezeigt werden.


Abbildung 20: Ablaufskizze LED Output


Es kann dazu kommen, dass ein Link mehrere Effekte ausführen muss. Hier kommt das Effect Blending ins Spiel. Das Effect Blending berechnet aus mehreren Effekten die Farben im Link an jeder Stelle, an der die Effekte übereinander liegen um einen geschmeidigen Zusammenfluss der verschiedenen Effekte zu ermöglichen. Dadurch entsteht im ganzen Baum eine schlüssig zusammenhängende Lichtanimation, die sich genau nach dem Benutzer richtet.

Diagramme

Der Code basiert auf folgenden Diagrammen.


Abbildung 21: Aktivitätsdiagramm LED
Abbildung 22: Klassendiagramm LED


Code

Im Team LED wurde häufig mit Pair-Programming und dem Vier-Augen-Prinzip gearbeitet.

User Interface

Das User Interface wurde für die zweidimensionale Ausgabe entwickelt, die im LED-Team hauptsächlich zum Testen des Codes gedient hat. Das Interface wurde mithilfe der Klasse ofParameter von openFrameworks erstellt. Über diese Parameter kann man verschiedene Eigenschaften, wie die Größe einer LED, die Anzahl der LEDs in einem Link und die Effektlänge einstellen. Über die Network Methode updateLinks() werden den Links die neuen Parameter mitgeteilt.

Draw Link

Um einen Link zu zeichnen werden die Start- und Endposition als dreidimensionale Vektoren festgelegt. Zu Anfang werden die Positionen für den zweidimensionalen Raum konvertiert, indem die z-Position auf null gesetzt wird. Die vorher festgelegte Anzahl der LEDs wird auf dem durch die Start- und Endpositionen bestimmten Streckenabschnitt in Form von Ellipsen gezeichnet. Der letztendliche zweidimensionalen Output der LED-Stripes besteht aus zwei Komponenten: dem LED-Netzwerk an sich, sowie den Effekten. Das LED-Netzwerk basiert auf der Struktur der Links-Strands und des Netzwerks. Die Effekte erzeugen dabei die konkreten RGB Werte. Eine LED ruft immer jeden Effekt, der an ihrer Stelle aktiv ist, auf, und blendet diese nach definierten Verfahren zusammen. dadurch ergibt sich die Farbe, welche an einer bestimmten LED angezeigt wird. Das Setup der LEDs erfolgt entweder manuell per Maus oder vom Brain. Auch die Effekte laufen entweder manuell von einer lokalen UI definiert (links) oder vom Brain vorgegeben. (rechts)


Abbildung 23: Beispiele LEDs


Effekte

Wie bereits erwähnt hat die Installation verschiedene Effektarten, mit verschiedenen Geltungsbereichen. Der Network- Strand und Local-Effect bekommen die gemeinsamen Eigenschaften von der Klasse Effects vererbt. Jede Effektart hat verschiedene Effekttypen, die mit einer ID (Zahl 1 – 5) gekennzeichnet sind. Diese ID wird zusammen mit anderen Effektinformationen vom Brain an das Network übertragen. Abhängig von dieser ID wird in einem switch die mathematische Funktion für den jeweiligen Effekttypen ausgewählt. Viele der Funktionen haben wurden durch reines Herumprobieren herausgefunden. Dafür war Google ein leicht zu bedienendes Tool.


Abbildung 24: LED Graph von z= y/2*sin(x)


Ein etwas komplexerer Effekt ist der Sägezahneffekt. Hierfür musste eine neue Größe, die _sawSize, eingeführt werden. Für den Effekt wird diese solange vom aktuellen y-Wert abgezogen, bis die Differenz 0 ergibt. Dadurch entsteht ein Effekt, der auf einem Graphen folgendermaßen aussieht.


Abbildung 25: LED Sägezahngraph


Partikelsystem

In der Computergrafik werden Partikelsysteme zum Zeichnen unscharfer Objekte wie Flüssigkeiten, Wolken, Feuer oder Staub verwendet. Das Grundkonzept ist ein große Anzahl von bewegenden Partikel und deren Bewegungskontrolle. Vor fast 40 Jahren schrieb Reeves [1983] in einem Journal folgende Definition: „A particle system is a collection of many minute particles that together represent a fuzzy object. Over a period of time, particles are generated into a system, move and change from within the system, and die from the system.“ So haben sich im Laufe der Zeit die Möglichkeiten zur Generierung von Partikelsystemen weiterentwickelt, sodass beispielsweise bereits Game Enginees Unity oder Unreal vorgefertigte Scripte mit interfaces für Partikelsysteme liefern, was den Prozess für Entwickler beschleunigen kann. Die Aufgabe dieses Teams war es ein Partikelsystem von Grund auf in Open-Frameworks zu erschaffen. Das Partikelsystem sollte auf einem Display im Stamm des CO/OP TREES angezeigt werden und aktiviert werden, sobald der Anwender den Bildschirm berührt. Das System vom vorangegangen Semester wurde verworfen, sodass zu Beginn ein neues Konzept entworfen werden musste. Dabei sollte das Brain das Partikelsystem aktivieren können.

Konzept

In der Verkleidung des Baumstammes ist ein Monitor installiert, dessen Anzeigebild als interaktives Element dient. Der Monitor unterbricht die LED-Strips, welche von der Bodenplatte bis zur Baumkrone verlaufen und den Zyklus des Baumes darstellen. Der Nutzer soll die LED- Strips symbolisch wieder miteinander verknüpfen. Dafür muss er das Anzeigebild verändern können.


Abbildung 26: Konzeptentwurf


Das System kann nur anhand übermittelter Messwerte auf den Nutzer reagieren. Durch einen Abstandsensor, der oberhalb des Monitors installiert ist, wird der Benutzereingriff erfasst. Die Nähe der Handfläche zum Monitor kann dadurch eine Reaktion des Systems auslösen. Die Interaktion funktioniert berührungslos und ist somit in einer realen Installation robuster. Durch den Einsatz eines einzigen Sensors ist die Möglichkeit für die Steuerung des Anzeigebildes begrenzt. Die Animation kann lediglich auf einen ab- und aufsteigenden Wert reagieren. Zusätzlich zur gesamten Rauminstallation des CO/OP TREE ist das Anzeigebild ein Blickfang. Der Besucher soll dadurch noch näher an den interaktiven Baum angelockt werden. Der Bildschirm für die Anzeige kann als Fenster ins Innere des CO/OP TREEs angesehen werden. Die Aufgabe des Nutzers ist es das angezeigte Bild in Bewegung zu bringen. Das Ziel ist eine Verknüpfung mit den oberen LED-strips im Baumstamm herzustellen, damit diese aufleuchten. Bei der Wahl des Bildmotives wurde Bezug auf das Themengebiet Baum genommen. Der technische Charakter des CO/OP TREEs wurde im Anzeigebild beibehalten. Zunächst wurde die Idee des vorherigen Semester Wasseradern als ansteuerbares Motiv zu nutzen übernommen. Nach einer längeren Phase der Ideenfindung wurde dies auf ein wachsendes Wurzelwerk geändert. Hiermit werden die Wurzeln der Bodenplatte aufgegriffen. Wenn keine Interaktion durchgeführt wird, zeigt der Monitor ein anderes Motiv in der Mitte des Fensters an. Sobald Sensorwerte übermittelt werden, entstehen aus diesem Motiv heraus die Wurzeln. Das Standbild war eine Darstellung von Jahresringen eines Baumes. Diese wirken bewegt und kommen nicht zum Stillstand. Somit wird der Besucher der Installation aufgefordert zum Monitor näherzutreten und die interaktive Möglichkeit auszutesten.


Abbildung 27: Emitterbild


Umsetzung

Die Umsetzung des Partikelsystems erfolgte mit Hilfe von openFrameworks. Die plattformübergreifende Bibliothek mit C++ Klassen erleichterte die Erstellung der Anwendung.

Partikelsystem als Basis

Für die interaktive Umsetzung eignete sich ein Partikelsystem. Durch die Ansammlung von vielen einfachen Partikeln, die sich verschieben lassen, kann die Form der Jahresringe und der dynamischen Wurzeln nachgebildet. Auf dem Abbild der Jahresringe bündeln sich die einzelne Partikel. Unter ausführlicher Anleitung und Hilfe von Herrn Brendel entstand zunächst ein Grundsystem, welches aus den Klassen

  • ofApp.cpp: dient zur allgemeinen Verwaltung des Programmes
  • system.cpp: dient zur Organisation und Steuerung der Partikelansammlung
  • particle.cpp: Umsetzung eines einzelnen Partikel-objekts

bestand. In der particle-Klasse werden die Eigenschaften: aktuelle Position, Beschleunigung und Geschwindigkeit, Lebensdauer und vergangene Lebenszeit, sowie Größe und Farbe für einen einzelnes Partikel-objekt als Variablen festgelegt. Diese Werte können über die system-Klasse für alle Partikel abgeändert und deren genaue Verhaltensweise bestimmt werden. In der system-Klasse wird die Ansammlung der Partikel in einem Vektor deklariert (‚particles‘). Jedes einzelne Partikel-objekt kann mithilfe eines C++ Pointers angesprochen werden. In der system-Klassenmethode update() werden die Partikel generiert. Hier findet ebenso eine Überprüfung der Lebenszeit statt. Sollte ein Partikel diese überschritten haben wird er aus dem Partikelsystem gelöscht.


Abbildung 28: System.cpp


Emitterbild

Schon in der Phase der Konzeptfindung wurde dem Team geraten, die Partikel mithilfe eines Bildes zu platzieren und ihr Bewegungsverhalten zu steuern. Durch die Anleitung von Herrn Brendel konnte diese Vorgehensweise mit in das Partikelsystem integriert werden. Bei der Platzierung und Generierung neuer Partikel wurde als Emitter ein Bild in RGB eingesetzt. Das Bild selbst, wird nicht angezeigt. Die Partikel orientieren sich an den weißen Pixeln des eingelesenen Bildes. Die Positionen der weißen Pixel werden ausgelesen. Im Anschluss werden diese auf die neuen Partikel übertragen und dienen als ‚Emitter punkte‘.


Abbildung 29: Anzeigebild ohne aktiven Sensor


In der System-Klasse wurden hierfür die berechneten x/y-Koordinaten für alle farbig ausgelesenen Pixel zu einer Liste hinzugefügt. Die darin gespeicherten Koordinaten werden anschließend den Partikeln mitgeteilt.

Wurzelbildung

Wenn Sensorwerte auf Grund eines Benutzereingriff von System erfasst werden, beginnen die einzelnen Partikel sich an einen Wurzelstrang entlang zu bewegen. Ein Wurzelstrang ist ein Pfad, der aus einer Abfolge von Anziehungspunkten besteht. Das Ende der einzelnen Wurzeln liegt an den LED-strips, die sich oberhalb und unterhalb des Bildschirmrandes befinden. Die erste Umsetzungsidee wurde als Basis genutzt: Zunächst wurden Radien, die sich nach außen hin zu gleichen Abständen vergrößern erstellt. Auf diesen liegen Attraktor-Punkte für die Partikel. Nachdem die Partikel einen Knoten erreicht haben, wählen sie einen neuen auf den kommenden Radius aus. Die Hürde dieser Umsetzungsidee, liegt darin das Bewegungsverhalten der Partikel wie einzelne Wurzelgeflechte aussehen zu lassen. Die Partikel bewegen sich zu gradlinig und zielgerichtet. Ebenso wählen die Partikel zufällig einen neuen Attraktor-Punkt aus und nicht den ihnen am naheliegendsten. Anschließend wurden die Knotenpunkte der Pfade mithilfe einer anderen Berechnung festgelegt: Die gewollte Anzahl der Pfade wurde durch 360◦ geteilt. Mit diesem Wert konnten die Pfade mit einem regelmäßigen Abstand nach außen verlaufen lassen. Eine gezielte Ausrichtung zu den Positionen der LED-strips wurde erst im späteren Verlauf hinzugefügt. Die angegebene Anzahl der Knoten wurde durch die Länge vom Fensterrand aus bis zur Bildmitte geteilt. Somit konnte der benötigte Abstand der Knotenpunkte zueinander herausgefunden werden. Für einen einzelnen Pfad wurde der erste Knotenpunkt auf die Spitze des Vektors gesetzt, welcher von Bildmitte zur Abstandlänge verläuft. Für die folgenden Knotenpunkte wurde dem Vektor jeweils eine Abstandlänge hinzuaddiert. Daraufhin wurden die Knotenpunkte rotiert.


Abbildung 30: Ausgabe eines Zwischenschrittes - Wurzelgeflecht


Im Vergleich zur vorherigen Idee, werden die Pfade in der neuen Version einzeln erstellt und verlaufen zu einem festgelegten Endknotenpunkt. Eine Liste der gewollten Endpunkte, wird durch das ‚Brain‘ des CO/OP TREEs übermittelt. Die Endpunkte liegen nahe an den LED-strips und somit knüpfen die Wurzelpfade passend an die Position der LEDs an. Der Mittelpunkt des Anzeigefensters wird als Startpunkt festgelegt. Auf den Strecken zwischen Start und Endpunkt wurde ein ‚zick-zack‘ Pfad kreier. Für die Anziehungspunkte innerhalb eines Pfades wurden deren benötigte Abstände zueinander berechnet. Damit sich die Punkte nicht auf einer Linie befinden, werden diese per Zufall nach links oder rechts versetzt. In der Methode generateAttractors wird eine Vektorliste mit Pfaden befüllt.

Bewegungsverhalten der Partikel

Jedem neu erstellten Partikel wird ein Pfad aus einer Vektorliste zugeteilt. Dem Gesamtsystem kann der derzeitige Status des Abstandssensors mithilfe von OSC-Elementen mitgeteilt werden. Sobald der Sensor durch eine Benutzereingriff aktiviert wird, beginnen die Partikel nach außen zu streben. Sie durchlaufen die Abfolge der Knotenpunkte. Sobald die Partikel den letzten Knotenpunkt erreichen, werden sie aus dem Partikelsystem gelöscht. Dafür entstehen neue Partikel in der Fenstermitte. Es entsteht ein Partikelstrom und die Wurzeln werden von den sich bewegenden Partikeln abgebildet.


Abbildung 31: Anzeigebild Partikelsystem - aktiver Sensor


Gestaltung und Effekte

Für die Entwicklung wurden einige GUI Elemente in das Ausgabefenster gesetzt. Damit musste bei der Abänderung von Parameterwerten, welche für die Erstellung der Pfade wichtig sind, nicht zwischen Ausgabefenster und Entwicklungsumgebung gewechselt werden. Mithilfe der GUI werden die Parameter reguliert. Als Anzeige der Knotenpunkte wurden Baumringe als Bildmotiv genutzt. Zur Erstellung des Bildes wurde Adobe Photoshop genutzt. Hierbei wurden tiefgehende Details weggelassen. Da die Partikel in ständiger Bewegung sind, können diese keine Feinheiten als Motiv abbilden. Um die visuelle Darstellung der Wurzeln aufzuwerten wird den Partikeln ein neuer Farbwert zugeordnet, sobald diese einen bestimmten Knotenpunkt erreicht haben. Wenn die Partikel sich nahe am Endpunkt befinden, nehmen sie die Farbe der LED-strips an. Die aktuelle Farbe wird durch das ‚Brain‘ des CO/OP TREEs übermittelt. Anstelle eines klassischen ‚Trail Effektes‘, bei dem die Partikel einen Schweif hinter sich zeichnen, werden kleine Linien hinter den Partikeln angezeigt. Diese werden erst bei einem aktiven Sensor erstellt. Die gezeichneten kurzen Linien verhelfen zu einem besseren Wurzelcharakter. Die ausgebildeten Wurzelstränge wirken dadurch plastischer.

Funktionsweise des Partikelsystems

Zusammenfassend funktioniert das System wie in folgender Abbildung dargestellt:

  1. Bild ist eingelesen als „Emitterbild“
  2. Davon werden alle Pixel ausgelesen und die Liste erstellt, wo Pixel nicht schwarz sind
  3. Partikel entstehen auf diesen Pixeln
  4. Entstandene Partikel bekommen PfadId zugewiesen
  5. Hauptpfade(Wurzelstrang) wird generiert
  6. Liste Hauptpfade wird zweimal kopiert und einmal nach rechts und die andere Kopie nach links rotiert.


Abbildung 32: Funktionsweise des Partikelsystems


Game Engine

Zur Hälfte des Sommersemesters folgte nach langer Unklarheit die Bestätigung eines kompletten Online-Semesters. Diese Änderung machte einen Bau der Installation nun gänzlich unmöglich. Aufgrund dieser Tatsache entschied der Dozent in Absprache mit dem Projektteam deshalb, dass stattdessen eine Simulation des „CO/OP Tree“ in einer Game Engine realisiert werden soll. In- und Output der Installation sollten dabei von der Game Engine übernommen werden. Lediglich die Verarbeitung und Berechnung von Sensorwerten und Effektparametern sollte im Brain geschehen. Eine OSC Anbindung blieb deshalb weiterhin zwingend notwendig. Zur Umsetzung der Teilaufgabe wurde das weitere Unter-Team Game Engine gegründet, welches sich um die genannten Aufgaben kümmern sollte.

Wahl der Game Engine

Als erste Aufgabe des Teams „Game Engine“ galt es eine passende Engine für die Realisierung aller Aufgaben auszuwählen. Zur engeren Auswahl standen dabei Unity 3D und die Unreal Engine (Herausgeber Epic Games). Einstimmig entschied sich das Team für die Unreal Engine, da diese - wie der bereits bestehende Source Code – auf der Programmiersprache C++ basiert. Ein weiteres Kriterium für die Auswahl war, dass die Engine außerordentlich gut dokumentiert ist, was die ohnehin relativ lange Einarbeitungsphase deutlich erleichtern und beschleunigen konnte. Ebenfalls konnten die Laborassistenten bereits Erfahrungen im Umgang mit der Unreal Engine vorweisen, wodurch die Entscheidung für die Nutzung dieses Tools alternativlos wurde.

Einführung eines Versionierungssystems

Aufgrund Corona wurde dieses Semester rein online abgehalten, somit war kein persönlicher Kontakt im Team möglich. Um eine unkomplizierte Zusammenarbeit in Bezug auf die Unreal Engine 4 zu gewährleisten, wurde ein GitHub Repository für das Projekt angelegt. So hatte jedes Teammitglied die Möglichkeit, auf die Teilprojekte der anderen Mitglieder zuzugreifen. Um unnötige Daten im Repository zu vermeiden, wurde eine .gitignore-Datei angelegt, welche alle temporären Dateien, die von der Game Engine automatisch erstellt werden, ausschließt. Zudem wurde für jedes Teammitglied bzw. für jeden Aufgabenteil, wie Input, Output und Game Design, ein eigener Branch erstellt um Konflikte zu vermeiden. Da vor allem zu Beginn die Aufgaben in voneinander unabhängigen Projekten erledigt wurden, stellte dies kein Problem dar. Am Ende wurden die einzelnen Projekte manuell in eine gemeinsame Version migriert.

Aufgaben der Game Engine

Wie oben bereits beschrieben, soll die Game Engine für In- und Output der simulierten Installation „CO/OP Tree“ dienen. Im 3-dimensionalen Raum soll dem Nutzer die Möglichkeit gegeben werden, wie auch bei einer echten Anwendung, die Installation umrunden zu können und diese bedienen zu können. Durch diese Möglichkeit kann der Nutzer ebenfalls eine ähnliche nachgeahmte Erfahrung mit der Interaktion des Baumes erleben. Durch die nahezu grenzenlosen Möglichkeiten der Engine konnte auf diesen Weg auch ein abstraktes Setting gewählt werden, welches die Nutzer potentiell noch verstärkter in seinen Bann ziehen könnte. Da der Schritt des realen Baus der Installation „CO/OP Tree“ nicht mehr zur Aufgabenstellung zählte, stand mit der Simulation ein hohes Potential für vielseitige und neue Kreativität zur Verfügung. Die Nachfolgende Abbildung zeigt die Einbindung der Game Engine in das Gesamtsystem. Der Input soll Sensoren ersetzen, die im realen Fall zur Anwendung gekommen wären. Im Output werden die LED’s des Baumes ausgegeben und durch diese simulierten Sensoren gesteuert. Dabei muss die Anwendung stets in der Lage sein mittels OSC über das Brain miteinander zu kommunizieren.


Abbildung 33: Einbindung der Game Engine in das Gesamtsystem


Die anfallenden drei Aufgabenbereiche ließen sich somit gut untergliedern:

  • Input
  • Übertragung
  • Output

Das 3D-Modell

Am Ausgangspunkt der Simulationsarbeit galt es das bestehende 3D-Modell des vorherigen Projekt Semesters zu segmentieren (vereinfachen) und in die Unreal Engine zu importieren. Die nachfolgende Abbildung zeigt den Vergleich der beiden 3D-Modelle aus dem 1. und 2. Projektsemester. Zur Erleichterung der Texturierung in der Game Engine wurde zuerst die Anzahl aller Objekte reduziert. Ebenfalls wurden Details überarbeitet und verbessert.


Abbildung 34: Vergleich der 3D-Modelle Projektsemester 1 & 2


Zum Import des in der 3D Software Cinema 4D erstellten Modells in die Unreal Engine wurde bei Recherchearbeiten das Tool „Datasmith“ entdeckt. Datasmith bietet dem Nutzer die Möglichkeit, die .c4d Datei in die Unreal Engine 4 zu importieren und dabei gleichzeitig dessen Hierarchie zu erhalten. Auch Texturen, sowie Licht und Kameras können dabei mit importiert werden. So können einzelne Bestandteile des Modells einfacher texturiert werden.

Programmierung des Inputs

Die Inputprogrammierung in der Game Engine bestand aus der sogenannten Player Location und dem ‚Aktivieren‘ der einzelnen Sensoren. Diese Programmierung wurde zu Beginn mittels Blueprint erstellt, anschließend wurde das Ganze noch auf Basis von C++ Code umgeschrieben. Dies wird im Folgenden genauer erläutert.

Mit Blueprint

Blueprints stellen das visuelle Skriptsystem innerhalb der Unreal Engine dar. Anstatt Code Zeile für Zeile schreiben zu müssen, kann man mit Blueprints alles visuell erledigen. Einfügen von Knoten, Einstellen ihrer Eigenschaften in einer Benutzeroberfläche, Verbinden mit dem nächsten Knotenpunkt. Auch für den Input in der Game Engine wurde vorerst die Blueprint-Funktion verwendet. Bei der realen Installation würde der Interakteur auf den Baum zulaufen, die Sensoren auf der Bodenplatte aktivieren und anschließend mit den einzelnen Würfeln interagieren. In der Game Engine gibt es diese Sensoren nicht. Man kann weder sehen wo sich der Spieler befindet, noch welchen Würfel er beispielsweise berührt. Daher musste als erstes die Position des Spielers übermittelt werden. Hierfür wurde eine Blueprint-Klasse erstellt, welche die X-, Y- und Z-Koordinate des Spielers speichert und diese ausgibt. Diesen Daten werden dann an OSC weitergeleitet. Diese Weiterleitung konnte jedoch in diesem Blueprint nicht erfolgreich umgesetzt werden, da das OSC-Blueprint zu diesem Zeitpunkt nicht funktionierte.


Abbildung 35: Blueprint Player Location
Abbildung 36: Ausgabe der Player Location Koordinaten


Neben der Player Location musste noch festgestellt werden, wann der Spieler einen der Sensoren betritt und wann er diesen wieder verlässt. Hierfür wurden Trigger Boxen an den jeweiligen Stellen der Sensoren erstellt. Diese senden ebenfalls eine OSC-Nachricht sobald der Spieler diese betritt und auch wieder verlässt.

Mit C++ Code

Da der LED-Code für die Einbindung in die Game Engine bereits von Open Frameworks in C++ Code umgesetzt wurde, wurde der bereits erstellte Blueprint Code ebenfalls in C++ Code übersetzt, um ein leichteres und schnelleres Implementieren zu gewährleisten. Sowohl die Player Location als auch die Trigger Boxen wurden übersetzt. Für beide Teile wurde in der Game Engine ein Actor gesetzt, auf den der Code übertragen wurde. Der Actor der Trigger Boxen muss aktuell in der Engine noch manuell an die richtigen Stellen platziert werden, eine automatische Platzierung müsste durch das Brain noch erfolgen.


Abbildung 37: Code der Collisionboxes


Leider trat zum Ende des Projekts das Problem auf, dass der fertige Code der 2D-Simulation nicht vollständig in C++ umgesetzt werden konnte. Daher konnte keine vollständige Übertragung in die Game Engine erfolgen. Dies war der Grund, weshalb der Input in der Endversion nicht eingebunden werden konnte.

Save Game

Zusätzlich zur Option, dass die aktuellen Werte an OSC gesendet werden, wurde eine Option zum Speichern eingebaut. Hierfür wurde wieder die Blueprint-Funktion der Game Engine verwendet. Es besteht nun die Möglichkeit, den aktuellen ‘Spielstand’ zu speichern. Drückt man auf der Tastatur die Taste G speichert Unreal Engine automatisch die sogenannte Player Location, die Player Rotation und die Actor Scale 3D Position. Diese Daten werden dann lokal im Ordner des Projekts in einer .sav Datei abgespeichert.


Abbildung 38: Blueprint der Save Game Option


Übertragung mit OSC

Da die Game Engine wie alle anderen Komponenten über OSC kommunizieren muss, war ein Sender und Empfänger vonnöten, der OSC Nachrichten empfängt und weitergibt. Hierfür wurde in der Unreal Engine mit Blueprint ein OSC Sender und Receiver erstellt, der die vom Brain kommende Daten empfängt und eigene Nachrichten aussendet. Dies ließ sich zu Beginn relativ gut umsetzen. Sobald das Startevent aktiv ist und etwas empfangen wird, wird ein Custom Event getriggert, welches permanent auf ein Kommando wartet. Sobald der erste Input eintrifft, wird die IP Adresse aufgegriffen, auf die auch wieder zurückgesendet wird. Nach dem Senden der Zieladresse wird ein OSC Timer gestartet.


Abbildung 39: Custom Event OSC Timer


Dieser startet fortlaufend den OSC Sender. Sobald etwas in der Message List vorhanden ist, wird es in festgelegten Abständen gesendet. Ein anderes Custom Event fügt OSC Messages hinzu, welches an jeder Stelle des Blueprints aufgerufen werden kann.


Abbildung 40: Custom Event zum Hinzufügen von OSC Messages


Allerdings wurde bald klar, dass mehrere Ports benötigt wurden, was aber in Blueprint auch nach ausführlicher Recherche nicht umsetzbar war. Deswegen musste schließlich doch auf C++ Ebene programmiert werden. Dazu wurde der „OSC Element“ Code, welcher in Visual Studio verfasst wurde, entsprechend angeglichen, damit er für die Unreal Engine lesbar wurde. Zahlreiche openFrameworks-eigene Bezeichnungen können von der Unreal Engine 4 nicht gelesen werden, weswegen mit einer gründlichen Recherche die einzelnen Begriffe übersetzt wurden. Danach wurde schrittweise getestet, ob der umgewandelte Code von der Engine nun erkannt wird und integriert.

Output

Die erste wesentliche Aufgabe in Bezug auf den Output bestand darin, den LED Output mithilfe der Game Engine auszugeben. Idee war es zu diesem frühen Zeitpunkt noch Cubes in der simulierten Welt auszugeben, welche die benötigten LEDs repräsentieren sollen. Über Materialveränderungen kann die Farbe der LEDs in Echtzeit variiert werden und weitere Effekte erstellt werden. Somit erweiterte sich der erste Arbeitsschritt um die Erstellung eines OSC-Receivers auf der Seite der Game Engine, welcher die Random Floats eines bestehenden Visual Studio Programmes entgegennimmt. Auf Basis dieser übertragenen Werte werden die RGB-Werte eines in Unreal Engine 4 erzeugten Materials verändert.

OSC-Receiver

Die OSC-Anbindung erfolgte über ein externes Plug-In, welches unter https://github.com/monsieurgustav/UE4-OSC gefunden wurde. Das Plug-In ermöglicht eine OSC-Kommunikation über Blueprints. Auf Basis dieser Funktionalität wurde ein OSC-Receiver erstellt, welcher RGB-Werte der bestehenden Input-Anwendung entgegennehmen konnte. Mithilfe weiterer Blueprint-Nodes wurden diese Werte der OSC-Nachricht entnommen und gespeichert. Die Abbildung 41 zeigt den Blueprint Aufbau, der für den Nachrichtenempfang notwendig war.


Abbildung 41: OSC-Receiver über Blueprints


Dynamisches Material

Da sich die Materialeigenschaften der “LED-Cubes“ während der Laufzeit des Programms verändern müssen, musste hierfür ein so genanntes „dynamisches Material“ mit der Unreal Engine 4 erzeugt werden. Nur dieses besondere Material ist während der Laufzeit des Programms veränderbar. Die nächste Abbildung zeigt wie die über OSC empfangenen Werte zunächst zu einer „Linear Color“ konvertiert werden, um anschließend als Value für einen „Vector Parameter“ genutzt werden zu können.


Abbildung 42: Dynamisches Material über OSC empfangener RGB-Werte


Diese Idee der Realisierung wurde zunächst weiterentwickelt aber letztendlich auch wieder verworfen.

LED Arrays

Auf Basis der bereits beschriebenen Vorgehensweise wurde die Idee im Austausch mit einem Laborassistenten weiterentwickelt. LED Arrays sollen generiert werden, um die Platzierung zahlreicher einzelner LED-Cubes zu vermeiden. Abbildung 43: Blueprint Aufbau des 2D-Arrays. Die Abbildung zeigt den Blueprint-Aufbau zur Erstellung eines Cube-Arrays. Der verwendete Aufbau erfolgte auf der Grundlage eines Tutorials.


Abbildung 43: Blueprint Aufbau des 2D-Arrays


Dynamischer LED Output

Da der vorherige Ansatz keine dynamische Positionierung und Effektberechnung der einzelnen „LED’s“ berücksichtigte, wurde in Diskussion mit einem Teammitglied nach weiteren Lösungsansätzen gesucht. Als Ergebnis der Überlegungen ergab sich der nächste Ansatz, den bestehenden C++ Code des „LED-Teams“ von ofx C++ in das benötigte Unreal C++ zu übersetzen. Der LED-Code war zu diesem Zeitpunkt bereits zu großen Teilen funktionsfähig und konnte somit schon für diesen Zweck genutzt werden. Zur Verwendung des LED-Codes mussten zahlreiche Methoden und Datentypen des openFrameworks zunächst umgeschrieben werden.

Erstellung des LED-Actors

Im Unterschied zu gewöhnlichen C++ Anwendungen können Objekte in der Unreal Engine nicht über den gewohnten Aufruf „new „xy“ erzeugt werden, sondern müssen "gespawnt" werden. Nachfolgend sind alle ausgeführten Arbeitsschritte dokumentiert, die nötig waren um ein Objekt spawnen (vom englischen to spawn: hervorbringen) zu können. Hierfür muss als erstes ein Unreal C++ Actor erstellt werden. In der Unreal Engine Documentation wird ein „Actor“ folgendermaßen beschrieben: „Actor is the base class for an Object that can be placed or spawned in a level. Actors may contain a collection of ActorComponents, which can be used to control how actors move, how they are rendered, etc. The other main function of an Actor is the replication of properties and function calls across the network during play.“ Diese Actor C++ Class wird über die Unreal Engine erstellt, ehe sich die Klasse in der verknüpften Entwicklungsumgebung, in diesem Fall Visual Studio Code, scripten lässt. Die folgende Abbildung zeigt die .h Datei der „LED Actor“-Klasse. Hier wird dem Actor sowohl ein „static Mesh“ als auch das bereits kennengelernte „dynamic Material“ zugewiesen.


Abbildung 44: Header Datei des "LED Actors"


Abbildung 45 und 46 zeigen nun die Initialisierung des static Mesh und des Materials in der .cpp Datei des „LED-Actors“. Über den „Constructor Helper“ wird in der Ordnerstruktur der Unreal-Anwendung nach dem Mesh „Shape_Sphere“ gesucht und anschließend dem im Header erstelltem static Mesh zugewiesen. Nun hat jeder erzeugte LED-Actor eine Kugel als Ausgangs-Mesh, welches repräsentativ eine LED darstellen soll.


Abbildung 45: Initialisierung des Meshes


Wie auch bereits für das Mesh, wird das zuvor in der Unreal Engine erzeugte Material über den Construction Helper gesucht und bei erfolgreichem Fund der LEDSphere zugewiesen.


Abbildung 46: Zuweisung des Materials


Nun kann in der „BeginPlay-Methode“ (wird einmal beim Starten des Programms ausgeführt) oder in der „Tick-Methode“ (wird jeden Frame aufgerufen) die Farbe des Materials geändert werden. Die nachfolgende Abbildung zeigt eine beispielhafte Setzung der RGB-Werte auf Random Floats.


Abbildung 47: Farbsetzung in der "Tick-Methode"


Nun ist der LED-Actor für das Spawnen vorbereitet und kann im nächsten Schritt erzeugt werden.

Spawnen des LED-Actors

Der übersetzte Code des „LED-Teams“ sah es vor, dass die „LED-Actors“ in „Links“ sitzen, welche sich wiederum in einem „Network“ befinden. Deshalb müssen die „LED-Actors“ aus dem Code des Networks heraus gespawnt werden. Abbildung 48 zeigt dabei den Spawn-Vorgang. Über den Aufruf der Methode „addLink“ werden Links mit Start- und Endpositionen gespawnt.


Abbildung 48: Spawnen eines Links


Ein Link spawnt bei seinem Aufruf wiederum die zuvor erstellten „LED-Actors“. Die nachfolgende Abbildung zeigt auch diesen Schritt, welcher vom Ablauf her identisch ist.


Abbildung 49: Spawnen der "LED-Actor" in einem Link


Mit Hilfe dieser Art der Umsetzung sind Positionierungen und Effekte dynamisch und übertragbar. Die gleiche Vorgehensweise wurde für die Baumkrone übernommen, welche separat gespawnt wird. Die Abbildung zeigt den dynamisch gespawnten Baum zusammen mit den LEDs.


Abbildung 50: CO/OP Tree nach dem Spawnen von LEDs und Krone


Weitere Arbeiten am Code wurden anschließend vom Team LED übernommen, da eine Einarbeitung in die umfangreichen Strukturen des Teams zu aufwändig und zeitintensiv gewesen wäre.

Game Design

Aufgrund der zahlreichen gestalterischen Möglichkeiten, welche die Unreal Engine bietet, wurde die Installation in eine abstrakte virtuelle Umgebung gesetzt. Dabei stand im Fokus, dass für die Projektdemonstration ein eindrucksvolles Ergebnis erzielt werden kann. Durch diesen Ansatz ergaben sich weitere zahlreiche neue Aufgaben auf der Agenda, die im Anschluss realisiert wurden und in den folgenden Abschnitten genauer beschrieben werden. Die nächste Abbildung zeigt das finale Level Design.


Abbildung 51: Auszug des Game Designs


Der steuerbare Charakter

Nach internen Teambesprechungen und dem für den Dozenten erstellten Storyboard ergab sich die nächste Aufgabe, einen „third person character“ als steuerbaren Charakter in die Simulation zu integrieren. Nach weiteren Überlegungen verfolgte der Verfasser die Idee, eine wechselbare Kamerasicht einzubauen, die es dem Nutzer ermöglicht zwischen first- und third-person Ansicht zu wechseln. Der Grundgedanke verfolgte das Ziel, dass ein reales Betrachtungserlebnis nachgebildet werden sollte. Die Realisierung des „third person character“ erfolgte mit einer einfachen Kamera, die mit einem „Spring Arm“ über dem Charakter platziert wurde. Über Blueprints kann die Steuerung dieser Kamera definiert werden. Dann wurde eine weitere Kamera auf Augenhöhe der Spielfigur platziert, welche die „first person“ Ansicht darstellt. Mittels Blueprints kann per Tastendruck des Buchstabens ‚c‘ zwischen beiden Kameras hin- und her geschalten werden. Die nachfolgenden Abbildungen zeigen den Aufbau des Charakters im Viewport und die integrierten Blueprints, die dessen Steuerung mit Maus, Tastatur und Kamerawechsel ermöglichen.


Abbildung 52: First- & Third-Person Charakter im Viewport
Abbildung 53: Blueprints für Charakter Movement l
Abbildung 54: Change Camera Blueprints


Das Spiel- und Pausenmenü

Wie bei jedem guten Spiel sollte auch die Simulation des CO/OP Trees mit einem Spielmenü vervollständigt werden. Ausgehend vom Spielmenü kann die Simulation gestartet und auch kleine Einstellungen getroffen werden. Um den Nutzer nachhaltig zu branden, wurde das im Vorsemester erstellte CI zur Realisierung der gestalterischen Elemente genutzt. Die Abbildung zeigt das Spielmenü beim Ausführen der Simulation.


Abbildung 55: Das Spielmenü beim Start der Simulation


Die Logik und Funktionsweise der Buttons wird dabei wieder durch Blueprints gesteuert. Folgende Abbildung zeigt den Blueprint-Aufbau.


Abbildung 56: Blueprints des Spielmenüs


Auf Basis dieser Funktionsweise wurde ebenfalls ein Pausenmenü implementiert, welches über Tastendruck aufgerufen werden kann. Von hier aus kann man zurück in das Hauptmenü gelangen oder das Spiel beenden.


Abbildung 57: Blueprints des Pausenmenüs


Das Leveldesign

Um den Nutzer möglichst einfach in die abstrakte Welt von CO/OP Tree eintauchen zu lassen, erstellte der Verfasser aus Assets und mit Hilfe von Unreal Internen Tools eine Umgebung in der Simulation. Diese Umgebung soll einen Wald darstellen, in dem der technische „CO/OP Tree“ platziert ist. Diese Arbeiten waren zwar äußerst zeitaufwendig und aufgrund mangelnder Rechnerleistung schwierig zu realisieren. Der Workflow gestaltete sich dabei folgendermaßen: die ausgewählten Assets wurden über den Epic Games Marketplace bezogen und in die Unreal Engine importiert. Nun erfolgten eine akribische Sichtung und Platzierung dieser Assets. Wie beim Arbeiten mit jeder 3D Software können diese Assets im Viewport hin- und her bewegt, skaliert und rotiert werden. Dabei wiesen die genutzten Assets neben dem Mesh auch schon Texturen und Animationen auf. Schließlich musste alles nur noch nach den Vorstellungen des Verfassers in der virtuellen Umgebung platziert werden. Die Vorkenntnisse im Umgang mit 3D Software erleichterten diesen Vorgang enorm. Anschließend folgte die Ausleuchtung der Simulation. Hierfür wurde ein „Directional Light“ ausgewählt und verwendet, welches einer „Sky Sphere“ zugeordnet wurde und somit das realistische Sonnenlicht in der Game Engine nachbildet. Durch Rotation des Lichts kann zwischen Uhrzeiten und somit dem zugehörigen Sonnenstand variiert werden. Durch diese Lichtquelle konnten realistische Schatten erzeugt werden, die sich dem Licht in Echtzeit anpassen. Außerdem wurden integrierte Post-Processing-Methoden genutzt, um die Szenerie in eine Nachtszene zu ändern. Die Verwendung bläulicher Lichter, Färbung durch Manipulation der Gradationskurven und die Nutzung von Nebel ermöglichten dieses Erscheinungsbild. Kleinere Highlights wurden mit einem Partikelsystem realisiert, welches mit Hilfe eines „Emmissiven Materials“ Glühwürmchen darstellen sollten, die sich in der Umgebung hin- und her bewegen. Einzelne „Point Lights“ sind verteilt in der Szenerie zu finden und sorgen für weitere Lichtquellen. Um all diesen optischen Anpassungen einen letzten Feinschliff zu verleihen, wurde ein „Post Process Volume“ eingesetzt, welches nochmals einige kleine Akzente, wie z.B. „Blooming“ setzen kann. Insgesamt gestalteten sich die optischen Arbeiten nur als schwierig, da die Rechnerleistung bzw. Grafikkartenleistung des zur Verfügung stehenden Rechners gerade noch ausreichend waren. Für das Licht-Building wurde zum Beispiel ein Zeitaufwand von 30 Minuten beansprucht. Die Abbildung zeigt die getroffenen Entscheidungen zum Design sowie die erwähnten Glühwürmchen.


Abbildung 58: Leveldesign


Erstellen von Glühwürmchen

Der Baum wurde letztendlich in einen Wald bei Nacht gesetzt. Um diese Atmosphäre noch realistischer zu gestalten, wurden Glühwürmchen eingefügt. Hierfür wurde das bereits vorgefertigte Partikelsystem von Unreal Engine benutzt. In diesem Partikelsystem mussten jedoch noch einige Einstellungen manuell vorgenommen werden. Für die Partikeloberfläche beispielsweise wurde ein extra Material erstellt. Auch die Größe der einzelnen Partikel, die Lebensdauer oder die Geschwindigkeit musste noch angepasst werden. Abschließend hat man die Möglichkeit, das fertige Partikelsystem an jede beliebige Stelle und so oft man möchte zu platzieren.


Abbildung 59: Gestaltung des Materials
Abbildung 60: Partikelsystem der Glühwürmchen


Design

Konzeptentwurf

Zusätzlich zur Präsentation wurde am Design des Baumes für repräsentative Zwecke gearbeitet. Es wurden neue Entwürfe für den CO/OP TREE als aufgebaute Installation im Raum gestaltet.


Abbildung 61: Konzeptzeichnungen des CO/OP TREE


Hierbei wurde die Bodenplatte, Baum und der Umraum entworfen und mit Tuschestift gezeichnet, eingescannt und in Photoshop nachbearbeitet. Zusätzlich wurden passende Silhouetten von Besuchern der Installation entworfen, die beliebig eingefügt werden konnten. Die Zeichnungen fanden in der Präsentation Anwendung und in der Studienarbeit des Fachs Medienkonzeption.

Plakatgestaltung

Für den Ablauf aller Projektpräsentationen wurde ein Plakat benötigt, wofür als Design-Vorlage das Plakat des letzten Semesters diente. Das finale Plakat enthält wieder die Logos jeder Gruppe und den Zeitplan. Hierbei wurden Quadrate als verbindende Elemente benutzt. Den gedrehten Quadraten wurde eine neue Farbe und Ausrichtung gegeben, außerdem wurde die Positionen der typografischen Elemente überarbeitet.


Abbildung 62: Plakat Projektpräsentationen


Präsentation

Präsentationsvideo

Als bekannt wurde, dass die Präsentation nicht live stattfinden würde, wurde ein Präsentationsvideo erstellt, welches am Präsentationstag gezeigt wurde. Hier wurde mit Adobe Premiere Pro gearbeitet, da hierbei der größte Bearbeitungsspielraum gegeben ist. Es lassen sich beispielsweise problemlos Tonspuren separat vom Videobild bearbeiten, Grafiken beliebig lang anzeigen und bewegen, Videos skalieren und positionieren und auch Texte einfügen. Die aufgenommenen Sprechervideos wurden gesichtet und die separat aufgenommenen Tonspuren mit den Videos synchronisiert und hinzugefügt. Anschließend wurden Versprecher, Fehlversuche und zu lange Pausen herausgeschnitten. Danach wurden alle Videos an dieselbe Lautstärke angeglichen, die Mono- in Stereospuren umgewandelt und Rauschfilter benutzt, um das Eigenrauschen des Aufnahmemikrofons zu reduzieren. Diese nun fertigen Sprechervideos wurden separat exportiert und in einer neuen Premiere Pro Projektdatei hinter vorher in Photoshop erstellte Folien mit „Cut-Outs“ gelegt, die als entsprechende Masken fungierten. Zu Beginn jedes Themenbereichs der Präsentation werden alle beteiligten Teammitglieder gezeigt. Danach übernimmt der Sprecher der jeweiligen Thematik. Jeder Sprecher wird zu Beginn und teilweise zum Ende seines Parts in einer größeren Ansicht gezeigt. Für die Zwischensequenzen, in denen über den Inhalt des Projekts referiert wird, wurde das Sprechervideo skaliert, sodass es in kleinerer Ansicht im Fenster der rechten oberen Ecke der Präsentationsfolien erscheint.


Abbildung 63: Premiere Pro Sprecheransicht verkleinert
Abbildung 64: Premiere Pro Sprecheransicht Vollbild


Zusätzlich wurden Folientexte erstellt und selbsterstellte Grafiken und GIFs eingefügt, die zeitlich passend bei der entsprechenden Erwähnung des Sprechers angezeigt werden mussten.


Abbildung 65: Präsentationsfolie mit GIFs und Grafiken


Nachdem alle Sprecherparts ihre fertigen Folien hatten, wurden Ein-, Über- und Ausblendungen hinzugefügt, beim Ton wie auch beim Bild. So lässt sich das Präsentationsvideo ohne irritierende visuelle wie akustische Sprünge oder abrupte Stopps ansehen. Abschließend wurde das circa 17-minütige Video exportiert und auf die durch die Professoren bereitgestellte Plattform hochgeladen.


Abbildung 66: Schnittbild des gesamten Videos


Demovideo

Für das Demovideo wurden einige Game Design Anpassungen vorgenommen sowie ein Material für den Baum entwickelt, welches einen pulsierenden Effekt zeigt, da die LED-3D-Integration zeitlich leider knapp nicht mehr fertig wurde. Für einen Trailer-artigen Effekt wurden Kamerafahrten durchgeführt, die den Baum im nächtlichen Wald aus unterschiedlichen Perspektiven, Ausschnitten und Distanzen zeigt. Zusätzlich wurden unterschiedliche Einblicke in diverse Interfaces wie Input und LED gezeigt, sowie das animierte Partikelsystem. Abschließend wurde ein O-Ton eingesprochen, der den Betrachter des Demovideos inhaltlich durch die unterschiedlichen Sequenzen leitet.


Abbildung 67: Material-Hack


Fazit

Zusammenfassend ist das sich über zwei Semester ersteckende interdisziplinäre Projekt als voller Erfolg zu bewerten. Trotz der Größe des Projektteams und der schwierigen Situation, bedingt durch die weltweite Pandemie, konnten sehr gute Ergebnisse erzielt werden. Die Kommunikation im Team war stets einwandfrei und verlief problemlos. Die erschwerten Umstände konnten durch mehrere wöchentliche Meetings und den regelmäßigen guten Austausch zwischen den Projektmitgliedern unkompliziert überwunden werden. Anregungen durch Dozenten und Laborassistenten konnten an entscheidenden Stellen weiterhelfen und wurden daher stets in die Arbeiten integriert. Durch das stetige Verbessern von internen Abläufen war bis zum Schluss eine gute Struktur geschaffen worden, die zielorientiertes Arbeiten ermöglichte. Ausblickend ist es nun möglich, die digitale Version des „CO/OP TREE“ mit einer realen Installation zu ersetzen. Auch wenn Sound- und Temperaturwürfel bisher nicht umgesetzt wurden, ist es trotzdem gelungen, alle anderen OpenFrameworks Komponenten miteinander zu verbinden. Für zukünftige Erweiterungen könnten diese Elemente noch in Erwägung gezogen werden.