Dschungel-Rendering

Für Fragen zu Grafik APIs wie DirectX und OpenGL sowie Shaderprogrammierung.

Dschungel-Rendering

Beitragvon Jonathan » 23.01.2013, 01:25

Nabend,

wie ich ja schonmal am Rande erwähnt habe, würde ich gerne meine 'Grafikengine' neu schreiben. Hauptsächlich geht es mir zunächst erst einmal darum, Unmengen an Vegetation schnell rendern zu können, aber dafür bietet mein bisheriges Grafikgrundgerüst einfach keine gute Grundlage.

Mal als Zusammenfassung, was ich jetzt habe:
Eine Klasse, die ein 3D Modell repräsentiert, das sich selber zeichnen kann. Im Hintergrund unterklasse für Submeshes, Materialien, ein Manager um nichts doppelt zu laden und so weiter. Problem: Ich kann nichts Objektübergreifend optimieren, habe pro Submesh pro Material einen Drawcall, alles wird zigfach redundant gesetzt. Meh.

Neue Ansatz:
Globaler Manager für Renderjobs, der die gesamte Szene rendert. Das ganze basiert ein wenig auf folgendem:
viewtopic.php?f=7&t=2766&p=35197 (Außenwelten rendern)
viewtopic.php?f=4&t=2748 (Datenorientierung)
Im Grunde genommen möchte ich meine Renderjobs gecullt und nach Material sortiert rendern. Das scheint mir das Grundprinzip für effizientes Szene-Rendering zu sein (ein wenig LOD ist auch dabei).

Anfangen möchte ich mit Vegetation, daher der Thread-Titel. Mein bisheriger Plan ist folgender:
Ich habe ein Modell (Grasbüschel, Blume, Busch, etc.; aber nur ein Material) und ein Bereich den ich damit füllen möchte. Dort generiere ich jetzt Positionen und Ausrichtungen (evtl. Vertex-Farben oder sonstiges) und benutze Instancing um dieses Modell in einem Rutsch zu zeichnen. Für eine komplette Wiese/Wald würde ich 3-6 Modelle nehmen, und auf jedes die obige Lösung anwenden.
Als kleine Optimierung würde ich den großen Bereich vielleicht noch in Tiles unterteilen, für jedes einen Sichtbarkeitstest machen und evtl. LOD anschalten, bzw. auf große Entfernung ganz ausblenden. Das aufteilen kann man ja irgendwie dynamisch machen, indem man sagt, es sollen immer mindestens 100 Modelle auf einmal gerendert werden, oder so.
Im Overgroth-Blog waren noch einige nette Ideen, beispielsweise Objekte aus dem Boden fahren zu lassen, um sie langsam einzublenden (so dass sie nicht aufpoppen), oder Gras mit der darunterliegenden Bodenfarbe einzufärben. Aber das sind ja ansich nur kleinere Spielereien die man hinterher im Shader macht (wie auch Animationen, dazu gibt es einen netten GPU-Gems Artikel), von Rendern dürfte das ja mehr oder wenige unabhängig sein.

Später würde ich das ganze zu einer generellen Render-Job-Verwaltung ausbauen, die auch einzelne Meshs rendern kann und so. Da werde ich dann sicherlich nochmal ein paar Fragen zu stellen, zunächst geht es mir nur um Gras.

Was haltet ihr davon? Gibt es noch prinzipielle Tipps? Im Grunde genommen möchte ich möglichst komplexe Szenen rendern, aber das ganze sollte in realistischer Zeit von einer einzelnen Person umsetzbar sein.
Lieber dumm fragen, als dumm bleiben!
Benutzeravatar
Jonathan
Establishment
 
Beiträge: 1218
Registriert: 04.08.2004, 20:06

Re: Dschungel-Rendering

Beitragvon Schrompf » 23.01.2013, 12:23

Mach erstmal die RenderJob Queue, damit sparst Du eine Menge Shader-, Textur- und Zustandsänderungen ein, das dürfte schon eine Menge bringen. Alles andere ergibt sich dann.
Häuptling von Dreamworlds. Baut an was Neuem. Hilft nebenbei nur höchst selten an der Open Asset Import Library mit.
Benutzeravatar
Schrompf
Thomas Ziegenhagen
Moderator
 
Beiträge: 3747
Registriert: 26.02.2009, 00:44
Wohnort: Dresden
Benutzertext: Lernt nur selten dazu

