Ausgabe Verarbeitung

Diese Seite beschreibt, wie die Murl Engine einen Szenengraphen verarbeitet, um Ausgabedaten zu erzeugen, d.h. wenn ein Sound abgespielt oder ein Objekt gerendert wird. Solltest du bisher noch nicht mit Szenengraphen gearbeitet haben, empfehlen wir, zuerst das Cube Tutorial durchzuarbeiten. Dort wird im Abschnitt Version 2: Paket erstellen erklärt, wie ein einfacher Szenengraph aus einer XML-Datei erstellt wird.

Grundlagen

Einfach ausgedrückt: Zum Erzeugen der Ausgabedaten, sucht und verarbeitet die Murl Engine im aktuellen Szenengraphen nach all jenen Knoten, die eine visuelle oder akustische Ausgabe erzeugen könnten. Dieser Prozess wiederholt sich für jedes einzelne Frame. Im Idealfall passiert dies ungefähr 60 Mal pro Sekunde, abhängig von der genauen Bildwiederholfrequenz des Bildschirms. In der Praxis kann dieser Wert auch unter die Bildwiederholfrequenz des Bildschirms fallen, wenn die Szenenkomplexität zu hoch bzw. die Leistungsfähigkeit von CPU oder Grafikprozessor zu niedrig ist.

Die Abarbeitung des Szenengraphen (Traversierung) wird grundsätzlich von oben nach unten durchgeführt. Sehen wir uns die Definitionsdatei eines sehr einfachen (nicht funktionierenden) XML-Szenengraphen an:

<?xml version="1.0" ?>

<Graph>
    <CubeGeometry/>
    <Node>
        <PlaneGeometry/>
    </Node>
</Graph>

Für diesen Szenengraphen ist garantiert, dass immer der CubeGeometry Knoten vor dem Node Knoten verarbeitet wird, welcher wiederum vor dem PlaneGeometry Knoten verarbeitet wird. Hinweis: Das XML-Wurzelelement <Graph> repräsentiert nicht einen Graphenknoten an sich, sondern zeigt nur, dass diese bestimmte XML-Datei eine Beschreibung eines Szenengraphen und nicht eine andere XML-Ressource ist.

Die folgenden Abschnitte geben einen Überblick über verschiedene, für die Ausgabe relevante Knotenklassen, die in einem Szenengraphen verwendet werden können:

Geometrie und Sound

Generell wird jede visuelle Ausgabe durch Knoten definiert, welche das Graph::IDrawable Interface implementieren. Diese Knoten repräsentieren üblicherweise mehr oder weniger komplexe dreidimensionalen Geometriedaten. Ein PlaneGeometry Knoten beispielsweise repräsentiert eine sehr einfache Geometrie, nämlich eine aus vier einzelnen Eckpunkten zusammengesetzte flache, rechteckige Fläche. Ein ResourceMeshGeometry Knoten kann wiederum ein Geometrieobjekt mit hunderten oder tausenden einzelnen Eckpunkten (vertices) im dreidimensionalen Raum darstellen, das von einem 3D-Modellierungsprogramm, wie z.B. Blender oder Maya, erstellt wurde.

Die Ausgabe von Sounds wird von Knoten repräsentiert, welche das Graph::IPlayable Interface implementieren. Derzeit macht das nur der AudioSequence Knoten. Er nimmt eine bestimmte Anzahl an Soundobjekten und spielt sie in einer nahtlosen Abfolge ab. Sound Knoten werden ebenfalls im dreidimensionalen Raum platziert und können daher positionsabhängig abgespielt werden.

Beachte hier das Wort "dreidimensional": Objekte im Szenengraphen der Murl Engine werden immer in einem virtuellen 3D-Koordinatensystem platziert. Wenn du eine reine 2D-Anwendung erstellten möchtest, kannst du einfach eine der drei Koordinatenachsen weglassen und die Objekte nur auf den zwei verbleibenden Achsen positionieren. Weitere Details dazu findest du unter Reines 2D-Rendering.

