Instanzen für alles verwenden?


16

Durch das Instanziieren wird die Leistung (erheblich) verbessert, wenn mehrere (Hunderttausende) Kopien desselben Netzes gleichzeitig gerendert werden. Aber wie viel Overhead hat es, wenn genau eine Kopie mit einem Zeichnungsaufruf gerendert wird? Wäre es eine gute oder eine schlechte Idee, Instanzen für alle vom Motor gerenderten Geometrien zu verwenden?

Bearbeiten: Nehmen wir an, wir erstellen ein FPS-Spiel. Die meisten Objekte haben nur eine Instanz: ein Messer, ein Gewehr, ein Maschinengewehr, ein Gebäude und einen Funkturm. Es gibt aber auch Objekte mit mehreren Instanzen: Bäume (z. B. 3 Baumarten mit Hunderten von Instanzen), Gras und so weiter. Ich meine: Anstatt die Objekte mit einer Instanz auf die "traditionelle" Art und Weise zu rendern und Bäume und Gras unter Verwendung von Instanzen rendern wir sie alle Verwendung von Instanzen. Unser Funkturm hat also nur eine Instanz (deren Informationen wir in einem Instanzdatenpuffer speichern) und wir rendern diesen Turm mit einer Art DrawInstanced()Aufruf mit gleichem Instanzzähler 1. Dasselbe gilt für alle anderen Objekte (Bäume und Gras haben natürlich mehrere Instanzen).

Meine Frage lautet also: Ist es eine schlechte Idee, eine einzelne Instanz eines Objekts mithilfe von Instanzen zu zeichnen? Hat die Instanzierung einen zu hohen Overhead (in Bezug auf Speicher und Leistung) oder ist dies in irgendeiner Weise unerwünscht, um Objekte mit einer einzelnen Instanz zu rendern?

Antworten:


19

Unter D3D9 mit XPDM möchten Sie mit ziemlicher Sicherheit, wo immer möglich, eine Instanz erstellen. Der Aufwand für Draw Calls ist so hoch, dass es Sinn macht. In diesem Szenario kann der Überkreuzungspunkt nur 2 oder 3 Instanzen betragen.

Wenn Sie nur eine Instanz eines bestimmten Netzes haben, scheint es auf der Oberfläche verlockend, es nicht instanziiert zu zeichnen. Schauen Sie sich jedoch an, worum es geht:

  • Sie müssen vom Laden von Daten in einen instanzspezifischen Puffer zum Hochladen von Shader-Konstanten wechseln.
  • Sie müssen zwei Kopien Ihres Vertex-Shaders aufbewahren: eine für instanziierte und eine für nicht instanziierte.
  • Sie müssen zwei Kopien Ihres Rendering-Codes aufbewahren: ebenfalls.
  • Sie müssen den Shader wechseln.
  • Sie müssen die Scheitelpunktformate wechseln.
  • Möglicherweise müssen Sie die Scheitelpunktpuffer wechseln.
  • Und dann müssen Sie es noch einmal wiederholen, wenn Sie für die nächste Gruppe von Maschen wieder zum instanziierten Zeichnen zurückkehren möchten.

Auch wenn Sie nur ein einziges Netz haben (wie das Waffenmodell in einem FPS), gibt es Fälle, in denen das Instanzieren nützlich ist. Angenommen, Sie führen eine Multipass-Lichtakkumulation in einem Forward-Renderer und mit einem Z-Prepass durch. Anstelle eines zusätzlichen Durchgangs für jedes Licht erstellen Sie Ihre Lichtdaten pro Instanz und zeichnen sie instanziiert.

Basierend auf dem ersten Szenario lautet die Moral der Geschichte: Wenn eine Objektklasse überhaupt Instanzen verwenden kann, ist es sinnvoll, immer Instanzen für alle Objekte dieser Klasse zu verwenden.

Basierend auf dem zweiten Szenario ist die Moral der Geschichte, dass Instanzen nicht offensichtliche Verwendungen haben können, die über das bloße Sagen von "Ich muss 20 Bäume zeichnen" hinausgehen.


