Le framework de génération procédurale de contenu (PCG) est une trousse à outils qui vous permet de créer vos propres contenus et outils procéduraux dans l'Unreal Engine. Le traitement de PCG avec le processeur graphique permet aux artistes et concepteurs techniques d'envoyer de nombreuses tâches de traitement par PCG directement au processeur graphique afin de libérer des ressources sur le processeur.
Le traitement PCG avec processeur graphique est efficace pour diverses tâches, comme le traitement de points, la génération en temps d'exécution et la génération de maillage statique.
Le traitement par le processeur graphique est actuellement disponible sur un petit nombre de nœuds, notamment des points de copie et le générateur de maillage statique, ainsi qu'un nouveau nœud HLSL personnalisé ajouté. Il peut être scripté à l'aide du langage HLSL.
D'autres nœuds prenant en charge l'exécution sur le processeur graphique seront disponibles à l'avenir.
Les nœuds configurés pour cibler le processeur graphique sont étiquetés avec processeur graphique dans le graphique PCG. Un sous-ensemble de nœuds de processeur graphique connectés s'exécute conjointement de manière efficace sur le processeur graphique et est appelé un graphique de calcul.
Number | Description |
1 | Transfert de données entre le CPU et le processeur graphique. Ces points représentent un coût en performances. |
2 | Les nœuds d'exécution du processeur graphique qui sont exécutés ensemble. |
Le ciblage du processeur graphique peut augmenter les performances par rapport à l'exécution du processeur lorsqu'il existe suffisamment de points dans les données pour utiliser pleinement le matériel du processeur graphique. De plus, une séquence de nœuds de processeur graphique connectés par un nœud générateur de maillage statique compatible avec le processeur graphique offre un chemin rapide pour l'apparition des maillages statiques.
Il est important de noter que le transfert de données entre le processeur et le processeur graphique ainsi que la préparation d'un graphique de calcul pour l'exécution implique un coût en processeur. Par conséquent, la meilleure façon d'utiliser la fonctionnalité d'exécution du processeur graphique consiste à regrouper les nœuds compatibles avec le processeur graphique et à réduire au minimum la quantité de données transférées vers et depuis chaque graphe de calcul.
Nœuds pris en charge
Nœud HLSL personnalisé
Le nœud HLSL personnalisé peut être utilisé pour des tâches de traitement de données arbitraires qui doivent être scriptées via un code source HLSL créé par l'utilisateur. Le code source est injecté dans un shader de calcul et exécuté sur des éléments de données en parallèle sur le matériel du processeur graphique.
Ce nœud fournit un accès de bas niveau au matériel du processeur graphique et il est disponible pour les utilisateurs avancés.
Option
| Description |
Type de noyau | Sélectionne un préréglage pour le comportement du nœud. Les options disponibles sont documentées dans la section Types de noyau de nœud HLSL personnalisés ci-dessous. |
Broches d'entrée | Définit les données prises en entrée. Si vous ouvrez la liste déroulante, vous aurez accès aux options suivantes :
|
Broches de sortie | Définit les données de sortie du nœud. Regroupe les mêmes options que les broches d'entrée, avec des options supplémentaires pour paramétrer les données de sortie. Elles sont abordées dans la section Configuration des broches ci-dessous. |
Remplacement de la source du noyau | Utilisé pour remplacer votre champ Source Shader par une ressource UComputeSource. |
Sources supplémentaires | Permet de référencer des ressources UComputeSource supplémentaires à empaqueter avec votre nœud HLSL. |
Désactiver les erreurs de données de broche non écrites | Met en sourdine les alertes sur les broches de sortie avec des données potentiellement non initialisées. |
Valeur de départ | Définit la valeur de départ utilisée pour piloter la génération aléatoire. |
Vider le HLSL préparé | Affiche les données HLSL préparées dans le journal lorsqu'elles sont générées à des fins de débogage. |
Vider les descriptions de données | Affiche les descriptions des données d'entrée et de sortie dans le journal lorsqu'il est généré pour le débogage. |
Afficher les valeurs de débogage du shader | Fournit une journalisation de débogage simple à partir du code Shader. Abordé dans Débogage du HLSL personnalisé ci-dessous. |
Éditeur de source HLSL
L'éditeur de source HLSL permet de créer rapidement des nœuds HLSL personnalisés. Vous pouvez le trouver dans l'éditeur de graphique PCG, sous Fenêtre-> Éditeur de source HLSL, ou en sélectionnant un nœud HLSL personnalisé et en cliquant sur le bouton Ouvrir l'éditeur source dans les paramètres du nœud.
L'éditeur de source HLSL est constitué de trois parties :
Panneau Déclarations
Fonctions de shader
Source du shader
Le panneau Déclarations sert de référence à l'API pour l'écriture du code Shader. Les déclarations sont générées automatiquement à partir des paramètres du nœud HLSL personnalisé, tels que le type de noyau et les paramètres des broche d'entrée/sortie.
Le champ Fonctions de shader permet aux auteurs de créer des fonctions réutilisables à appeler dans leur source Shader.
Le champ Shader source est là où vous implémentez le point d'entrée principal pour l'implémentation de votre noyau.
Types de noyau de nœud HLSL personnalisés
Le type de noyau définit un préréglage pour le comportement du nœud.
Processeur de points
Le noyau de type Processeur de points est idéal pour modifier les points. Il nécessite que la broche d'entrée et de sortie principale soit de type Point et exécute le code HLSL une fois pour chaque point. Les données envoyées par la broche de sortie principale ont la même disposition que celles envoyées par la broche d'entrée principale, ce qui signifie que le nombre de données et le nombre d'éléments sont identiques.
Tous les points de la sortie principale sont automatiquement initialisés à partir de l'entrée principale. Il suffit donc de définir les attributs de sortie qui doivent être modifiés.
Vous pouvez également utiliser le processeur de point pour créer des broches d'entrée et de sortie supplémentaires que vous devez configurer manuellement pour définir le type de données et le nombre de données/éléments.
Générateur de points
Le type de noyau Générateur de points est idéal pour créer et remplir un ensemble de points. Cela nécessite que la broche de sortie principale soit de type Point et exécute le code HLSL une fois pour chaque point.
Ce type de noyau dispose des options supplémentaires suivantes :
Option
| Description |
Nombre de points
| Détermine le nombre de points générés. Le code de shader est exécuté sur chaque point généré. |
À l'instar du processeur de points, vous pouvez utiliser le générateur de points pour créer des broches d'entrée et de sortie supplémentaires, que vous devez configurer manuellement pour définir le type de données et le nombre de données ou d'éléments souhaités.
Personnalisée
Le type de noyau personnalisé permet des contrôles précis de l'exécution pour des cas d'utilisation avancés. Contrairement aux deux autres types de noyau, aucun paramètre n'est appliqué aux broches d'entrée ou de sortie, car le nœud n'implique aucune relation spécifique entre l'entrée et la sortie. Les données de sortie doivent être configurées dans les paramètres des broches de sortie documentés ci-dessous. Le nombre de threads qui doivent exécuter le code de shader doit également être configuré.
Ce type de noyau dispose des options supplémentaires suivantes :
Option | Description |
Envoyer le nombre de thread | Détermine le nombre de threads que le code de shader utilise pour s'exécuter. Les modes suivants sont disponibles :
|
Configuration des broches
Toutes les broches qui ne sont pas pilotées par le type de noyau doivent être configurées manuellement.
Pour les broches de sortie, il est nécessaire de décrire explicitement la taille et la disposition des données, qui peuvent être définies dans le menu déroulant Propriétés du processeur graphique des paramètres de la broche de sortie.
Mode d'initialisation | Décrit comment les données de sortie de cette broche seront initialisées. Le menu contient les modes suivants :
|
Broches à partir desquelles initialiser | Définit les broches d'entrée desquelles initialiser les données de cette broche. |
Mode de comptage des données | Définit le nombre d'objets de données. Le menu contient les modes suivants :
|
Multiplicité des données | Combine les nombres de données s'il y a plusieurs broches à partir desquelles initialiser. Modes disponibles :
|
Mode Nombre d'éléments | Définit le nombre d'éléments. Le menu contient les modes suivants :
|
Multiplicité des éléments | Combine les nombres d'éléments s'il y a plusieurs broches à partir desquelles initialiser. Modes disponibles :
|
Mode d'héritage des attributs | Définit comment hériter des noms, types et valeurs des attributs. Le menu contient les modes suivants :
|
Attributs à créer | Définit une liste de nouveaux attributs à créer dans les données de sortie. |
Débogage du HLSL personnalisé
Les fonctionnalités d'affichage de débogage (raccourci par défaut 'D') et d'inspection (raccourci par défaut 'A') fonctionnent pour les nœuds de processeur graphique et permettent d'inspecter les données qui transitent par ces nœuds de processeur graphique.
Il est également possible de déboguer le code de shader personnalisé en activant l'option Afficher les valeurs de débogage du shader du nœud HLSL personnalisé. Vous disposez ainsi d'une nouvelle fonction WriteDebugValue, que vous pouvez utiliser pour écrire des valeurs float dans un tampon qui se connecte lors de l'exécution. La taille de la mémoire tampon est contrôlée par la propriété Debug Buffer Size.
Exemples
Exemple 1 : décalage de hauteur avec une sinusoïde
Dans l'exemple ci-dessous, un processeur de point est utilisé pour appliquer un décalage de hauteur sinusoïdal à un ensemble de points.
Le code suivant a été ajouté au champ Source du shader de la fenêtre de l'éditeur de source HLSL :
// 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’.
Exemple 2 : création d'un attribut
Dans l'exemple ci-dessous, un générateur de points est utilisé pour créer une grille de points et utilise un ensemble d'attributs pour contrôler la hauteur de la grille.
Le code suivant a été ajouté au champ Source du shader de la fenêtre de l'éditeur de source HLSL :
// 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.
Les attributs sont accessibles dans le code de shader à l'aide des fonctions Get et Set fournies. Il est également possible d'interroger l'attribut par son nom en l'entourant de guillemets. Par exemple, « GridHeight ».
Exemple 3 : génération de maillages aléatoires dans un Paysage
Le nœud HLSL personnalisé est aussi capable d'exécuter une séquence d'opérations.
Dans l'exemple ci-dessous, le code du shader effectue les opérations suivantes :
Crée plusieurs points sur un paysage.
Applique un ajustement de position aléatoire à chaque point.
Définit la position du point
Écrit une valeur de départ aléatoire à chaque point
Lit un ensemble d'attributs contenant une liste de maillages statiques et assigne un maillage aléatoire à chaque point.
En aval du nœud HLSL se trouve un générateur de maillage statique, dont l'exécution du processeur graphique est activée et dont l'attribut de maillage est défini sur "MeshPath".
Sur le processeur graphique, les attributs de type Chaîne, Nom, Chemin d'objet logiciel, Chemin de classe logicielle deviennent des StringKeys, qui identifient de manière unique chaque chaîne.
Le code suivant a été ajouté au champ Source du shader de la fenêtre Source HLSL :
// 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);
Nœud de générateur de maillage statique
Vous pouvez demander au nœud du générateur de maillage statique de s'exécuter sur le processeur graphique en cochant l'option Exécuter sur le GPU dans les paramètres du nœud.
Instanciation procédurale
Lorsque le générateur de maillage statique est configuré pour s'exécuter sur le processeur graphique, il configure les instances de maillage entièrement sur le processeur graphique, ce qui permet d'économiser du temps processeur et de la mémoire. Cela utilise le composant de maillage statique instancié procéduralement. Cela peut être très efficace pour générer des maillages, mais c'est expérimental et cela s'accompagne des inconvénients suivants :
Les instances ne sont pas conservées ou enregistrées. Elles n'existent qu'au temps d'exécution dans la mémoire du processeur graphique.
Le cas d'utilisation principal est la génération à l'exécution.
L'éclairage statique précalculé et le HLOD requièrent des informations d'instance conservées et ne sont pas pris en charge pour le moment.
Plusieurs fonctionnalités nécessitent actuellement un accès du processeur aux données d'instance et ne sont pas prises en charge :
Collisions / physique
Navigation
Ray tracing
Affecter l'éclairage du champ de distance
L'implémentation du processeur graphique est expérimental et les fonctionnalités du générateur de maillage statique ne sont pas toutes prises en charge.
Types de sélecteur de maillage
Les sélecteurs de maillage suivants sont pris en charge lors de l'exécution sur le processeur graphique et, en raison de la façon dont les instances sont allouées, il existe de légères différences de comportement.
Pondéré (PCGMeshSelectorWeighted)
De la même manière que l'implémentation du processeur, ce mode utilise les valeurs de départ aléatoires de point d'entrée et les pondérations de sélection configurées pour sélectionner aléatoirement le maillage pour chaque instance. Ces maillages doivent être définis sur le nœud plutôt que pilotés par un attribut.
Le système utilise des pondérations pour déterminer le nombre d'instances à allouer pour chaque maillage. Une surattribution est effectuée sur la base d'un algorithme heuristique afin de limiter les risques de saturer l'attribution pour une ou plusieurs primitives et de perdre des instances.
Ce mode repose sur l'attribut Seed pour s'assurer que les points sont bien initialisés, par exemple en utilisant la fonction de shader fournie `ComputeSeedFromPosition()`. Si toutes les valeurs de départ de point sont définies sur la même valeur, la même sélection est effectuée pour tous les points et l'attribution approximative peut être dépassée, ce qui entraînera une suppression d'instances dans le résultat.
Par attribut (PCGMeshSelectorByAttribute)
Les autres types de sélecteurs de maillage (par exemple, PCGMeshSelectorWeightedByCategory) ne sont pas pris en charge actuellement lors de l'exécution sur le processeur graphique.
Le nombre final d'instances allouées peut être inspecté en sélectionnant les composants de maillage statique générés de façon procédurale et en cochant la propriété Num Instances.
Empaquetage des données d'instance
Comme pour l'exécution du processeur, les attributs peuvent être empaquetés dans des données d'instance.
Le système doit savoir, avant l'exécution du processeur graphique, combien d'attributs seront empaquetés. Par conséquent, seul le type d'empaquetage par attribut (PCGInstanceDataPackerByAttribute) est pris en charge.
Autres nœuds
Les nœuds suivants prennent actuellement en charge l'exécution du processeur graphique :
Copier les points
Partition de l'attribut
Actuellement, seul le partitionnement sur des attributs de type String, Soft Object Path ou Soft Class Path est pris en charge.
Normal vers la densité
Compte de données
Générateur de maillage statique
HLSL personnalisé
Exécution du processeur non prise en charge.
Sources de calcul
Les ressources de source de calcul facilitent le partage du code source et réduisent la duplication de code entre les nœuds.
Les ressources prennent en charge l'édition en ligne du code source HLSL avec la mise en évidence de la syntaxe et la syntaxe PCG spécifique, comme les étiquettes de données et les noms d'attributs.
Les ressources de source de calcul peuvent également référencer d'autres ressources de source de calcul en utilisant la propriété Sources supplémentaires, qui crée des hiérarchies de dépendance entre plusieurs sources de calcul.
Étiquettes de données
Les étiquettes de données peuvent être utilisées pour référencer les données par étiquette plutôt que par index dans la source HLSL personnalisée. Les étiquettes de données sont communiquées sur les données par le biais de balises avec le préfixe PCG_DATA_LABEL.
Certains nœuds étiquettent automatiquement leurs données de sortie, notamment :
Obtenir les données de texture
Obtenir les données de texture virtuelle
Générer des mappages d'herbe
Générer des textures d'herbe
La PCG prend en charge l'échantillonnage des couches d'herbe du paysage à partir d'un matériau de paysage spécifié afin de faciliter les flux de travail de génération procédurale à l'exécution.
Configurez votre matériau de paysage avec un nœud de sortie d'herbe du paysage. Pour plus d'informations sur la configuration d'un matériau de paysage, consultez Matériaux de paysage.
Connectez vos données de paysage dans un nœud Générer des cartes d'herbe. Sélectionnez les types d'herbes souhaités directement à l'aide de la fonction de remplacement ou d'exclusion.
Échantillonnez les textures de mappage d'herbe. Vous pouvez échantillon par index ou par les étiquettes de données automatiquement assignées. Le code suivant a été ajouté au champ Source du shader de la fenêtre de l'éditeur de source HLSL :
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;
Si vous prévoyez d'échantillonner les textures de votre mappage d'herbe uniquement sur le processeur graphique, vous pouvez activer l'option Ignorer la relecture du processeur graphique dans le graphique PCG afin d'améliorer considérablement les performances.
Couches de paysage peintes :
Génération résultante :
Utilisation de textures virtuelles dans la PCG
La PCG prend en charge l'utilisation de textures virtuelles dans le cadre de votre flux de travail de génération procédurale de contenu.
Échantillonnage de texture virtuelle
Les textures virtuelles peuvent être échantillonnées à partir des données de Paysage pour améliorer les performances de l'échantillonnage de la hauteur.
Exemple 1 : données de paysage
Pour échantillonner des données de paysage en utilisant des textures virtuelles, assurez-vous que l'option Échantillons de textures virtuelles est activée dans les paramètres du nœud Get Landscape Data. Le nœud Landscape Data peut ainsi utiliser n'importe quelle texture virtuelle fournie par le matériau de paysage correspondant.
Cela ne concerne que l'échantillonnage du processeur graphique.
// 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);
Exemple 2 : données de texture virtuelle
Pour échantillonner une texture virtuelle, interrogez le monde pour les composants de texture virtuelle à l'exécution. Chacun produira des données de texture virtuelle, balisées avec une étiquette de données pour la ressource de texture virtuelle à l'exécution.
float3 Position = CreateGrid2D(ElementIndex, NumPoints, GetComponentBoundsMin(), GetComponentBoundsMax());
// Sample virtual textures
bool bInsideVolume;
float3 BaseColor;
float Specular;
float Roughness;
float WorldHeight;
float3 Normal;
float Displacement;
Préparation de la texture virtuelle
Il est important de s'assurer que les textures virtuelles sont préparées avant la génération, sinon les résultats d'échantillonnage peuvent être inexacts.
Pour demander la préparation de texture virtuelle, ajoutez un paramètre de graphique du type FPCGVirtualTexturePrimingInfo à votre graphique de PCG. Cela donne accès aux options suivantes :
Texture virtuelle | Définit la texture virtuelle à préparer. |
Grille | Définit la plus grande grille sur laquelle la texture virtuelle est échantillonnée dans le graphique. Les textures virtuelles sont préparées pour le rayon de génération imposé par cette grille. |
Taille de texel du monde | Définit la taille souhaitée d'un texel dans la texture virtuelle préparée. Cela déterminera le niveau de la MIPmap qui doit être préparé. |
Vous pouvez contrôler la préparation des textures virtuelles à l'aide de la commande de console pcg.VirtualTexturePriming.Enable. Vous pouvez déboguer cette fonctionnalité avec la commande pcg.VirtualTexturePriming.DebugDrawTexturePrimingBounds.