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