Nanite-Vegetation ist eine Reihe integraler Systeme, die Nanites virtualisiertes Geometrie-Rendering verwenden, um dichte, extrem detaillierte Vegetation in großem Maßstab zu erzielen. Nanite-Vegetation nutzt alte und neue Techniken, um offene Welten mit großen Ausblicken und höherer Qualität zu einem Bruchteil der ursprünglichen Frame-Kosten zu rendern. Sie nutzt Instanziierung, geskinnte Meshs, Voxelisierung, Animation und Materialmerkmale. Die Kombination ermöglicht es, stabilere Welten mit lebensechter und animierter Vegetation zu erschaffen.
Um die Ziele von Nanite-Vegetation und ihre Entwicklung zu verstehen, ist es wichtig zu verstehen, dass das, was in der Vergangenheit funktioniert hat, für die Zukunft bei der Erschaffung dieser Art von vollständig realisierten Welten nicht mehr effizient ist.
Schauen wir uns an, warum die „alte Art“ der Entwicklung von Vegetation für Nanite-Vegetation nicht gut funktioniert:
Alpha-Maskierung: Nanite funktioniert damit nicht gut, da es zu viel Überziehen führt und eine möglicherweise teure Maskenfunktion ausgeführt werden muss. Die Verwendung der Alpha-Maskierung bedeutet auch, dass Vegetation weiterhin als flache Karten gerendert würde und nicht mit der geometrischen Komplexität, die möglich ist.
Vollständige Nanite-Dreieckdarstellung: Dies führt zu suboptimalem Ausblenden von Clustern und schlechter Simplifizierung in der Ferne. Zudem würde jede Vegetationsart viel Festplattenspeicher erfordern, um sie zu speichern.
Welt-Positionsversatz (WPO): Die Verwendung von WPO in einem Material zur Bewegung von Blättern und Zweigen der Vegetation ist eine Möglichkeit, um Wind zu simulieren. Das ist keine gute Wahl für das, was Nanite rendern kann, da es Berechnungen pro Scheitelpunkt hinzufügt und suboptimale Cluster-Grenzen erzwingt, da man nicht wissen kann, wie ein Material einen Scheitelpunkt bewegt, was bedeutet, dass die Berechnungen konservativer sein müssen.
Du hast jetzt eine ungefähre Vorstellung davon, was nicht gut funktioniert. Sehen wir uns die Nanite-Vegetation-Pipeline an, um vollständig modellierte Bäume zu rendern, bis hin zu einzelnen Blättern und Nadeln. Sie muss auf große offene Welten skalierbar und dabei speichereffizient, performant und dynamisch sein, ohne dass Detailgrad-Meshs (LOD) benötigt werden.
Zu diesem Zweck besteht Nanite-Vegetation aus drei Systemen:
Nanite-Zusammensetzungen sind die „Teile“, die zu extrem detaillierten Instanzen bei einem Stück Vegetation werden. Dies kann Speicher- und Festplattengröße erheblich verringern.
Nanite-Voxel sind Ansammlungs-Voxel in nahezu Pixelgröße, die Dreieckdetails, Animation und Materialeigenschaften basierend auf der Kameraentfernung speichern. Dreiecke können nahtlos zu Voxeln werden, um das Problem des Renderings von dichten und dynamisch aggregierten Dreieck-Meshs zu lösen. Diese Voxel sind für das Auge aufgrund ihrer Größe auf dem Bildschirm nicht zu erkennen.
Nanite-Skinning definiert, wie Vegetation sich dynamisch mit Systemen wie Wind verhält, wobei Wind durch eine Bone-Hierarchie simuliert wird. Da Nanite-Vegetation kein WPO zur Simulation von Animation verwendet, kann es optimale Clustergrenzen verwenden.
Im folgenden Beispiel siehst du, wie all dies zusammenkommt. Wenn die Kamera in das Detail hineinzoomt, siehst du, wie dicht und detailliert der Baum bis hinab zu den einzelnen Tannenzweigen ist. Wenn sich die Kamera weiter entfernt, gehen die Nanite-Cluster nahtlos in Voxel über, sobald sie klein genug werden. So können Bäume ihr volumetrisches Aussehen auf Entfernungen beibehalten, ohne auf Reklametafeln oder LODs in der Ferne zurückgreifen zu müssen.
Dieser Baum besteht aus:
41 Millionen Dreiecken
12 einzigartigen Zusammensetzungsteilen
2160 Zusammensetzung-Teilinstanzen
850 Skelett-Bones
Aktivieren von Nanite-Vegetation
Um Nanite-Vegetation für dein Projekt zu aktivieren, navigiere zu Projekteinstellungen > Rendering und aktiviere das Feld für Nanite-Vegetation. Du musst den Editor neu starten, damit die Änderungen wirksam werden.
Nanite-Zusammensetzungen
Nanite-Zusammensetzungen sind eine Schlüsselkomponente von Nanite-Vegetation und wurden entwickelt, um das Rendering komplexer, wiederholbarer Geometrie wie Ästen und Wedeln eines Baumes effizient zu verarbeiten. Zusammensetzungen arbeiten sowohl mit statischen als auch mit Skelett-Mesh-Assets und ermöglichen die „Mikro-Instanziierung“ kleiner, extrem detaillierter Teile. Sie können bis zu 65.000 Instanzen anderer Meshs enthalten. Diese Instanzen werden als „Teile“ der Zusammensetzung bezeichnet. Dieser Ansatz spart eine erhebliche Menge Festplatten- und Streaming-Speicher, wobei er einen kleinen Performance-Kompromiss beim Cluster-Ausblenden hat.
Nanite-Zusammensetzungen arbeiten mit den Clustern der Teil-Meshs und codieren sie in der Hierarchie des endgültigen Mesh, ohne die Geometrie der Teile zur Erstellungszeit zu duplizieren. Zur Laufzeit handhabt Nanite die Teil-Instanzen, indem es ihre endgültige Transformation auf Anfrage während des Cluster-Ausblendens berechnet, während es in der Hierarchie abwärts arbeitet.
Auf Nicht-Nanite-Plattformen werden die Dreiecke der Teile transformiert und zu einem einzigen Mesh zusammengeführt. Von dort aus wird es vereinfacht, um ein Fallback-Mesh zu erstellen, das genauso funktioniert wie reguläre Nanite-Fallback-Meshs.
Zusammensetzungen sind ein wichtiger Bestandteil von Nanite-Vegetation. Ohne sie gäbe es nicht genug Festplatten- oder Streaming-Speicher, um einen großen Wald zu rendern, wie er in der technischen Demo von Unreal Fest The Witcher 4 zu sehen ist. Zum Beispiel verringerte sich der UASSET-Festplattenspeicher des größten Baums in der Demonstration von 3,5 Gigabyte (Gb) auf etwa 29 Megabyte (Mb). Der Streaming-Speicher nur eines der Bäume in einer bestimmten Ansicht wurde von etwa 36 Mb auf etwa 2,7 Mb verringert. Durch diese Art des Speicherns ist es möglich, 500.000 Instanzen von Dutzenden von Baumvarianten in einer Szene zu rendern, wobei jeder Baum extrem detailliert ist und jeweils zwischen einer und zehn Millionen Polygonen aufweist.
Weitere Informationen zur Verwendung und Erstellung von Nanite-Zusammensetzungen in Unreal Engine findest du unter Nanite-Zusammensetzungen.
Nanite-Voxel
Nanite-Voxel sind Voxel in fast Pixelgröße, die Detail, Animation und Materialeigenschaften der repräsentierten Geometrie sowie das volumetrische Aussehen von Dingen, wie etwa Blätter von Bäumen, erhalten. Frühere Nanite-Techniken, die verhindern sollten, dass Blätter in der Ferne ihre Form verlieren, funktionierten gut genug, indem bei den überlebenden Dreiecken wieder ein Oberflächenbereich hinzugefügt wurde, wenn sie durch den Vereinfachungsprozess eliminiert wurden. Das war eine Korrektur dafür, dass die Vegetationsgeometrie spärlich wurde, wenn vereinfachte Cluster in der Ferne gerendert wurden.
Rasterisierungsprozess
Nanite-Voxel können die allgemeine Silhouette der Geometrie (nicht verbundene Stücke) während der Vereinfachung auf Distanz erhalten. Beim Vereinfachen von Clustern dieser voxel-fähigen Meshs voxelisiert Nanite Builder diese in Cluster von maximal 128 4x4x4-Voxel-Blöcken. Der Vereinfachungsfehler der Voxel-Darstellung ist der entscheidende Faktor, ob die Vereinfachung den Wechsel von Dreiecken zu Voxeln vornimmt. Sie wechselt zu Voxeln, wenn dies zu einem geringeren Fehler führen würde als die Verwendung von Dreiecken.
Zur Laufzeit werden Voxel-Cluster getrennt von Dreieck-Clustern ausgelagert und mit einer speziellen Shader-Permutation gerastert. Die Cluster werden in Tiefen-Buckets sortiert und von vorne nach hinten gerastert, um die Vorteile früher Z-Tests zu erzielen, wobei das Endergebnis in der Regel eine bessere Distanz über gerasterte Dreiecke erreicht.
Unten findest du einige Beispiele der Voxelisierung, visualisiert an einem eigenständigen Asset und in der technischen Demo von „The Witcher 4“.
Shader-Prozess
In dem Bereich, der von einem einzigen Voxel abgedeckt wird, können viele Oberflächen mit unterschiedlichen Normalen enthalten sein. Anstatt eine einzige Normale pro Voxel zu speichern, wird eine Verteilung von Normalen gespeichert. Dieses Konzept ähnelt der Art und Weise, wie die Materialrauheit die Verteilung von Mikrofacetten für die Schattierung steuert.
Beim Schreiben in den GBuffer wird stochastisch pro Pixel eine Normale aus dieser Verteilung gewählt. In einer zukünftigen Version wird diese Verteilung direkt in der Schattierung berücksichtigt, ebenso wie die Rauheit. Das verringert Rauschen und wurde bereits in der Demo von Witcher 4 verwendet.
Dies erfordert zusätzliche Daten, um die Statistik für die Verteilung zu speichern. Aktuell wird das im Alpha-Kanal der Scheitelpunktfarbe gespeichert, was bedeutet, dass alles überschrieben wird, was dort war. Dies kann in Zukunft dazu führen, dass Daten unabhängig von der Scheitelpunktfarbe getrennt werden.
Aktivieren von Nanite-Voxeln
So aktivierst du die Nanite-Voxelisierung:
Suche im Details-Panel in einem statischen Mesh in der Kategorie Nanite-Einstellungen.
Suche Formbeständigkeit und verwende die Dropdown-Liste, um Voxelisieren auszuwählen.
Einige Eigenschaften unter dieser Dropdown-Liste werden verfügbar, um zu bearbeiten, wann Voxelisieren festgelegt wird. Diese sollten in den meisten Fällen (wenn überhaupt) in Projekten nicht angepasst werden. Einige befinden sich noch in Entwicklung und funktionierten aktuell noch nicht wie beabsichtigt, wenn überhaupt. Diese Einstellungen werden sich in zukünftigen Versionen von Unreal Engine wahrscheinlich ändern oder entfernt werden, wenn Nanite-Vegetation ausgereifter ist.
Verwendung von Nanite-Skinning für die Animation von Nanite-Vegetation
Wenn es um Animation von Vegetation in Spielen geht, wird ein Großteil davon mit Welt-Positionsversatz (World Position Offset, WPO) im Material durchgeführt, normalerweise bei Materialien für Äste und Blätter von Bäumen. Da der WPO für einen bestimmten Scheitelpunkt ein beliebiger Versatz sein kann, müssen Künstler die maximale WPO-Verschiebung eines beliebigen Materials für den ungünstigsten Fall festlegen, um die Ausblendungsgrenzen für die korrekte Ausblendung dieser Vegetations-Assets aufzufüllen. Das kann jedoch zu übermäßig konservativen Grenzen führen, die zu hohen Überziehungskosten beitragen.
Da WPO auch die Scheitelpunkt-Shader-Logik ändert, wird jedes Material in separate Absendungen aufgeteilt, was mit GPU-Kosten verbunden ist. Bei vielen Materialien können diese programmierbaren Raster-Behälter ein Performance Problem darstellen.
Nanite-Skinning behebt dieses Problem, da genauere Grenzen aus Skinning-Matrizen berechnet werden können und alles den Rasterisierer mit fester Funktion verwenden kann.
Im folgenden Bild werden 100.000 Bones aktualisiert, was auf der GPU etwa 0,1 Millisekunden dauert, was Nanite-Vegetation sehr schnell und skalierbar macht. Bei Bäumen wird eine Animation nicht mehr automatisch angewendet, wenn sie eine bestimmte Größe unterschreitet. Wind kann auf Bäume in sehr großer Entfernung einwirken, um die Immersion zu verbessern. Das gilt auch für Gras und Sträucher, die Skelett-Meshs nutzen.
Plugin Dynamic Wind
Dieses Plugin ist experimentell.
Das Plugin Dynamic Wind ist auf die Kombination mit Nanite-Vegetation ausgelegt. Es erfordert eine gewisse zusätzliche Einrichtung mit einem Dynamic Wind Skeletal Data-Asset für ein bestimmtes Skelett-Mesh. Die Daten in diesem Asset klassifizieren Bones des Skeletts in Simulationsgruppen, die dem System helfen, Bone-Ketten in der Simulation logisch zu identifizieren und es dir ermöglichen, den Windeinfluss pro Gruppe anzupassen.
Du kannst das Plugin im Plugins-Browser unter der Kategorie Rendering aktivieren.
Das Plugin bietet eine skriptgesteuerte Asset-Aktion, mit der die notwendigen Daten aus einer .JSON-Datei importiert werden können. Hier findest du auch ein USD-Schema (Universal Scene Description), das du auf ein Skelett anwenden kannst, um diese Daten bereitzustellen, sowie ein Beispiel-Python-Script zum Erstellen einer JSON-Datei aus dem USD.
Transformations-Provider-Daten für Dynamic Wind
Skelett-Meshs, die Benutzerdaten aus einem Dynamic Wind Data-Asset enthalten, können diese Daten verwenden, um Windanimation in einer instanziierten Geskinntes-Mesh-Komponente zu steuern.
Um Wind auf einem geskinnten Mesh zu aktivieren, musst du die Dropdown-Liste Transformations-Provider auf der Komponente verwenden, um die Transformations-Provider-Daten auszuwählen. Dadurch wird ein neues Dynamic Wind Data-Asset für das Mesh erstellt.
Dieses Asset wird benötigt, um die Komponente im Windsystem zu registrieren. Sie dient (zu diesem Zeitpunkt) keinem anderen Zweck.
Die aktuellen Einschränkungen sind:
Hinzufügen einer stärker physikbasierten Simulation wie Nahfeld.
Bietet nur Unterstützung für die globale Windrichtung.
Keine Kollision mit Spielern oder Objekten.
Die Dynamischer-Wind-Skelettdaten müssen mit einer JSON-Datei importiert werden.
Für die Zukunft ist geplant, dass dies beim Importieren eines USD automatisch importiert wird.
Hinzufügen von Anpassungen an den Dynamischer-Wind-Transformations-Provider-Daten.
Performance-Tipps für Nanite-Skinning
Obwohl Nanite-Skinning bei Bewegung durch Vegetation besser funktioniert als WPO, ist es trotzdem wichtig, auf die Performance zu achten.
Beachte folgende Bereiche:
Die Performance bei virtuellen Shadow-Maps (VSM) erfordert, dass du die Animation in der Ferne deaktivierst.
Instanziierte Meshs, die deaktiviert sind, wechseln zu einem nicht geskinnten Raster-Behälter und werden wie ein statisches Mesh mit einer festen Funktion gerendert (in Binden-Pose).
Nutze Min. Bildschirmgröße der Animation für die Komponente, um das Skinning zu deaktivieren, wenn das Objekt auf dem Bildschirm klein ist.
Dies ähnelt der Einstellung Weltpositionsversatz, Deaktivierungsdistanz, abgesehen davon, dass sie immer aktiv ist. Wenn dies auf 0 belassen wird, wird der globale Standardwert verwendet, der 1/10 (0,1) der Größe des Objekts entspricht, wenn die Animation angehalten wird. Du kannst dies mit dem Konsolenbefehl
r.Skinning.DefaultAnimationMinScreenSizeändern.