Qt Quick 3D - Exemple de passes utilisateur
Illustre la création de passes de rendu personnalisées dans Qt Quick 3D.

}
L'exemple « Passages utilisateur » montre comment créer des passages de rendu personnalisés dans Qt Quick 3D. Il met en œuvre un pipeline de rendu à éclairage différé utilisant plusieurs passages de rendu définis par l'utilisateur et explique comment gérer la séquence de rendu complète : géométrie opaque, skybox, éléments 2D intégrés à la scène et géométrie transparente.
Désactivation des passes de rendu internes
Par défaut, Qt Quick 3D utilise un ensemble de passes de rendu internes pour rendre la scène 3D. Vous pouvez parfois souhaiter désactiver ces passes internes et implémenter votre propre pipeline de rendu à l'aide de passes de rendu définies par l'utilisateur.
Pour désactiver les passes de rendu internes, définissez la propriété ` renderOverrides ` de l’ View3D sur ` View3D.DisableInternalPasses`.
View3D {
id: view3D
anchors.fill: parent
renderOverrides: View3D.DisableInternalPasses
environment: ExtendedSceneEnvironment {
lightProbe: Texture {
textureData: ProceduralSkyTextureData {
}
}
backgroundMode: SceneEnvironment.SkyBox
}Si vous désactivez les passes de rendu internes, vous devrez fournir le résultat de la passe de couleur principale à l’ View3D pour qu’il puisse afficher quoi que ce soit à l’écran.
Pass de tampon de géométrie
Dans cet exemple, le premier passage de rendu personnalisé est un passage de tampon de géométrie (G-buffer) qui rend la géométrie de la scène dans plusieurs cibles de rendu, en stockant différentes propriétés de matériau dans chaque cible. L’exemple fourni est un sous-ensemble des propriétés de matériau complètes fournies par les matériaux 3D d’ Qt Quick, en se concentrant sur les propriétés nécessaires à une implémentation de base de l’éclairage différé.
Notre RenderPass est défini dans GBufferPass.qml:
RenderPass {
id: gbufferPass
clearColor: Qt.rgba(0.0, 0.0, 0.0, 0.0)
property alias layerMask: filter.layerMask
required property RenderPassTexture depthTexture
RenderPassTexture {
id: gbuffer0
format: RenderPassTexture.RGBA16F
// rgb: baseColor (linear), a: metalness
}
RenderPassTexture {
id: gbuffer1
format: RenderPassTexture.RGBA16F
// rgb: normal, a: roughness
}
RenderPassTexture {
id: gbuffer2
format: RenderPassTexture.RGBA16F
// rgb: emissive, a: ao/spare
}
commands: [
ColorAttachment { target: gbuffer0; name: "GBUFFER0" },
ColorAttachment { target: gbuffer1; name: "GBUFFER1" },
ColorAttachment { target: gbuffer2; name: "GBUFFER2" },
DepthTextureAttachment { target: gbufferPass.depthTexture },
RenderablesFilter {
id: filter
renderableTypes: RenderablesFilter.Opaque
}
]
materialMode: RenderPass.AugmentMaterial
augmentShader: "gbuffer_augment.glsl"
}Il définit 3 attachements de couleur et 1 attachement de profondeur. Le passage nécessite 3 textures qui sont définies en tant qu’objets « RenderPassTexture » au sein de l’objet RenderPass. Ces 3 RenderPassTextures sont utilisées comme cibles pour les attachements de couleur du passage, tandis que l’attachement de profondeur utilise une texture de profondeur fournie en dehors du passage.
L’ RenderPass lui-même est configuré en mode « AugmentMaterial », ce qui signifie qu’il enrichira les matériaux des objets rendus à l’aide d’un code de shader supplémentaire. Le shader d’enrichissement est fourni dans le fichier « gbuffer_augment.glsl », qui transmet les propriétés de matériau requises aux différentes cibles de rendu.
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);
}Vous voyez ici comment la couleur de base, la métallicité, la normale mondiale, la rugosité et la position mondiale sont stockées dans les trois attaches de couleur du G-buffer.
Pour utiliser concrètement le passage G-buffer dans le pipeline de rendu, nous devons en créer une instance dans ` Main.qml` et fournir la texture de profondeur requise :
RenderPassTexture {
id: mainDepthStencilTexture
format: RenderPassTexture.Depth24Stencil8
}
GBufferPass {
id: gbufferPass
layerMask: ContentLayer.Layer0 | ContentLayer.Layer1
depthTexture: mainDepthStencilTexture
}
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
}Trois instances d’ RenderOutputProvider sont créées pour fournir des références aux textures du G-buffer rendues, qui seront utilisées dans la passe d’éclairage suivante.
La propriété « layerMask » de la passe G-buffer est configurée pour ne rendre que les objets se trouvant sur ContentLayer.Layer0 et ContentLayer.Layer1. Cela nous permet de contrôler quels objets sont rendus dans la passe G-buffer en définissant leur propriété « layers » en conséquence.
Pass de couleur principale et sous-pass de rendu
Plutôt qu’un seul passage de rendu plat, cet exemple utilise un « composite mainColorPass » qui gère les textures de couleur principale et de profondeur, et orchestre l’ensemble du rendu via une séquence d’enfants de type « SubRenderPass ».
Chaque SubRenderPass partage les mêmes cibles de rendu que le pass externe et s’exécute dans l’ordre. Cela permet de construire facilement un pipeline de rendu en couches où chaque étape s’ajoute au résultat de la précédente.
RenderPass {
id: mainColorPass
clearColor: "black"
// Preserve depth across SubRenderPasses so geometry depth is available
// when rendering the skybox, transparent objects, and 2D items.
renderTargetFlags: RenderPass.RenderTargetFlags.PreserveDepthStencilContents
commands: [
ColorAttachment {
target: mainColorTexture
},
DepthTextureAttachment {
target: mainDepthStencilTexture
},
RenderablesFilter {
// Nothing renders directly in the outer pass; all rendering
// is delegated to the SubRenderPasses below.
renderableTypes: RenderablesFilter.None
},
// 1. Deferred lighting: shade opaque geometry stored in the G-buffer.
SubRenderPass {
renderPass: RenderPass {
id: deferredLightingPass
materialMode: RenderPass.OriginalMaterial
commands: [
PipelineStateOverride {
// The full-screen quad must not write or test depth;
// geometry depth was already written by the G-buffer pass.
depthWriteEnabled: false
depthTestEnabled: false
},
RenderablesFilter { layerMask: ContentLayer.Layer13 }
]
}
},
// 2. Skybox: render the environment behind all scene geometry.
SubRenderPass {
renderPass: RenderPass {
id: skyboxPass
passMode: RenderPass.SkyboxPass
commands: [
PipelineStateOverride {
// The skybox is rendered "at infinity" so it must
// depth-test (to be hidden by geometry) but must not
// write depth.
depthTestEnabled: true
depthWriteEnabled: false
}
]
}
},
// 3. 2D items: render any Qt Quick Items embedded in the 3D scene.
SubRenderPass {
renderPass: RenderPass {
id: item2DPass
passMode: RenderPass.Item2DPass
}
},
// 4. Transparent objects: render blended geometry on top of everything else.
SubRenderPass {
renderPass: RenderPass {
id: transparentItemPass
materialMode: RenderPass.OriginalMaterial
commands: [
RenderablesFilter {
renderableTypes: RenderablesFilter.Transparent
layerMask: ContentLayer.Layer0 | ContentLayer.Layer1
},
PipelineStateOverride {
// Enable alpha blending and depth testing so transparent
// objects sort correctly against opaque geometry.
blendEnabled: true
depthTestEnabled: true
targetBlend0.enable: true
targetBlend0.srcColor: RenderTargetBlend.SrcAlpha
targetBlend0.dstColor: RenderTargetBlend.OneMinusSrcAlpha
targetBlend0.srcAlpha: RenderTargetBlend.One
targetBlend0.dstAlpha: RenderTargetBlend.OneMinusSrcAlpha
}
]
}
}
]
}Le pass externe définit renderableTypes: RenderablesFilter.None afin que rien ne soit rendu directement dans le pass parent — tout le rendu est délégué aux sous-pass. Le drapeau « PreserveDepthStencilContents » garantit que les valeurs de profondeur écrites par le pass G-buffer sont disponibles pour chaque sous-pass.
Sous-pass d’éclairage différé
Le premier sous-pass exécute le calcul de l’éclairage différé. Il effectue le rendu du modèle « deferredLightingQuad » en plein écran, qui échantillonne les textures du G-buffer et évalue l’éclairage pour chaque pixel.
Model {
id: deferredLightingQuad
layers: ContentLayer.Layer13
castsShadows: false
receivesShadows: false
geometry: PlaneGeometry {
// geometry doesn't matter, just need 4 verts
plane: PlaneGeometry.XY
}
materials: [
CustomMaterial {
id: lightingPassMaterial
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"
}
]
}L’ deferredLightingQuad est placé sur « ContentLayer.Layer13 » (Cache de profondeur désactivé) afin qu’il soit invisible pour le passage G-buffer et rendu uniquement par ce sous-passage.
Un « PipelineStateOverride » désactive à la fois les écritures de profondeur et les tests de profondeur pour le quad. Le passage du G-buffer a déjà écrit la profondeur correcte pour la géométrie de la scène ; le quad plein écran ne doit donc ni modifier ni tester la profondeur.
Sous-pass Skybox
Le deuxième sous-pass effectue le rendu de la skybox de l’environnement de la scène à l’aide du mode de pass spécial « RenderPass.SkyboxPass ». « Qt Quick 3D» se charge de dessiner la géométrie de la skybox en utilisant les paramètres « lightProbe » et « backgroundMode » de l’ SceneEnvironment.
Un « PipelineStateOverride » active le test de profondeur afin que la skybox soit correctement masquée derrière la géométrie de la scène, tandis que les écritures de profondeur sont désactivées car la skybox se trouve « à l’infini » et ne doit jamais occulter la géométrie.
Sous-pass des objets transparents
Les objets transparents ne peuvent pas être stockés dans le G-buffer car ils nécessitent un mélange trié de l’arrière vers l’avant. Ils sont donc rendus en dernier à l’aide de leurs matériaux d’origine via un sous-pass dédié.
Le cône transparent de la scène est déclaré comme suit :
Model {
id: cone
layers: ContentLayer.Layer1
source: "#Cone"
y: 100
materials: [
PrincipledMaterial {
baseColor: Qt.rgba(0.0, 1.0, 0.0, 0.5)
alphaMode: PrincipledMaterial.Blend
metalness: 0.0
roughness: 0.5
}
]
}Le sous-pass transparent utilise une « RenderablesFilter » pour sélectionner uniquement les éléments de rendu transparents sur les couches correspondantes, et une « PipelineStateOverride » active le mélange alpha tout en conservant le test de profondeur actif afin que les objets transparents soient correctement triés par rapport à la géométrie opaque.
Les objets transparents doivent être rendus après toutes les passes opaques afin que le tampon de profondeur soit entièrement rempli avant que le mélange n'ait lieu.
Éléments 2D dans un sous-pass 3D
Qt Quick La 3D peut intégrer des éléments 2D standard d’ Qt Quick au sein de la scène 3D en utilisant Node comme conteneur. Pour inclure ces éléments dans un pipeline de rendu personnalisé, ajoutez un sous-pass avec passMode: RenderPass.Item2DPass.
Node {
x: -200
y: 100
Item {
anchors.centerIn: parent
ColumnLayout {
Button {
text: "Click Me!"
}
Rectangle {
color: "blue"
implicitWidth: 50
implicitHeight: 50
NumberAnimation on rotation {
from: 0
to: 360
duration: 4000
loops: Animation.Infinite
running: true
}
}
}
}
NumberAnimation on eulerRotation.y {
from: 0
to: 360
duration: 6000
loops: Animation.Infinite
running: true
}
}Le mode « Item2DPass » indique à Qt Quick 3D de rendre tous les éléments Qt Quick qui sont des enfants de nœuds 3D dans la cible de rendu actuelle, en les composant avec le contenu 3D déjà présent.
Rendu à l’écran
Enfin, pour afficher à l’écran le résultat de nos passes de rendu personnalisées, nous devons nous assurer que la texture de couleur principale de l’ View3D est mise à jour avec le résultat de la passe de couleur principale.
SimpleQuadRenderer {
texture: Texture {
textureProvider: mainColorPassProvider
}
}
RenderPassTexture {
id: mainColorTexture
format: RenderPassTexture.RGBA16F
}
RenderOutputProvider {
id: mainColorPassProvider
textureSource: RenderOutputProvider.UserPassTexture
renderPass: mainColorPass
attachmentSelector: RenderOutputProvider.Attachment0
}L'SimpleQuadRenderer sert à copier la texture de couleur principale générée par l'mainColorPass vers le framebuffer de l'View3D. L'RenderOutputProvider expose la première attache de couleur de l'mainColorPass sous forme de texture que l'SimpleQuadRenderer peut échantillonner.
© 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.