effizientes Rendern von Chunksystemen im GM

    • GM 8

    Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

    • effizientes Rendern von Chunksystemen im GM

      Mir ist im aktuellen Projekt die Frage aufgekommen, wie denn nun -speziell im GM, aber gern auch allgemein- ein effizientes Rendersystem für 2D/3D Welten aussehen könnte. Mein Ansatz, ohne bisherige Erfahrungen mit dem Rendern von größeren Datenmengen war:

      1. Aufteilung der Maps in Chunks, um das ganze häppchenweise zu verarbeiten.
      2. Laden der relevanten Chunks. Besser gesagt ausschließlich die umliegenden Chunks und löschen der ungenutzten.
      3. Erstellung der Instanzen via Frustum Culling ähnlichem Verfahren (Nur Innerhalb des Sichtfelds Instanzen von Objekten erstellen, hier aber eher ein Rechteck anstelle einer Pyramide). Hierbei durchlaufe ich die Chunks und prüfe, ob die Position innerhalb des Sichtfelds liegt.
      4. Ein Nebeneffekt des Chunkdurchlaufs ist der Else-Zweig, der ungesehene Instanzen zerstört.

      Soweit zur Planung, hat sich als ziemlich ineffizient herausgestellt. Ein Großteil des Slowdowns ist dem Durchlaufen der Chunks und dem Prüfen der Positionen geschuldet, das Erstellen der Instanzen dürfte relativ performant sein, lediglich die Anzahl vieler Instanzen bereitet mir Bauchschmerzen. Bekämpft hab ich das durch die Verkleinerung des Sichtfelds und einem seltenerem Durchlauf/ Positionsprüfung der Chunks. Leider nur reine Schadensbegrenzung.

      Immer wieder sieht man hier und auf der sandbox.yoyogames.com/ ziemlich aufwändige 3D Projekte, die mit den GM internen 3D Funktionen realisiert wurden. Jedoch auch viele Interessante Ansätze, die an einem ähnlichen Problem wie bei mir scheitern.

      Habt ihr Vorschläge, Rat oder Erfahrung?
    • Schon die aller einfachste Methode mit dem Deaktivieren und Aktivieren von instanzen ausprobiert, statt einem komplett eigenem Chunksystem? Hat in meinen Fällen bisher immer ausgereicht um in großen Räumen die Performance in einen grünen Bereich zu bringen.
    • Ich habe eine Art Chunk-System für mein Projekt entwickelt, allerdings in GMS nicht GM8.

      Dafür lasse ich je nach Variable die ich speichern will Grids erstellen.
      Die erste Dimension gibt dabei die Segmente der Map an, und die zweite Dimension den Wert.
      Mein Chunk-System gilt also nur auf einer Achse (auf der Map), ich habe noch keine Erfahrung mit 2D- oder gar 3D-Chunk-Systemen.
      Die Größe eines Grids ist z.b. 3330x48.
      3330 ist sozusagen die Map-Länge, in dem Fall die Anzahl aller Segmente auf einer Ebene. Ein neues Segment beginnt bei mir alle 256 Pixel.
      48 ist die Anzahl aller Instanzen die in diesem Segment gespeichert werden dürfen. Ich setze hier eine Obergrenze, damit Spieler keine Maps im Editor machen können,
      die ein gewisses Performance-Budget überschreiten.

      Hier beschreibe ich ein wenig wie ich das gemacht habe, aber das Video ist nicht wirklich umfassend erklärend.
      Ich habe auch einen Prototypen erstellt den man im Video sieht, leider kann ich aufgrund von Internetbeschränkungen momentan nichts hochladen was nicht in Textform ist,
      aber wenn du Interesse hast kann ich es am 1. September hochladen, inkl. weiterer Anpassungen und/oder Erklärungen.

      domis4 schrieb:

      lediglich die Anzahl vieler Instanzen bereitet mir Bauchschmerzen.

      Wieviele Instanzen musst du denn ungefähr darstellen?
    • TrunX schrieb:

      Schon die aller einfachste Methode mit dem Deaktivieren und Aktivieren von instanzen ausprobiert, statt einem komplett eigenem Chunksystem? Hat in meinen Fällen bisher immer ausgereicht um in großen Räumen die Performance in einen grünen Bereich zu bringen.


      Daran hatte ich noch gar nicht gedacht, bzw gleich als ineffizient abgestempelt (böse yyg Gerüchte). Dann würde das durchlaufen der Maps komplett wegfallen, da 4 im Speicher sind und der GM selbstständig innerhalb der Region die Objekte aktiviert/ außerhalb deaktiviert. Da setz ich mich mal dran, thx!

      RLP schrieb:


      Wieviele Instanzen musst du denn ungefähr darstellen?

      Thx für den Link, in der View sind derzeit ca 100 aktive Objekte (selbstdarstellende 3D Objekte ohne/mit wenig weiteren Aktivitäten oder Dummies für's Auslösen der Kollision oder Events). Eine Map beinhaltet ca < 400. Aus der Java Ecke bin noch große Objektmengen gewohnt. Ich hab zwar noch nicht ausprobiert, ob es was bringt, werkle aber schon in die Richtung die Verwaltung über eine einzige Instanz eines Objekttyps mit Listen der darzustellenden Modellen. Da würde dann Trun'X Lösung leider nicht mehr in Frage kommen. Ich lass das mal gegeneinander antretten

      EDIT: deine 3330 beziehen sich auf deine Y Achse und 48 deine X? Damit wäre dein System meinem überlegen, ich durchlaufe maximal im worst case bei 8 gleichzeitig geladenen Maps 3200x5 Einträge auf 8 Listeneinträge verteilt und kontrolliere somi, ob der Listeneintrag überhaupt erst angesprochen wird. Sprich Listeneintrag 0 enthält das Grid der Map 0, der aktiven Map und dort findet sich im Grideintrag 0/0 die erste Instanz. die X/Y/Z Koordinaten kommen dann aus den Grideinträgen [1], [2], [3] usw zustande.

      Sollte ich das richtig verstanden haben und du durchläufst die komplette Map, instanziierst du dann nur, wenn nötig und löschst ansonsten?

      Dieser Beitrag wurde bereits 6 mal editiert, zuletzt von domis4 ()

    • domis4 schrieb:

      EDIT: deine 3330 beziehen sich auf deine Y Achse und 48 deine X? Damit wäre dein System meinem überlegen, ich durchlaufe maximal im worst case bei 8 gleichzeitig geladenen Maps 3200x5 Einträge auf 8 Listeneinträge verteilt und kontrolliere somi, ob der Listeneintrag überhaupt erst angesprochen wird. Sprich Listeneintrag 0 enthält das Grid der Map 0, der aktiven Map und dort findet sich im Grideintrag 0/0 die erste Instanz. die X/Y/Z Koordinaten kommen dann aus den Grideinträgen [1], [2], [3] usw zustande.

      Sollte ich das richtig verstanden haben und du durchläufst die komplette Map, instanziierst du dann nur, wenn nötig und löschst ansonsten?

      Bei mir wird immer nur eine Map gleichzeitig geladen. Um zu verhindern, dass die Abfrage die ganze Map durchläuft berechne ich mit ein paar Variablen die aktiven Segmente.
      Dafür schreibe ich z.B: chunk_active = (view_yview div 128) //128 ist die Höhe eines Segments und berechne mir ausgehend von der Variable die umliegenden Segmente die sich ebenfalls in der View befinden und speichere diese in zusätzliche Variablen.
      (Das betrifft in dem Fall die aktive (spielbare) Ebene, ohne Parallaxeffekt, die 3 anderen Ebenen kämen in meinem Fall noch dazu und werden natürlich anders berechnet)

      Somit brauche ich nur die paar Chunks/Segmente (pro Ebene) durchzugehen und wenn ich bei der for-Schleife auf einen Leereintrag komme (in dem Fall habe ich als Wert -10 verwendet, frag mich nicht warum^^)
      wird der Schleifendurchlauf im aktuellen Chunk übersprungen und zum nächsten gewechselt. Das ist möglich weil alle Chunks wie Stacks behandelt werden wenn ein Eintrag gelöscht wurde, obwohl es eigtl. ein Grid ist.
      Somit passt sich also der Überprüfungsaufwand so ziemlich 1:1 daran an wie voll die Chunks beladen sind.

      Das ganze System kommt erst zum Zug wenn die Schwelle zu einem neuen Chunk überschritten ist.
      Dafür habe ich neben chunk_active-Variablen auch chunk_active_previous-Variablen die im End-Step-Event an die chunk_active-Variablen angepasst werden.
      Immer wenn ein Wert abweicht wird er also wieder angepasst, und der Inhalt der "aktiven" Chunks überprüft und ggf. geladen.

      Dann werden die Instanzen an ein Creation-Stack übergeben, welches
      (üblicherweise mit einer Geschwindigkeit von 10 Instanzen per Step) alle Instanzen nach und nach generiert.

      Alle restlichen Instanzen die außerhalb des Prüfspektrums liegen werden gelöscht.
      Das führt natürlich dazu, dass jede Änderung an einer Instanz im Chunk/Grid-System mitgespeichert werden muss
      (sofern es in irgendeiner Form persistent sein soll), das System muss also flexibel genug sein.

      Summa summarum wurde ich in meinem Fall durch den Parallax-Effekt dazu gezwungen mir ein eigenes System zu basteln, da mir die instance_deactivate-Funktionen
      nicht flexibel genug waren. Außerdem konnte ich feststellen, dass ab 3000 - 4000 Instanzen auch mit instance_deactivate... die Performance in die Knie ging.
      Durch das eigene System brauche ich mich darum nicht mehr zu kümmern und könnte Millionen Instanzen in einer Map haben, und es würde sich lediglich negativ auf die Ladedauer der Map
      und die Dateigröße auswirken, und selbst das würde absolut im Rahmen bleiben. Ja, und möglicherweise auch beim Betreten von neuen Chunks, wenn diese prall gefüllt sind,
      was aber durch den Creation-Stack abgeschwächt wird.