Passes de rendu définies par l’utilisateur dans Qt Quick 3D
Qt Quick 3D fournit une API de haut niveau pour le rendu 3D qui gère automatiquement la plupart des détails de rendu. Cependant, pour des cas d’utilisation avancés, les applications peuvent avoir besoin d’un contrôle total sur le pipeline de rendu. Les passes de rendu définies par l’utilisateur permettent cela en autorisant les applications à désactiver le pipeline de rendu interne et à définir leurs propres passes personnalisées.
Les passes de rendu utilisateur permettent de mettre en œuvre des techniques de rendu avancées telles que :
- L'ombrage et l'éclairage différés
- Effets de rendu multipasse
- Pipelines de post-traitement personnalisés
- Le rendu sélectif avec filtrage par calque
- Effets dans l'espace écran (occlusion ambiante, reflets, etc.)
- Techniques personnalisées de mappage d'ombres
- Passes de visualisation de débogage
Niveaux de personnalisation
Qt Quick 3D propose trois niveaux complémentaires de personnalisation du rendu, chacun adapté à différents cas d'utilisation :
| Niveau | Portée | Cas d'utilisation |
|---|---|---|
| Effect | Post-traitement | Applique des effets après le rendu de la scène (flou, étalonnage des couleurs, etc.) |
| CustomMaterial | Shaders par matériau | Shaders de sommets et de fragments personnalisés pour chaque matériau |
| RenderPass (Passes de rendu utilisateur) | Contrôle complet du pipeline | Rendu différé, passes multiples, cibles de rendu personnalisées |
Les passes de rendu utilisateur (RenderPass) offrent un contrôle maximal, vous permettant soit de compléter, soit de remplacer entièrement le pipeline de rendu par défaut. Cela vient compléter les options « CustomMaterial » et « Effect » : CustomMaterial permet de personnaliser le rendu de chaque objet, tandis que les passes de rendu utilisateur contrôlent la stratégie et l’architecture globales du rendu.
Utilisation des passes de rendu utilisateur
Les passes de rendu utilisateur peuvent être utilisées de deux manières :
Compléter les passes internes
Vous pouvez ajouter des objets « RenderPass » personnalisés au pipeline de rendu par défaut sans désactiver les passes internes. Cela s’avère utile pour effectuer un rendu vers des textures qui seront ensuite utilisées par Effect ou CustomMaterial, ou pour créer des cibles de rendu auxiliaires.
View3D {
// Internal passes still run normally
RenderPassTexture { id: customTexture; format: RenderPassTexture.RGBA16F }
RenderPass {
// Custom pass renders to texture
commands: [
ColorAttachment { target: customTexture },
DepthStencilAttachment { }
]
}
// Use customTexture in an Effect or material
}Remplacer les passes internes
Pour un contrôle total sur le pipeline de rendu, désactivez le rendu interne d’ Qt Quick 3D en définissant la propriété renderOverrides:
View3D {
renderOverrides: View3D.DisableInternalPasses
// Your custom render passes go here
}Lorsque les passes internes sont désactivées, Qt Quick 3D n’effectuera aucun rendu par défaut. Cela signifie que vous devez :
- Définir au moins une cible de rendu ( RenderPass ) pour rendre votre scène
- Fournir la texture de sortie finale à afficher via un « SimpleQuadRenderer » ou un mécanisme similaire
- Gérer tous les aspects du rendu, y compris les tampons de profondeur, la transparence, etc.
Remarque : la désactivation des passes internes vous offre un contrôle total, mais vous en confère également l’entière responsabilité. Les fonctionnalités telles que le rendu automatique des ombres, le tri des transparences et les reflets de l’environnement doivent être implémentées dans vos passes personnalisées si nécessaire.
Concepts fondamentaux
Les passes de rendu définies par l’utilisateur s’articulent autour de plusieurs composants clés :
RenderPass
Le type ` RenderPass ` est l’élément constitutif principal. Il définit une opération de rendu unique avec un ensemble de commandes qui contrôlent ce qui est rendu et comment. Chaque passe peut :
- Effectuer un rendu sur une ou plusieurs textures de couleur (jusqu’à 4 cibles de rendu simultanées)
- Écrire des informations de profondeur et de stencil
- Filtrer les objets à rendre en fonction des couches
- Remplacer l’état du pipeline graphique (mélange, culling, etc.)
- Utiliser les matériaux d’origine, les enrichir avec des shaders personnalisés ou les remplacer entièrement
RenderPassTexture
Le type « RenderPassTexture » définit les textures servant de cibles de rendu. Il peut s'agir de textures de couleur dans divers formats (RGBA8, RGBA16F, RGBA32F, etc.) ou de textures de profondeur/stencil. Les textures de passe de rendu sont utilisées comme sorties d'une passe et peuvent servir d'entrées de texture pour les passes suivantes.
RenderOutputProvider
Le type ` RenderOutputProvider ` relie les passes de rendu en exposant les textures de sortie d’une passe sous forme d’entrées de texture pouvant être utilisées par des matériaux ou d’autres passes. Ceci est essentiel pour le rendu multipasse, où les passes ultérieures doivent lire les résultats des passes précédentes.
ContentLayer
Le singleton ` ContentLayer ` fournit des constantes de couche (de Layer0 à Layer23) utilisées pour filtrer les objets à rendre dans chaque passe. En affectant des objets à des couches spécifiques et en utilisant des commandes de rendu ` RenderablesFilter ` dans vos passes, vous pouvez contrôler avec précision ce qui est rendu dans chaque passe.
Commandes de rendu
Chaque RenderPass contient une liste de commandes qui configurent son comportement :
- ColorAttachment: Spécifie une cible de rendu couleur
- DepthStencilAttachment: Spécifie la gestion de la profondeur et du stencil
- DepthTextureAttachment: Utilise une texture pour la sortie de profondeur
- RenderablesFilter: Filtre les objets par calque et par type (opaque/transparent)
- PipelineStateOverride: Contrôle l'état du pipeline graphique
SubRenderPass: Exécute un autre passage de rendu au sein de ce passage- AddDefine: Ajoute des définitions de préprocesseur de shader
Modes de matériau
Chaque « RenderPass » dispose d’une propriété « materialMode » qui contrôle la manière dont les matériaux sont gérés lors du rendu. Les trois modes offrent différents niveaux de contrôle des matériaux :
Mode OriginalMaterial
Ce mode effectue le rendu des objets sans modifier les matériaux qui leur sont attribués. Il est utile lorsque vous souhaitez contrôler la structure du pipeline de rendu (passes multiples, cibles de rendu personnalisées) tout en conservant le comportement standard des matériaux.
RenderPass {
materialMode: RenderPass.OriginalMaterial
commands: [
ColorAttachment { target: myColorTexture },
DepthStencilAttachment { }
]
}Mode « AugmentMaterial »
Ce mode injecte du code de shader personnalisé dans le pipeline de matériaux existant. Il est particulièrement utile pour le rendu différé, où vous devez transmettre des données supplémentaires (telles que les normales, les positions, etc.) à plusieurs cibles de rendu tout en conservant le comportement de base du matériau.
RenderPass {
materialMode: RenderPass.AugmentMaterial
augmentShader: "my_augment.glsl"
commands: [
ColorAttachment { target: gbuffer0; name: "GBUFFER0" },
ColorAttachment { target: gbuffer1; name: "GBUFFER1" },
DepthStencilAttachment { }
]
}Le fichier de shader d’extension contient une fonction « MAIN_FRAGMENT_AUGMENT() » :
void MAIN_FRAGMENT_AUGMENT()
{
// Access material properties
vec3 color = BASE_COLOR.rgb;
float metal = METALNESS;
float rough = ROUGHNESS;
vec3 normal = normalize(WORLD_NORMAL);
// Write to multiple render targets
GBUFFER0 = vec4(color, metal);
GBUFFER1 = vec4(normal * 0.5 + 0.5, rough);
}Voir Shaders d’extension pour cibles de rendu multiples pour plus de détails.
Mode OverrideMaterial
Ce mode remplace tous les matériaux des objets par un seul et même matériau. Il est utile pour des passes spécialisées telles que le shadow mapping, la pré-passe de profondeur ou la visualisation de débogage.
RenderPass {
materialMode: RenderPass.OverrideMaterial
overrideMaterial: CustomMaterial {
fragmentShader: "depth_only.frag"
// All objects will use this material
}
commands: [
DepthTextureAttachment { target: depthTexture }
]
}Commandes de passe de rendu
Les commandes sont spécifiées dans la propriété « commands » et s’exécutent dans l’ordre où elles sont définies.
Pièce jointe de couleur
La commande « ColorAttachment » spécifie une cible de rendu de couleur. La propriété « name » définit la manière dont l’attachement est accessible dans les shaders d’augmentation.
ColorAttachment {
target: myTexture // RenderPassTexture to render to
name: "GBUFFER0" // Name for shader access (optional)
}Vous pouvez avoir jusqu’à 4 attaches de couleur par passe (pour plusieurs cibles de rendu).
Attachments de profondeur
Il existe deux façons de gérer la profondeur :
DepthStencilAttachment utilise un tampon de profondeur/stencil implicite :
DepthStencilAttachment { } // Creates depth/stencil buffer automaticallyDepthTextureAttachment utilise une texture explicite pour la sortie de profondeur :
RenderPassTexture {
id: depthTex
format: RenderPassTexture.Depth24Stencil8
}
DepthTextureAttachment {
target: depthTex // Explicit depth texture
}Utilisez l'option « DepthTextureAttachment » lorsque vous avez besoin de partager le tampon de profondeur entre plusieurs passes ou de l'utiliser comme entrée de texture dans les shaders.
Filtre Renderables
La commande « RenderablesFilter » contrôle quels objets sont rendus en fonction de leur affectation de calque et de leur type de rendu.
RenderablesFilter {
layerMask: ContentLayer.Layer0 | ContentLayer.Layer1
renderableTypes: RenderablesFilter.Opaque
}La propriété « layerMask » utilise l’opération OR bit à bit pour combiner les couches. La propriété « renderableTypes » peut prendre les valeurs suivantes :
RenderablesFilter.Opaque: Rendu des objets opaques uniquementRenderablesFilter.Transparent: Afficher uniquement les objets transparentsRenderablesFilter.Opaque| RenderablesFilter.Transparent : Rendu des deux
Remplacement de l’état du pipeline
La commande ` PipelineStateOverride ` offre un contrôle précis de l’état du pipeline graphique. Elle permet de remplacer le test de profondeur, le mélange, le culling, le mode polygonal, etc.
PipelineStateOverride {
depthTestEnabled: true
depthWriteEnabled: false
blendEnabled: true
cullMode: PipelineStateOverride.Back
polygonMode: PipelineStateOverride.Fill
}Voir Contrôle de l'état du pipeline pour plus d'exemples.
Sous-pass de rendu
La commande SubRenderPass permet une composition hiérarchique des passes de rendu en exécutant une autre passe de rendu au sein de la passe en cours.
RenderPass {
id: parentPass
commands: [
ColorAttachment { target: colorTex },
SubRenderPass { renderPass: childPass },
// More commands after child pass
]
}
RenderPass {
id: childPass
// This pass executes within parentPass
}Ajouter une définition
La commande « AddDefine » ajoute des définitions de préprocesseur de shader qui affectent la compilation des shaders.
AddDefine {
name: "USE_SPECIAL_MODE"
value: 1
}Exemple simple : rendu en passe unique
Voici un exemple minimal illustrant les passes de rendu définies par l'utilisateur :
import QtQuick
import QtQuick3D
import QtQuick3D.Helpers
View3D {
anchors.fill: parent
renderOverrides: View3D.DisableInternalPasses
// Camera and lights
PerspectiveCamera { z: 300 }
DirectionalLight { }
// Define render target texture
RenderPassTexture {
id: colorTarget
format: RenderPassTexture.RGBA16F
}
// Define the render pass
RenderPass {
id: mainPass
materialMode: RenderPass.OriginalMaterial
clearColor: "skyblue"
commands: [
ColorAttachment { target: colorTarget },
DepthStencilAttachment { }
]
}
// Display the result
SimpleQuadRenderer {
texture: Texture {
textureProvider: RenderOutputProvider {
textureSource: RenderOutputProvider.UserPassTexture
renderPass: mainPass
attachmentSelector: RenderOutputProvider.Attachment0
}
}
}
// Scene content
Model {
source: "#Sphere"
materials: PrincipledMaterial {
baseColor: "red"
metalness: 0.0
roughness: 0.3
}
}
}Cet exemple :
- Désactive les passes internes
- Crée une texture cible de rendu (colorTarget)
- Définit un passage de rendu qui effectue le rendu vers cette texture
- Utilise « RenderOutputProvider » pour exposer la texture
- Affiche le résultat avec SimpleQuadRenderer
- Rendu d’une sphère avec un matériau standard
Utilisation des calques
Le singleton ` ContentLayer ` fournit des constantes permettant d’organiser les objets en couches, ce qui offre un contrôle précis sur ce qui est rendu à chaque passe.
Constantes de calque
Qt Quick 3D propose 24 calques personnalisables :
ContentLayer.Layer0via `ContentLayer.Layer23` : couches individuellesContentLayer.LayerAll: Toutes les couches utilisateur combinéesContentLayer.LayerNone: Aucun calque
Remarque : les calques 24 à 31 sont réservés à un usage interne.
Attribution d’objets à des calques
Attribuez des objets à des calques à l'aide de la propriété layers:
Model {
source: "#Cube"
layers: ContentLayer.Layer0
materials: PrincipledMaterial { baseColor: "red" }
}
Model {
source: "#Sphere"
layers: ContentLayer.Layer1 | ContentLayer.Layer2
materials: PrincipledMaterial { baseColor: "blue" }
}Les objets peuvent appartenir à plusieurs couches grâce à l'opération OU binaire.
Filtrage par calque
Utilisez la propriété ` RenderablesFilter ` dans vos passes de rendu pour sélectionner les calques à rendre :
RenderPass {
id: pass1
commands: [
ColorAttachment { target: texture1 },
RenderablesFilter {
layerMask: ContentLayer.Layer0
}
]
// Only renders objects on Layer0 (red cube)
}
RenderPass {
id: pass2
commands: [
ColorAttachment { target: texture2 },
RenderablesFilter {
layerMask: ContentLayer.Layer1 | ContentLayer.Layer2
}
]
// Only renders objects on Layer1 or Layer2 (blue sphere)
}Cas d’utilisation : rendu sélectif
Un exemple concret consiste à rendre certains objets sous forme de superpositions filaires :
View3D {
renderOverrides: View3D.DisableInternalPasses
RenderPassTexture { id: colorTex; format: RenderPassTexture.RGBA16F }
RenderPassTexture { id: depthTex; format: RenderPassTexture.Depth24Stencil8 }
// Pass 1: Render solid objects
RenderPass {
id: solidPass
commands: [
ColorAttachment { target: colorTex },
DepthTextureAttachment { target: depthTex },
RenderablesFilter { layerMask: ContentLayer.Layer0 }
]
}
// Pass 2: Render wireframe overlay
RenderPass {
id: wireframePass
commands: [
ColorAttachment { target: colorTex },
DepthTextureAttachment { target: depthTex },
PipelineStateOverride {
polygonMode: PipelineStateOverride.Line
depthTestEnabled: true
depthWriteEnabled: false
},
RenderablesFilter { layerMask: ContentLayer.Layer1 }
]
}
SimpleQuadRenderer {
texture: Texture {
textureProvider: RenderOutputProvider {
textureSource: RenderOutputProvider.UserPassTexture
renderPass: wireframePass
attachmentSelector: RenderOutputProvider.Attachment0
}
}
}
Model {
source: "#Sphere"
layers: ContentLayer.Layer0 // Rendered solid
materials: PrincipledMaterial { baseColor: "blue" }
}
Model {
source: "#Sphere"
layers: ContentLayer.Layer1 // Rendered as wireframe
materials: PrincipledMaterial { baseColor: "yellow" }
}
}Gestion des textures
Les passes de rendu utilisateur s'appuient fortement sur les textures, à la fois en tant que cibles de rendu et en tant qu'entrées pour les passes ou les matériaux suivants.
Formats de textures des passes de rendu
RenderPassTexture prend en charge divers formats adaptés à différents cas d'utilisation :
Formats de couleur :
| Format | Description | Cas d'utilisation |
|---|---|---|
| RGBA8 | 8 bits par canal | Sortie couleur standard, consommation de mémoire réduite |
| RGBA16F | 16 bits en virgule flottante | Rendu HDR, tampons intermédiaires |
| RGBA32F | 32 bits en virgule flottante | Calculs haute précision |
| R8, R16, R16F, R32F | Variantes monocanal | Données en niveaux de gris, tampons spécialisés |
Formats de profondeur :
| Format | Description |
|---|---|
| Profondeur 16 | Profondeur de 16 bits |
| Profondeur 24 | Profondeur de 24 bits |
| Profondeur 32 | Profondeur de 32 bits |
| Profondeur 24, pochoir 8 | Profondeur de 24 bits + pochoir de 8 bits |
Exemples de définitions de textures :
RenderPassTexture {
id: hdrColorBuffer
format: RenderPassTexture.RGBA16F // HDR color
}
RenderPassTexture {
id: depthBuffer
format: RenderPassTexture.Depth24Stencil8 // Depth + stencil
}
RenderPassTexture {
id: normalBuffer
format: RenderPassTexture.RGBA16F // Store normals
}Partage de textures entre les passes
Plusieurs passes peuvent partager la même texture de profondeur, ce qui permet d'effectuer des tests de profondeur d'une passe à l'autre :
RenderPassTexture {
id: sharedDepth
format: RenderPassTexture.Depth24Stencil8
}
RenderPass {
id: geometryPass
commands: [
ColorAttachment { target: colorTex1 },
DepthTextureAttachment { target: sharedDepth }
]
}
RenderPass {
id: transparentPass
renderTargetFlags: RenderPass.PreserveDepthStencilContents
commands: [
ColorAttachment { target: colorTex2 },
DepthTextureAttachment { target: sharedDepth }
// Uses depth from geometryPass for depth testing
]
}Fournisseur de sortie de rendu
L'RenderOutputProvider expose les sorties des passes de rendu en tant qu'entrées d'Texture s :
// Define a render pass with color output
RenderPass {
id: firstPass
commands: [
ColorAttachment { target: intermediateTexture }
]
}
// Expose its output
RenderOutputProvider {
id: intermediateProvider
textureSource: RenderOutputProvider.UserPassTexture
renderPass: firstPass
attachmentSelector: RenderOutputProvider.Attachment0
}
// Use in a material
CustomMaterial {
property TextureInput inputTex: TextureInput {
texture: Texture { textureProvider: intermediateProvider }
}
fragmentShader: "process.frag"
}La propriété « attachmentSelector » spécifie quelle attache de couleur utiliser lorsqu’un passage comporte plusieurs cibles de rendu :
RenderOutputProvider.Attachment0: Première attache de couleurRenderOutputProvider.Attachment1: Deuxième attachement de couleurRenderOutputProvider.Attachment2: Troisième attachement de couleurRenderOutputProvider.Attachment3: Quatrième attachement de couleur
Exemple de chaînage de passes
Plusieurs passes peuvent être enchaînées, chaque passe traitant la sortie de la passe précédente :
View3D {
renderOverrides: View3D.DisableInternalPasses
// Intermediate textures
RenderPassTexture { id: tex0; format: RenderPassTexture.RGBA16F }
RenderPassTexture { id: tex1; format: RenderPassTexture.RGBA16F }
RenderPassTexture { id: tex2; format: RenderPassTexture.RGBA16F }
// Pass 1: Render scene
RenderPass {
id: scenePass
commands: [
ColorAttachment { target: tex0 },
DepthStencilAttachment { }
]
}
// Pass 2: Process tex0 -> tex1
RenderPass {
id: process1
materialMode: RenderPass.OriginalMaterial
commands: [
ColorAttachment { target: tex1 }
]
}
Model {
layers: ContentLayer.Layer10
geometry: PlaneGeometry { }
materials: CustomMaterial {
property TextureInput input: TextureInput {
texture: Texture {
textureProvider: RenderOutputProvider {
textureSource: RenderOutputProvider.UserPassTexture
renderPass: scenePass
}
}
}
fragmentShader: "effect1.frag"
}
}
// Pass 3: Process tex1 -> tex2
RenderPass {
id: process2
commands: [
ColorAttachment { target: tex2 },
RenderablesFilter { layerMask: ContentLayer.Layer11 }
]
}
Model {
layers: ContentLayer.Layer11
geometry: PlaneGeometry { }
materials: CustomMaterial {
property TextureInput input: TextureInput {
texture: Texture {
textureProvider: RenderOutputProvider {
textureSource: RenderOutputProvider.UserPassTexture
renderPass: process1
}
}
}
fragmentShader: "effect2.frag"
}
}
// Display final result
SimpleQuadRenderer {
texture: Texture {
textureProvider: RenderOutputProvider {
textureSource: RenderOutputProvider.UserPassTexture
renderPass: process2
}
}
}
}Contrôle de l'état du pipeline
La commande ` PipelineStateOverride ` offre un contrôle détaillé de l’état du pipeline graphique, permettant de personnaliser le test de profondeur, le mélange, le culling, et bien plus encore.
Test et écriture de profondeur
Contrôlez la manière dont les valeurs de profondeur sont testées et écrites :
PipelineStateOverride {
depthTestEnabled: true
depthWriteEnabled: true
depthFunction: PipelineStateOverride.LessOrEqual
}La propriété ` depthFunction ` peut prendre les valeurs suivantes :
Never,Less,Equal,LessOrEqualGreater,NotEqual,GreaterOrEqual,Always
Mélange
Activer et configurer le mélange pour la transparence :
PipelineStateOverride {
blendEnabled: true
// Uses default blend mode (source alpha blending)
}Pour plusieurs cibles de rendu, utilisez des états de fusion par cible. PipelineStateOverride expose les propriétés de type valeur par pièce jointe targetBlend0 à targetBlend7 (de type renderTargetBlend) et les énumérations de facteur de fusion et d’opération se trouvent dans l’espace de noms RenderTargetBlend:
PipelineStateOverride {
targetBlend0.enable: true
targetBlend0.srcColor: RenderTargetBlend.SrcAlpha
targetBlend0.dstColor: RenderTargetBlend.OneMinusSrcAlpha
targetBlend0.opColor: RenderTargetBlend.Add
targetBlend1.enable: false // No blending for attachment 1
}Élimination
Contrôle du culling des faces :
PipelineStateOverride {
cullMode: PipelineStateOverride.Back // Override material's cull mode to Back
}La définition de cullMode ici remplace la valeur que le matériau spécifierait autrement pour ce passage. Options : None (pas de culling), Front (culling des faces avant), Back (culling des faces arrière).
Rendu filaire
Rendu de la géométrie sous forme de fil de fer :
PipelineStateOverride {
polygonMode: PipelineStateOverride.Line
cullMode: PipelineStateOverride.None // Show both sides
}L'polygonMode e peut être Fill (par défaut) ou Line (fil de fer).
Rectangles de découpe
Limiter le rendu à une zone rectangulaire :
PipelineStateOverride {
usesScissor: true
scissor: Qt.rect(100, 100, 400, 300) // x, y, width, height
}Contrôle de la fenêtre d'affichage
Remplacer la fenêtre d’affichage :
PipelineStateOverride {
viewport: Qt.rect(0, 0, 800, 600)
}Exemple complet : superposition en fil de fer
Cet exemple effectue un rendu normal d’une scène, puis superpose une version filaire :
View3D {
renderOverrides: View3D.DisableInternalPasses
RenderPassTexture { id: color; format: RenderPassTexture.RGBA16F }
RenderPassTexture { id: depth; format: RenderPassTexture.Depth24Stencil8 }
// Solid pass
RenderPass {
id: solidPass
clearColor: "black"
commands: [
ColorAttachment { target: color },
DepthTextureAttachment { target: depth },
RenderablesFilter {
layerMask: ContentLayer.Layer0
renderableTypes: RenderablesFilter.Opaque
}
]
}
// Wireframe overlay
RenderPass {
id: wirePass
renderTargetFlags: RenderPass.PreserveColorContents |
RenderPass.PreserveDepthStencilContents
commands: [
ColorAttachment { target: color },
DepthTextureAttachment { target: depth },
PipelineStateOverride {
polygonMode: PipelineStateOverride.Line
depthTestEnabled: true
depthWriteEnabled: false
blendEnabled: true
},
RenderablesFilter { layerMask: ContentLayer.Layer0 }
]
}
SimpleQuadRenderer {
texture: Texture {
textureProvider: RenderOutputProvider {
textureSource: RenderOutputProvider.UserPassTexture
renderPass: wirePass
}
}
}
PerspectiveCamera { z: 300 }
DirectionalLight { }
Model {
source: "#Sphere"
layers: ContentLayer.Layer0
materials: PrincipledMaterial {
baseColor: "blue"
metalness: 0.5
roughness: 0.3
}
}
}Shaders d’augmentation pour plusieurs cibles de rendu
Lorsque vous utilisez le mode « RenderPass.AugmentMaterial », vous fournissez un shader d’augmentation qui injecte du code personnalisé dans le shader de fragment du matériau. Cela s’avère particulièrement utile pour le rendu différé, où vous devez exporter les données du matériau vers plusieurs cibles de rendu (MRT).
La fonction MAIN_FRAGMENT_AUGMENT
Votre fichier de shader d’augmentation doit définir une fonction « MAIN_FRAGMENT_AUGMENT() » :
void MAIN_FRAGMENT_AUGMENT()
{
// Your custom shader code here
}Cette fonction est appelée pendant le shader de fragment, une fois les calculs du matériau terminés, ce qui vous donne accès aux propriétés du matériau et vous permet d'écrire dans des sorties personnalisées.
Variables intégrées disponibles
À l’intérieur de ` MAIN_FRAGMENT_AUGMENT()`, le moteur remplace un ensemble de macros qui exposent les données du pipeline de matériaux. Seules les macros répertoriées ci-dessous font partie de l’API du shader d’augmentation :
| Macro | Type | Description |
|---|---|---|
BASE_COLOR | vec4 | Couleur de base du matériau (espace de couleur linéaire, après traitement du matériau). |
METALNESS | float | Métallicité du matériau comprise entre 0,0 et 1,0. |
ROUGHNESS | float | Rugosité du matériau comprise entre 0,0 et 1,0. |
WORLD_NORMAL | vec3 | Normale de surface dans l'espace mondial (après mappage normal). |
WORLD_TANGENT | vec3 | Vecteur tangent dans l'espace mondial. |
WORLD_BINORMAL | vec3 | Vecteur binormale dans l'espace mondial. |
DIFFUSE_LIGHT | vec3 | Contribution cumulée de la lumière diffuse. |
SPECULAR_LIGHT | vec3 | Contribution cumulée de la lumière spéculaire. |
EMISSIVE_LIGHT | vec3 | Contribution émissive du matériau. |
F0 | vec3 | Réflectance de Fresnel à incidence normale. |
F90 | vec3 | Réflectance de Fresnel à incidence rasante. |
Remarque : certains exemples (notamment celui du rendu différé ci-dessous) lisent la position du fragment dans l'espace mondial via qt_varWorldPos. Il s’agit du nom variable sous-jacent du moteur, et non d’une macro « augment-shader » ; il appartient à la même catégorie semi-publique que les fichiers « .glsllib » décrits dans la section « Fonctionnalités de shaders intégrées » : il fonctionne en pratique, mais sa stabilité n’est pas garantie d’une version à l’autre.
Écriture dans des sorties nommées
Les attachements de couleur de votre passe de rendu peuvent porter des noms correspondant à des variables de sortie de votre shader :
RenderPass {
commands: [
ColorAttachment { target: tex0; name: "GBUFFER0" },
ColorAttachment { target: tex1; name: "GBUFFER1" },
ColorAttachment { target: tex2; name: "GBUFFER2" }
]
}Dans votre shader « augment » :
void MAIN_FRAGMENT_AUGMENT()
{
GBUFFER0 = vec4(...); // Writes to first attachment
GBUFFER1 = vec4(...); // Writes to second attachment
GBUFFER2 = vec4(...); // Writes to third attachment
}Qt Quick La 3D prend en charge jusqu’à 4 attaches de couleur simultanées (GBUFFER0 à GBUFFER3).
Exemple complet de shader d’augmentation
Voici un exemple complet de passe G-buffer avec rendu différé :
// gbuffer_augment.glsl
void MAIN_FRAGMENT_AUGMENT()
{
// Get material properties
vec3 baseColor = BASE_COLOR.rgb;
float metalness = METALNESS;
float roughness = ROUGHNESS;
vec3 worldNormal = normalize(WORLD_NORMAL);
vec3 worldPos = qt_varWorldPos;
// GBuffer 0: Albedo (RGB) + Metalness (A)
GBUFFER0 = vec4(baseColor, metalness);
// GBuffer 1: World Normal (RGB) + Roughness (A)
// Encode normal from [-1,1] to [0,1] for storage
GBUFFER1 = vec4(worldNormal * 0.5 + 0.5, roughness);
// GBuffer 2: World Position
GBUFFER2 = vec4(worldPos, 1.0);
}Utilisées avec un passage de rendu (RenderPassTexture, les instances sont déclarées comme des enfants directs de l’ View3D qui les englobe et sont référencées par leur identifiant) :
View3D {
RenderPassTexture { id: gbuffer0; format: RenderPassTexture.RGBA16F }
RenderPassTexture { id: gbuffer1; format: RenderPassTexture.RGBA16F }
RenderPassTexture { id: gbuffer2; format: RenderPassTexture.RGBA16F }
RenderPass {
id: gbufferPass
materialMode: RenderPass.AugmentMaterial
augmentShader: "gbuffer_augment.glsl"
commands: [
ColorAttachment { target: gbuffer0; name: "GBUFFER0" },
ColorAttachment { target: gbuffer1; name: "GBUFFER1" },
ColorAttachment { target: gbuffer2; name: "GBUFFER2" },
DepthStencilAttachment { }
]
}
}Préservation du comportement des matériaux
Le shader d’augmentation s’exécute en complément du pipeline de matériaux normal, et non à sa place. Cela signifie que :
- les textures, les propriétés et les calculs du matériau sont toujours pris en compte
- Vous ajoutez des sorties supplémentaires, sans remplacer la sortie de couleur principale
- La sortie RGBA du matériau d'origine est toujours écrite dans la première annexe de couleur, sauf si elle est remplacée
Si vous avez uniquement besoin de générer des données personnalisées et que vous n’avez pas besoin des calculs standard du matériau, envisagez plutôt d’utiliser « RenderPass.OverrideMaterial ».
Quand utiliser « Augment » ou « Override » ?
Utilisez « AugmentMaterial » lorsque :
- Vous avez besoin des propriétés du matériau (métallicité, rugosité, normales) pour les G-buffers
- Vous souhaitez tirer parti des fonctionnalités existantes des matériaux, telles que le mappage de textures
- vous avez besoin de plusieurs cibles de rendu contenant des données de matériau
Utilisez « OverrideMaterial » lorsque :
- Vous avez besoin d'un comportement identique pour tous les objets (prépassage de profondeur, cartes d'ombres)
- Vous n’avez pas besoin de propriétés spécifiques à chaque matériau
- Vous souhaitez obtenir des performances maximales en contournant les calculs liés aux matériaux
Fonctionnalités de shaders intégrées
Les shaders d’augmentation et les matériaux personnalisés utilisés dans les passes de rendu ont accès à l’infrastructure de shaders intégrée d’ Qt Quick 3D via un système d’inclusion. Ces fichiers de bibliothèque de shaders (.glsllib) fournissent des fonctionnalités d’éclairage, d’ombres, de tonemapping, et bien plus encore.
Syntaxe d'inclusion :
Utilisez les directives ` \#include ` dans votre code de shader pour importer des fonctionnalités :
#include "tonemapping.glsllib"
#include "lightsData.glsllib"
#include "shadowMapping.glsllib"
#include "funcprocessPunctualLighting.glsllib"
void MAIN()
{
// Use included functions
vec3 color = qt_tonemap(hdrColor);
}Bibliothèques de shaders disponibles :
Ces bibliothèques de shaders se trouvent dans le moteur à l'emplacement src/runtimerender/res/effectlib/ et sont considérées comme semi-publiques: elles sont utilisables dans les shaders utilisateur mais ne bénéficient pas des mêmes garanties de compatibilité binaire que le reste de l'API publique de Qt.
| Bibliothèque | Description |
|---|---|
tonemapping.glsllib | Fournit la fonction ` qt_tonemap() ` pour la conversion HDR vers LDR à l’aide de l’algorithme de tonemapping intégré |
lightsData.glsllib | Contient des informations d’éclairage de scène (positions, couleurs et directions des lumières, etc.) accessibles dans les calculs d’éclairage personnalisés |
shadowMapping.glsllib | Fournit des fonctions d’échantillonnage à partir des cartes d’ombres par défaut, permettant aux matériaux personnalisés de recevoir des ombres |
funcprocessPunctualLighting.glsllib | Contient des fonctions d’ qt_processPunctualLighting() et d’autres fonctions d’éclairage intégrées pour les calculs d’éclairage PBR standard |
sampleProbe.glsllib | Fonctions permettant d’échantillonner des sondes d’éclairage basées sur des images (qt_sampleDiffuse(), qt_sampleGlossyPrincipled()) |
Exemple : éclairage personnalisé avec les fonctions intégrées
Voici un exemple de shader de fragment utilisant les fonctionnalités d’éclairage intégrées :
#include "lightsData.glsllib"
#include "funcprocessPunctualLighting.glsllib"
#include "tonemapping.glsllib"
#include "sampleProbe.glsllib"
void MAIN()
{
vec3 worldPos = ...; // From G-buffer or varying
vec3 normal = ...;
vec3 viewDir = normalize(CAMERA_POSITION - worldPos);
vec3 baseColor = ...;
float roughness = ...;
float metalness = ...;
vec3 F0 = mix(vec3(0.04), baseColor, metalness);
vec3 diffuseAccum = vec3(0.0);
vec3 specAccum = vec3(0.0);
// Use built-in punctual lighting (directional, point, spot lights)
qt_processPunctualLighting(diffuseAccum,
specAccum,
baseColor,
worldPos,
normal,
viewDir,
vec3(1.0), // specularAmount
vec3(1.0), // specularTint
roughness,
metalness,
F0,
vec3(1.0)); // F90
// Add image-based lighting
vec4 probeDiffuse = vec4(baseColor, 1.0) * qt_sampleDiffuse(normal);
vec4 probeSpecular = qt_sampleGlossyPrincipled(normal, viewDir, F0, roughness);
diffuseAccum += probeDiffuse.rgb;
specAccum += probeSpecular.rgb;
vec3 color = diffuseAccum + specAccum;
// Apply tonemapping
FRAGCOLOR = vec4(qt_tonemap(color), 1.0);
}Remarque : ces bibliothèques de shaders constituent une API semi-publique. Bien qu’elles soient stables et destinées à être utilisées dans des shaders personnalisés, Qt ne garantit pas que leur implémentation interne ou les fonctions disponibles resteront inchangées d’une version à l’autre. Cependant, les fonctions couramment utilisées telles que ` qt_tonemap() ` et ` qt_processPunctualLighting() ` ont peu de chances de subir des modifications significatives.
Exemple avancé : le rendu différé
Le rendu différé est une technique dans laquelle les informations géométriques sont rendues sur plusieurs textures (appelées « G-buffer » ou « tampon de géométrie ») lors d’un premier passage, puis les calculs d’éclairage sont effectués lors d’un deuxième passage à l’aide des données géométriques stockées. Cette approche est particulièrement efficace lorsque vous disposez de nombreuses lumières, car chaque pixel n’est ombré qu’une seule fois, quel que soit le nombre de lumières.
Architecture du rendu différé
Le pipeline de rendu différé se compose de deux passes principales :
- Passe de géométrie (passe du G-buffer): rend la géométrie de la scène sur plusieurs cibles de rendu, en stockant les propriétés des matériaux telles que l’albédo, les normales, la rugosité, la métallicité et la position dans l’espace.
- Passe d’éclairage: elle effectue le rendu d’un quad plein écran qui échantillonne les G-buffers et effectue des calculs d’éclairage pour chaque pixel en fonction des données géométriques stockées.
Implémentation de la passe G-Buffer
Commencez par définir un passage G-buffer qui transmet les données de matériau à plusieurs cibles de rendu :
GBufferPass.qml : Les cibles de rendu du G-buffer sont exposées sous forme de propriétés obligatoires afin que l’ View3D e qui les englobe puisse les fournir et lire leurs sorties :
import QtQuick
import QtQuick3D
RenderPass {
id: gbufferPass
clearColor: Qt.rgba(0.0, 0.0, 0.0, 0.0)
property alias layerMask: filter.layerMask
// Provided by the View3D that uses this pass
required property RenderPassTexture gbuffer0 // rgb: baseColor, a: metalness
required property RenderPassTexture gbuffer1 // rgb: normal, a: roughness
required property RenderPassTexture gbuffer2 // rgb: world pos, a: spare
required property RenderPassTexture depthTexture
materialMode: RenderPass.AugmentMaterial
augmentShader: "gbuffer_augment.glsl"
commands: [
ColorAttachment { target: gbufferPass.gbuffer0; name: "GBUFFER0" },
ColorAttachment { target: gbufferPass.gbuffer1; name: "GBUFFER1" },
ColorAttachment { target: gbufferPass.gbuffer2; name: "GBUFFER2" },
DepthTextureAttachment { target: gbufferPass.depthTexture },
RenderablesFilter {
id: filter
renderableTypes: RenderablesFilter.Opaque
}
]
}gbuffer_augment.glsl :
void MAIN_FRAGMENT_AUGMENT()
{
vec3 baseColor = BASE_COLOR.rgb;
float metalness = METALNESS;
float roughness = ROUGHNESS;
vec3 worldNormal = normalize(WORLD_NORMAL);
// GBuffer 0: albedo + metalness
GBUFFER0 = vec4(baseColor, metalness);
// GBuffer 1: normal (encoded to 0..1) + roughness
GBUFFER1 = vec4(worldNormal * 0.5 + 0.5, roughness);
// GBuffer 2: world position
GBUFFER2 = vec4(qt_varWorldPos, 1.0);
}Le shader d’augmentation accède aux propriétés de matériau calculées par le pipeline de matériau et les écrit dans les trois pièces jointes du G-buffer. Les normales sont encodées dans l’intervalle [-1,1] à [0,1] pour le stockage.
Implémentation de la passe d’éclairage
La passe d’éclairage effectue le rendu d’un quadrilatère en plein écran qui échantillonne les G-buffers et calcule l’éclairage :
// Lighting pass model (full-screen quad)
Model {
id: deferredLightingQuad
layers: ContentLayer.Layer13 // Dedicated layer for lighting quad
geometry: PlaneGeometry {
plane: PlaneGeometry.XY // Quad in screen space
}
materials: CustomMaterial {
// Texture inputs for G-buffers
property TextureInput gbuffer0: TextureInput {
enabled: true
texture: Texture { textureProvider: gbuffer0Provider }
}
property TextureInput gbuffer1: TextureInput {
enabled: true
texture: Texture { textureProvider: gbuffer1Provider }
}
property TextureInput gbuffer2: TextureInput {
enabled: true
texture: Texture { textureProvider: gbuffer2Provider }
}
shadingMode: CustomMaterial.Unshaded
fragmentShader: "lighting.frag"
vertexShader: "lighting.vert"
}
}
// Lighting pass renders the quad to main output
RenderPass {
id: deferredLightingPass
materialMode: RenderPass.OriginalMaterial
commands: [
ColorAttachment { target: mainColorTexture },
DepthStencilAttachment { },
RenderablesFilter { layerMask: ContentLayer.Layer13 }
]
}Le shader de sommets d’éclairage (lighting.vert) crée un quadrilatère en plein écran en coordonnées normalisées du périphérique, et le shader de fragments (lighting.frag) échantillonne les G-buffers et effectue les calculs d’éclairage.
Intégration complète
Voici comment intégrer les deux passes dans un View3D:
View3D {
renderOverrides: View3D.DisableInternalPasses
// Main output texture
RenderPassTexture { id: mainColorTexture; format: RenderPassTexture.RGBA16F }
// Shared depth texture
RenderPassTexture { id: mainDepthStencilTexture; format: RenderPassTexture.Depth24Stencil8 }
// G-buffer render targets
RenderPassTexture { id: gbuffer0Tex; format: RenderPassTexture.RGBA16F }
RenderPassTexture { id: gbuffer1Tex; format: RenderPassTexture.RGBA16F }
RenderPassTexture { id: gbuffer2Tex; format: RenderPassTexture.RGBA16F }
// G-buffer pass
GBufferPass {
id: gbufferPass
layerMask: ContentLayer.Layer0 | ContentLayer.Layer1
gbuffer0: gbuffer0Tex
gbuffer1: gbuffer1Tex
gbuffer2: gbuffer2Tex
depthTexture: mainDepthStencilTexture
}
// Expose G-buffer outputs
RenderOutputProvider {
id: gbuffer0Provider
textureSource: RenderOutputProvider.UserPassTexture
renderPass: gbufferPass
attachmentSelector: RenderOutputProvider.Attachment0
}
RenderOutputProvider {
id: gbuffer1Provider
textureSource: RenderOutputProvider.UserPassTexture
renderPass: gbufferPass
attachmentSelector: RenderOutputProvider.Attachment1
}
RenderOutputProvider {
id: gbuffer2Provider
textureSource: RenderOutputProvider.UserPassTexture
renderPass: gbufferPass
attachmentSelector: RenderOutputProvider.Attachment2
}
// Lighting pass (defined above)
// Display final result
SimpleQuadRenderer {
texture: Texture {
textureProvider: RenderOutputProvider {
textureSource: RenderOutputProvider.UserPassTexture
renderPass: deferredLightingPass
attachmentSelector: RenderOutputProvider.Attachment0
}
}
}
// Scene objects
Model {
layers: ContentLayer.Layer0
source: "#Sphere"
materials: PrincipledMaterial {
baseColor: "red"
metalness: 0.5
roughness: 0.3
}
}
// Camera and lights
PerspectiveCamera { z: 300 }
DirectionalLight { eulerRotation.x: -45 }
}Flux de rendu
Le rendu se déroule comme suit :
- Passage G-buffer: les objets de la scène situés sur les couches Layer0 et Layer1 sont rendus. Pour chaque objet, le shader d’augmentation écrit l’albédo, les normales, la rugosité, la métallicité et la position dans trois attaches de couleur. La profondeur est écrite dans la texture de profondeur partagée.
- Pass d’éclairage: le quad plein écran de la couche 13 est rendu. Son matériau personnalisé échantillonne les trois textures du G-buffer et la texture de profondeur, reconstitue les informations de la scène et effectue les calculs d’éclairage (lumières directionnelles, éclairage basé sur l’image, etc.) pour produire la couleur éclairée finale.
- Affichage: Le résultat de la passe d’éclairage est affiché via SimpleQuadRenderer.
Avantages et limites
Avantages :
- Efficace avec de nombreuses lumières (chaque pixel n’est éclairé qu’une seule fois)
- Complexité de l’éclairage indépendante de la complexité de la scène
- Facilité de mise en œuvre des effets en espace écran
- Dissocie les passes de géométrie et d'éclairage
Limites :
- Bande passante mémoire plus élevée en raison des lectures/écritures dans le G-buffer
- Pas de MSAA matériel (nécessite un anti-aliasing alternatif)
- La transparence nécessite un passage direct distinct
- Pipeline plus complexe à mettre en place et à maintenir
Pour un exemple complet et fonctionnel, consultez l'exemple «Qt Quick 3D - User Passes ».
Exemple complet de pipeline de rendu
Un pipeline de rendu personnalisé et réaliste doit souvent combiner plusieurs types de passes : géométrie opaque, arrière-plan skybox, superpositions 2D et objets transparents. Voici un exemple complet montrant comment organiser ces éléments à l'aide d'SubRenderPass pour une composition hiérarchique :
View3D {
renderOverrides: View3D.DisableInternalPasses
environment: SceneEnvironment {
backgroundMode: SceneEnvironment.SkyBox
lightProbe: Texture {
textureData: ProceduralSkyTextureData { }
}
}
RenderPassTexture {
id: mainColorTexture
format: RenderPassTexture.RGBA16F
}
RenderPassTexture {
id: mainDepthStencilTexture
format: RenderPassTexture.Depth24Stencil8
}
// Main pass orchestrates the complete render path:
// 1. Opaque geometry (deferred)
// 2. Skybox background
// 3. 2D UI overlays
// 4. Transparent objects (forward)
RenderPass {
id: mainColorPass
clearColor: "black"
renderTargetFlags: RenderPass.PreserveDepthStencilContents
commands: [
ColorAttachment { target: mainColorTexture },
DepthTextureAttachment { target: mainDepthStencilTexture },
RenderablesFilter {
renderableTypes: RenderablesFilter.None // Parent doesn't render
},
// Sub-pass 1: Deferred lighting
SubRenderPass {
renderPass: RenderPass {
id: deferredLightingPass
materialMode: RenderPass.OriginalMaterial
commands: [
PipelineStateOverride {
depthWriteEnabled: false
depthTestEnabled: false
},
RenderablesFilter { layerMask: ContentLayer.Layer13 }
]
}
},
// Sub-pass 2: Skybox (behind everything)
SubRenderPass {
renderPass: RenderPass {
passMode: RenderPass.SkyboxPass
commands: [
PipelineStateOverride {
depthTestEnabled: true
depthWriteEnabled: false
}
]
}
},
// Sub-pass 3: 2D Qt Quick content
SubRenderPass {
renderPass: RenderPass {
passMode: RenderPass.Item2DPass
}
},
// Sub-pass 4: Transparent objects (forward rendering)
SubRenderPass {
renderPass: RenderPass {
materialMode: RenderPass.OriginalMaterial
commands: [
RenderablesFilter {
renderableTypes: RenderablesFilter.Transparent
layerMask: ContentLayer.Layer0 | ContentLayer.Layer1
},
PipelineStateOverride {
blendEnabled: true
depthTestEnabled: true
depthWriteEnabled: false
}
]
}
}
]
}
// G-buffer pass (referenced by deferred lighting)
GBufferPass {
id: gbufferPass
layerMask: ContentLayer.Layer0 | ContentLayer.Layer1
depthTexture: mainDepthStencilTexture
}
// Full-screen quad for deferred lighting
Model {
layers: ContentLayer.Layer13
geometry: PlaneGeometry { plane: PlaneGeometry.XY }
materials: CustomMaterial {
property TextureInput gbuffer0: TextureInput {
texture: Texture {
textureProvider: RenderOutputProvider {
textureSource: RenderOutputProvider.UserPassTexture
renderPass: gbufferPass
attachmentSelector: RenderOutputProvider.Attachment0
}
}
}
// ... other G-buffer inputs
shadingMode: CustomMaterial.Unshaded
fragmentShader: "lighting.frag"
vertexShader: "lighting.vert"
}
}
// Display final result
SimpleQuadRenderer {
texture: Texture {
textureProvider: RenderOutputProvider {
textureSource: RenderOutputProvider.UserPassTexture
renderPass: mainColorPass
}
}
}
// Opaque 3D content
Model {
layers: ContentLayer.Layer0
source: "#Sphere"
materials: PrincipledMaterial { baseColor: "red" }
}
// Transparent 3D content
Model {
layers: ContentLayer.Layer1
source: "#Cone"
materials: PrincipledMaterial {
baseColor: Qt.rgba(0.0, 1.0, 0.0, 0.5)
alphaMode: PrincipledMaterial.Blend
}
}
// 2D content in 3D space
Node {
x: -200
y: 100
Item {
Button { text: "Click Me!" }
Rectangle {
color: "blue"
width: 50; height: 50
}
}
}
PerspectiveCamera { z: 300 }
DirectionalLight { eulerRotation.x: -45 }
}Concepts clés
SubRenderPass pour l'organisation hiérarchique :
Le passage principal utilise des commandes « SubRenderPass » pour exécuter les passages enfants les uns après les autres. Le passage parent lui-même n’effectue aucun rendu (RenderablesFilter.None), il se contente d’orchestrer les passages enfants. Cela offre une structure claire et permet le partage du tampon de profondeur entre tous les sous-passages.
Modes de passe :
RenderPass.UserPass(par défaut) : rendu personnalisé avec votre géométrie et vos matériauxRenderPass.SkyboxPass: Rendu de la skybox d’environnement à partir de SceneEnvironmentRenderPass.Item2DPass: Rendu du contenu 2D d’ Qt Quick intégré à la scène 3D
Ordre de rendu :
- La géométrie opaque est rendue dans le G-buffer
- Éclairage différé appliqué au quad plein écran
- Skybox rendu derrière la géométrie (test de profondeur activé, écriture de profondeur désactivée)
- Superpositions de l'interface utilisateur 2D rendues par-dessus
- Les objets transparents sont rendus en dernier avec un effet de fusion
Partage du tampon de profondeur :
L'mainDepthStencilTexture est partagée entre les passes à l'aide de la fonction ` PreserveDepthStencilContents`. Cela garantit que le skybox est rendu derrière la géométrie et que les objets transparents sont correctement testés par rapport à la géométrie opaque.
Contenu Item2D :
Qt Quick Les éléments 2D (boutons, rectangles, texte, etc.) placés dans des objets « Node » sont rendus par RenderPass.Item2DPass. Ces éléments sont positionnés dans l’espace 3D mais rendus sous forme de superpositions 2D pouvant recevoir des entrées souris ou tactiles.
Considérations relatives aux performances
Les passes de rendu définies par l’utilisateur offrent un contrôle maximal, mais nécessitent une réflexion approfondie sur leurs implications en termes de performances.
Choix des formats de texture
Choisissez les formats de texture en fonction de vos besoins :
| Format | Taille par pixel | Cas d'utilisation |
|---|---|---|
| RGBA8 | 4 octets | Sortie finale, tampons de couleur simples |
| RGBA16F | 8 octets | Contenu HDR, tampons intermédiaires, normales |
| RGBA32F | 16 octets | Calculs de haute précision, positions |
| R16F | 2 octets | HDR monocanal (profondeur, AO, etc.) |
Pour un tampon d'image de 1920 × 1080 :
- RGBA8 : environ 8 Mo
- RGBA16F : environ 16 Mo
- RGBA32F : environ 32 Mo
- Trois G-buffers RGBA16F : environ 48 Mo
Recommandation : utilisez RGBA16F pour les tampons intermédiaires et RGBA8 ou R8 lorsque cela suffit.
Rendu différé vs rendu direct
| Aspect | Rendu différé | Rendu direct |
|---|---|---|
| Nombreuses lumières | Efficace (O(lumières + pixels)) | Coûteux (O(lumières * objets)) |
| Bande passante mémoire | Élevée (lectures/écritures dans le G-buffer) | Faible |
| Transparence | Nécessite un passage distinct | Prise en charge native |
| MSAA | Non pris en charge directement | Le MSAA matériel fonctionne |
| Complexité de la configuration | Plus complexe | Plus simple |
Utilisez le rendu différé lorsque :
- vous disposez de nombreuses lumières (10 ou plus)
- Les effets dans l'espace écran sont importants
- La scène est principalement opaque
Utilisez le rendu direct lorsque :
- Peu de lumières (<5)
- Beaucoup de transparence
- La bande passante mémoire est limitée
- Un pipeline plus simple est préférable
Optimisation de l'ordre des passes
Les passes de rendu s'exécutent dans l'ordre où elles sont rencontrées. Optimisez en :
- Rendu de la géométrie opaque avant la géométrie transparente
- En utilisant un pré-pass de profondeur lorsque cela est avantageux (réduit le surdessin dans les scènes complexes)
- Minimiser les changements de cible de rendu
- Réutiliser les tampons de profondeur d’un passage à l’autre lorsque cela est possible
Indicateurs de cible de rendu
La propriété « renderTargetFlags » contrôle le comportement de la mémoire :
RenderPass {
// First pass: write new content
renderTargetFlags: 0 // Default: clear render targets
}
RenderPass {
// Second pass: add to existing content
renderTargetFlags: RenderPass.PreserveColorContents |
RenderPass.PreserveDepthStencilContents
}
RenderPass {
// Depth not needed after this pass
renderTargetFlags: RenderPass.DoNotStoreDepthStencilContents
}PreserveColorContents/PreserveDepthStencilContents : conserve les données existantes (par exemple, pour un rendu en plusieurs passes vers la même cible).
DoNotStoreDepthStencilContents : indique que les données de profondeur et de stencil peuvent être ignorées (sur certains matériels, cela peut améliorer les performances en évitant les écritures en mémoire).
Quand utiliser les passes utilisateur
Envisagez d’utiliser des passes de rendu utilisateur lorsque :
- Mise en œuvre du rendu différé
- La création d’effets complexes en plusieurs passes
- Besoin d’un contrôle explicite sur l’ordre de rendu
- lors de la mise en œuvre de techniques de rendu personnalisées
- Créer des effets dans l’espace écran nécessitant des données géométriques
Évitez les passes utilisateur lorsque :
- Le rendu par défaut répond à vos besoins
- Vous n'avez besoin que d'un post-traitement (utilisez plutôt Effect )
- Vous n'avez besoin que de shaders de matériaux personnalisés (utilisez plutôt CustomMaterial )
- Les performances sont essentielles et des passes supplémentaires seraient inutiles
Modèles courants et cas d'utilisation
Les passes de rendu utilisateur permettent de nombreuses techniques de rendu avancées. Voici quelques modèles courants :
Ombrage/éclairage différé
Stockez les attributs de géométrie dans des G-buffers et effectuez l'éclairage dans l'espace écran. Ce sujet est abordé en détail dans l'exemple avancé : Rendu différé.
Détection des contours et tracé des contours
Effectuez un rendu normal de la scène, puis appliquez la détection des contours lors d’un deuxième passage :
// Pass 1: Render scene with normals/depth
RenderPass {
id: scenePass
commands: [
ColorAttachment { target: colorTex },
DepthTextureAttachment { target: depthTex }
]
}
// Pass 2: Edge detection using depth discontinuities
RenderPass {
id: edgePass
commands: [
ColorAttachment { target: outlineTex },
RenderablesFilter { layerMask: ContentLayer.Layer10 }
]
}
Model {
layers: ContentLayer.Layer10
geometry: PlaneGeometry { }
materials: CustomMaterial {
property TextureInput depthInput: TextureInput {
// depthProvider is the id of a RenderOutputProvider that exposes
// depthTex as a sampleable texture (see "Render Output Provider"
// earlier in this page).
texture: Texture { textureProvider: depthProvider }
}
fragmentShader: "edge_detect.frag"
// Shader samples depth, computes gradients, draws edges
}
}Chaînes de post-traitement personnalisées
Enchaînez plusieurs effets de post-traitement en transmettant la sortie de chaque passe à la suivante via RenderOutputProvider. Consultez l’exemple « Pass Chaining » pour découvrir un exemple concret de chaîne à plusieurs étapes (scenePass → process1 → process2 → affichage).
Superposition sélective de fil de fer
Affichez certains objets en mode plein et d’autres sous forme de superpositions filaires. Consultez l’exemple dans la section « Utilisation des calques ».
Visualisation de débogage
Créez des passes de débogage permettant de visualiser les normales, la profondeur ou d’autres données :
// Normal visualization pass
RenderPass {
materialMode: RenderPass.OverrideMaterial
overrideMaterial: CustomMaterial {
fragmentShader: "debug_normals.frag"
// FRAGCOLOR = vec4(normalize(NORMAL) * 0.5 + 0.5, 1.0);
}
commands: [
ColorAttachment { target: debugTex }
]
}Mappage d’ombres personnalisé
Implémentez un mappage d’ombres personnalisé avec un contrôle explicite :
// Shadow map pass (render from light's perspective)
RenderPass {
id: shadowPass
materialMode: RenderPass.OverrideMaterial
overrideMaterial: CustomMaterial {
fragmentShader: "depth_only.frag"
}
commands: [
DepthTextureAttachment { target: shadowMapTex }
]
}
// Main pass using shadow map
RenderPass {
id: mainPass
commands: [
ColorAttachment { target: colorTex },
DepthStencilAttachment { }
]
}
// Materials in main pass sample shadowMapTex for shadow testingConsidérations importantes
Lorsque vous travaillez avec des passes de rendu utilisateur, gardez à l'esprit ces points importants :
Gestion des ombres
Les passes de rendu utilisateur n' intègrent pas automatiquement le rendu d'ombre interne d'Qt Quick 3D. Si vous désactivez les passes internes et que vous avez besoin d'ombres, vous devez :
- Mettre en œuvre vos propres passes de shadow mapping
- Rendu de la scène depuis la perspective de la source lumineuse vers une texture de profondeur
- Échantillonner la carte d’ombres dans vos calculs d’éclairage
Sinon, dans les cas plus simples, vous n'aurez peut-être pas besoin d'ombres ou pourrez utiliser des cartes d'ombres précalculées.
HDR et mappage de tons
Lorsque vous utilisez des cibles de rendu en virgule flottante (RGBA16F, RGBA32F), votre rendu s'effectue dans un espace HDR linéaire. Vous devez appliquer un mappage de tons lors de votre passe d'affichage finale pour convertir le résultat en LDR affichable :
CustomMaterial {
fragmentShader: "tonemap.frag"
}// In tonemap.frag
vec3 tonemap(vec3 hdr) {
// Simple Reinhard tonemapping
return hdr / (hdr + vec3(1.0));
}
void MAIN() {
vec3 hdrColor = texture(hdrInput, UV0).rgb;
FRAGCOLOR = vec4(tonemap(hdrColor), 1.0);
}Qt Quick 3D fournit une fonction d'qt_tonemap() e dans les shaders qui peut être utilisée à cette fin.
Génération de textures de profondeur
Lorsque vous avez besoin de la profondeur sous forme de texture (pour des effets tels que la profondeur de champ), utilisez ` DepthTextureAttachment ` à la place de ` DepthStencilAttachment` :
RenderPassTexture {
id: depthTex
format: RenderPassTexture.Depth24Stencil8
}
RenderPass {
commands: [
ColorAttachment { target: colorTex },
DepthTextureAttachment { target: depthTex }
// depthTex can now be sampled in shaders
]
}Valeurs d’effacement et gestion des cibles de rendu
Chaque passe peut spécifier des valeurs de réinitialisation :
RenderPass {
clearColor: Qt.rgba(0.0, 0.0, 0.0, 0.0)
depthClearValue: 1.0
stencilClearValue: 0
}Lorsqu’un passage ne conserve pas le contenu (par défaut), les cibles de rendu sont effacées et remplacées par ces valeurs avant le rendu. Lorsque ` PreserveColorContents ` ou ` PreserveDepthStencilContents ` est défini, le contenu existant est conservé et les valeurs d’effacement sont ignorées.
Bonnes pratiques d’organisation des calques
Organisez vos calques de manière logique :
- Calques 0 à 2: objets principaux de la scène
- Calques 3-4: objets transparents (passage distinct)
- Calques 10 et plus: quadrilatères en plein écran pour le post-traitement
- Calques 15 et plus: superpositions d’interface utilisateur/de débogage
Documentez l'utilisation de vos calques dans les commentaires et veillez à la cohérence dans toute votre application.
Compatibilité des shaders
Les shaders Augment et les matériaux personnalisés utilisés dans les passes de rendu doivent être compatibles avec l’infrastructure de shaders d’ Qt Quick 3D :
- Utilisez une syntaxe compatible GLSL
- Incluez les directives
\#includeappropriées pour les fonctions d'Qt Quick 3D - Tenez compte des variables intégrées disponibles
- Testez sur toutes les plateformes cibles (OpenGL, Vulkan, Metal, D3D)
Limitations des cibles de rendu multiples
Lors de l'utilisation de cibles de rendu multiples (MRT) :
- 4 cibles de rendu couleur au maximum
- Toutes les cibles de rendu doivent avoir les mêmes dimensions
- L'état de fusion peut être spécifié pour chaque attachement via PipelineStateOverride
- Tous les matériels ne prennent pas en charge les MRT (vérifiez les capacités de l'appareil)
Transparence
Les objets transparents posent des difficultés avec le rendu différé. Approches courantes :
- Passage direct pour les objets transparents: rendre la géométrie opaque de manière différée, et la géométrie transparente dans un passage direct distinct
- G-buffer transparent distinct: rendre la géométrie transparente dans un ensemble distinct de G-buffers avec le mélange activé
- Transparence pondérée avec mélange indépendant de l'ordre: utiliser des techniques OIT spécialisées
Dans la plupart des cas, un passage direct distinct pour les objets transparents est la solution la plus simple.
Référence API
Le tableau suivant fournit une référence complète de tous les types liés aux passes de rendu utilisateur :
| Fonctionnalité | Type QML | Description |
|---|---|---|
| Définition du passage de rendu principal | RenderPass | Définit un passage de rendu avec des commandes et un mode de matériau |
| Textures de cible de rendu | RenderPassTexture | Texture utilisée comme cible de rendu (couleur ou profondeur/stencil) |
| Fournisseur de sortie de texture | RenderOutputProvider | Expose la sortie du passage de rendu en tant qu’entrée de texture |
| Constantes de couche | ContentLayer | Singleton fournissant des constantes de filtrage de couche |
| Sortie couleur | ColorAttachment | Spécifie une cible de rendu couleur |
| Profondeur/stencil (par défaut) | DepthStencilAttachment | Utilise un tampon de profondeur/stencil implicite |
| Profondeur/stencil (texture) | DepthTextureAttachment | Utilise une texture de profondeur explicite |
| Filtrage des objets | RenderablesFilter | Filtre les objets par couche et par type |
| État du pipeline | PipelineStateOverride | Remplace l'état du pipeline graphique |
| Exécution de passes imbriquées | SubRenderPass | Exécute un autre passage de rendu |
| Définitions de shader | AddDefine | Ajoute une définition du préprocesseur de shader |
| État de fusion par cible | renderTargetBlend | Configuration de fusion pour MRT |
| Aide à l’affichage | SimpleQuadRenderer | Rendu de la sortie finale vers View3D |
Types associés
| Type | Description |
|---|---|
| CustomMaterial | Matériau personnalisé avec shaders de sommets/fragments |
| Effect | Effets de post-traitement |
| View3D | Vue 3D avec la propriété « renderOverrides » |
| Model | Modèle 3D avec la propriété « layers » |
Exemples
- Qt Quick 3D - Exemples de passes utilisateur: exemple complet de rendu différé
Voir aussi
- Données programmables relatives aux matériaux, aux effets, à la géométrie et aux textures: présentation des fonctionnalités de personnalisation 3D d'Qt Quick
- Qt Quick Architecture 3D: Comprendre le pipeline de rendu
© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.