Szenendiagramm als Objektcontainer?

8

Das Szenendiagramm enthält Spielknoten, die Spielobjekte darstellen. Auf den ersten Blick mag es praktisch erscheinen, Scene Graph als physischen Container für Spielobjekte zu verwenden, anstatt beispielsweise std :: vector <>.

Meine Frage ist, ist es praktisch, Scene Graph zu verwenden, um die Spielobjekte zu enthalten , oder sollte es nur verwendet werden, um Verknüpfungen zwischen Szenenobjekten und Knoten zu definieren, während die Objekte in einem separaten Container wie std :: vector <> gespeichert bleiben?

Bunkai.Satori
quelle
Hat jemand eine Idee? Ich plane, sowohl Scene Graph als auch Game Actors / Nodes zu verwenden, als auch Vector, um verschiedene Sortierungen durchzuführen, die schneller sein sollten als das Sortieren eines mehrwegigen SceneGraph-Baums.
Bunkai.Satori
@ All: Ich habe noch eine Frage: Enthält SceneGraph die gesamte Karte oder sollte sie nur einen Kartenteil enthalten, beispielsweise den sichtbaren Bereich? Offensichtlich wird das Szenendiagramm dann kontinuierlich aktualisiert, wenn sich der Spieler über die Karte bewegt.
Bunkai.Satori

Antworten:

5

Die Entscheidung, welche Art von Szenenverwaltung verwendet werden soll, hängt sehr stark von der Art der Logik ab, die Sie ausführen möchten. Betrachten Sie die verschiedenen Konsumenten Ihrer Szene:

Verbraucher rendern

Der Renderer möchte wahrscheinlich nur wissen, was für den Benutzer zu einem bestimmten Zeitpunkt aktuell sichtbar ist. Es möchte eine begrenzte Volumenhierarchie für schnelles Keulen ( BVH-Wiki-Artikel) , damit herausgefunden werden kann, dass ein Stuhl in einem Boot nicht gezeichnet werden muss, da die Grenzen des Bootes außerhalb des Sichtstumpfs liegen. Dies könnte in einen Octree eingebettet sein .

Es könnte auch eine Idee sein wollen, dass sich der Stuhl auf dem Rücken im Boot befindet und dass das Boot auf einigen Wellen auf und ab rollt, wenn es endlich in Sicht kommt. Auf diese Weise können Sie die endgültigen Weltkoordinaten der Eckpunkte des Stuhls ermitteln und die Stuhl- und Bootstransformationen verketten und damit fertig werden (dies erleichtert auch Ihre Arbeit als Programmierer).

Eine weitere Sichtweise auf dieses Problem besteht darin, dass der Renderer wahrscheinlich eine gute Karte ausführt und letztendlich nur einen Stapel Dreiecke sortieren möchte, um Textur-, Shader-, Material-, Beleuchtungs- und Transformationszustandsänderungen zu minimieren. Letzteres wird Ihnen wahrscheinlich mehr helfen als ein BVH, was die Leistung betrifft.

Game Logic Consumer

Die Spielelogik möchte wahrscheinlich nur eine flache Liste von Dingen, die von einem Nachrichtensystem miteinander kommunizieren können, daher ist ein std :: vector wahrscheinlich in Ordnung.

Das Spiel möchte möglicherweise auch einen Weg finden, um zu verfolgen, wer was am nächsten ist. In diesem Fall kann daher eine Art [nächster Nachbar] [3] hilfreich sein. Dies kann auch von einem BVH bereitgestellt werden, aber das Hoch- und Runterfahren des Diagramms kann ärgerlich sein.

Das Spiel möchte vielleicht sogar nur wissen, dass sich bei Bewegung von A auch Punkt B von A bewegen sollte. In diesem Fall kehren wir zu einer Art Transformationshierarchie zurück.

Physik-Verbraucher

Ihre Spielphysik möchte möglicherweise eine [spezielle Darstellung] [4] von Innenräumen für eine sehr schnelle Kollisionserkennung. Alternativ kann eine Art Octree oder [räumliches Hashing] [5] verwendet werden, um effizient Dinge zu finden, die kollidieren könnten.

Keine der oben genannten Physikdatenstrukturen sieht wirklich wie ein "Szenendiagramm" im Java3D-Sinne aus.

Audio-Verbraucher