Re: Dschungel-Rendering

Beitragvon Jonathan » 23.01.2013, 12:41

Ja ok.
Wobei ich die Engine erstmal im Hinterkopf behalten möchte und zunächst nur das Gras machen will, welches ich dann später irgendwie in die Engine integrieren will. Hast du noch konkrete Tipps für die Vegetation?
Lieber dumm fragen, als dumm bleiben!
Benutzeravatar
Jonathan
Establishment
 
Beiträge: 1218
Registriert: 04.08.2004, 20:06

Re: Dschungel-Rendering

Beitragvon Schrompf » 23.01.2013, 13:29

Gras würde ich als Spezialfall implementieren, nämlich große Mengen per Instancing. Du könntest auch statische Meshes mit vielen Instanzen generieren, aber die Lösung habe ich vor langer Zeit schon seingelassen, weil mir immer die Buffer übergelaufen sind, bevor ich meine Wunsch-Vegetationsdichte erreicht hatte.

Ich wollte mal ausprobieren, ob es was bringt, den Instancing-Buffer dynamisch jedes Frame zu füllen. Es gibt da immer das Problem, dass Du hinreichend große Segmente von Vegetation pro DrawCall brauchst, damit der Wechsel der Vertex Declaration und der Shader sich lohnt. Aber dann haust Du pro Segment soviele Flächen raus, dass das Culling sehr grob arbeitet. Als Beispiel: meine Farne werden von 30m bis 35m ausgeblendet, aber die Bewuchs-Segmente sind allein ~20m groß. Im schlimmsten Fall zeichne ich also Massen unsichtbarer Farne noch bis 55m Abstand zur Kamera. Und wir haben es hier mit O(n²) zu tun, ich zeichne da also vielleicht doppelt so viele unsichtbare Flächen wie sichtbare Flächen. Und davon dann noch Schatten-Passes, und evtl. Multipass ab der vierten/fünften Lichtquelle. Aua.

Daher meine Überlegung: ich unterteile meinen Bewuchs nochmal in kleinere Segmente zu je ~5m, was bei meinen Bewuchsmodellen etwa 20 Instanzen entspricht. Ich habe pro ~25m-Segment ein Objekt, dass alle Instanzen verwaltet und cullt. Aber das will ich auch intern nochmal kleinere Segmente cullen lassen, und die sichtbaren Instanzen werden dann in einem dynamischen VertexBuffer hochgeladen. Damit könnte ich nicht nur die Instanz-Anzahl etwa halbieren, sondern habe auch dynamische Verzerrungsmöglichkeiten, wenn z.B. ein Monster das Gras plattgedrückt hat. Ok, dafür bräuchte ich evtl. mehr kleinere Instanzen, aber das Prinzip ist klar. Ob der Gewinn allerdings den Aufriss wert ist, weiß ich nicht.

Ok, jetzt weiß ich es. Ich habe bei den Splitterwelten ganz andere Probleme als den Bewuchs. Im Dorf: abschalten des Bewuchses senkt den Gesamt-Polycount von 2,3 Millionen auf 1,6 Millionen und verbessert die Framerate von 36 auf 37 fps. Im Wald: abschalten des Bewuchses senkt den Polycount von 1,4 Millionen auf 1,1 Millionen und erhöht die Framerate von 57 auf 59 fps. Das ist lächerlich. Selbst das uralte Auto-Instancing, was ich mal der Engine beigebracht hatte, bringt plötzlich mehr, nämlich 63 fps. Tss. Klingt, als wäre es die ganze Arbeit eigentlich nicht wert.

Irgendwann bau ich mal auf einen Deferred Renderer oder Tiled Forward Renderer um, um die Massen an Shader-Wechsel loszuwerden. Und das Textur-Zusammenfass-Tool für den Editor wäre echt nötig.
Häuptling von Dreamworlds. Baut an was Neuem. Hilft nebenbei nur höchst selten an der Open Asset Import Library mit.
Benutzeravatar
Schrompf
Thomas Ziegenhagen
Moderator
 
Beiträge: 3747
Registriert: 26.02.2009, 00:44
Wohnort: Dresden
Benutzertext: Lernt nur selten dazu

Re: Dschungel-Rendering

Beitragvon CodingCat » 23.01.2013, 13:45

