Effiziente Methode zum Rendern von massivem Gelände in XNA


10

Ich erstelle ein XNA-Spiel, das viel Platz für die Spieler benötigt. Derzeit ist die von mir verwendete Testhöhenkarte 4096 x 4096 und wird als 4-Bit-BMP gespeichert.

Ich versuche, diese riesige Höhenkarten-Datei zu nehmen und im Spiel zu rendern. Das Problem, auf das ich stoße, ist die Tatsache, dass es ineffizient ist, das gesamte Gelände auf einmal in den Speicher zu laden, da der Großteil des verfügbaren Speichers verwendet wird.

Ein weiteres Problem, auf das ich gestoßen bin, ist, dass ich das Terrain aufgrund eines in XNA festgelegten Hard-Limits nicht alle in einem Grundelement rendern kann.

Vor diesem Hintergrund bin ich auf eine Reihe von Lösungen gestoßen, die ich unten aufgeführt habe:

  • Rendern basierend auf dem Standort des aktuellen Benutzers - Zeichnen Sie im Grunde genommen ein Quadrat um den Benutzer, unabhängig von seiner Ausrichtung innerhalb der Welt. Dies ist auch nicht genau das, was ich wollte, da Sie immer noch Speicherplatz rendern, den der Benutzer nicht sieht.
  • Rendern basierend auf der Ausrichtung und Position des Benutzers - Ich habe eine Formel gefunden, um ein Dreieck abzurufen, das die Pixel der Höhenkarte enthalten soll, die gerendert werden sollen. Dies erwies sich jedoch als sehr schwierig.
  • Aufteilen des Geländes in mehrere Blöcke und Rendern derjenigen, die dem Benutzer am nächsten sind - Immer noch nicht sehr effizient, da Sie immer noch Blöcke rendern, die die Leute nicht sehen. Und es ist arbeitsintensiv, weil ich dann meine Höhenkarte in mehrere Teile aufteilen muss und die Skalierbarkeit zu einem großen Problem wird.

Nachdem ich diese Lösungen ausprobiert habe, habe ich keine Ideen mehr, was ich tun soll. Ich habe einige Antworten erhalten, in denen mir Leute sagen, dass ich diese komplexen Algorithmen ausführen soll, aber ich habe einfach keine Ahnung, wie ich sie angehen soll.

Im Grunde frage ich nach einer einfachen und unkomplizierten Methode, um in XNA gewaltiges Terrain mit höchster Effizienz zu rendern.

Ich bin ziemlich neu in der Spieleentwicklung im Allgemeinen, aber ich bin bereit zu recherchieren, ob es vielversprechend erscheint.

Update 1: Nachdem ich die Geoclipmapping-Methode untersucht hatte, begann ich damit zu codieren. Ich habe die ganze Mathematik erledigt und das Spiel läuft. Es ist jedoch äußerst ineffizient - was wahrscheinlich eine schlechte Codierung meinerseits ist. Es läuft mit 2FPS und verwendet einen ganzen Kern meiner CPU. Ich werde versuchen, den Code zu verbessern, aber ich denke, ich brauche mehr Hilfe. Hier ist ein Pastebin des Codes für die Terrain-Manager-Klasse. Ich werde später mit weiteren Ergebnissen zurückkehren, falls ich es jemals effizienter machen sollte.


1
Interessanterweise scheint die Technik, über die Sie sprechen, der zu ähneln, die ID Software in ihrem kommenden Spiel Rage verwendet. Sie verwenden eine 'Megatextur' und streamen dann die erforderlichen Teile davon in die GPU. Er hat darüber gesprochen, aber hier ist ein Wikipedia-Artikel, der vielleicht inspirierend ist: en.wikipedia.org/wiki/MegaTexture

Antworten:


5

Der Chunks-Ansatz wird normalerweise verwendet. Selten ist es effizient, jedes Dreieck von Hunderttausenden zu testen, um festzustellen, ob Sie es rendern sollten. Stattdessen verwenden die meisten Terrain-Rendering-Algorithmen eine räumliche Datenstruktur , um die sichtbaren Teile des Terrains dynamisch zu rendern.