Die folgende Liste enthält Beschreibungen von unterschiedlichen Geometrieknoten für unterschiedliche Zwecke:

  • PlaneGeometry: Dieser Knoten repräsentiert eine einfache, rechteckige Fläche, welche zum schnellen Rendern von z.B. 2D-Grafiken am Bildschirm verwendet werden kann. Flächen können auf die gewünschte Ausgabegröße skaliert werden. Außerdem ist es möglich lediglich Ausschnitte einer 2D-Grafik zu zeichnen, indem man die Texturkoordinaten der Eckpunkte anpasst; siehe Tutorial #07: Images.
  • PlaneSequenceGeometry: Dieser Geometrieknoten ist einer einfachen Fläche sehr ähnlich, benötigt aber zusätzlich eine Atlas-Ressource um den anzuzeigenden Bildausschnitt auszuwählen. Durch Setzten eines Indexwertes kann schnell zwischen verschiedenen Bildausschnitten umgeschalten werden. Unter Verwendung eines Timeline-Knotens und einer Animationsressource können die einzelnen Sub-Grafiken auch als Animation abgespielt werden; siehe Tutorial #08: Animated Images und die Atlas Generator Referenzseite.
  • CubeGeometry: Dieser Knoten repräsentiert einen einfachen dreidimensionalen Einheits-Würfel (mit Kantenlänge 1), welcher einfach auf die gewünschte Ausgabegröße skaliert werden kann; siehe Tutorial #01: Cube.
  • ResourceMeshGeometry: Eine Resource-Mesh-Geometrie kann zum Rendern von beliebigen 3D-Modellen am Bildschirm verwendet werden, wobei die eigentlichen Modelldaten aber in einer eigenen Mesh-Ressource gespeichert werden. Mesh-Ressourcen werden üblicherweise vom Scene Converter Tool erstellt; siehe Scene Converter Referenzseite.
  • ResourceBspGeometry: Dieser Geometrieknoten ist einer Resource-Mesh-Geometrie sehr ähnlich, benötigt aber zusätzliche BSP-Sichtbarkeitsdaten, die in der Mesh-Ressource enthalten sein müssen. Dieser Knoten kann beispielsweise in Spielen die die Egoperspektive verwenden, zum effizienteren Rendern von Dungeons verwendet werden; siehe die Scene Converter Referenzseite.
  • GenericGeometry: Dieser Knoten ermöglicht den direkten Zugriff auf die untersten Datenstrukturen eines Geometrieobjekts, wie beispielsweise Vertex Buffer und Index Buffer. Damit können 3D-Modelle programmatisch erstellt und geändert werden.

Kameras und Listeners

Da alle Objekte in einer virtuellen 3D-Welt positioniert sind, der Ausgabebildschirm jedoch nur zweidimensional ist, muss ein Mapping oder eine Transformation der 3D-Koordinaten zu 2D-Koordinaten des Bildschirms stattfinden. Für zeichenbare Objekte kann dies durch die Verwendung von Kameras erfolgen, z.B. durch einen Camera-Knoten.

In Analogie zu zeichenbaren Objekten und Kameras, erfolgt die Transformation bei Sound Objekten durch die Verwendung einer Audio-Senke (Listener), wie beispielsweise einem Listener-Knoten. Sowohl Kameras als auch Listener werden in der virtuellen 3D-Welt positioniert und ausgerichtet. Somit ist es auch möglich, sich durch die virtuelle Welt zu bewegen.

Die Positionierung und Ausrichtung von Kamera- und Listener-Knoten erfolgt getrennt von den restlichen Knoten. Dazu dienen eigene CameraTransform- und ListenerTransform-Knoten, die über ihr cameraId bzw. listenerId Attribut mit genau einer Kamera bzw. einem Listener verbunden werden. Dadurch ist es möglich, eine Kamera irgendwo im Szenengraphen zu definieren und ihre Position später festzulegen. Definiert man beispielsweise den CameraTransform-Knoten als Kind der Haupttransformation des Spielers, bewegt sich die Kamera immer zusammen mit dem Spieler mit.

Culler

Culler sind ein nützliches Feature, wenn man mit großen Szenengraphen arbeitet, bei denen aber immer nur ein kleiner Teil der virtuellen Welt sichtbar ist. Culler entfernen (engl. cull) vor dem eigentlichen Rendern alle Geometrie-Objekte die aktuell nicht sichtbar sind. Dadurch kann die Rendergeschwindigkeit erhöht bzw. die Szene detaillierter gestaltet werden.

  • Culler Knoten sind eine einfache Möglichkeit, um Geometrie zu entfernen, die außerhalb des sichtbaren View-Frustums der aktiven perspektivischen Kamera liegen; siehe Tutorial #01: Cube für eine kurze Einführung dazu. Dieser Vorgang ist sehr effizient, d.h. eine 3D-Anwendung sollte dieses Feature nach Möglichkeit nutzen.
  • ResourceBspCuller Knoten verwenden die BSP-Sichtbarkeitsdaten, welche in einem Objekt einer Mesh-Ressource gespeichert sind, um zu bestimmen, ob ein Geometrieobjekt von einem aktiven Kamerapunkt aus sichtbar sein könnte. Zusätzlich kann dieser Cullertyp auch Geometrie entfernen, die hinter einer Wand liegt, z.B. innerhalb eines Gebäudes oder Dungeons; siehe die Scene Converter Referenzseite.
Zu beachten
Culler können mittels des parentCullerId Attributs auch miteinander verkettet werden. Dadurch ist es möglich, ein kombiniertes Cullerobjekt zu erstellen, das z.B. zuerst einen schnellen Culler anwendet und erst danach einen ResourceBspCuller, der mehr Zeit in Anspruch nimmt.

Programme, Materialien, Parameter und Texturen

Eine zentrale Eigenschaft von Geometrieobjekten in der Murl Engine ist, dass diese keine Informationen darüber enthalten, wie sie tatsächlich auf den Bildschirm gezeichnet werden. Sie beinhalten primär lediglich die Geometriedaten. Dadurch können Geometrieobjekte mehrfach mit verschiedenen Materialien, Farben und Texturen verwendet werden. In der Murl Engine wird also das "was" gerendert wird (die Geometrie) und das "wie" es im Szenengraphen gerendert wird getrennt definiert.

