Ist es möglich, einen Würfel mit weniger als 24 Eckpunkten zu konstruieren?

14

Ich habe eine würfelbasierte Welt wie Minecraft und frage mich, ob es eine Möglichkeit gibt, einen Würfel mit weniger als 24 Scheitelpunkten zu konstruieren, um die Speichernutzung zu reduzieren.

Es scheint mir aus zwei Gründen nicht möglich zu sein: Die Normalen würden nicht richtig herauskommen und Per-Face-Texturen würden nicht funktionieren.

Ist das der Fall oder irre ich mich? Vielleicht gibt es eine schicke neue DX11-Technologie, die helfen kann?

Bearbeiten: Zur Verdeutlichung habe ich zwei Anforderungen: Ich benötige Oberflächennormalen für jede Würfelfläche, um eine ordnungsgemäße Beleuchtung zu gewährleisten, und ich benötige eine Möglichkeit, einen anderen Index in einem Texturarray für jede Würfelfläche zu adressieren

Telanor
quelle
1
Möchten Sie die Speichernutzung der Grafikkarte oder die RAM-Nutzung reduzieren ?
Doppelgreener
1
Die Scheitelpunktdaten werden derzeit im RAM und auf der GPU gespeichert, wodurch beide reduziert würden.
Telanor

Antworten:

9

Wenn Sie nur Normalen pro Fläche benötigen und Ihre Texkoordinaten für eine Fläche streng 0/0, 0/1, 1/0, 1/1 (oder ähnlich wie für Ihr Layout) sind, können Sie einen Würfel mit 8 Vert konstruieren und entweder 30 (Strip mit Neustart) oder 36 (Liste) Indizes. Rufen Sie die Normalen und Texcoords mit einer konstanten Array-Suche auf der Grundlage von SV_VertexID in Ihrem Vertex-Shader ab.

Wenn Sie dies tun, müssen Sie nicht einmal Texcoords oder Normalen in Ihren Vertex-Puffer aufnehmen, wodurch Sie noch mehr Speicherplatz sparen.