Jonathan hat geschrieben:Neue Ansatz:
Globaler Manager für Renderjobs, der die gesamte Szene rendert. Das ganze basiert ein wenig auf folgendem:
viewtopic.php?f=7&t=2766&p=35197 (Außenwelten rendern)
viewtopic.php?f=4&t=2748 (Datenorientierung)

Ich habe im Zuge meiner Experimente zu Datenorientierung die globale Render Job Queue nahezu komplett entfernt. Global sammle ich nur noch nicht-kommutative Render Jobs ein, z.B. bei Tiefensortierung. Sonstige Meshes verarbeite ich gruppiert, sortiert nach Materialien/Shader-Passes, und kann diese dann ggf. mit Instancing in einem Draw Call rendern. Die globale Job Queue habe ich aus folgenden Gründen entfernt: Wie du richtig feststellst, lassen sich unabhängig behandelte Objekte unbekannten Typs schlecht zusammenfassen - selbst wenn du in deiner globalen Job Queue ein passendes Sortierkriterium gefunden hast, fehlt noch immer die Logik, konsekutive gleichartige Jobs zu einem Draw Call zusammenzufassen. Behandelst du die Objekte hingegen in Typgruppen, ist dieser Schritt trivial, weil du alle notwendigen Daten kennst und direkt vorliegen hast. Obendrein lassen sich die unterschiedlichen Daten verschiedener Jobtypen schwerlich auf einen Nenner bringen; nicht-lokale Indirektionen werden erforderlich, um zu jedem gerenderten Job die passenden Daten zu erhalten.

Schrompf hat geschrieben:Mach erstmal die RenderJob Queue, damit sparst Du eine Menge Shader-, Textur- und Zustandsänderungen ein, das dürfte schon eine Menge bringen. Alles andere ergibt sich dann.

Insbesondere im Fall des eigentlichen Themas dieses Threads würde ich auf verallgemeinertes Rendering mittels einer Job Queue verzichten und stattdessen Vegetation direkt pro Vegetationstyp mit spezialisiertem Culling (z.B. die angesprochenen Tiles) und Instancing rendern. Das macht die Dinge sowohl einfacher als auch effizient. Das kommt natürlich auf die Art der Vegetation und deren Häufigkeit an, insbesondere ob wir hier von Gras reden oder eher Bäumen.
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
Benutzeravatar
CodingCat
Establishment
 
Beiträge: 1856
Registriert: 02.03.2009, 22:25
Wohnort: Student @ KIT

Re: Dschungel-Rendering

Beitragvon Schrompf » 23.01.2013, 14:38

Hm, dann haben wir wohl verschiedene Definitionen von Renderjobs. Bei mir ist ein Renderjob quasi nur ein DrawCall mit dazugehörigen Daten, die lassen sich gut sortieren und gruppieren. Bei mir gibt es allerdings auch keine globale Job Queue, sondern nur ein Rudel Queues, die dynamisch für jeweils einen Renderpass allokiert und gefüllt werden, um danach sortiert und ausgeführt zu werden.

Das ist glaube ich der Hauptunterschied - Du gehst, wenn ich mich recht erinnere, ja von einer globalen Queue aus, die quasi statisch zur Szene gehört.
Häuptling von Dreamworlds. Baut an was Neuem. Hilft nebenbei nur höchst selten an der Open Asset Import Library mit.
Benutzeravatar
Schrompf
Thomas Ziegenhagen
Moderator
 
Beiträge: 3747
Registriert: 26.02.2009, 00:44
Wohnort: Dresden
Benutzertext: Lernt nur selten dazu

Re: Dschungel-Rendering

Beitragvon CodingCat » 23.01.2013, 15:17

Ich bin hier vor allem von Jonathans "Globalem Manager für Renderjobs" ausgegangen, wie genau das bei dir aussieht ging aus deinem Post ja ohnehin nicht hervor. Aber genau darauf wollte ich hinaus: Lieber Verwaltung und Rendering in spezialisierten Gruppen/Queues als in einer globalen Queue mit Objekten unbekannten Typs. Deinem letzten Post entnehme ich, dass du das genauso hälst.
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
Benutzeravatar
CodingCat
Establishment
 
Beiträge: 1856
Registriert: 02.03.2009, 22:25
Wohnort: Student @ KIT


Zurück zu Grafikprogrammierung

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 2 Gäste