Eine einfach zu implementierende Datenstruktur wird als Quadtree bezeichnet . Kurz gesagt, um einen Quadtree zu verwenden, würden Sie den Betrachtungsstumpf des Spielers finden, ihn mit der obersten Ebene des Quadtree schneiden und für alle Teile, die teilweise sichtbar sind (dh die Stumpf-Ebenen schneiden den Block), alle Kinder unterteilen und testen Brocken, die außerhalb des Kegelstumpfes weglassen. Dies ergibt eine ziemlich enge Annäherung an die tatsächlich sichtbare Geometrie mit nur wenigen Rekursionsstufen.

Fortgeschrittenere Terrain-Renderer verwenden einen Algorithmus, um nicht nur die sichtbare Geometrie, sondern auch die Details dieser Geometrie abzustimmen. Geomipmapping (und sein relatives Geoclipmapping) ist derzeit relativ beliebt, ist aber keine triviale Implementierung.

edit: Hier ist eine anständige Beschreibung sowohl des Geoclipmapping als auch des Kegelstumpfes.

Ich habe auch Zweifel, ob 4 Bits für die Höhenkarte tatsächlich ausreichen, um ein gut aussehendes Terrain zu erzeugen, es sei denn, Sie glätten das Ergebnis stark.


Ich habe mir diesen Artikel angesehen und mich entschlossen, zuerst die Geoclipmapping-Methode zu verwenden, da es anscheinend am effizientesten ist, eine große Menge an Gelände anzuzeigen. Ich werde mit meinen Ergebnissen zurückschicken.

3

Jeder Ansatz, bei dem Sie pro Frame arbeiten müssen, um Daten auf die GPU zu laden, ist fehlerhaft.

Hier ist eine grobe Darstellung eines Ansatzes, der gut funktionieren sollte:

Sie sollten Ihr Gelände in (ziemlich große) Blöcke aufteilen und diese Blöcke in feste Scheitelpunktpuffer laden (die Bittiefe Ihrer Höhenkarte spielt keine Rolle!). Diese Vertex-Puffer befinden sich einfach im GPU-Speicher und warten darauf, gerendert zu werden. Sie müssen mit einer geeigneten Blockgröße experimentieren, aber 128 x 128 ist vielleicht ein guter Anfang.

In einem Gelände mit einer Größe von 4096 x 4096 sind Sie ein wenig jenseits der Grenze dessen, was ich auf einmal bequem auf die GPU laden würde - es sind wahrscheinlich ein paar hundert MB Scheitelpunktdaten (obwohl Sie diese auf ~ 64 MB reduzieren könnten, wenn Sie es sind klug). Daher müssen Sie möglicherweise Vertex-Puffer von der GPU im Hintergrund laden und entladen.

(Wenn Sie das Laden von Chunks im Hintergrund implementieren, sollte dies extrem skalierbar sein!)

Nachdem Sie die Scheitelpunktdaten auf der GPU gespeichert haben, ist es an der Zeit, die Sichtbarkeit pro Chunk- Culling durchzuführen . Sie müssen den Befehl nicht senden, um einen Block zu rendern, wenn Sie wissen, dass er sich hinter der Kamera befindet.

Sie sollten fast nie pro Dreieck auf der CPU aussortieren!

Die GPU erkennt Dreiecke, die sich außerhalb des Bildschirms befinden, viel schneller als jemals zuvor.

Weitere Informationen zur Leistung finden Sie in dieser Antwort auf der Game Dev-Website.


0

Ich bin keineswegs ein Experte bei XNA. Bitte korrigieren Sie mich, wenn ich falsch liege, aber ich hatte den Eindruck, dass für solche Situationen tatsächlich eine Optimierung eingebaut ist. Ich weiß, dass Sie in der Lage sind, eine Renderentfernung festzulegen, und nach diesem Punkt wird nichts mehr gerendert. In Ihrem Fall wäre dies das verbleibende Gelände. Dies hinterlässt jedoch einen ziemlich unattraktiven Vorteil für Ihre gerenderte Welt, sodass Sie so etwas wie das Beschlagen implementieren müssten, das die meisten Open-World-Spiele haben.


Es gibt integrierte Lösungen, aber das Problem, auf das ich gestoßen bin, war, dass ich versucht habe, ein großes Grundelement zu rendern, das die Grenze für Polygone für Grundelemente überschritten hat. Daher würde es nicht zeichnen, sondern nur eine Ausnahme auslösen.
Sammarks
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.