Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qtquick3d-userpasses.qdoc
Go to the documentation of this file.
1
// Copyright (C) 2025 The Qt Company Ltd.
2
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
3
4
/*!
5
\page qtquick3d-userpasses.html
6
\title User-Defined Render Passes in Qt Quick 3D
7
\brief Controlling the rendering pipeline with custom render passes
8
9
\since 6.11
10
11
Qt Quick 3D provides a high-level API for 3D rendering that handles most rendering
12
details automatically. However, for advanced use cases, applications may need complete
13
control over the rendering pipeline. User-defined render passes enable this by allowing
14
applications to disable the internal rendering pipeline and define their own custom passes.
15
16
User render passes enable advanced rendering techniques such as:
17
18
\list
19
\li Deferred shading and lighting
20
\li Multi-pass rendering effects
21
\li Custom post-processing pipelines
22
\li Selective rendering with layer-based filtering
23
\li Screen-space effects (ambient occlusion, reflections, etc.)
24
\li Custom shadow mapping techniques
25
\li Debug visualization passes
26
\endlist
27
28
\section1 Levels of Customization
29
30
Qt Quick 3D offers three complementary levels of rendering customization, each suited
31
to different use cases:
32
33
\table
34
\header
35
\li Level
36
\li Scope
37
\li Use Cases
38
\row
39
\li \l Effect
40
\li Post-processing
41
\li Applies effects after the scene is rendered (blur, color grading, etc.)
42
\row
43
\li \l CustomMaterial
44
\li Per-material shaders
45
\li Custom vertex and fragment shaders for individual materials
46
\row
47
\li \l RenderPass (User Render Passes)
48
\li Complete pipeline control
49
\li Deferred rendering, multiple passes, custom render targets
50
\endtable
51
52
User render passes (\l RenderPass) provide the most control, allowing you to either
53
supplement or completely replace the default rendering pipeline. This complements
54
\l CustomMaterial and \l Effect: \l CustomMaterial customizes how individual objects
55
are rendered, while user render passes control the overall rendering strategy and
56
architecture.
57
58
\section1 Using User Render Passes
59
60
User render passes can be used in two ways:
61
62
\section2 Supplementing Internal Passes
63
64
You can add custom \l RenderPass objects alongside the default rendering pipeline without
65
disabling internal passes. This is useful for rendering to textures that are then used by
66
\l Effect or \l CustomMaterial, or for creating auxiliary render targets.
67
68
\qml
69
View3D {
70
// Internal passes still run normally
71
72
RenderPassTexture { id: customTexture; format: RenderPassTexture.RGBA16F }
73
74
RenderPass {
75
// Custom pass renders to texture
76
commands: [
77
ColorAttachment { target: customTexture },
78
DepthStencilAttachment { }
79
]
80
}
81
82
// Use customTexture in an Effect or material
83
}
84
\endqml
85
86
\section2 Replacing Internal Passes
87
88
For complete control over the rendering pipeline, disable Qt Quick 3D's internal rendering
89
by setting the \l{View3D::renderOverrides}{renderOverrides} property:
90
91
\qml
92
View3D {
93
renderOverrides: View3D.DisableInternalPasses
94
95
// Your custom render passes go here
96
}
97
\endqml
98
99
When internal passes are disabled, Qt Quick 3D will not perform any default rendering.
100
This means you must:
101
102
\list
103
\li Define at least one \l RenderPass to render your scene
104
\li Provide the final output texture to display via \l SimpleQuadRenderer or similar mechanism
105
\li Handle all rendering aspects including depth buffers, transparency, etc.
106
\endlist
107
108
\note Disabling internal passes gives you complete control, but also complete responsibility.
109
Features like automatic shadow rendering, transparency sorting, and environment reflections
110
must be implemented in your custom passes if needed.
111
112
\section1 Core Concepts
113
114
User-defined render passes are built from several key components:
115
116
\section2 RenderPass
117
118
The \l RenderPass type is the main building block. It defines a single rendering operation
119
with a set of commands that control what gets rendered and how. Each pass can:
120
121
\list
122
\li Render to one or more color textures (up to 4 simultaneous render targets)
123
\li Write depth and stencil information
124
\li Filter which objects to render based on layers
125
\li Override graphics pipeline state (blending, culling, etc.)
126
\li Use original materials, augment them with custom shaders, or override them entirely
127
\endlist
128
129
\section2 Pass Ordering
130
131
The pass hierarchy determines the render order: nested passes render \e before
132
their parent, so a pass that produces a texture consumed by another pass is
133
declared as a child of its consumer, and results merge towards the top of the
134
hierarchy. A pass's nesting depth is the number of RenderPass ancestors it
135
has; other ancestors, such as \l Node items used for grouping, are transparent
136
and do not affect the order. A deeper-nested pass renders before all passes at
137
shallower depths, so its output is available to every consumer that frame, not
138
only its parent. The relative render order of passes at the same nesting
139
depth is not defined; use nesting to express an ordering requirement.
140
141
Nesting affects ordering only; a nested pass still renders into its own render
142
target, and its output is consumed through a \l RenderOutputProvider. To render
143
into the parent pass's render target instead, reference the pass from a
144
\l SubRenderPass command; such a pass is invoked by its parent and never
145
renders on its own.
146
147
\section2 RenderPassTexture
148
149
The \l RenderPassTexture type defines textures that serve as render targets. These can be
150
color textures in various formats (RGBA8, RGBA16F, RGBA32F, etc.) or depth/stencil
151
textures. Render pass textures are used as outputs from one pass and can be used as
152
texture inputs to subsequent passes.
153
154
\section2 RenderOutputProvider
155
156
The \l RenderOutputProvider type connects render passes by exposing the output textures
157
from one pass as texture inputs that can be used by materials or other passes. This is
158
essential for multi-pass rendering where later passes need to read the results of
159
earlier passes.
160
161
\section2 ContentLayer
162
163
The \l ContentLayer singleton provides layer constants (Layer0 through Layer23) used for
164
filtering which objects render in which pass. By assigning objects to specific layers and
165
using \l RenderablesFilter in your passes, you can control precisely what gets rendered
166
in each pass.
167
168
\section2 Render Commands
169
170
Each \l RenderPass contains a list of commands that configure its behavior:
171
172
\list
173
\li \l ColorAttachment: Specifies a color render target
174
\li \l DepthStencilAttachment: Specifies depth/stencil handling
175
\li \l DepthTextureAttachment: Uses a texture for depth output
176
\li \l RenderablesFilter: Filters objects by layer and type (opaque/transparent)
177
\li \l PipelineStateOverride: Controls graphics pipeline state
178
\li \c SubRenderPass: Executes another render pass within this pass
179
\li \l AddDefine: Adds shader preprocessor defines
180
\endlist
181
182
\section1 Material Modes
183
184
Each \l RenderPass has a \l{RenderPass::materialMode}{materialMode} property that controls
185
how materials are handled during rendering. The three modes offer different levels of
186
material control:
187
188
\section2 OriginalMaterial Mode
189
190
This mode renders objects with their assigned materials unchanged. It's useful when you
191
want to control the rendering pipeline structure (multiple passes, custom render targets)
192
but keep the material behavior standard.
193
194
\qml
195
RenderPass {
196
materialMode: RenderPass.OriginalMaterial
197
commands: [
198
ColorAttachment { target: myColorTexture },
199
DepthStencilAttachment { }
200
]
201
}
202
\endqml
203
204
\section2 AugmentMaterial Mode
205
206
This mode injects custom shader code into the existing material pipeline. It's particularly
207
useful for deferred rendering where you need to output additional data (like normals,
208
positions, etc.) to multiple render targets while preserving the material's base behavior.
209
210
\qml
211
RenderPass {
212
materialMode: RenderPass.AugmentMaterial
213
augmentShader: "my_augment.glsl"
214
commands: [
215
ColorAttachment { target: gbuffer0; name: "GBUFFER0" },
216
ColorAttachment { target: gbuffer1; name: "GBUFFER1" },
217
DepthStencilAttachment { }
218
]
219
}
220
\endqml
221
222
The augment shader file contains a \c{MAIN_FRAGMENT_AUGMENT()} function:
223
224
\badcode
225
void MAIN_FRAGMENT_AUGMENT()
226
{
227
// Access material properties
228
vec3 color = BASE_COLOR.rgb;
229
float metal = METALNESS;
230
float rough = ROUGHNESS;
231
vec3 normal = normalize(WORLD_NORMAL);
232
233
// Write to multiple render targets
234
GBUFFER0 = vec4(color, metal);
235
GBUFFER1 = vec4(normal * 0.5 + 0.5, rough);
236
}
237
\endcode
238
239
See \l{Augment Shaders for Multiple Render Targets} for more details.
240
241
\section2 OverrideMaterial Mode
242
243
This mode replaces all object materials with a single material. It's useful for specialized
244
passes like shadow mapping, depth prepass, or debug visualization.
245
246
\qml
247
RenderPass {
248
materialMode: RenderPass.OverrideMaterial
249
overrideMaterial: CustomMaterial {
250
fragmentShader: "depth_only.frag"
251
// All objects will use this material
252
}
253
commands: [
254
DepthTextureAttachment { target: depthTexture }
255
]
256
}
257
\endqml
258
259
\section1 Render Pass Commands
260
261
Commands are specified in the \l{RenderPass::commands}{commands} property and execute
262
in the order they are defined.
263
264
\section2 Color Attachment
265
266
The \l ColorAttachment command specifies a color render target. The \c name property
267
defines how the attachment is accessed in augment shaders.
268
269
\qml
270
ColorAttachment {
271
target: myTexture // RenderPassTexture to render to
272
name: "GBUFFER0" // Name for shader access (optional)
273
}
274
\endqml
275
276
You can have up to 4 color attachments per pass (for multiple render targets).
277
278
\section2 Depth Attachments
279
280
There are two ways to handle depth:
281
282
\b{DepthStencilAttachment} uses an implicit depth/stencil buffer:
283
284
\qml
285
DepthStencilAttachment { } // Creates depth/stencil buffer automatically
286
\endqml
287
288
\b{DepthTextureAttachment} uses an explicit texture for depth output:
289
290
\qml
291
RenderPassTexture {
292
id: depthTex
293
format: RenderPassTexture.Depth24Stencil8
294
}
295
296
DepthTextureAttachment {
297
target: depthTex // Explicit depth texture
298
}
299
\endqml
300
301
Use \l DepthTextureAttachment when you need to share the depth buffer between multiple
302
passes or use it as a texture input in shaders.
303
304
\section2 Renderables Filter
305
306
The \l RenderablesFilter command controls which objects are rendered based on their layer
307
assignment and renderable type.
308
309
\qml
310
RenderablesFilter {
311
layerMask: ContentLayer.Layer0 | ContentLayer.Layer1
312
renderableTypes: RenderablesFilter.Opaque
313
}
314
\endqml
315
316
The \c layerMask property uses bitwise OR to combine layers. The \c renderableTypes
317
property can be:
318
\list
319
\li \c RenderablesFilter.Opaque: Render only opaque objects
320
\li \c RenderablesFilter.Transparent: Render only transparent objects
321
\li \c RenderablesFilter.Opaque | RenderablesFilter.Transparent: Render both
322
\endlist
323
324
\section2 Pipeline State Override
325
326
The \l PipelineStateOverride command provides fine-grained control over graphics pipeline
327
state. It can override depth testing, blending, culling, polygon mode, and more.
328
329
\qml
330
PipelineStateOverride {
331
depthTestEnabled: true
332
depthWriteEnabled: false
333
blendEnabled: true
334
cullMode: PipelineStateOverride.Back
335
polygonMode: PipelineStateOverride.Fill
336
}
337
\endqml
338
339
See \l{Pipeline State Control} for more examples.
340
341
\section2 Sub Render Pass
342
343
The \c SubRenderPass command allows hierarchical composition of render passes by executing
344
another render pass within the current pass.
345
346
\qml
347
RenderPass {
348
id: parentPass
349
commands: [
350
ColorAttachment { target: colorTex },
351
SubRenderPass { renderPass: childPass },
352
// More commands after child pass
353
]
354
}
355
356
RenderPass {
357
id: childPass
358
// This pass executes within parentPass
359
}
360
\endqml
361
362
\section2 Add Define
363
364
The \l AddDefine command adds shader preprocessor defines that affect shader compilation.
365
366
\qml
367
AddDefine {
368
name: "USE_SPECIAL_MODE"
369
value: 1
370
}
371
\endqml
372
373
\section1 Simple Example: Single Pass Rendering
374
375
Here's a minimal example showing user-defined render passes:
376
377
\qml
378
import QtQuick
379
import QtQuick3D
380
import QtQuick3D.Helpers
381
382
View3D {
383
anchors.fill: parent
384
renderOverrides: View3D.DisableInternalPasses
385
386
// Camera and lights
387
PerspectiveCamera { z: 300 }
388
DirectionalLight { }
389
390
// Define render target texture
391
RenderPassTexture {
392
id: colorTarget
393
format: RenderPassTexture.RGBA16F
394
}
395
396
// Define the render pass
397
RenderPass {
398
id: mainPass
399
materialMode: RenderPass.OriginalMaterial
400
clearColor: "skyblue"
401
402
commands: [
403
ColorAttachment { target: colorTarget },
404
DepthStencilAttachment { }
405
]
406
}
407
408
// Display the result
409
SimpleQuadRenderer {
410
texture: Texture {
411
textureProvider: RenderOutputProvider {
412
textureSource: RenderOutputProvider.UserPassTexture
413
renderPass: mainPass
414
attachmentSelector: RenderOutputProvider.Attachment0
415
}
416
}
417
}
418
419
// Scene content
420
Model {
421
source: "#Sphere"
422
materials: PrincipledMaterial {
423
baseColor: "red"
424
metalness: 0.0
425
roughness: 0.3
426
}
427
}
428
}
429
\endqml
430
431
This example:
432
\list 1
433
\li Disables internal passes
434
\li Creates a render target texture (colorTarget)
435
\li Defines a render pass that renders to that texture
436
\li Uses RenderOutputProvider to expose the texture
437
\li Displays the result with SimpleQuadRenderer
438
\li Renders a sphere with standard material
439
\endlist
440
441
\section1 Working with Layers
442
443
The \l ContentLayer singleton provides constants for organizing objects into layers,
444
allowing fine-grained control over what renders in each pass.
445
446
\section2 Layer Constants
447
448
Qt Quick 3D provides 24 user-assignable layers:
449
\list
450
\li \c ContentLayer.Layer0 through \c ContentLayer.Layer23: Individual layers
451
\li \c ContentLayer.LayerAll: All user layers combined
452
\li \c ContentLayer.LayerNone: No layers
453
\endlist
454
455
\note Layers 24-31 are reserved for internal use.
456
457
\section2 Assigning Objects to Layers
458
459
Assign objects to layers using the \l{Model::layers}{layers} property:
460
461
\qml
462
Model {
463
source: "#Cube"
464
layers: ContentLayer.Layer0
465
materials: PrincipledMaterial { baseColor: "red" }
466
}
467
468
Model {
469
source: "#Sphere"
470
layers: ContentLayer.Layer1 | ContentLayer.Layer2
471
materials: PrincipledMaterial { baseColor: "blue" }
472
}
473
\endqml
474
475
Objects can belong to multiple layers using bitwise OR.
476
477
\section2 Filtering by Layer
478
479
Use \l RenderablesFilter in your render passes to select which layers to render:
480
481
\qml
482
RenderPass {
483
id: pass1
484
commands: [
485
ColorAttachment { target: texture1 },
486
RenderablesFilter {
487
layerMask: ContentLayer.Layer0
488
}
489
]
490
// Only renders objects on Layer0 (red cube)
491
}
492
493
RenderPass {
494
id: pass2
495
commands: [
496
ColorAttachment { target: texture2 },
497
RenderablesFilter {
498
layerMask: ContentLayer.Layer1 | ContentLayer.Layer2
499
}
500
]
501
// Only renders objects on Layer1 or Layer2 (blue sphere)
502
}
503
\endqml
504
505
\section2 Use Case: Selective Rendering
506
507
A practical example is rendering certain objects as wireframe overlays:
508
509
\qml
510
View3D {
511
renderOverrides: View3D.DisableInternalPasses
512
513
RenderPassTexture { id: colorTex; format: RenderPassTexture.RGBA16F }
514
RenderPassTexture { id: depthTex; format: RenderPassTexture.Depth24Stencil8 }
515
516
// Pass 1: Render solid objects
517
RenderPass {
518
id: solidPass
519
commands: [
520
ColorAttachment { target: colorTex },
521
DepthTextureAttachment { target: depthTex },
522
RenderablesFilter { layerMask: ContentLayer.Layer0 }
523
]
524
}
525
526
// Pass 2: Render wireframe overlay
527
RenderPass {
528
id: wireframePass
529
commands: [
530
ColorAttachment { target: colorTex },
531
DepthTextureAttachment { target: depthTex },
532
PipelineStateOverride {
533
polygonMode: PipelineStateOverride.Line
534
depthTestEnabled: true
535
depthWriteEnabled: false
536
},
537
RenderablesFilter { layerMask: ContentLayer.Layer1 }
538
]
539
}
540
541
SimpleQuadRenderer {
542
texture: Texture {
543
textureProvider: RenderOutputProvider {
544
textureSource: RenderOutputProvider.UserPassTexture
545
renderPass: wireframePass
546
attachmentSelector: RenderOutputProvider.Attachment0
547
}
548
}
549
}
550
551
Model {
552
source: "#Sphere"
553
layers: ContentLayer.Layer0 // Rendered solid
554
materials: PrincipledMaterial { baseColor: "blue" }
555
}
556
557
Model {
558
source: "#Sphere"
559
layers: ContentLayer.Layer1 // Rendered as wireframe
560
materials: PrincipledMaterial { baseColor: "yellow" }
561
}
562
}
563
\endqml
564
565
\section1 Texture Management
566
567
User render passes rely heavily on textures both as render targets and as inputs to
568
subsequent passes or materials.
569
570
\section2 Render Pass Texture Formats
571
572
\l RenderPassTexture supports various formats for different use cases:
573
574
\b{Color Formats:}
575
\table
576
\header
577
\li Format
578
\li Description
579
\li Use Case
580
\row
581
\li RGBA8
582
\li 8-bit per channel
583
\li Standard color output, lower memory usage
584
\row
585
\li RGBA16F
586
\li 16-bit floating point
587
\li HDR rendering, intermediate buffers
588
\row
589
\li RGBA32F
590
\li 32-bit floating point
591
\li High precision calculations
592
\row
593
\li R8, R16, R16F, R32F
594
\li Single channel variants
595
\li Grayscale data, specialized buffers
596
\endtable
597
598
\b{Depth Formats:}
599
\table
600
\header
601
\li Format
602
\li Description
603
\row
604
\li Depth16
605
\li 16-bit depth
606
\row
607
\li Depth24
608
\li 24-bit depth
609
\row
610
\li Depth32
611
\li 32-bit depth
612
\row
613
\li Depth24Stencil8
614
\li 24-bit depth + 8-bit stencil
615
\endtable
616
617
Example texture definitions:
618
619
\qml
620
RenderPassTexture {
621
id: hdrColorBuffer
622
format: RenderPassTexture.RGBA16F // HDR color
623
}
624
625
RenderPassTexture {
626
id: depthBuffer
627
format: RenderPassTexture.Depth24Stencil8 // Depth + stencil
628
}
629
630
RenderPassTexture {
631
id: normalBuffer
632
format: RenderPassTexture.RGBA16F // Store normals
633
}
634
\endqml
635
636
\section2 Sharing Textures Between Passes
637
638
Multiple passes can share the same depth texture, allowing depth testing across passes:
639
640
\qml
641
RenderPassTexture {
642
id: sharedDepth
643
format: RenderPassTexture.Depth24Stencil8
644
}
645
646
RenderPass {
647
id: geometryPass
648
commands: [
649
ColorAttachment { target: colorTex1 },
650
DepthTextureAttachment { target: sharedDepth }
651
]
652
}
653
654
RenderPass {
655
id: transparentPass
656
renderTargetFlags: RenderPass.PreserveDepthStencilContents
657
commands: [
658
ColorAttachment { target: colorTex2 },
659
DepthTextureAttachment { target: sharedDepth }
660
// Uses depth from geometryPass for depth testing
661
]
662
}
663
\endqml
664
665
\section2 Render Output Provider
666
667
The \l RenderOutputProvider exposes render pass outputs as \l Texture inputs:
668
669
\qml
670
// Define a render pass with color output
671
RenderPass {
672
id: firstPass
673
commands: [
674
ColorAttachment { target: intermediateTexture }
675
]
676
}
677
678
// Expose its output
679
RenderOutputProvider {
680
id: intermediateProvider
681
textureSource: RenderOutputProvider.UserPassTexture
682
renderPass: firstPass
683
attachmentSelector: RenderOutputProvider.Attachment0
684
}
685
686
// Use in a material
687
CustomMaterial {
688
property TextureInput inputTex: TextureInput {
689
texture: Texture { textureProvider: intermediateProvider }
690
}
691
fragmentShader: "process.frag"
692
}
693
\endqml
694
695
The \c attachmentSelector property specifies which color attachment to use when a pass
696
has multiple render targets:
697
\list
698
\li \c RenderOutputProvider.Attachment0: First color attachment
699
\li \c RenderOutputProvider.Attachment1: Second color attachment
700
\li \c RenderOutputProvider.Attachment2: Third color attachment
701
\li \c RenderOutputProvider.Attachment3: Fourth color attachment
702
\endlist
703
704
\section2 Pass Chaining Example
705
706
Multiple passes can be chained together where each pass processes the output of
707
the previous pass. Each producer is nested inside its consumer, so it renders
708
first (see \l{Pass Ordering}):
709
710
\qml
711
View3D {
712
renderOverrides: View3D.DisableInternalPasses
713
714
// Intermediate textures
715
RenderPassTexture { id: tex0; format: RenderPassTexture.RGBA16F }
716
RenderPassTexture { id: tex1; format: RenderPassTexture.RGBA16F }
717
RenderPassTexture { id: tex2; format: RenderPassTexture.RGBA16F }
718
719
// Pass 3: Process tex1 -> tex2
720
RenderPass {
721
id: process2
722
commands: [
723
ColorAttachment { target: tex2 },
724
RenderablesFilter { layerMask: ContentLayer.Layer11 }
725
]
726
727
// Pass 2: Process tex0 -> tex1; renders before process2
728
RenderPass {
729
id: process1
730
materialMode: RenderPass.OriginalMaterial
731
commands: [
732
ColorAttachment { target: tex1 }
733
]
734
735
// Pass 1: Render scene; renders before process1
736
RenderPass {
737
id: scenePass
738
commands: [
739
ColorAttachment { target: tex0 },
740
DepthStencilAttachment { }
741
]
742
}
743
}
744
}
745
746
Model {
747
layers: ContentLayer.Layer10
748
geometry: PlaneGeometry { }
749
materials: CustomMaterial {
750
property TextureInput input: TextureInput {
751
texture: Texture {
752
textureProvider: RenderOutputProvider {
753
textureSource: RenderOutputProvider.UserPassTexture
754
renderPass: scenePass
755
}
756
}
757
}
758
fragmentShader: "effect1.frag"
759
}
760
}
761
762
Model {
763
layers: ContentLayer.Layer11
764
geometry: PlaneGeometry { }
765
materials: CustomMaterial {
766
property TextureInput input: TextureInput {
767
texture: Texture {
768
textureProvider: RenderOutputProvider {
769
textureSource: RenderOutputProvider.UserPassTexture
770
renderPass: process1
771
}
772
}
773
}
774
fragmentShader: "effect2.frag"
775
}
776
}
777
778
// Display final result
779
SimpleQuadRenderer {
780
texture: Texture {
781
textureProvider: RenderOutputProvider {
782
textureSource: RenderOutputProvider.UserPassTexture
783
renderPass: process2
784
}
785
}
786
}
787
}
788
\endqml
789
790
\section1 Pipeline State Control
791
792
The \l PipelineStateOverride command provides detailed control over graphics pipeline state,
793
allowing customization of depth testing, blending, culling, and more.
794
795
\section2 Depth Testing and Writing
796
797
Control how depth values are tested and written:
798
799
\qml
800
PipelineStateOverride {
801
depthTestEnabled: true
802
depthWriteEnabled: true
803
depthFunction: PipelineStateOverride.LessOrEqual
804
}
805
\endqml
806
807
The \c depthFunction property can be:
808
\list
809
\li \c Never, \c Less, \c Equal, \c LessOrEqual
810
\li \c Greater, \c NotEqual, \c GreaterOrEqual, \c Always
811
\endlist
812
813
\section2 Blending
814
815
Enable and configure blending for transparency:
816
817
\qml
818
PipelineStateOverride {
819
blendEnabled: true
820
// Uses default blend mode (source alpha blending)
821
}
822
\endqml
823
824
For multiple render targets, use per-target blend states. \l PipelineStateOverride
825
exposes the per-attachment value-type properties \c targetBlend0 through
826
\c targetBlend7 (of type \l renderTargetBlend) and the blend factor and
827
operation enums are in the \c RenderTargetBlend namespace:
828
829
\qml
830
PipelineStateOverride {
831
targetBlend0.enable: true
832
targetBlend0.srcColor: RenderTargetBlend.SrcAlpha
833
targetBlend0.dstColor: RenderTargetBlend.OneMinusSrcAlpha
834
targetBlend0.opColor: RenderTargetBlend.Add
835
836
targetBlend1.enable: false // No blending for attachment 1
837
}
838
\endqml
839
840
\section2 Culling
841
842
Control face culling:
843
844
\qml
845
PipelineStateOverride {
846
cullMode: PipelineStateOverride.Back // Override material's cull mode to Back
847
}
848
\endqml
849
850
Setting \c cullMode here overrides the value the material would otherwise specify
851
for this pass. Options: \c None (no culling), \c Front (cull front faces),
852
\c Back (cull back faces).
853
854
\section2 Wireframe Rendering
855
856
Render geometry as wireframes:
857
858
\qml
859
PipelineStateOverride {
860
polygonMode: PipelineStateOverride.Line
861
cullMode: PipelineStateOverride.None // Show both sides
862
}
863
\endqml
864
865
The \c polygonMode can be \c Fill (default) or \c Line (wireframe).
866
867
\section2 Scissor Rectangles
868
869
Limit rendering to a rectangular region:
870
871
\qml
872
PipelineStateOverride {
873
usesScissor: true
874
scissor: Qt.rect(100, 100, 400, 300) // x, y, width, height
875
}
876
\endqml
877
878
\section2 Viewport Control
879
880
Override the viewport:
881
882
\qml
883
PipelineStateOverride {
884
viewport: Qt.rect(0, 0, 800, 600)
885
}
886
\endqml
887
888
\section2 Complete Example: Wireframe Overlay
889
890
This example renders a scene normally, then overlays a wireframe version:
891
892
\qml
893
View3D {
894
renderOverrides: View3D.DisableInternalPasses
895
896
RenderPassTexture { id: color; format: RenderPassTexture.RGBA16F }
897
RenderPassTexture { id: depth; format: RenderPassTexture.Depth24Stencil8 }
898
899
// Solid pass
900
RenderPass {
901
id: solidPass
902
clearColor: "black"
903
commands: [
904
ColorAttachment { target: color },
905
DepthTextureAttachment { target: depth },
906
RenderablesFilter {
907
layerMask: ContentLayer.Layer0
908
renderableTypes: RenderablesFilter.Opaque
909
}
910
]
911
}
912
913
// Wireframe overlay
914
RenderPass {
915
id: wirePass
916
renderTargetFlags: RenderPass.PreserveColorContents |
917
RenderPass.PreserveDepthStencilContents
918
commands: [
919
ColorAttachment { target: color },
920
DepthTextureAttachment { target: depth },
921
PipelineStateOverride {
922
polygonMode: PipelineStateOverride.Line
923
depthTestEnabled: true
924
depthWriteEnabled: false
925
blendEnabled: true
926
},
927
RenderablesFilter { layerMask: ContentLayer.Layer0 }
928
]
929
}
930
931
SimpleQuadRenderer {
932
texture: Texture {
933
textureProvider: RenderOutputProvider {
934
textureSource: RenderOutputProvider.UserPassTexture
935
renderPass: wirePass
936
}
937
}
938
}
939
940
PerspectiveCamera { z: 300 }
941
DirectionalLight { }
942
943
Model {
944
source: "#Sphere"
945
layers: ContentLayer.Layer0
946
materials: PrincipledMaterial {
947
baseColor: "blue"
948
metalness: 0.5
949
roughness: 0.3
950
}
951
}
952
}
953
\endqml
954
955
\section1 Augment Shaders for Multiple Render Targets
956
957
When using \c{RenderPass.AugmentMaterial} mode, you provide an augment shader that injects
958
custom code into the material's fragment shader. This is particularly useful for deferred
959
rendering where you need to output material data to multiple render targets (MRT).
960
961
\section2 The MAIN_FRAGMENT_AUGMENT Function
962
963
Your augment shader file must define a \c{MAIN_FRAGMENT_AUGMENT()} function:
964
965
\badcode
966
void MAIN_FRAGMENT_AUGMENT()
967
{
968
// Your custom shader code here
969
}
970
\endcode
971
972
This function is called during the fragment shader after material calculations are complete,
973
giving you access to material properties and the ability to write to custom outputs.
974
975
\section2 Available Built-in Variables
976
977
Inside \c{MAIN_FRAGMENT_AUGMENT()}, the engine substitutes a set of macros
978
that expose material pipeline data. Only the macros listed below are part of
979
the augment shader API:
980
981
\table
982
\header
983
\li Macro
984
\li Type
985
\li Description
986
\row
987
\li \c BASE_COLOR
988
\li vec4
989
\li Material base color (linear color space, after material processing).
990
\row
991
\li \c METALNESS
992
\li float
993
\li Material metalness in the range 0.0 to 1.0.
994
\row
995
\li \c ROUGHNESS
996
\li float
997
\li Material roughness in the range 0.0 to 1.0.
998
\row
999
\li \c WORLD_NORMAL
1000
\li vec3
1001
\li World-space surface normal (post normal-mapping).
1002
\row
1003
\li \c WORLD_TANGENT
1004
\li vec3
1005
\li World-space tangent vector.
1006
\row
1007
\li \c WORLD_BINORMAL
1008
\li vec3
1009
\li World-space binormal vector.
1010
\row
1011
\li \c DIFFUSE_LIGHT
1012
\li vec3
1013
\li Accumulated diffuse light contribution.
1014
\row
1015
\li \c SPECULAR_LIGHT
1016
\li vec3
1017
\li Accumulated specular light contribution.
1018
\row
1019
\li \c EMISSIVE_LIGHT
1020
\li vec3
1021
\li Material emissive contribution.
1022
\row
1023
\li \c F0
1024
\li vec3
1025
\li Fresnel reflectance at normal incidence.
1026
\row
1027
\li \c F90
1028
\li vec3
1029
\li Fresnel reflectance at grazing incidence.
1030
\endtable
1031
1032
\note Some examples (including the deferred-rendering one below) read the
1033
world-space fragment position via \c qt_varWorldPos. This is the engine's
1034
underlying varying name, not an augment-shader macro, and falls into the
1035
same \e {semi-public} category as the \c .glsllib files described in
1036
\l{Built-in Shader Facilities}: it works in practice but is not guaranteed
1037
to remain stable across releases.
1038
1039
\section2 Writing to Named Outputs
1040
1041
Color attachments in your render pass can have names that correspond to output variables
1042
in your shader:
1043
1044
\qml
1045
RenderPass {
1046
commands: [
1047
ColorAttachment { target: tex0; name: "GBUFFER0" },
1048
ColorAttachment { target: tex1; name: "GBUFFER1" },
1049
ColorAttachment { target: tex2; name: "GBUFFER2" }
1050
]
1051
}
1052
\endqml
1053
1054
In your augment shader:
1055
1056
\badcode
1057
void MAIN_FRAGMENT_AUGMENT()
1058
{
1059
GBUFFER0 = vec4(...); // Writes to first attachment
1060
GBUFFER1 = vec4(...); // Writes to second attachment
1061
GBUFFER2 = vec4(...); // Writes to third attachment
1062
}
1063
\endcode
1064
1065
Qt Quick 3D supports up to 4 simultaneous color attachments (GBUFFER0 through GBUFFER3).
1066
1067
\section2 Complete Augment Shader Example
1068
1069
Here's a complete example for a deferred rendering G-buffer pass:
1070
1071
\badcode
1072
// gbuffer_augment.glsl
1073
void MAIN_FRAGMENT_AUGMENT()
1074
{
1075
// Get material properties
1076
vec3 baseColor = BASE_COLOR.rgb;
1077
float metalness = METALNESS;
1078
float roughness = ROUGHNESS;
1079
vec3 worldNormal = normalize(WORLD_NORMAL);
1080
vec3 worldPos = qt_varWorldPos;
1081
1082
// GBuffer 0: Albedo (RGB) + Metalness (A)
1083
GBUFFER0 = vec4(baseColor, metalness);
1084
1085
// GBuffer 1: World Normal (RGB) + Roughness (A)
1086
// Encode normal from [-1,1] to [0,1] for storage
1087
GBUFFER1 = vec4(worldNormal * 0.5 + 0.5, roughness);
1088
1089
// GBuffer 2: World Position
1090
GBUFFER2 = vec4(worldPos, 1.0);
1091
}
1092
\endcode
1093
1094
Used with a render pass (\c RenderPassTexture instances are declared as
1095
direct children of the enclosing \c View3D and referenced by id):
1096
1097
\qml
1098
View3D {
1099
RenderPassTexture { id: gbuffer0; format: RenderPassTexture.RGBA16F }
1100
RenderPassTexture { id: gbuffer1; format: RenderPassTexture.RGBA16F }
1101
RenderPassTexture { id: gbuffer2; format: RenderPassTexture.RGBA16F }
1102
1103
RenderPass {
1104
id: gbufferPass
1105
materialMode: RenderPass.AugmentMaterial
1106
augmentShader: "gbuffer_augment.glsl"
1107
commands: [
1108
ColorAttachment { target: gbuffer0; name: "GBUFFER0" },
1109
ColorAttachment { target: gbuffer1; name: "GBUFFER1" },
1110
ColorAttachment { target: gbuffer2; name: "GBUFFER2" },
1111
DepthStencilAttachment { }
1112
]
1113
}
1114
}
1115
\endqml
1116
1117
\section2 Preserving Material Behavior
1118
1119
The augment shader runs \e{in addition to} the normal material pipeline, not instead of it.
1120
This means:
1121
1122
\list
1123
\li The material's textures, properties, and calculations still occur
1124
\li You're adding extra outputs, not replacing the primary color output
1125
\li The original material's RGBA output is still written to the first color attachment unless overridden
1126
\endlist
1127
1128
If you only need to output custom data and don't need the standard material calculations,
1129
consider using \c{RenderPass.OverrideMaterial} instead.
1130
1131
\section2 When to Use Augment vs Override
1132
1133
Use \c AugmentMaterial when:
1134
\list
1135
\li You need material properties (metalness, roughness, normals) for G-buffers
1136
\li You want to leverage existing material features like texture mapping
1137
\li You need multiple render targets with material data
1138
\endlist
1139
1140
Use \c OverrideMaterial when:
1141
\list
1142
\li You need identical behavior for all objects (depth prepass, shadow maps)
1143
\li You don't need per-material properties
1144
\li You want maximum performance by bypassing material calculations
1145
\endlist
1146
1147
\section2 Built-in Shader Facilities
1148
1149
Augment shaders and custom materials used in render passes have access to Qt Quick 3D's
1150
built-in shader infrastructure through an include system. These shader library files
1151
(\c{.glsllib}) provide functionality for lighting, shadows, tonemapping, and more.
1152
1153
\b{Include Syntax:}
1154
1155
Use \c{\#include} directives in your shader code to import functionality:
1156
1157
\badcode
1158
#include "tonemapping.glsllib"
1159
#include "lightsData.glsllib"
1160
#include "shadowMapping.glsllib"
1161
#include "funcprocessPunctualLighting.glsllib"
1162
1163
void MAIN()
1164
{
1165
// Use included functions
1166
vec3 color = qt_tonemap(hdrColor);
1167
}
1168
\endcode
1169
1170
\b{Available Shader Libraries:}
1171
1172
These shader libraries are located in the engine at \c{src/runtimerender/res/effectlib/}
1173
and are considered \e{semi-public}: they are usable in user shaders but do not have the
1174
same binary compatibility guarantees as the rest of Qt's public API.
1175
1176
\table
1177
\header
1178
\li Library
1179
\li Description
1180
\row
1181
\li \c{tonemapping.glsllib}
1182
\li Provides \c{qt_tonemap()} function for HDR to LDR conversion using the built-in
1183
tonemapping algorithm
1184
\row
1185
\li \c{lightsData.glsllib}
1186
\li Contains scene lighting information (light positions, colors, directions, etc.)
1187
that can be accessed in custom lighting calculations
1188
\row
1189
\li \c{shadowMapping.glsllib}
1190
\li Provides functions for sampling from the default shadow maps, enabling custom
1191
materials to receive shadows
1192
\row
1193
\li \c{funcprocessPunctualLighting.glsllib}
1194
\li Contains \c{qt_processPunctualLighting()} and other built-in lighting functions
1195
for standard PBR lighting calculations
1196
\row
1197
\li \c{sampleProbe.glsllib}
1198
\li Functions for sampling image-based lighting probes (\c{qt_sampleDiffuse()},
1199
\c{qt_sampleGlossyPrincipled()})
1200
\endtable
1201
1202
\b{Example: Custom Lighting with Built-in Functions}
1203
1204
Here's an example fragment shader using the built-in lighting facilities:
1205
1206
\badcode
1207
#include "lightsData.glsllib"
1208
#include "funcprocessPunctualLighting.glsllib"
1209
#include "tonemapping.glsllib"
1210
#include "sampleProbe.glsllib"
1211
1212
void MAIN()
1213
{
1214
vec3 worldPos = ...; // From G-buffer or varying
1215
vec3 normal = ...;
1216
vec3 viewDir = normalize(CAMERA_POSITION - worldPos);
1217
vec3 baseColor = ...;
1218
float roughness = ...;
1219
float metalness = ...;
1220
1221
vec3 F0 = mix(vec3(0.04), baseColor, metalness);
1222
1223
vec3 diffuseAccum = vec3(0.0);
1224
vec3 specAccum = vec3(0.0);
1225
1226
// Use built-in punctual lighting (directional, point, spot lights)
1227
qt_processPunctualLighting(diffuseAccum,
1228
specAccum,
1229
baseColor,
1230
worldPos,
1231
normal,
1232
viewDir,
1233
vec3(1.0), // specularAmount
1234
vec3(1.0), // specularTint
1235
roughness,
1236
metalness,
1237
F0,
1238
vec3(1.0)); // F90
1239
1240
// Add image-based lighting
1241
vec4 probeDiffuse = vec4(baseColor, 1.0) * qt_sampleDiffuse(normal);
1242
vec4 probeSpecular = qt_sampleGlossyPrincipled(normal, viewDir, F0, roughness);
1243
diffuseAccum += probeDiffuse.rgb;
1244
specAccum += probeSpecular.rgb;
1245
1246
vec3 color = diffuseAccum + specAccum;
1247
1248
// Apply tonemapping
1249
FRAGCOLOR = vec4(qt_tonemap(color), 1.0);
1250
}
1251
\endcode
1252
1253
\note These shader libraries are semi-public API. While they are stable and intended for
1254
use in custom shaders, Qt does not guarantee that their internal implementation or
1255
available functions will remain unchanged between releases. However, commonly used functions
1256
like \c{qt_tonemap()} and \c{qt_processPunctualLighting()} are unlikely to change
1257
significantly.
1258
1259
\section1 Advanced Example: Deferred Rendering
1260
1261
Deferred rendering is a technique where geometry information is rendered to multiple textures
1262
(called a G-buffer or geometry buffer) in a first pass, and lighting calculations are performed
1263
in a second pass using the stored geometry data. This approach is particularly efficient when
1264
you have many lights, as each pixel is shaded only once regardless of the number of lights.
1265
1266
\section2 Deferred Rendering Architecture
1267
1268
The deferred rendering pipeline consists of two main passes:
1269
1270
\list 1
1271
\li \b{Geometry Pass (G-Buffer Pass)}: Renders scene geometry to multiple render targets,
1272
storing material properties such as albedo, normals, roughness, metalness, and world position.
1273
\li \b{Lighting Pass}: Renders a full-screen quad that samples the G-buffers and performs
1274
lighting calculations for each pixel based on the stored geometry data.
1275
\endlist
1276
1277
\section2 G-Buffer Pass Implementation
1278
1279
First, define a G-buffer pass that outputs material data to multiple render targets:
1280
1281
\b{GBufferPass.qml:} The G-buffer render targets are exposed as required
1282
properties so the enclosing \c View3D supplies them and can read their
1283
outputs:
1284
1285
\qml
1286
import QtQuick
1287
import QtQuick3D
1288
1289
RenderPass {
1290
id: gbufferPass
1291
clearColor: Qt.rgba(0.0, 0.0, 0.0, 0.0)
1292
1293
property alias layerMask: filter.layerMask
1294
1295
// Provided by the View3D that uses this pass
1296
required property RenderPassTexture gbuffer0 // rgb: baseColor, a: metalness
1297
required property RenderPassTexture gbuffer1 // rgb: normal, a: roughness
1298
required property RenderPassTexture gbuffer2 // rgb: world pos, a: spare
1299
required property RenderPassTexture depthTexture
1300
1301
materialMode: RenderPass.AugmentMaterial
1302
augmentShader: "gbuffer_augment.glsl"
1303
1304
commands: [
1305
ColorAttachment { target: gbufferPass.gbuffer0; name: "GBUFFER0" },
1306
ColorAttachment { target: gbufferPass.gbuffer1; name: "GBUFFER1" },
1307
ColorAttachment { target: gbufferPass.gbuffer2; name: "GBUFFER2" },
1308
DepthTextureAttachment { target: gbufferPass.depthTexture },
1309
RenderablesFilter {
1310
id: filter
1311
renderableTypes: RenderablesFilter.Opaque
1312
}
1313
]
1314
}
1315
\endqml
1316
1317
\b{gbuffer_augment.glsl:}
1318
\badcode
1319
void MAIN_FRAGMENT_AUGMENT()
1320
{
1321
vec3 baseColor = BASE_COLOR.rgb;
1322
float metalness = METALNESS;
1323
float roughness = ROUGHNESS;
1324
vec3 worldNormal = normalize(WORLD_NORMAL);
1325
1326
// GBuffer 0: albedo + metalness
1327
GBUFFER0 = vec4(baseColor, metalness);
1328
1329
// GBuffer 1: normal (encoded to 0..1) + roughness
1330
GBUFFER1 = vec4(worldNormal * 0.5 + 0.5, roughness);
1331
1332
// GBuffer 2: world position
1333
GBUFFER2 = vec4(qt_varWorldPos, 1.0);
1334
}
1335
\endcode
1336
1337
The augment shader accesses material properties computed by the material pipeline and
1338
writes them to the three G-buffer attachments. Normals are encoded from [-1,1] to [0,1]
1339
range for storage.
1340
1341
\section2 Lighting Pass Implementation
1342
1343
The lighting pass renders a full-screen quad that samples the G-buffers and computes lighting:
1344
1345
\qml
1346
// Lighting pass model (full-screen quad)
1347
Model {
1348
id: deferredLightingQuad
1349
layers: ContentLayer.Layer13 // Dedicated layer for lighting quad
1350
1351
geometry: PlaneGeometry {
1352
plane: PlaneGeometry.XY // Quad in screen space
1353
}
1354
1355
materials: CustomMaterial {
1356
// Texture inputs for G-buffers
1357
property TextureInput gbuffer0: TextureInput {
1358
enabled: true
1359
texture: Texture { textureProvider: gbuffer0Provider }
1360
}
1361
property TextureInput gbuffer1: TextureInput {
1362
enabled: true
1363
texture: Texture { textureProvider: gbuffer1Provider }
1364
}
1365
property TextureInput gbuffer2: TextureInput {
1366
enabled: true
1367
texture: Texture { textureProvider: gbuffer2Provider }
1368
}
1369
1370
shadingMode: CustomMaterial.Unshaded
1371
fragmentShader: "lighting.frag"
1372
vertexShader: "lighting.vert"
1373
}
1374
}
1375
1376
// Lighting pass renders the quad to main output
1377
RenderPass {
1378
id: deferredLightingPass
1379
materialMode: RenderPass.OriginalMaterial
1380
1381
commands: [
1382
ColorAttachment { target: mainColorTexture },
1383
DepthStencilAttachment { },
1384
RenderablesFilter { layerMask: ContentLayer.Layer13 }
1385
]
1386
}
1387
\endqml
1388
1389
The lighting vertex shader (\c lighting.vert) creates a full-screen quad in normalized
1390
device coordinates, and the fragment shader (\c lighting.frag) samples the G-buffers and
1391
performs lighting calculations.
1392
1393
\section2 Complete Integration
1394
1395
Here's how to integrate both passes in a View3D:
1396
1397
\qml
1398
View3D {
1399
renderOverrides: View3D.DisableInternalPasses
1400
1401
// Main output texture
1402
RenderPassTexture { id: mainColorTexture; format: RenderPassTexture.RGBA16F }
1403
1404
// Shared depth texture
1405
RenderPassTexture { id: mainDepthStencilTexture; format: RenderPassTexture.Depth24Stencil8 }
1406
1407
// G-buffer render targets
1408
RenderPassTexture { id: gbuffer0Tex; format: RenderPassTexture.RGBA16F }
1409
RenderPassTexture { id: gbuffer1Tex; format: RenderPassTexture.RGBA16F }
1410
RenderPassTexture { id: gbuffer2Tex; format: RenderPassTexture.RGBA16F }
1411
1412
// Lighting pass (commands as defined above). The G-buffer pass is nested
1413
// inside its consumer, so it renders first and the lighting quad samples
1414
// this frame's G-buffers.
1415
RenderPass {
1416
id: deferredLightingPass
1417
materialMode: RenderPass.OriginalMaterial
1418
commands: [
1419
ColorAttachment { target: mainColorTexture },
1420
DepthStencilAttachment { },
1421
RenderablesFilter { layerMask: ContentLayer.Layer13 }
1422
]
1423
1424
// G-buffer pass
1425
GBufferPass {
1426
id: gbufferPass
1427
layerMask: ContentLayer.Layer0 | ContentLayer.Layer1
1428
gbuffer0: gbuffer0Tex
1429
gbuffer1: gbuffer1Tex
1430
gbuffer2: gbuffer2Tex
1431
depthTexture: mainDepthStencilTexture
1432
}
1433
}
1434
1435
// Expose G-buffer outputs
1436
RenderOutputProvider {
1437
id: gbuffer0Provider
1438
textureSource: RenderOutputProvider.UserPassTexture
1439
renderPass: gbufferPass
1440
attachmentSelector: RenderOutputProvider.Attachment0
1441
}
1442
1443
RenderOutputProvider {
1444
id: gbuffer1Provider
1445
textureSource: RenderOutputProvider.UserPassTexture
1446
renderPass: gbufferPass
1447
attachmentSelector: RenderOutputProvider.Attachment1
1448
}
1449
1450
RenderOutputProvider {
1451
id: gbuffer2Provider
1452
textureSource: RenderOutputProvider.UserPassTexture
1453
renderPass: gbufferPass
1454
attachmentSelector: RenderOutputProvider.Attachment2
1455
}
1456
1457
// Display final result
1458
SimpleQuadRenderer {
1459
texture: Texture {
1460
textureProvider: RenderOutputProvider {
1461
textureSource: RenderOutputProvider.UserPassTexture
1462
renderPass: deferredLightingPass
1463
attachmentSelector: RenderOutputProvider.Attachment0
1464
}
1465
}
1466
}
1467
1468
// Scene objects
1469
Model {
1470
layers: ContentLayer.Layer0
1471
source: "#Sphere"
1472
materials: PrincipledMaterial {
1473
baseColor: "red"
1474
metalness: 0.5
1475
roughness: 0.3
1476
}
1477
}
1478
1479
// Camera and lights
1480
PerspectiveCamera { z: 300 }
1481
DirectionalLight { eulerRotation.x: -45 }
1482
}
1483
\endqml
1484
1485
\section2 Rendering Flow
1486
1487
The rendering proceeds as follows:
1488
1489
\list 1
1490
\li \b{G-buffer Pass}: Renders first because it is nested inside the lighting
1491
pass. Scene objects on Layer0 and Layer1 are rendered. For each object,
1492
the augment shader writes albedo, normals, roughness, metalness, and position to three
1493
color attachments. Depth is written to the shared depth texture.
1494
\li \b{Lighting Pass}: The full-screen quad on Layer13 is rendered. Its custom material
1495
samples the three G-buffer textures and the depth texture, reconstructs the scene
1496
information, and performs lighting calculations (directional lights, image-based lighting,
1497
etc.) to produce the final lit color.
1498
\li \b{Display}: The result of the lighting pass is displayed via SimpleQuadRenderer.
1499
\endlist
1500
1501
\section2 Advantages and Limitations
1502
1503
\b{Advantages:}
1504
\list
1505
\li Efficient with many lights (each pixel lit once)
1506
\li Lighting complexity independent of scene complexity
1507
\li Easy to implement screen-space effects
1508
\li Decouples geometry and lighting passes
1509
\endlist
1510
1511
\b{Limitations:}
1512
\list
1513
\li Higher memory bandwidth due to G-buffer reads/writes
1514
\li No hardware MSAA (requires alternative anti-aliasing)
1515
\li Transparency requires separate forward pass
1516
\li More complex pipeline to set up and maintain
1517
\endlist
1518
1519
For a complete working example, see \l{Qt Quick 3D - User Passes Example}.
1520
1521
\section1 Complete Rendering Pipeline Example
1522
1523
A realistic custom rendering pipeline often needs to combine multiple pass types: opaque
1524
geometry, skybox background, 2D overlays, and transparent objects. Here's a complete example
1525
showing how to organize these using \c SubRenderPass for hierarchical composition:
1526
1527
\qml
1528
View3D {
1529
renderOverrides: View3D.DisableInternalPasses
1530
1531
environment: SceneEnvironment {
1532
backgroundMode: SceneEnvironment.SkyBox
1533
lightProbe: Texture {
1534
textureData: ProceduralSkyTextureData { }
1535
}
1536
}
1537
1538
RenderPassTexture {
1539
id: mainColorTexture
1540
format: RenderPassTexture.RGBA16F
1541
}
1542
1543
RenderPassTexture {
1544
id: mainDepthStencilTexture
1545
format: RenderPassTexture.Depth24Stencil8
1546
}
1547
1548
// Main pass orchestrates the complete render path:
1549
// 1. Opaque geometry (deferred)
1550
// 2. Skybox background
1551
// 3. 2D UI overlays
1552
// 4. Transparent objects (forward)
1553
RenderPass {
1554
id: mainColorPass
1555
clearColor: "black"
1556
renderTargetFlags: RenderPass.PreserveDepthStencilContents
1557
1558
commands: [
1559
ColorAttachment { target: mainColorTexture },
1560
DepthTextureAttachment { target: mainDepthStencilTexture },
1561
RenderablesFilter {
1562
renderableTypes: RenderablesFilter.None // Parent doesn't render
1563
},
1564
1565
// Sub-pass 1: Deferred lighting
1566
SubRenderPass {
1567
renderPass: RenderPass {
1568
id: deferredLightingPass
1569
materialMode: RenderPass.OriginalMaterial
1570
commands: [
1571
PipelineStateOverride {
1572
depthWriteEnabled: false
1573
depthTestEnabled: false
1574
},
1575
RenderablesFilter { layerMask: ContentLayer.Layer13 }
1576
]
1577
}
1578
},
1579
1580
// Sub-pass 2: Skybox (behind everything)
1581
SubRenderPass {
1582
renderPass: RenderPass {
1583
passMode: RenderPass.SkyboxPass
1584
commands: [
1585
PipelineStateOverride {
1586
depthTestEnabled: true
1587
depthWriteEnabled: false
1588
}
1589
]
1590
}
1591
},
1592
1593
// Sub-pass 3: 2D Qt Quick content
1594
SubRenderPass {
1595
renderPass: RenderPass {
1596
passMode: RenderPass.Item2DPass
1597
}
1598
},
1599
1600
// Sub-pass 4: Transparent objects (forward rendering)
1601
SubRenderPass {
1602
renderPass: RenderPass {
1603
materialMode: RenderPass.OriginalMaterial
1604
commands: [
1605
RenderablesFilter {
1606
renderableTypes: RenderablesFilter.Transparent
1607
layerMask: ContentLayer.Layer0 | ContentLayer.Layer1
1608
},
1609
PipelineStateOverride {
1610
blendEnabled: true
1611
depthTestEnabled: true
1612
depthWriteEnabled: false
1613
}
1614
]
1615
}
1616
}
1617
]
1618
}
1619
1620
// G-buffer pass (referenced by deferred lighting)
1621
GBufferPass {
1622
id: gbufferPass
1623
layerMask: ContentLayer.Layer0 | ContentLayer.Layer1
1624
depthTexture: mainDepthStencilTexture
1625
}
1626
1627
// Full-screen quad for deferred lighting
1628
Model {
1629
layers: ContentLayer.Layer13
1630
geometry: PlaneGeometry { plane: PlaneGeometry.XY }
1631
materials: CustomMaterial {
1632
property TextureInput gbuffer0: TextureInput {
1633
texture: Texture {
1634
textureProvider: RenderOutputProvider {
1635
textureSource: RenderOutputProvider.UserPassTexture
1636
renderPass: gbufferPass
1637
attachmentSelector: RenderOutputProvider.Attachment0
1638
}
1639
}
1640
}
1641
// ... other G-buffer inputs
1642
shadingMode: CustomMaterial.Unshaded
1643
fragmentShader: "lighting.frag"
1644
vertexShader: "lighting.vert"
1645
}
1646
}
1647
1648
// Display final result
1649
SimpleQuadRenderer {
1650
texture: Texture {
1651
textureProvider: RenderOutputProvider {
1652
textureSource: RenderOutputProvider.UserPassTexture
1653
renderPass: mainColorPass
1654
}
1655
}
1656
}
1657
1658
// Opaque 3D content
1659
Model {
1660
layers: ContentLayer.Layer0
1661
source: "#Sphere"
1662
materials: PrincipledMaterial { baseColor: "red" }
1663
}
1664
1665
// Transparent 3D content
1666
Model {
1667
layers: ContentLayer.Layer1
1668
source: "#Cone"
1669
materials: PrincipledMaterial {
1670
baseColor: Qt.rgba(0.0, 1.0, 0.0, 0.5)
1671
alphaMode: PrincipledMaterial.Blend
1672
}
1673
}
1674
1675
// 2D content in 3D space
1676
Node {
1677
x: -200
1678
y: 100
1679
Item {
1680
Button { text: "Click Me!" }
1681
Rectangle {
1682
color: "blue"
1683
width: 50; height: 50
1684
}
1685
}
1686
}
1687
1688
PerspectiveCamera { z: 300 }
1689
DirectionalLight { eulerRotation.x: -45 }
1690
}
1691
\endqml
1692
1693
\section2 Key Concepts
1694
1695
\b{SubRenderPass for Hierarchical Organization:}
1696
1697
The main pass uses \c SubRenderPass commands to execute child passes in sequence. The
1698
parent pass itself doesn't render anything (\c{RenderablesFilter.None}), it just
1699
orchestrates the child passes. This provides a clear structure and allows depth buffer
1700
sharing across all sub-passes.
1701
1702
\b{Pass Modes:}
1703
1704
\list
1705
\li \c{RenderPass.UserPass} (default): Custom rendering with your geometry and materials
1706
\li \c{RenderPass.SkyboxPass}: Renders the environment skybox from \l SceneEnvironment
1707
\li \c{RenderPass.Item2DPass}: Renders 2D Qt Quick content embedded in the 3D scene
1708
\endlist
1709
1710
\b{Render Order:}
1711
1712
\list 1
1713
\li Opaque geometry rendered to G-buffer
1714
\li Deferred lighting applied to full-screen quad
1715
\li Skybox rendered behind geometry (depth test enabled, depth write disabled)
1716
\li 2D UI overlays rendered on top
1717
\li Transparent objects rendered last with blending
1718
\endlist
1719
1720
\b{Depth Buffer Sharing:}
1721
1722
The \c mainDepthStencilTexture is shared across passes using \c PreserveDepthStencilContents.
1723
This ensures skybox renders behind geometry and transparent objects test against opaque
1724
geometry correctly.
1725
1726
\b{Item2D Content:}
1727
1728
Qt Quick 2D items (Button, Rectangle, Text, etc.) placed in \l Node objects are rendered
1729
by \c{RenderPass.Item2DPass}. These items are positioned in 3D space but rendered as 2D
1730
overlays that can receive mouse/touch input.
1731
1732
\section1 Performance Considerations
1733
1734
User-defined render passes provide maximum control but require careful consideration of
1735
performance implications.
1736
1737
\section2 Texture Format Choices
1738
1739
Choose texture formats based on your needs:
1740
1741
\table
1742
\header
1743
\li Format
1744
\li Size per Pixel
1745
\li Use Case
1746
\row
1747
\li RGBA8
1748
\li 4 bytes
1749
\li Final output, simple color buffers
1750
\row
1751
\li RGBA16F
1752
\li 8 bytes
1753
\li HDR content, intermediate buffers, normals
1754
\row
1755
\li RGBA32F
1756
\li 16 bytes
1757
\li High precision calculations, positions
1758
\row
1759
\li R16F
1760
\li 2 bytes
1761
\li Single-channel HDR (depth, AO, etc.)
1762
\endtable
1763
1764
For a 1920x1080 framebuffer:
1765
\list
1766
\li RGBA8: ~8 MB
1767
\li RGBA16F: ~16 MB
1768
\li RGBA32F: ~32 MB
1769
\li Three RGBA16F G-buffers: ~48 MB
1770
\endlist
1771
1772
\b{Recommendation:} Use RGBA16F for intermediate buffers and RGBA8 or R8 where sufficient.
1773
1774
\section2 Deferred vs Forward Rendering
1775
1776
\table
1777
\header
1778
\li Aspect
1779
\li Deferred Rendering
1780
\li Forward Rendering
1781
\row
1782
\li Many lights
1783
\li Efficient (O(lights + pixels))
1784
\li Expensive (O(lights * objects))
1785
\row
1786
\li Memory bandwidth
1787
\li High (G-buffer reads/writes)
1788
\li Lower
1789
\row
1790
\li Transparency
1791
\li Requires separate pass
1792
\li Natural support
1793
\row
1794
\li MSAA
1795
\li Not directly supported
1796
\li Hardware MSAA works
1797
\row
1798
\li Setup complexity
1799
\li More complex
1800
\li Simpler
1801
\endtable
1802
1803
\b{Use deferred rendering when:}
1804
\list
1805
\li You have many lights (10+)
1806
\li Screen-space effects are important
1807
\li Scene is mostly opaque
1808
\endlist
1809
1810
\b{Use forward rendering when:}
1811
\list
1812
\li Few lights (<5)
1813
\li Lots of transparency
1814
\li Memory bandwidth is constrained
1815
\li Simpler pipeline is preferable
1816
\endlist
1817
1818
\section2 Pass Ordering Optimization
1819
1820
Render passes execute in nesting order: deeper-nested passes render first;
1821
the relative order of passes at equal depth is not defined (see
1822
\l{Pass Ordering}). Optimize by:
1823
1824
\list
1825
\li Rendering opaque geometry before transparent geometry
1826
\li Using depth prepass when beneficial (reduces overdraw in complex scenes)
1827
\li Minimizing render target switches
1828
\li Reusing depth buffers across passes when possible
1829
\endlist
1830
1831
\section2 Render Target Flags
1832
1833
The \l{RenderPass::renderTargetFlags}{renderTargetFlags} property controls memory behavior:
1834
1835
\qml
1836
RenderPass {
1837
// First pass: write new content
1838
renderTargetFlags: 0 // Default: clear render targets
1839
}
1840
1841
RenderPass {
1842
// Second pass: add to existing content
1843
renderTargetFlags: RenderPass.PreserveColorContents |
1844
RenderPass.PreserveDepthStencilContents
1845
}
1846
1847
RenderPass {
1848
// Depth not needed after this pass
1849
renderTargetFlags: RenderPass.DoNotStoreDepthStencilContents
1850
}
1851
\endqml
1852
1853
\b{PreserveColorContents/PreserveDepthStencilContents:} Keep existing data (e.g., for
1854
multi-pass rendering to same target).
1855
1856
\b{DoNotStoreDepthStencilContents:} Hint that depth/stencil can be discarded (on some
1857
hardware this can improve performance by avoiding memory writes).
1858
1859
\section2 When to Use User Passes
1860
1861
Consider using user render passes when:
1862
1863
\list
1864
\li Implementing deferred rendering
1865
\li Creating complex multi-pass effects
1866
\li Needing explicit control over render order
1867
\li Implementing custom rendering techniques
1868
\li Building screen-space effects that need geometry data
1869
\endlist
1870
1871
\b{Avoid user passes when:}
1872
\list
1873
\li Default rendering meets your needs
1874
\li You only need post-processing (use \l Effect instead)
1875
\li You only need custom material shaders (use \l CustomMaterial instead)
1876
\li Performance is critical and extra passes would be wasteful
1877
\endlist
1878
1879
\section1 Common Patterns and Use Cases
1880
1881
User render passes enable many advanced rendering techniques. Here are some common patterns:
1882
1883
\section2 Deferred Shading/Lighting
1884
1885
Store geometry attributes in G-buffers and perform lighting in screen space. Covered in
1886
detail in \l{Advanced Example: Deferred Rendering}.
1887
1888
\section2 Edge Detection and Outlining
1889
1890
Render scene normally, then apply edge detection in a second pass:
1891
1892
\qml
1893
// Pass 1: Render scene with normals/depth
1894
RenderPass {
1895
id: scenePass
1896
commands: [
1897
ColorAttachment { target: colorTex },
1898
DepthTextureAttachment { target: depthTex }
1899
]
1900
}
1901
1902
// Pass 2: Edge detection using depth discontinuities
1903
RenderPass {
1904
id: edgePass
1905
commands: [
1906
ColorAttachment { target: outlineTex },
1907
RenderablesFilter { layerMask: ContentLayer.Layer10 }
1908
]
1909
}
1910
1911
Model {
1912
layers: ContentLayer.Layer10
1913
geometry: PlaneGeometry { }
1914
materials: CustomMaterial {
1915
property TextureInput depthInput: TextureInput {
1916
// depthProvider is the id of a RenderOutputProvider that exposes
1917
// depthTex as a sampleable texture (see "Render Output Provider"
1918
// earlier in this page).
1919
texture: Texture { textureProvider: depthProvider }
1920
}
1921
fragmentShader: "edge_detect.frag"
1922
// Shader samples depth, computes gradients, draws edges
1923
}
1924
}
1925
\endqml
1926
1927
\section2 Custom Post-Processing Chains
1928
1929
Chain multiple post-processing effects together by feeding each pass's output
1930
into the next via \l RenderOutputProvider. See
1931
\l{Pass Chaining Example} for a worked example of a multi-stage chain
1932
(\c scenePass → \c process1 → \c process2 → display).
1933
1934
\section2 Selective Wireframe Overlay
1935
1936
Render some objects solid and others as wireframe overlays. See the example in
1937
\l{Working with Layers}.
1938
1939
\section2 Debug Visualization
1940
1941
Create debug passes that visualize normals, depth, or other data:
1942
1943
\qml
1944
// Normal visualization pass
1945
RenderPass {
1946
materialMode: RenderPass.OverrideMaterial
1947
overrideMaterial: CustomMaterial {
1948
fragmentShader: "debug_normals.frag"
1949
// FRAGCOLOR = vec4(normalize(NORMAL) * 0.5 + 0.5, 1.0);
1950
}
1951
commands: [
1952
ColorAttachment { target: debugTex }
1953
]
1954
}
1955
\endqml
1956
1957
\section2 Custom Shadow Mapping
1958
1959
Implement custom shadow mapping with explicit control:
1960
1961
\qml
1962
// Shadow map pass (render from light's perspective)
1963
RenderPass {
1964
id: shadowPass
1965
materialMode: RenderPass.OverrideMaterial
1966
overrideMaterial: CustomMaterial {
1967
fragmentShader: "depth_only.frag"
1968
}
1969
commands: [
1970
DepthTextureAttachment { target: shadowMapTex }
1971
]
1972
}
1973
1974
// Main pass using shadow map
1975
RenderPass {
1976
id: mainPass
1977
commands: [
1978
ColorAttachment { target: colorTex },
1979
DepthStencilAttachment { }
1980
]
1981
}
1982
1983
// Materials in main pass sample shadowMapTex for shadow testing
1984
\endqml
1985
1986
\section1 Important Considerations
1987
1988
When working with user render passes, keep these important points in mind:
1989
1990
\section2 Shadow Handling
1991
1992
User render passes do \b{not} automatically include Qt Quick 3D's internal shadow rendering.
1993
If you disable internal passes and need shadows, you must:
1994
1995
\list
1996
\li Implement your own shadow mapping passes
1997
\li Render the scene from light's perspective to a depth texture
1998
\li Sample the shadow map in your lighting calculations
1999
\endlist
2000
2001
Alternatively, for simpler cases, you may not need shadows or can use pre-baked shadow maps.
2002
2003
\section2 HDR and Tonemapping
2004
2005
When using floating-point render targets (RGBA16F, RGBA32F), your rendering is in linear
2006
HDR space. You must apply tonemapping in your final display pass to convert to displayable
2007
LDR:
2008
2009
\qml
2010
CustomMaterial {
2011
fragmentShader: "tonemap.frag"
2012
}
2013
\endqml
2014
2015
\badcode
2016
// In tonemap.frag
2017
vec3 tonemap(vec3 hdr) {
2018
// Simple Reinhard tonemapping
2019
return hdr / (hdr + vec3(1.0));
2020
}
2021
2022
void MAIN() {
2023
vec3 hdrColor = texture(hdrInput, UV0).rgb;
2024
FRAGCOLOR = vec4(tonemap(hdrColor), 1.0);
2025
}
2026
\endcode
2027
2028
Qt Quick 3D provides \c{qt_tonemap()} function in shaders that can be used for this purpose.
2029
2030
\section2 Depth Texture Generation
2031
2032
When you need depth as a texture (for effects like depth-of-field), use
2033
\l DepthTextureAttachment instead of \l DepthStencilAttachment:
2034
2035
\qml
2036
RenderPassTexture {
2037
id: depthTex
2038
format: RenderPassTexture.Depth24Stencil8
2039
}
2040
2041
RenderPass {
2042
commands: [
2043
ColorAttachment { target: colorTex },
2044
DepthTextureAttachment { target: depthTex }
2045
// depthTex can now be sampled in shaders
2046
]
2047
}
2048
\endqml
2049
2050
\section2 Clear Values and Render Target Management
2051
2052
Each pass can specify clear values:
2053
2054
\qml
2055
RenderPass {
2056
clearColor: Qt.rgba(0.0, 0.0, 0.0, 0.0)
2057
depthClearValue: 1.0
2058
stencilClearValue: 0
2059
}
2060
\endqml
2061
2062
When a pass doesn't preserve contents (default), render targets are cleared to these values
2063
before rendering. When \c PreserveColorContents or \c PreserveDepthStencilContents is set,
2064
existing content is kept and clear values are ignored.
2065
2066
\section2 Layer Organization Best Practices
2067
2068
Organize your layers logically:
2069
2070
\list
2071
\li \b{Layer0-2}: Main scene objects
2072
\li \b{Layer3-4}: Transparent objects (separate pass)
2073
\li \b{Layer10+}: Full-screen quads for post-processing
2074
\li \b{Layer15+}: UI/debug overlays
2075
\endlist
2076
2077
Document your layer usage in comments and be consistent across your application.
2078
2079
\section2 Shader Compatibility
2080
2081
Augment shaders and custom materials used in render passes must be compatible with Qt Quick
2082
3D's shader infrastructure:
2083
2084
\list
2085
\li Use GLSL-compatible syntax
2086
\li Include appropriate \c{\#include} directives for Qt Quick 3D functions
2087
\li Be aware of available built-in variables
2088
\li Test on all target platforms (OpenGL, Vulkan, Metal, D3D)
2089
\endlist
2090
2091
\section2 Multiple Render Targets Limitations
2092
2093
When using multiple render targets (MRT):
2094
2095
\list
2096
\li Maximum of 4 color attachments
2097
\li All attachments must have the same dimensions
2098
\li Blend state can be specified per-attachment via \l PipelineStateOverride
2099
\li Not all hardware supports MRT (check device capabilities)
2100
\endlist
2101
2102
\section2 Transparency
2103
2104
Transparent objects are challenging with deferred rendering. Common approaches:
2105
2106
\list
2107
\li \b{Forward pass for transparent}: Render opaque geometry deferred, transparent geometry
2108
in a separate forward pass
2109
\li \b{Separate transparent G-buffer}: Render transparent geometry to a separate set of
2110
G-buffers with blending enabled
2111
\li \b{Weighted blended order-independent transparency}: Use specialized OIT techniques
2112
\endlist
2113
2114
For most cases, a separate forward pass for transparent objects is simplest.
2115
2116
\section1 API Reference
2117
2118
The following table provides a complete reference of all types related to user render passes:
2119
2120
\table
2121
\header
2122
\li Feature
2123
\li QML Type
2124
\li Description
2125
\row
2126
\li Main render pass definition
2127
\li \l RenderPass
2128
\li Defines a rendering pass with commands and material mode
2129
\row
2130
\li Render target textures
2131
\li \l RenderPassTexture
2132
\li Texture used as render target (color or depth/stencil)
2133
\row
2134
\li Texture output provider
2135
\li \l RenderOutputProvider
2136
\li Exposes render pass output as texture input
2137
\row
2138
\li Layer constants
2139
\li \l ContentLayer
2140
\li Singleton providing layer filtering constants
2141
\row
2142
\li Color output
2143
\li \l ColorAttachment
2144
\li Specifies a color render target
2145
\row
2146
\li Depth/stencil (default)
2147
\li \l DepthStencilAttachment
2148
\li Uses implicit depth/stencil buffer
2149
\row
2150
\li Depth/stencil (texture)
2151
\li \l DepthTextureAttachment
2152
\li Uses explicit depth texture
2153
\row
2154
\li Object filtering
2155
\li \l RenderablesFilter
2156
\li Filters objects by layer and type
2157
\row
2158
\li Pipeline state
2159
\li \l PipelineStateOverride
2160
\li Overrides graphics pipeline state
2161
\row
2162
\li Nested pass execution
2163
\li \c SubRenderPass
2164
\li Executes another render pass
2165
\row
2166
\li Shader defines
2167
\li \l AddDefine
2168
\li Adds shader preprocessor define
2169
\row
2170
\li Per-target blend state
2171
\li \l renderTargetBlend
2172
\li Blend configuration for MRT
2173
\row
2174
\li Display helper
2175
\li \l SimpleQuadRenderer
2176
\li Renders final output to View3D
2177
\endtable
2178
2179
\section2 Related Types
2180
2181
\table
2182
\header
2183
\li Type
2184
\li Description
2185
\row
2186
\li \l CustomMaterial
2187
\li Custom material with vertex/fragment shaders
2188
\row
2189
\li \l Effect
2190
\li Post-processing effects
2191
\row
2192
\li \l View3D
2193
\li 3D view with \l{View3D::renderOverrides}{renderOverrides} property
2194
\row
2195
\li \l Model
2196
\li 3D model with \l{Model::layers}{layers} property
2197
\endtable
2198
2199
\section2 Examples
2200
2201
\list
2202
\li \l{Qt Quick 3D - User Passes Example}: Complete deferred rendering example
2203
\endlist
2204
2205
\section2 See Also
2206
2207
\list
2208
\li \l{Programmable Materials, Effects, Geometry, and Texture data}: Overview of Qt Quick 3D
2209
customization features
2210
\li \l{Qt Quick 3D Architecture}: Understanding the rendering pipeline
2211
\endlist
2212
2213
*/
qtquick3d
src
quick3d
doc
src
qtquick3d-userpasses.qdoc
Generated on
for Qt by
1.16.1