Die Art und Weise "wie" gerendert wird, kann durch die folgenden vier Elemente bestimmt werden:

Programmknoten

Programmknoten implementieren das IProgram Interface und sind eine Art "Rezept", das bestimmt, wie die Farbe der einzelnen Bildschirmpixel berechnet wird. Der Programmknoten definiert z.B. ob eine Texturgrafik benutzt werden soll, ob eine Lichtquelle berücksichtigt werden soll oder ob zusätzliche Farben in die Berechnung mit einfließen. Derzeit gibt es zwei solcher Knotenklassen:

  • FixedProgram Knoten bieten einen praktischen Weg, um ein Programm mit einfachen Eigenschaften zu definieren.
  • ShaderProgram Knoten können zur Implementierung von fortgeschrittenen Rendertechniken benutzt werden. Diese Techniken erlauben es, eigene GPU Shaderprogramme mit IShader Knoten zu erstellen; siehe Shader-basiertes Rendering.

Materialknoten

Materialknoten implementieren das IMaterial Interface und müssen immer direkt auf einen vorhandenen IProgram Knoten verweisen. Materialien definieren zusätzliche Eigenschaften für das Rendern, die nicht von einem Programm abgedeckt werden können, wie beispielsweise Alpha-Blending (Transparenz). Zusätzlich bestimmen Materialknoten, wie auf die einzelnen Surface-Buffer (Colorbuffer, Z-Buffer und Stencilbuffer) zugegriffen wird. Mehrere Materialknoten können auf den selben Programm-Knoten verweisen. Daher kann z.B. dasselbe Programm mit und ohne Transparenz verwendet werden.

Derzeit stehen zwei IMaterial-Klassen zur Verfügung:

Zu beachten
In der Murl Engine definieren Materialien, im Gegensatz zu einigen anderen Softwarepaketen, keinerlei Farben zum Rendern. Farbeigenschaften werden getrennt von der Materialdefinition erst mit Parameterknoten definiert.

Parameterknoten

Parameterknoten implementieren das IParameters Interface und definieren weitere Render-Eigenschaften wie z.B. Farben.

Es gibt drei IParameters-Klassen:

Texturknoten

Texturknoten implementieren das ITexture Interface. Eine Textur umschließt grundsätzlich Pixeldaten in irgendeiner Form und kann z.B. dafür genutzt werden, um eine Grafik auf ein Geometrieobjekt abzubilden (in Verbindung mit einem geeigneten IProgram).

Folgende Texturknoten stehen zur Verfügung:

  • FlatTexture Knoten definieren eine flache 2D-Grafik.
  • CubemapTexture Knoten bestehen aus sechs einzelnen 2D-Grafiken, die den sechs Seiten eines Würfels entsprechen (cube map).
  • MultiTexture Knoten können beispielsweise für Multi-Pass Rendering verwendet werden; siehe Multi-Pass Rendering.
  • Und viele spezielle Knoten, die dem hierarchischen Ableitungsdiagramm der Texture-Basisklasse entnommen werden können.

Lichtquellen

Die Beleuchtung einer Szene kann mit ILight Knoten durchgeführt werden. Damit eine Lichtquelle beim rendern berücksichtig wird, muss die Beleuchtung im aktiven Materialprogramm aktiviert sein, z.B. indem man das lightingEnabled Attribut für ein FixedProgram setzt oder indem man eine Lichtquellengleichung in einem ShaderProgram implementiert.

Die folgenden Lichtquellenknoten sind verfügbar:

  • Light Knoten definieren eine einzelne Lichtquelle im dreidimensionalen Raum.
  • MultiLight Knoten können für beispielsweise Multi-Pass Rendering verwendet werden; siehe Multi-Pass Rendering.

Die Position und Ausrichtung von Lichtquellen wird, genauso wie bei Kameras und Listeners, getrennt von ihrem eigentlichen Knoten definiert. Zur Transformation der Lichtquelle werden LightTransform Knoten benutzt. Dadurch ist es möglich, ein Licht irgendwo im Szenengraphen zu definieren und die Position später festzulegen z.B. als Stirnlampe am Kopf des Spieler-Charakters.

Nächste Schritte

So weit, so gut. Du solltest dir nun einen Überblick über die verfügbaren Knotenklassen und -Interfaces verschafft haben, die für die Ausgabe am Bildschirm benötigt werden. Trotzdem bleibt noch eine große Frage offen: Wie kann man all das miteinander verknüpfen?

Die Antwort darauf erhältst du auf der nächsten Seite (Output-States, Slots und Units). Dort findest du alles darüber, wie Knoten im Szenengraph für die Generierung der Ausgabedaten zusammenspielen. Das Schlüsselwort dazu lautet "state".


Copyright © 2011-2018 Spraylight GmbH.