Das Prozedurale Inhaltsgenerierung Framework (PCG) ist ein Werkzeugsatz zum Erstellen eigener prozeduraler Inhalte und Werkzeuge innerhalb der Unreal Engine. PCG GPU-Verarbeitung bietet technischen Künstlern und Designern die Fähigkeit, viele PCG-Verarbeitungsaufgaben direkt an die GPU zu senden, um Ressourcen auf der CPU verfügbar zu machen.
Die PCG GPU-Verarbeitung ist effizient für eine Vielzahl von Aufgaben, darunter die Punktverarbeitung, Laufzeitgenerierung und Statisches Mesh spawnen.
Die GPU-Verarbeitung ist derzeit auf einer kleinen Anzahl von Knoten verfügbar, darunter die Knoten Kopier-Punkte und Statisches Mesh Spawner sowie ein neuer Benutzerdefinierter HLSL-Knoten, der mit der HLSL-Sprache gescriptet werden können.
Zusätzliche Knoten, die die GPU-Ausführung unterstützen, werden in Zukunft verfügbar sein.
Knoten, die auf die GPU als Ziel festgelegt sind, werden im PCG-Diagramm mit GPU bezeichnet. Eine Teilmenge verbundener GPU-Knoten wird gemeinsam auf der GPU effizient ausgeführt und als Berechnungsdiagramm bezeichnet.
Number | Beschreibung |
1 | Übertragung von Daten zwischen CPU und GPU. Diese Punkte repräsentieren Performance Kosten. |
2 | GPU Ausführungsknoten, die zusammen ausgeführt werden. |
Die Ausrichtung auf die GPU kann zu Performance-Steigerungen gegenüber der CPU-Ausführung führen, wenn die Daten genügend Punkte enthalten, um die GPU-Hardware voll auszulasten. Zusätzlich bietet eine Sequenz von verbundenen GPU-Knoten mit einem GPU-aktivierten Statisches Mesh-Spawner-Knoten einen schnellen Pfad für Statisches Mesh spawnen.
Es ist wichtig zu beachten, dass die Übertragung von Daten zwischen CPU und GPU sowie die Vorbereitung eines Rechen-Diagramms für die Ausführung CPU-Kosten verursachen. Daher besteht die optimale Nutzung der GPU-Ausführungs-Funktion darin, GPU-fähige Knoten zu gruppieren und die Datenmenge, die in jeden Rechen-Diagramm hinein- und aus ihm heraus übertragen wird, zu minimieren.
Unterstützte Knoten
Benutzerdefinierter HLSL-Knoten
Der benutzerdefinierte HLSL Knoten kann für beliebige Datenverarbeitungsaufgaben verwendet werden, die über vom Benutzer erstellten HLSL Quellcode gescriptet werden. Der Quellcode wird in einen Compute-Shader injiziert und über Datenelemente parallel auf einer GPU-Hardware ausgeführt.
Dieser Knoten bietet Low-Level-Zugang zur GPU-Hardware und ist für fortgeschrittene Nutzer verfügbar.
Option
| Beschreibung |
Kernel Typ | Wählt eine Voreinstellung für das Verhalten des Knotens. Die verfügbaren Optionen sind im Benutzerdefinierte HLSL Knoten-Kernel-Typen Abschnitt weiter unten dokumentiert. |
Input-Pins | Definiert die Daten, die als Input verwendet werden. Das Öffnen des Rollouts bietet die folgenden Optionen:
|
Output-Pins | Definiert die Daten, die vom Knoten ausgegeben werden. Enthält die gleichen Optionen wie die Input-Pins, mit zusätzlichen Optionen zur Einstellung der Output-Daten. Diese werden im Abschnitt Pin-Einrichtung unten behandelt. |
Kernel-Quellen überschreiben | Wird verwendet, um Ihr Shader-Quelle-Feld durch ein UComputeSource-Asset zu ersetzen. |
Zusätzliche Quellen | Erlaubt Referenzen auf zusätzliche UComputeSource-Assets, die mit Ihrem benutzerdefinierten HLSL-Knoten gebündelt werden. |
Ungeschriebene Pin-Datenfehler stummschalten | Schaltet Warnungen auf Output-Pins mit potenziellen nicht initialisierten Daten stumm. |
Seed | Definiert den Seed-Wert, der zur Steuerung der Zufallsgenerierung verwendet wird. |
Cooked HLSL speichern | Gibt die Cooked-HLSL-Daten in das Log aus, wenn sie zum Debugging generiert werden. |
Datenbeschreibungen speichern | Gibt die Datenbeschreibungen der Input- und Output-Daten in das Log aus, wenn diese zum Debugging erstellt werden. |
Print Shader Debug Werte | Bietet einfaches Debug-Logging über Shader -Code. Behandelt in Debugging von benutzerdefinierten HLSL Abschnitt weiter unten dokumentiert. |
HLSL Quelle Editor
Der HLSL Quelle Editor ermöglicht die schnelle Erstellung von benutzerdefinierten HLSL Knoten. Er befindet sich im PCG Diagramm-Editor unter Fenster->HLSL Quelle Editor oder durch Auswahl eines benutzerdefinierten HLSL-Knotens und Klicken auf die Schaltfläche Open Source Editor in den Knoteneinstellungen.
Der HLSL-Quelle-Editor hat drei Teile:
Deklarationen-Panel
Shader-Funktionen
Shader-Quelle
Der Deklarations-Panel dient als API-Referenz zum Schreiben Ihres Shader-Codes. Die Deklarationen werden automatisch aus den benutzerdefinierten HLSL-Knoten-Einstellungen generiert, darunter der Kernel-Typ und die Input/Output-Pin-Einstellungen.
Das Feld Shader-Funktionen ermöglicht es Autoren, wiederverwendbare Funktionen zu erstellen, die in ihrer Shader-Quelle aufgerufen werden.
Das Feld Shader Quelle legt den Haupt-Einstiegspunkt für Ihre Kernel Implementierung fest.
Benutzerdefinierte HLSL-Knoten-Kernel-Typen
Der Kernel Typ definiert eine Voreinstellung für das Verhalten des Knoten.
Punkt Prozessor
Der Kernel-Typ Punkt Prozessor eignet sich ideal zum Modifizieren von Punkten. Dafür müssen der primäre Input und Output-Pin den Typ „Punkt“ haben und der HLSL Code wird einmal pro Punkt ausgeführt. Von den primären Output-Pins gesendete Daten haben dasselbe Layout wie die der primären Input-Pins, was bedeutet, dass die Anzahl der Daten und der Elemente identisch ist.
Alle Punkte im Primär-Output werden automatisch über den Primär-Input initialisiert, sodass Sie nur Output Attribute festlegen müssen, die geändert werden sollen.
Sie können den Prozessor auch nutzen, um zusätzliche Input- und Output-Pins zu erstellen, die Sie manuell konfigurieren müssen, um den gewünschten Datentyp und die Anzahl der Daten/Elemente festzulegen.
Punkt Generator
Der Kernel-Typ Punkt Generator eignet sich ideal zum Erstellen und Füllen eines Sets von Punkten. Dafür muss der primäre Output-Pin den Typ „Punkt“ haben und führt den HLSL Code einmal für jeden Punkt aus.
Dieser Kernel -Typ hat die folgenden zusätzlichen Optionen:
Option
| Beschreibung |
Punktanzahl
| Bestimmt die Anzahl der Punkte, die generiert werden. Der Shader-Code wird auf jedem generierten Punkt ausgeführt. |
Ähnlich wie mit dem Punkt-Prozessor können Sie den Punkt-Generator verwenden, um zusätzliche Input- und Output-Pins zu erstellen, die Sie manuell konfigurieren müssen, um den gewünschten Datentyp und die Anzahl der Daten oder Elemente festzulegen.
Benutzerdefiniert
Der Kernel-Typ Benutzerdefiniert ermöglicht eine fein abgestimmte Kontrolle über die Ausführung für erweiterte Anwendungsfälle. Im Gegensatz zu den anderen beiden Kernel-Typen werden an den Input- oder Output-Pins keine Einstellungen erzwungen, da der Knoten keine spezifische Beziehung zwischen Input und Output annimmt. Die Output-Daten müssen in den Output-Pin-Einstellungen konfiguriert werden, die unten dokumentiert sind. Die Anzahl der Threads, die den Shader-Code ausführen sollen, muss ebenfalls konfiguriert werden.
Dieser Kernel -Typ hat die folgenden zusätzlichen Optionen:
Option | Beschreibung |
Thread-Anzahl versenden | Bestimmt die Anzahl der Threads, die der Shader-Code zur Ausführung verwendet. Die folgenden Modi sind verfügbar:
|
Pin-Einrichtung
Alle Pins, die nicht vom Kernel-Typ angesteuert werden, sollten manuell konfiguriert werden.
Für Output-Pins ist es erforderlich, die Daten-Größe und das Layout explizit zu beschreiben. Diese können unter dem Dropdown-Liste-Menü GPU Eigenschaften in den Einstellungen für Output-Pin festgelegt werden.
Initialisierungsmodus | Beschreibt, wie die Output-Daten für diesen Pin initialisiert werden. Das Menü enthält die folgenden Modi:
|
Pins zum Initialisieren von | Definiert die Input-Pins, mit denen die Daten dieses Pins initialisiert werden sollen. |
Datenanzahl-Modus | Definiert die Anzahl der Datenobjekte. Das Menü enthält die folgenden Modi:
|
Datenvielfalt | Kombiniert die Anzahl der Daten, wenn mehrere Pins zum Initialisieren vorhanden sind. Verfügbare Modi:
|
Elementanzahl-Modus | Definiert die Anzahl der Elemente. Das Menü enthält die folgenden Modi:
|
Elementvielfalt | Kombiniert die Anzahl der Elemente, wenn mehrere Pins zum Initialisieren vorhanden sind. Verfügbare Modi:
|
Attributvererbungsmodus | Definiert, wie Attributnamen, Typen und Werte vererbt werden. Das Menü enthält die folgenden Modi:
|
Attribute zum Erstellen | Definiert eine Liste neuer Attribute, die in den Output-Daten erstellt werden sollen. |
Debugging von benutzerdefinierten HLSL
Die Funktionen „Debug-Anzeige“ (Standard-Tastaturkürzel „D“) und „Untersuchung“ (Standard-Tastaturkürzel „A“) funktionieren für GPU-Knoten und aktivieren die Untersuchung der Daten, die durch die GPU-Knoten fließen.
Es ist auch möglich, benutzerdefinierten Shader-Code zu debuggen, indem Sie die Option „Shader-Debug-Werte ausgeben“ im Knoten „Benutzerdefiniertes HLSL“ aktivieren. Dadurch wird eine neue Funktion WriteDebugValue verfügbar, die verwendet werden kann, um Float in einen Buffer zu schreiben, der während der Ausführung protokolliert wird. Die Größe wird durch die Eigenschaft Debug Buffer Größe kontrolliert.
Beispiele
Beispiel 1: Höhenversatz mit einer Sinuskurve
Im folgenden Beispiel wird ein Punkt-Prozessor verwendet, um einen Sinuskurve-basierten Höhenversatz auf einen Satz von Punkten anzuwenden.
Der folgende Code wird zum Feld Shader-Quelle des Fensters des HLSL Quelle Editor hinzugefügt:
// Get the position of the incoming point from input pin ‘In’.
float3 Position = In_GetPosition(In_DataIndex, ElementIndex);
// Compute a sine wave with amplitude 500cm and wavelength 400cm.
const float Wave = 500.0f * sin(Position.x / 400.0f);
// Add the wave to the Z coordinate of the point’s position.
Position.z += Wave;
// Write the offset position to the output point on pin ‘Out’.
Beispiel 2: Erstellen eines Attributs
Im folgenden Beispiel wird ein Punkt-Generator verwendet, um ein Raster aus Punkten zu erstellen und verwendet ein Attributsatz, um die Höhe des Rasters zu kontrollieren.
Der folgende Code wird zum Feld Shader-Quelle des Fensters des HLSL Quelle Editor hinzugefügt:
// Get PCG Component bounds.
const float3 BoundsMin = GetComponentBoundsMin();
const float3 BoundsMax = GetComponentBoundsMax();
// Get the current point position in a 2D grid, based on the
// number of points and the component bounds.
float3 Position = CreateGrid2D(ElementIndex, NumPoints, BoundsMin, BoundsMax);
Position.z += InHeight_GetFloat(0, 0, 'GridHeight');
// Set the point's position.
Atribute können im Shader-Code mithilfe der bereitgestellten Get- und Set-Funktionen abgerufen werden. Das Abfragen der Attribute nach Namen erfolgt durch Einschließen in Anführungszeichen. Zum Beispiel, ‚GridHeight‘.
Beispiel 3: Zufällige Meshs in einer Landschaft spawnen
Der benutzerdefinierte HLSL Knoten kann auch eine Sequenz von Operationen ausführen.
Im folgenden Beispiel führt der Shader-Code die folgenden Operationen aus:
Erstellt mehrere Punkte in einer Landschaft.
Wendet eine zufällig Position auf jeden Punkt an.
Legt die Punktposition fest
Schreibt einen zufälligen Seed-Wert in jeden Punkt
Liest einen Attributsatz, der eine Liste statischer Meshs enthält, und weist jedem Punkt ein zufälliges Mesh zu.
Unterhalb des benutzerdefinierten HLSL-Knotens befindet sich ein statischer Mesh-Spawner mit aktivierter GPU-Ausführung und dem Mesh-Attributsatz ‚MeshPath‘.
Bei GPU-Attributen des Typs String, String-Name, Sanfter Objekt Pfad, Sanfter Klassen Pfad werden sie zu StringKeys, die jeden String eindeutig identifizieren.
Der folgende Code wird dem Feld Shader-Quelle des Fensters der HLSL-Quelle hinzugefügt:
// Get generation volume bounds
const float3 BoundsMin = GetComponentBoundsMin();
const float3 BoundsMax = GetComponentBoundsMax();
// Compute a position on a 2D grid within the volume.
float3 Pos = CreateGrid2D(ElementIndex, NumPoints, BoundsMin, BoundsMax);
// Initialize the random seed from the position.
uint Seed = ComputeSeedFromPosition(Pos);
Statischer Mesh-Spawner-Knoten
Sie können den Statischen Mesh-Spawner-Knoten auf der GPU ausführen lassen, indem Sie in den Knoteneinstellungen die Option Auf GPU ausführen aktivieren.
Prozedurale Instanzierung
Wenn der Statische Mesh Spawner auf der GPU ausgeführt werden soll, erstellt er Mesh-Instanzen komplett auf der GPU, was CPU-Zeit und Speicher spart. Dies wird die Prozedurale instanzierte Statische Mesh-Komponente verwenden. Dies kann ein sehr effizienter Pfad zum Spawnen von Meshs sein, ist aber experimentell und bringt folgende Kompromisse mit sich:
Instanzen werden in keiner Weise persistent oder gespeichert. Sie existieren nur zur Laufzeit im GPU Speicher.
Daher ist der primäre Anwendungsfall die Laufzeitgenerierung.
Statische gebakte Beleuchtung und HLOD erfordern persistente Instanz und werden zur Zeit ebenfalls nicht unterstützt.
Mehrere Funktionen erfordern derzeit CPU-Zugriff zu Instanzdaten und werden nicht unterstützt:
Kollisionen / Physik
Navigation
Ray Tracing
Distanzfeldbeleuchtung beeinflussen
Die GPU Implementierung ist experimentell und nicht alle Funktionen von Statisches Mesh Spawner werden unterstützt.
Mesh-Selektortypen
Die folgenden Mesh-Selektoren werden bei der Ausführung auf der GPU unterstützt. Aufgrund der Art der Instanzierung gibt es geringfügige Unterschiede im Verhalten.
Gewichtet (PCGMeshSelectorWeighted)
Ähnlich wie bei der CPU-Implementierung verwendet dieser Modus die Input Zufallsgenerator und die konfigurierten Auswahlgewichte, um das Mesh für jede Instanz zufällig auszuwählen. Diese Meshs müssen auf dem Knoten festgelegt werden und dürfen nicht durch Attribute gesteuert werden.
Das System verwendet Gewichte, um zu bestimmen, wie viele Instanzen jedem Mesh zugewiesen werden sollen. Eine Überbelegung wird auf der Grundlage einer Heuristik vorgenommen, um die Wahrscheinlichkeit zu minimieren, dass die Belegung für eine oder mehrere Primitive gesättigt wird und Instanzen verloren gehen.
Dieser Modus ist vom Seed-Attribut der Punkte abhängig, die gut initialisiert sind, zum Beispiel durch Verwendung der bereitgestellten Shader-Funktion ‚ComputeSeedFromPosition()‘. Wenn alle Punkt-Seeds auf denselben Wert gesetzt sind, wird für alle Punkte dieselbe Auswahl getroffen, und die geschätzte Zuweisung kann überschritten werden, was dazu führt, dass Instanzen im Ergebnis fehlen.
Mit Attribut (PCGMeshSelectorByAttribute)
Andere Mesh-Selektortypen (zum Beispiel PCGMeshSelectorWeightedByCategory) werden derzeit bei der Ausführung auf der GPU nicht unterstützt.
Die endgültige Anzahl der zugewiesenen Instanzen kann untersucht werden, indem die generierten Prozedural instanzierten statischen Mesh-Komponenten ausgewählt und die Eigenschaft Num Instanzen überprüft werden.
Instanzdatenpaketierung
Ähnlich wie bei der CPU-Ausführung können Attribute in Instanzdaten gepackt werden.
Das System muss vor der GPU-Ausführung wissen, wie viele Attribute gepackt werden, daher wird nur der Packertyp nach Attributen (PCGInstanceDataPackerByAttribute) unterstützt.
Andere Knoten
Die folgenden Knoten unterstützen aktuell die GPU-Ausführung:
Punkte kopieren
Attributaufteilung
Unterstützt aktuell nur die Aufteilung nach Attributen des Typs String, Soft-Objektpfad oder Soft-Klasse-Pfad.
Normal zu Dichte
Datenanzahl
Spawner für statisches Mesh
Benutzerdefiniertes HLSL
CPU Ausführung nicht unterstützt.
Berechnungsquellen
Berechnungsquelle-Assets machen den Austausch von Quellcode einfacher und verringern die Duplizierung von Code zwischen Knoten.
Die Assets unterstützen die Inline-Bearbeitung des HLSL-Quellcodes mit Syntaxhervorhebung und PCG-spezifischer Syntax wie Daten-Labels und Attributnamen.
Berechnungsquelle-Assets können auch auf andere Berechnungsquellen-Assets verweisen, indem Sie die Eigenschaft Zusätzliche Quellen verwenden, die Abhängigkeitshierarchien zwischen mehreren Berechnungsquellen erstellt.
Daten-Labels
Daten-Labels können verwendet werden, um in benutzerdefinierten HLSL Quellen auf Daten nach Label statt nach Index zu verweisen. Daten-Labels werden über Tags mit dem Präfix PCG_DATA_LABEL an Daten übermittelt.
Einige Knoten kennzeichnen ihre Output-Daten automatisch, darunter:
Texturdaten abrufen
Virtuelle Texturdaten abrufen
Gras-Maps generieren
Generierung von Gras-Maps
PCG unterstützt das Sampling von Landschaftsgras-Ebenen aus einem bestimmten Landschaftsmaterial, um prozedurale Laufzeit-Generierungs-Workflows zu unterstützen.
Richten Sie Ihr Landschaftmaterial mit einem Landschaftsgras Output-Knoten ein. Weitere Informationen zum Einrichten eines Landschaftsmaterials findest du unter Landschaftsmaterialien.
Verbinden Sie Ihre Landschaftsdaten mit einem Gras-Maps generieren Knoten. Wählen Sie die gewünschten Grasarten direkt über die Überschreiben oder durch Ausschluss aus.
Beispielen Sie Ihre Gras-Map-Texturen. Sie können nach Index oder den automatisch zugewiesenen Daten-Labels samplen. Der folgende Code wird zum Feld Shader-Quelle des Fensters des HLSL Quelle Editor hinzugefügt:
float3 Min = GetComponentBoundsMin();
float3 Max = GetComponentBoundsMax();
float3 Position = CreateGrid2D(ElementIndex, NumPoints, Min, Max);
uint Seed = ComputeSeedFromPosition(Position);
Position.xy += (float2(FRand(Seed), FRand(Seed)) - 0.5) * 45.0;
Position.z = LS_GetHeight(Position);
float Density = FRand(Seed);
float Thresh = GrassMaps_SampleWorldPos('GSM_PCGGrass1', Position.xy).x;
Wenn Sie vorhaben, Ihre Gras-Map-Texturen nur auf der GPU zu samplen, können Sie im PCG-Graphen die Option „Zurückschreiben auf die CPU überspringen” aktivieren, um die Performance deutlich zu verbessern.
Gemalte Landschaftsebenen:
Ergebnisgenerierung:
Verwendung von virtuellen Texturen in PCG
PCG unterstützt die Nutzung von virtuellen Texturen als Teil Ihres Workflow zum prozeduralen Inhalt.
Virtuelle Textur Sampling
Virtuelle Texturen können aus Landschaftsdaten gesamplet werden, um die Performance des Höhen-Samplings zu verbessern.
Beispiel 1: Landschaftsdaten
Um Landschaft mit virtuellen Texturen zu sampeln, stellen Sie sicher, dass Sample V in den Einstellungen der Knoten Landschaftsdaten abrufen aktiviert ist. Dies gibt dem Landschaft-Daten-Knoten die Fähigkeit, beliebige virtuelle Texturen, die durch das entsprechende Landschaft-Material bereitgestellt werden, zu verwenden.
Dies wirkt sich nur auf das GPU Sampling aus.
// Get Position and Height
float3 Position = CreateGrid2D(ElementIndex, NumPoints, GetComponentBoundsMin(), GetComponentBoundsMax());
Position.z = A_GetHeight(Position);
// Get Normal and Orientation
const float3 Normal = A_GetNormal(Position);
const FQuat Orientation = QuatFromNormal(Normal);
// Get Base Color
const float3 BaseColor = A_GetBaseColor(Position);
Beispiel 2: Virtuelle Texturdaten
Um eine virtuelle Textur zu sampeln, fragen Sie die Welt nach Komponenten für virtuelle Textur zur Laufzeit ab. Jede davon erzeugt virtuelle Texturdaten, mit einem Daten-Label für die Virtuelle Textur zur Laufzeit Asset getaggt.
float3 Position = CreateGrid2D(ElementIndex, NumPoints, GetComponentBoundsMin(), GetComponentBoundsMax());
// Sample virtual textures
bool bInsideVolume;
float3 BaseColor;
float Specular;
float Roughness;
float WorldHeight;
float3 Normal;
float Displacement;
Vorbereitung für virtuelle Textur
Es ist wichtig, sicherzustellen, dass die virtuellen Texturen vorbereitet werden, da Ihre Sampling-Ergebnisse sonst ungenau sein können.
Um die Vorbereitung für virtuelle Textur anzufragen, fügen Sie Parameter Ihrem PCG Diagramm des Typs FPCGVirtualTexturePrimingInfo hinzu. Dadurch werden folgende Optionen angezeigt:
Virtuelle Textur | Definiert die virtuelle Textur, die vorbereitet werden soll. |
Raster | Definiert das größte Raster, auf dem die virtuelle Textur im Diagramm gesampelt wird. Die virtuellen Texturen werden für den durch dieses Raster vorgegebenen Radius vorbereitet. |
Welt Texel Größe | Definiert die gewünschte Größe eines Texels in der vorbereiteten virtuellen Textur. Dadurch wird bestimmt, welcher Mip-Map-Level vorbereitet werden soll. |
Sie können die Vorbereitung für virtuelle Textur mit dem Konsolenbefehl pcg.VirtualTexturePriming.Enable steuern. Sie können diese Funktion mit dem Befehl pcg.VirtualTexturePriming.DebugDrawTexturePrimingBounds debuggen.