Die Gründe, die Sie angegeben haben, sind die gleichen, aus denen ich diese Frage gestellt habe. Vielen Dank.
NPS

12

(Auf meinem System habe ich es nirgendwo anders getestet.) In GL hat das Instanzieren eines einzelnen Netzes (Zeichnen mit count = 1) einen unangenehmen Overhead, aber ich weiß nicht, woher es kommt. Ich empfehle dringend, es nicht zu tun.

Ich habe dies vor ein paar Monaten in einer praktischen Anwendung getestet. Ich habe einige globale Beleuchtungsalgorithmen in der Crytek-Sponza-Szene codiert, die aus ungefähr 350 Maschen bestehen (ich erinnere mich nicht genau), von denen ein Paar eine Handvoll Instanzen gemeinsam hat. Am Anfang habe ich es so gemacht, wie Sie es vorgeschlagen haben, einfach alles instanziieren und den Rest mit der Instanzzahl 1 zeichnen, da dies den Rendering-Code ein wenig vereinfacht hat.

Wenn ich später den Renderer optimierte und von der Instanzierung der count = 1-Objekte auf die übliche Weise zurückging, sparte ich etwa 3,5 Millisekunden auf einem i7 3770k (und GTX 770) pro Frame Zeit bin. Das Umschalten der Netze mit mehreren Instanzen auf die herkömmliche Weise ersparte mir weitere 0,5 ms. Insgesamt ging die Anwendung von ca. 120 FPS auf ca. 230 FPS.

Diese Zahlen hängen natürlich immer davon ab, wo sich die Engpässe in Ihrer Anwendung befinden, und die letzten 0,5 ms können tatsächlich zu einer Verlangsamung in einer Anwendung führen, in der Sie stark an Draw Calls gebunden sind. Aber ansonsten hat das Instanzen meiner Erfahrung nach einen unangenehmen Overhead, wenn Sie nicht viele Dinge auf einmal zeichnen.


Interessant, aber es wäre schön, auch Daten für AMD- und Intel-Treiber zu sehen, sonst sollten Sie wirklich "Auf meinem System" anstelle von "In GL" sagen. Auf der anderen Seite ist die Tatsache, dass dies bei einigen Implementierungen nicht der Fall ist, Grund genug, eine Instanzierung zu vermeiden, wenn Sie sie nicht verwenden.
bcrist

2

Sie können sicher sein, dass das Zeichnen eines einzelnen Objekts in einer Instanz teurer ist als das normale Zeichnen eines einzelnen Objekts. Zum Beispiel bereitet sich die GPU auf eine große Anzahl von Objekten vor und diese Vorbereitung unterscheidet sich von der für ein einzelnes Objekt. Wie groß diese Leistungslücke ist, lässt sich jedoch nur durch Experimentieren feststellen und hängt stark von Ihrer tatsächlichen Rendering-Konfiguration ab. Die einzige Möglichkeit, dies sicher zu wissen, besteht darin, es selbst zu testen. Das Benchmarking eines einzelnen Draw Calls ist schwierig. Hier finden Sie einige Ideen, wie Sie vorgehen können.


2

Es ist 4 Jahre her ... und ich denke es ist sicher zu sagen, dass es vollkommen in Ordnung ist, "instanziierte" Draw Calls mit 1 einzureichen. Wie Sie vielleicht bemerkt haben, sind die neuen APIs DX12 und Vk beide eine Instanz Anzahl haben , die von 0 sein können NUM_INSTANCES . Beachten Sie auch, dass es kein DrawIndexed gibt (...) .

BEARBEITEN

Aus Vorsicht ist das Obige wahrscheinlich in Ordnung mit diesen modernen APIs, möglicherweise erfordert die Verwendung von etwas Altem wie Gl <3.3 oder DX11 eine Profilerstellung, wie von anderen Benutzern erwähnt.

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.