Eine Audio-Engine möchte nur Geometrie, möglicherweise einen potenziell sichtbaren (hörbaren) Satz oder eine Art Begrenzungsvolumenhierarchie, um die Schalldämpfung und -ausbreitung zu berechnen. Auch dies ist keine normale Art von Szenendiagramm, obwohl es sich möglicherweise um ein Geometriediagramm in Ihrer Szene handelt.

Letztendlich ... ... hängt es wirklich nur von den genauen Anforderungen Ihrer Anwendung ab. Ich würde vorschlagen, zunächst eine flache Liste zu verwenden und zu sehen, wo Ihre Probleme auftreten. Sie können sogar eine flache Liste mit einer Transformationshierarchie ausprobieren, da dies möglicherweise die einzige Art von Szenegraph ist, die aus anderen Gründen als der Effizienz nützlich ist.

Viel Glück!

ChrisE
quelle
@ ChrisE: +1 für ausgezeichnete Frage. Meiner Meinung nach ist dies hier die beste Antwort. Lassen Sie mich diese daher als akzeptierte Antwort markieren . Wenn ich es richtig verstanden habe, haben Sie bewiesen, dass Scene Graph nicht immer die ultimative Lösung ist. Sehen Sie insbesondere in Game Logic ein Szenendiagramm als die richtige Methode zum Aktualisieren der Transformation (Skalierung, Übersetzung) verwandter Objekte? Beispiel: Ein Stuhl befindet sich auf dem Boot, sodass die Koordinaten des Stuhls aktualisiert werden, wenn sich das Boot bewegt. Sehen Sie alternativ eine bessere Lösung für die Aktualisierung der relativen Koordinaten?
Bunkai.Satori
@ChrisE: Kann zusätzlich zu dem oben genannten, falls ein Szenendiagramm verwendet wird, es selbst als einziger Objekthalter für die Szene verwendet werden, oder würden Sie empfehlen, neben der Szene einen anderen Container (z. B. std :: vector <>) zu verwenden Graph?
Bunkai.Satori
2
Ich war gerade dabei, genau das vorzuschlagen. Ich würde versuchen, eine Transformationshierarchie (hier ein n-ary Baum, in dem Knoten ein übergeordnetes und mehrere untergeordnete Elemente haben und keine untergeordneten Elemente zwischen Knoten geteilt werden) beizubehalten, wobei jeder Knoten einen Verweis auf ein Spielobjekt enthält. Spielobjekte werden in einem separaten, flachen Array (z. B. std :: vector) gespeichert.
ChrisE
Während des Updates können Sie die flache Liste durchsuchen und eine Spielelogik ausführen. Wenn relative Bewegungen auftreten (z. B. wenn der Stuhl auf dem Boot nach vorne geschoben wird), verwenden Sie die Transformationshierarchie, um die endgültige Transformation von lokal zu Welt durch Gehen zu finden Up die Eltern Ihres Objekts und verketten ihre Transformationen. Dies verwendet die Transformationshierarchie für das, was am besten ist (Vereinfachung der relativen Bewegung), und ermöglicht es Ihnen dennoch, eine bequeme Liste von Objekten in der Nähe zu führen.
ChrisE
Eine weitere Verbesserung besteht darin, in jedem Objekt ein schmutziges Flag und eine Transformation von allem darüber in der Transformationshierarchie zu behalten. Die zwischengespeicherte Transformation von Eltern zu Welt (diese Transformation, die ich gerade erwähnt habe) bedeutet, dass Sie für alle Objektpositionsaktualisierungen nur eine Matrixmultiplikation durchführen müssen (die relative Transformation zu Eltern mit der Transformation von Eltern zu Welt). Jedes Mal, wenn Sie die relative Transformation aktualisieren, aktualisieren Sie auch Ihr Dirty-Flag.
ChrisE
3

Es gibt einen guten Grund, das Szenendiagramm nicht als Container für Spielobjekte zu verwenden, und das ist instanziierend. Wenn Sie einige Ressourcen wiederverwenden möchten, ist es viel sinnvoller, nur mehrmals auf die Ressource aus Ihrem Szenendiagramm zu verweisen, als mehrere tatsächliche Kopien zu haben.