Wenn Sie noch weiter gehen, können Sie immer noch bis zu 24 Vert pro Würfel gehen, aber Sie können auch Instanzen verwenden. Jeder Würfel hat eine feste Größe in Ihrem Scheitelpunktpuffer (1x1x1), und Sie haben einen Skalierungsfaktor und eine Position (vorausgesetzt, Ihre Würfel drehen sich nicht, wenn dies der Fall ist, eine Matrix) als instanzbezogene Daten. Im nicht rotierenden Fall betragen die einmaligen Kosten 24 Verts, aber dann benötigt jeder Würfel nur 6 Floats, um vollständig spezifiziert zu werden. Im rotierenden Fall sehen Sie 16 Floats, aber selbst das ist eine erhebliche Ersparnis (in diesem Fall besteht eine höhere Wahrscheinlichkeit, dass Sie CPU-seitige Matrixtransformationen in den Hintergrund drängen - für den nicht rotierenden Fall, in dem eine Matrix on the fly in erstellt wird Ihr Vertex-Shader - auch wenn er pro Vertex ausgeführt wird - ist so blöd schnell, dass Sie sich nicht einmal darum kümmern müssen.

Verwenden Sie für flächenbezogene Texturen einfach ein Texturarray. Sie müssen natürlich sicherstellen, dass jede solche Textur im Array die gleiche Größe hat, und Sie müssen Ihren aktuellen Stapel immer noch unterbrechen, wenn sich das Array selbst ändern muss, andernfalls ist dies in Ordnung. Fügen Sie Ihrer Scheitelpunktdefinition ein drittes Texkoord hinzu, das den für jede Fläche zu verwendenden Array-Slice definiert.

Sie benötigen hierfür keine GS, und sie sollte schneller ausgeführt werden als eine, da die Aktivierung der Geometrie-Shader-Stufe einen zusätzlichen Aufwand verursacht.

Ich habe einen Benchmark-Code in meiner Engine, der mit dieser Methode nur ein paar Würfel zeichnet, und ich kann problemlos über 300.000 Würfel durchkauen, während ich auf einer verhältnismäßig Low-End-GPU immer noch 60 fps lösche, ohne irgendetwas anderes zu tun, um den Prozess zu optimieren . Zugegeben, ich beleuchte oder texturiere sie nicht, aber ich habe Alpha-Blending aktiviert, Backface-Culling deaktiviert und insgesamt wird mein Teil "Ich tue nichts anderes, um es zu optimieren" abgewogen, sodass ich Ihnen eine vernünftige Vorstellung davon geben sollte Baseballstadion können Sie mit dieser Methode treffen.

Maximus Minimus
quelle
1
Ich habe zuvor Instanzen verwendet und sie eignen sich hervorragend für Cubes unter 40.000. Aber ich habe mindestens 256k Würfel und Instanzen haben das nicht mitgemacht. Die Verwendung von SV_VertexID mit einer Suche klingt jedoch sehr vielversprechend.
Telanor
Wie groß war der Puffer pro Instanz? Der Versuch, sie alle in einen riesigen Puffer zu stopfen, kann dazu führen, dass Ihre GPU erstickt wird. Normalerweise halte ich die Puffer pro Instanz auf genügend Platz für 64.000 Objekte (teile die Draw-Aufrufe, falls erforderlich), verwende das Discard / No-Overwrite-Muster und schreibe direkt in den zugeordneten Zeiger, anstatt von einem Zwischenarray zu kopieren, was sehr gut funktioniert .
Maximus Minimus
Außerdem ist es wichtig, die Anzahl der Karten niedrig zu halten. Das Zuordnen / Schreiben eines Würfels / Entfernen der Zuordnung für 40.000 Mal ist viel langsamer als das Zuordnen / Schreiben von 40.000 Würfeln / Entfernen der Zuordnung für nur ein Mal. Wenn Sie das erstere getan haben, versuchen Sie, auf das letztere zu wechseln.
Maximus Minimus
15

Ich denke, die Hauptoptimierung, die Sie vornehmen können, basiert auf der Tatsache, dass nicht jeder Würfel tatsächlich alle 24 Eckpunkte benötigt . Tatsächlich sind die einzigen Würfel, die 24 Eckpunkte benötigen, diejenigen, die in der Luft schweben, was wahrscheinlich selten vorkommt.

Generieren Sie in der Regel nur Quads für die mit Luft in Berührung kommenden Gesichter . Wenn sich also zwei Würfel berühren, müssen Sie keine Scheitelpunkte für das Gesicht generieren, in dem sie sich berühren.

Das folgende Bild zeigt dieses Konzept, jedoch zum leichteren Verständnis in 2D. Im Bild gibt es 11 belegte Blöcke (dargestellt durch die gefüllten grauen Kreise), für deren Darstellung normalerweise 4 x 11 = 44 Kanten erforderlich sind (4, da es sich um ein Quadrat und nicht um einen Würfel handelt). Aber wie Sie sehen, müssen Sie die Kanten nur wirklich zeichnen, wenn sie mit einem leeren Quadrat in Kontakt stehen, das in diesem Fall nur aus 8 Kanten besteht.

Bildbeschreibung hier eingeben

Wenn solch ein einfaches Beispiel in 2D es geschafft hat, 44 Kanten auf 8 Kanten zu reduzieren, stellen Sie sich die Vorteile in einer großen 3D-Welt vor ...

Dies ist der Ansatz, der in diesem Artikel beschrieben wird. Ich empfehle Ihnen, ihn zu lesen, obwohl er sich an OpenGL richtet. Die Konzepte sollten jedoch ziemlich universell sein.

Sie könnten wahrscheinlich auch einen Geometrie-Shader verwenden , um die Scheitelpunkte im laufenden Betrieb auf der GPU zu generieren, sodass sie nicht mehr im Speicher gespeichert werden müssen Welt.

David Gouveia
quelle
1
Sehr interessanter Artikel. Ich mache schon die Kantenoptimierung, was sicherlich sehr hilfreich ist. Ich werde Geometrie-Shader ausprobieren und sehen, ob das funktioniert.
Telanor
Meinen Sie, verwenden Sie den Geometrie-Shader und das Kreuzprodukt, um die Normalen zu berechnen? Ich habe darüber nachgedacht, ein separates Programm für flache Oberflächen zu erstellen (ich beschäftige mich nicht mit Texturen).
Dreta
@dreta Nicht nur das, sondern gehen Sie zu dem Punkt, an dem Sie nur die Würfelschwerpunkte als Punktliste übergeben, und alle Scheitelpunkte werden vom GS ausgegeben. Codieren Sie möglicherweise einige benachbarte Informationen in die Punkte, sodass der Shader nur die Flächen generiert, die wirklich benötigt werden, obwohl ich nicht darüber nachgedacht habe, wie.
David Gouveia
Wenn Sie die gewünschte Leistung wünschen, verwenden Sie keinen Geometrie-Shader ... Fast immer. Sie vermasseln die Pipeline komplett. Wenn Sie Geometrie auf der GPU generieren möchten, verwenden Sie einen Compute-Shader oder openCL
Robert Fraser