Jari Komppa
quelle
@ Jari: +1 für eine gute Antwort. Nach meinem Verständnis besteht der allgemeine Ansatz darin, einen separaten Container mit renderbaren Netzen zu haben. Das Szenendiagramm bezieht sich normalerweise auf den Container für renderbare Netze, um Informationen zur Objektform aufzunehmen. Außerdem enthält jeder Szenendiagrammknoten Transformationsinformationen. Jari, mit einem solchen Design, würde ich gerne wissen, ob es immer noch empfohlen wird, einen separaten std :: vector <>
-Container für Spielknoten
2
Abhängig - es kann nützlich sein, mehrere lineare Listen von Knoten zu haben, um die Verarbeitung von KI, Physik usw. zu beschleunigen. Aber ich würde dorthin gehen, nachdem ich gesehen habe, ob es sonst ein Problem gibt.
Jari Komppa
Zusammenfassend sollte es für den Anfang akzeptabel sein, nur einen SceneGraph zu haben, der alle Objekte in der Szene enthält. Können Sie uns bitte mitteilen, ob Kameras, Lichter und Auslöser ebenfalls im Szenendiagramm enthalten sein sollten?
Bunkai.Satori
Alles, was von der Transformationshierarchie betroffen ist, muss sich im Szenendiagramm befinden, aber ich würde dem Szenendiagramm immer noch nicht den Besitz geben, sondern es zur einfacheren Verarbeitung (Animation, Physik usw.) an anderer Stelle speichern.
Jari Komppa
Jari verstanden. Vielen Dank. Ich werde mit einer kleineren Version beginnen und weitere Container hinzufügen, um sie später bei Bedarf einfacher verarbeiten zu können.
Bunkai.Satori
2

Das Trennen Ihres Objektmodells und des Ansichtsmodells (Ihres Szenegraphen) ist normalerweise eine gute Idee.

Siehe diesen Artikel zu diesem Thema.

Dies ermöglicht unter anderem die Verwendung von Objektpools. Was für eine effiziente Speicherverwaltung unerlässlich sein könnte.

Nagler
quelle
+1 für einen guten Beitrag. Ich habe den Artikel durchgesehen. Es werden Programmiermuster behandelt, und wenn ich das richtig verstanden habe, würde das Objektmodell die Liste der Objekte in der Szene in einer Art std: vector <> -Container organisieren, während ViewModel dieselben Objekte enthält, die im Szenendiagramm organisiert sind. Im Szenendiagramm wären jedoch nur die aktuell angezeigten Objekte enthalten.
Bunkai.Satori
Und was ist mit Kameras, Auslösern, Lichtern? Würden sie auch Teil des Szenendiagramms sein?
Bunkai.Satori
@ Bunkai.Satori Nun, Sie könnten möglicherweise Dinge im Szenegraphen haben, die nicht auf dem Bildschirm angezeigt werden. Sie bauen Ihren Szenegraphen auf und können dann einen Culling-Algorithmus für den Szenegraphen ausführen, bevor Sie die sichtbaren Knoten rendern. Kameralichter und -auslöser können sowohl im Modell als auch im Ansichtsmodell vorhanden sein.
Nagler
Vielen Dank für Ihre Antwort. Wie wird das Keulen in der Praxis durchgeführt? Ist die gesamte Szene im Szenendiagramm enthalten oder gibt es nur den sichtbaren Teil? Wenn sich die gesamte Szene im Szenendiagramm befindet, wird das gesamte Szenendiagramm pro Frame durchlaufen, um nur den sichtbaren Bereich an die OpenGL / DirectX-API zu senden? Ich bezweifle, dass die gesamte Szene pro Frame an die API gesendet wird, da der sichtbare Teil normalerweise weniger als 5% von der gesamten Szene entfernt ist. Ist das Szenendiagramm alternativ so organisiert, dass die nächstgelegenen Bereiche ohne vollständige Fahrt pro Bild schnell abgerufen werden können?
Bunkai.Satori
Fügen Sie Ihre gesamte Szene in den Szenegraphen ein. Balancieren Sie den Graphen anhand eines bestimmten Kriteriums (z. B. könnten Sie daraus einen Ok-Baum machen). Durchlaufen Sie den Baum und bestimmen Sie, welche Knoten "sichtbar", "teilweise sichtbar" und "unsichtbar" sind, je nachdem, ob sich die Begrenzungsrahmen in Ihrer Ansicht als Kegelstumpf befinden. Sie können ein superleichtes "Sichtbarkeitsdiagramm" erstellen, das im Wesentlichen nur aus Verweisen auf SG-Knoten und einem Flag besteht. Nach dem Keulen des Kegelstumpfes können Sie den Baum erneut durchqueren, um das Keulen der Okklusion durchzuführen. Wiederholen Sie das Ausmerzen jedes Frames oder jedes Frames, in dem die Kamera oder Szene als "schmutzig" markiert wurde.
Nagler