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
11Qt Quick 3D provides a high-level API for 3D rendering that handles most rendering
12details automatically. However, for advanced use cases, applications may need complete
13control over the rendering pipeline. User-defined render passes enable this by allowing
14applications to disable the internal rendering pipeline and define their own custom passes.
15
16User 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
30Qt Quick 3D offers three complementary levels of rendering customization, each suited
31to 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
52User render passes (\l RenderPass) provide the most control, allowing you to either
53supplement or completely replace the default rendering pipeline. This complements
54\l CustomMaterial and \l Effect: \l CustomMaterial customizes how individual objects
55are rendered, while user render passes control the overall rendering strategy and
56architecture.
57
58\section1 Using User Render Passes
59
60User render passes can be used in two ways:
61
62\section2 Supplementing Internal Passes
63
64You can add custom \l RenderPass objects alongside the default rendering pipeline without
65disabling 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
69View3D {
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
88For complete control over the rendering pipeline, disable Qt Quick 3D's internal rendering
89by setting the \l{View3D::renderOverrides}{renderOverrides} property:
90
91\qml
92View3D {
93 renderOverrides: View3D.DisableInternalPasses
94
95 // Your custom render passes go here
96}
97\endqml
98
99When internal passes are disabled, Qt Quick 3D will not perform any default rendering.
100This 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.
109Features like automatic shadow rendering, transparency sorting, and environment reflections
110must be implemented in your custom passes if needed.
111
112\section1 Core Concepts
113
114User-defined render passes are built from several key components:
115
116\section2 RenderPass
117
118The \l RenderPass type is the main building block. It defines a single rendering operation
119with 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
131The \l RenderPassTexture type defines textures that serve as render targets. These can be
132color textures in various formats (RGBA8, RGBA16F, RGBA32F, etc.) or depth/stencil
133textures. Render pass textures are used as outputs from one pass and can be used as
134texture inputs to subsequent passes.
135
136\section2 RenderOutputProvider
137
138The \l RenderOutputProvider type connects render passes by exposing the output textures
139from one pass as texture inputs that can be used by materials or other passes. This is
140essential for multi-pass rendering where later passes need to read the results of
141earlier passes.
142
143\section2 ContentLayer
144
145The \l ContentLayer singleton provides layer constants (Layer0 through Layer23) used for
146filtering which objects render in which pass. By assigning objects to specific layers and
147using \l RenderablesFilter in your passes, you can control precisely what gets rendered
148in each pass.
149
150\section2 Render Commands
151
152Each \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
166Each \l RenderPass has a \l{RenderPass::materialMode}{materialMode} property that controls
167how materials are handled during rendering. The three modes offer different levels of
168material control:
169
170\section2 OriginalMaterial Mode
171
172This mode renders objects with their assigned materials unchanged. It's useful when you
173want to control the rendering pipeline structure (multiple passes, custom render targets)
174but keep the material behavior standard.
175
176\qml
177RenderPass {
178 materialMode: RenderPass.OriginalMaterial
179 commands: [
180 ColorAttachment { target: myColorTexture },
181 DepthStencilAttachment { }
182 ]
183}
184\endqml
185
186\section2 AugmentMaterial Mode
187
188This mode injects custom shader code into the existing material pipeline. It's particularly
189useful for deferred rendering where you need to output additional data (like normals,
190positions, etc.) to multiple render targets while preserving the material's base behavior.
191
192\qml
193RenderPass {
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
204The augment shader file contains a \c{MAIN_FRAGMENT_AUGMENT()} function:
205
206\badcode
207void 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
221See \l{Augment Shaders for Multiple Render Targets} for more details.
222
223\section2 OverrideMaterial Mode
224
225This mode replaces all object materials with a single material. It's useful for specialized
226passes like shadow mapping, depth prepass, or debug visualization.
227
228\qml
229RenderPass {
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
243Commands are specified in the \l{RenderPass::commands}{commands} property and execute
244in the order they are defined.
245
246\section2 Color Attachment
247
248The \l ColorAttachment command specifies a color render target. The \c name property
249defines how the attachment is accessed in augment shaders.
250
251\qml
252ColorAttachment {
253 target: myTexture // RenderPassTexture to render to
254 name: "GBUFFER0" // Name for shader access (optional)
255}
256\endqml
257
258You can have up to 4 color attachments per pass (for multiple render targets).
259
260\section2 Depth Attachments
261
262There are two ways to handle depth:
263
264\b{DepthStencilAttachment} uses an implicit depth/stencil buffer:
265
266\qml
267DepthStencilAttachment { } // Creates depth/stencil buffer automatically
268\endqml
269
270\b{DepthTextureAttachment} uses an explicit texture for depth output:
271
272\qml
273RenderPassTexture {
274 id: depthTex
275 format: RenderPassTexture.Depth24Stencil8
276}
277
278DepthTextureAttachment {
279 target: depthTex // Explicit depth texture
280}
281\endqml
282
283Use \l DepthTextureAttachment when you need to share the depth buffer between multiple
284passes or use it as a texture input in shaders.
285
286\section2 Renderables Filter
287
288The \l RenderablesFilter command controls which objects are rendered based on their layer
289assignment and renderable type.
290
291\qml
292RenderablesFilter {
293 layerMask: ContentLayer.Layer0 | ContentLayer.Layer1
294 renderableTypes: RenderablesFilter.Opaque
295}
296\endqml
297
298The \c layerMask property uses bitwise OR to combine layers. The \c renderableTypes
299property 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
308The \l PipelineStateOverride command provides fine-grained control over graphics pipeline
309state. It can override depth testing, blending, culling, polygon mode, and more.
310
311\qml
312PipelineStateOverride {
313 depthTestEnabled: true
314 depthWriteEnabled: false
315 blendEnabled: true
316 cullMode: PipelineStateOverride.Back
317 polygonMode: PipelineStateOverride.Fill
318}
319\endqml
320
321See \l{Pipeline State Control} for more examples.
322
323\section2 Sub Render Pass
324
325The \c SubRenderPass command allows hierarchical composition of render passes by executing
326another render pass within the current pass.
327
328\qml
329RenderPass {
330 id: parentPass
331 commands: [
332 ColorAttachment { target: colorTex },
333 SubRenderPass { renderPass: childPass },
334 // More commands after child pass
335 ]
336}
337
338RenderPass {
339 id: childPass
340 // This pass executes within parentPass
341}
342\endqml
343
344\section2 Add Define
345
346The \l AddDefine command adds shader preprocessor defines that affect shader compilation.
347
348\qml
349AddDefine {
350 name: "USE_SPECIAL_MODE"
351 value: 1
352}
353\endqml
354
355\section1 Simple Example: Single Pass Rendering
356
357Here's a minimal example showing user-defined render passes:
358
359\qml
360import QtQuick
361import QtQuick3D
362import QtQuick3D.Helpers
363
364View3D {
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
413This 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
425The \l ContentLayer singleton provides constants for organizing objects into layers,
426allowing fine-grained control over what renders in each pass.
427
428\section2 Layer Constants
429
430Qt 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
441Assign objects to layers using the \l{Model::layers}{layers} property:
442
443\qml
444Model {
445 source: "#Cube"
446 layers: ContentLayer.Layer0
447 materials: PrincipledMaterial { baseColor: "red" }
448}
449
450Model {
451 source: "#Sphere"
452 layers: ContentLayer.Layer1 | ContentLayer.Layer2
453 materials: PrincipledMaterial { baseColor: "blue" }
454}
455\endqml
456
457Objects can belong to multiple layers using bitwise OR.
458
459\section2 Filtering by Layer
460
461Use \l RenderablesFilter in your render passes to select which layers to render:
462
463\qml
464RenderPass {
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
475RenderPass {
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
489A practical example is rendering certain objects as wireframe overlays:
490
491\qml
492View3D {
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
549User render passes rely heavily on textures both as render targets and as inputs to
550subsequent 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
599Example texture definitions:
600
601\qml
602RenderPassTexture {
603 id: hdrColorBuffer
604 format: RenderPassTexture.RGBA16F // HDR color
605}
606
607RenderPassTexture {
608 id: depthBuffer
609 format: RenderPassTexture.Depth24Stencil8 // Depth + stencil
610}
611
612RenderPassTexture {
613 id: normalBuffer
614 format: RenderPassTexture.RGBA16F // Store normals
615}
616\endqml
617
618\section2 Sharing Textures Between Passes
619
620Multiple passes can share the same depth texture, allowing depth testing across passes:
621
622\qml
623RenderPassTexture {
624 id: sharedDepth
625 format: RenderPassTexture.Depth24Stencil8
626}
627
628RenderPass {
629 id: geometryPass
630 commands: [
631 ColorAttachment { target: colorTex1 },
632 DepthTextureAttachment { target: sharedDepth }
633 ]
634}
635
636RenderPass {
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
649The \l RenderOutputProvider exposes render pass outputs as \l Texture inputs:
650
651\qml
652// Define a render pass with color output
653RenderPass {
654 id: firstPass
655 commands: [
656 ColorAttachment { target: intermediateTexture }
657 ]
658}
659
660// Expose its output
661RenderOutputProvider {
662 id: intermediateProvider
663 textureSource: RenderOutputProvider.UserPassTexture
664 renderPass: firstPass
665 attachmentSelector: RenderOutputProvider.Attachment0
666}
667
668// Use in a material
669CustomMaterial {
670 property TextureInput inputTex: TextureInput {
671 texture: Texture { textureProvider: intermediateProvider }
672 }
673 fragmentShader: "process.frag"
674}
675\endqml
676
677The \c attachmentSelector property specifies which color attachment to use when a pass
678has 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
688Multiple passes can be chained together where each pass processes the output of the
689previous pass:
690
691\qml
692View3D {
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
773The \l PipelineStateOverride command provides detailed control over graphics pipeline state,
774allowing customization of depth testing, blending, culling, and more.
775
776\section2 Depth Testing and Writing
777
778Control how depth values are tested and written:
779
780\qml
781PipelineStateOverride {
782 depthTestEnabled: true
783 depthWriteEnabled: true
784 depthFunction: PipelineStateOverride.LessOrEqual
785}
786\endqml
787
788The \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
796Enable and configure blending for transparency:
797
798\qml
799PipelineStateOverride {
800 blendEnabled: true
801 // Uses default blend mode (source alpha blending)
802}
803\endqml
804
805For multiple render targets, use per-target blend states. \l PipelineStateOverride
806exposes the per-attachment value-type properties \c targetBlend0 through
807\c targetBlend7 (of type \l renderTargetBlend) and the blend factor and
808operation enums are in the \c RenderTargetBlend namespace:
809
810\qml
811PipelineStateOverride {
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
823Control face culling:
824
825\qml
826PipelineStateOverride {
827 cullMode: PipelineStateOverride.Back // Override material's cull mode to Back
828}
829\endqml
830
831Setting \c cullMode here overrides the value the material would otherwise specify
832for this pass. Options: \c None (no culling), \c Front (cull front faces),
833\c Back (cull back faces).
834
835\section2 Wireframe Rendering
836
837Render geometry as wireframes:
838
839\qml
840PipelineStateOverride {
841 polygonMode: PipelineStateOverride.Line
842 cullMode: PipelineStateOverride.None // Show both sides
843}
844\endqml
845
846The \c polygonMode can be \c Fill (default) or \c Line (wireframe).
847
848\section2 Scissor Rectangles
849
850Limit rendering to a rectangular region:
851
852\qml
853PipelineStateOverride {
854 usesScissor: true
855 scissor: Qt.rect(100, 100, 400, 300) // x, y, width, height
856}
857\endqml
858
859\section2 Viewport Control
860
861Override the viewport:
862
863\qml
864PipelineStateOverride {
865 viewport: Qt.rect(0, 0, 800, 600)
866}
867\endqml
868
869\section2 Complete Example: Wireframe Overlay
870
871This example renders a scene normally, then overlays a wireframe version:
872
873\qml
874View3D {
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
938When using \c{RenderPass.AugmentMaterial} mode, you provide an augment shader that injects
939custom code into the material's fragment shader. This is particularly useful for deferred
940rendering where you need to output material data to multiple render targets (MRT).
941
942\section2 The MAIN_FRAGMENT_AUGMENT Function
943
944Your augment shader file must define a \c{MAIN_FRAGMENT_AUGMENT()} function:
945
946\badcode
947void MAIN_FRAGMENT_AUGMENT()
948{
949 // Your custom shader code here
950}
951\endcode
952
953This function is called during the fragment shader after material calculations are complete,
954giving you access to material properties and the ability to write to custom outputs.
955
956\section2 Available Built-in Variables
957
958Inside \c{MAIN_FRAGMENT_AUGMENT()}, the engine substitutes a set of macros
959that expose material pipeline data. Only the macros listed below are part of
960the 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
1014world-space fragment position via \c qt_varWorldPos. This is the engine's
1015underlying varying name, not an augment-shader macro, and falls into the
1016same \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
1018to remain stable across releases.
1019
1020\section2 Writing to Named Outputs
1021
1022Color attachments in your render pass can have names that correspond to output variables
1023in your shader:
1024
1025\qml
1026RenderPass {
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
1035In your augment shader:
1036
1037\badcode
1038void 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
1046Qt Quick 3D supports up to 4 simultaneous color attachments (GBUFFER0 through GBUFFER3).
1047
1048\section2 Complete Augment Shader Example
1049
1050Here's a complete example for a deferred rendering G-buffer pass:
1051
1052\badcode
1053// gbuffer_augment.glsl
1054void 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
1075Used with a render pass (\c RenderPassTexture instances are declared as
1076direct children of the enclosing \c View3D and referenced by id):
1077
1078\qml
1079View3D {
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
1100The augment shader runs \e{in addition to} the normal material pipeline, not instead of it.
1101This 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
1109If you only need to output custom data and don't need the standard material calculations,
1110consider using \c{RenderPass.OverrideMaterial} instead.
1111
1112\section2 When to Use Augment vs Override
1113
1114Use \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
1121Use \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
1130Augment shaders and custom materials used in render passes have access to Qt Quick 3D's
1131built-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
1136Use \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
1144void MAIN()
1145{
1146 // Use included functions
1147 vec3 color = qt_tonemap(hdrColor);
1148}
1149\endcode
1150
1151\b{Available Shader Libraries:}
1152
1153These shader libraries are located in the engine at \c{src/runtimerender/res/effectlib/}
1154and are considered \e{semi-public}: they are usable in user shaders but do not have the
1155same 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
1185Here'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
1193void 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
1235use in custom shaders, Qt does not guarantee that their internal implementation or
1236available functions will remain unchanged between releases. However, commonly used functions
1237like \c{qt_tonemap()} and \c{qt_processPunctualLighting()} are unlikely to change
1238significantly.
1239
1240\section1 Advanced Example: Deferred Rendering
1241
1242Deferred 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
1244in a second pass using the stored geometry data. This approach is particularly efficient when
1245you have many lights, as each pixel is shaded only once regardless of the number of lights.
1246
1247\section2 Deferred Rendering Architecture
1248
1249The 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
1260First, 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
1263properties so the enclosing \c View3D supplies them and can read their
1264outputs:
1265
1266\qml
1267import QtQuick
1268import QtQuick3D
1269
1270RenderPass {
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
1300void 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
1318The augment shader accesses material properties computed by the material pipeline and
1319writes them to the three G-buffer attachments. Normals are encoded from [-1,1] to [0,1]
1320range for storage.
1321
1322\section2 Lighting Pass Implementation
1323
1324The 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)
1328Model {
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
1358RenderPass {
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
1370The lighting vertex shader (\c lighting.vert) creates a full-screen quad in normalized
1371device coordinates, and the fragment shader (\c lighting.frag) samples the G-buffers and
1372performs lighting calculations.
1373
1374\section2 Complete Integration
1375
1376Here's how to integrate both passes in a View3D:
1377
1378\qml
1379View3D {
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
1457The 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
1488For a complete working example, see \l{Qt Quick 3D - User Passes Example}.
1489
1490\section1 Complete Rendering Pipeline Example
1491
1492A realistic custom rendering pipeline often needs to combine multiple pass types: opaque
1493geometry, skybox background, 2D overlays, and transparent objects. Here's a complete example
1494showing how to organize these using \c SubRenderPass for hierarchical composition:
1495
1496\qml
1497View3D {
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
1666The main pass uses \c SubRenderPass commands to execute child passes in sequence. The
1667parent pass itself doesn't render anything (\c{RenderablesFilter.None}), it just
1668orchestrates the child passes. This provides a clear structure and allows depth buffer
1669sharing 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
1691The \c mainDepthStencilTexture is shared across passes using \c PreserveDepthStencilContents.
1692This ensures skybox renders behind geometry and transparent objects test against opaque
1693geometry correctly.
1694
1695\b{Item2D Content:}
1696
1697Qt Quick 2D items (Button, Rectangle, Text, etc.) placed in \l Node objects are rendered
1698by \c{RenderPass.Item2DPass}. These items are positioned in 3D space but rendered as 2D
1699overlays that can receive mouse/touch input.
1700
1701\section1 Performance Considerations
1702
1703User-defined render passes provide maximum control but require careful consideration of
1704performance implications.
1705
1706\section2 Texture Format Choices
1707
1708Choose 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
1733For 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
1789Render 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
1800The \l{RenderPass::renderTargetFlags}{renderTargetFlags} property controls memory behavior:
1801
1802\qml
1803RenderPass {
1804 // First pass: write new content
1805 renderTargetFlags: 0 // Default: clear render targets
1806}
1807
1808RenderPass {
1809 // Second pass: add to existing content
1810 renderTargetFlags: RenderPass.PreserveColorContents |
1811 RenderPass.PreserveDepthStencilContents
1812}
1813
1814RenderPass {
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
1821multi-pass rendering to same target).
1822
1823\b{DoNotStoreDepthStencilContents:} Hint that depth/stencil can be discarded (on some
1824hardware this can improve performance by avoiding memory writes).
1825
1826\section2 When to Use User Passes
1827
1828Consider 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
1848User render passes enable many advanced rendering techniques. Here are some common patterns:
1849
1850\section2 Deferred Shading/Lighting
1851
1852Store geometry attributes in G-buffers and perform lighting in screen space. Covered in
1853detail in \l{Advanced Example: Deferred Rendering}.
1854
1855\section2 Edge Detection and Outlining
1856
1857Render scene normally, then apply edge detection in a second pass:
1858
1859\qml
1860// Pass 1: Render scene with normals/depth
1861RenderPass {
1862 id: scenePass
1863 commands: [
1864 ColorAttachment { target: colorTex },
1865 DepthTextureAttachment { target: depthTex }
1866 ]
1867}
1868
1869// Pass 2: Edge detection using depth discontinuities
1870RenderPass {
1871 id: edgePass
1872 commands: [
1873 ColorAttachment { target: outlineTex },
1874 RenderablesFilter { layerMask: ContentLayer.Layer10 }
1875 ]
1876}
1877
1878Model {
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
1896Chain multiple post-processing effects together by feeding each pass's output
1897into 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
1903Render some objects solid and others as wireframe overlays. See the example in
1904\l{Working with Layers}.
1905
1906\section2 Debug Visualization
1907
1908Create debug passes that visualize normals, depth, or other data:
1909
1910\qml
1911// Normal visualization pass
1912RenderPass {
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
1926Implement custom shadow mapping with explicit control:
1927
1928\qml
1929// Shadow map pass (render from light's perspective)
1930RenderPass {
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
1942RenderPass {
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
1955When working with user render passes, keep these important points in mind:
1956
1957\section2 Shadow Handling
1958
1959User render passes do \b{not} automatically include Qt Quick 3D's internal shadow rendering.
1960If 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
1968Alternatively, for simpler cases, you may not need shadows or can use pre-baked shadow maps.
1969
1970\section2 HDR and Tonemapping
1971
1972When using floating-point render targets (RGBA16F, RGBA32F), your rendering is in linear
1973HDR space. You must apply tonemapping in your final display pass to convert to displayable
1974LDR:
1975
1976\qml
1977CustomMaterial {
1978 fragmentShader: "tonemap.frag"
1979}
1980\endqml
1981
1982\badcode
1983// In tonemap.frag
1984vec3 tonemap(vec3 hdr) {
1985 // Simple Reinhard tonemapping
1986 return hdr / (hdr + vec3(1.0));
1987}
1988
1989void MAIN() {
1990 vec3 hdrColor = texture(hdrInput, UV0).rgb;
1991 FRAGCOLOR = vec4(tonemap(hdrColor), 1.0);
1992}
1993\endcode
1994
1995Qt Quick 3D provides \c{qt_tonemap()} function in shaders that can be used for this purpose.
1996
1997\section2 Depth Texture Generation
1998
1999When you need depth as a texture (for effects like depth-of-field), use
2000\l DepthTextureAttachment instead of \l DepthStencilAttachment:
2001
2002\qml
2003RenderPassTexture {
2004 id: depthTex
2005 format: RenderPassTexture.Depth24Stencil8
2006}
2007
2008RenderPass {
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
2019Each pass can specify clear values:
2020
2021\qml
2022RenderPass {
2023 clearColor: Qt.rgba(0.0, 0.0, 0.0, 0.0)
2024 depthClearValue: 1.0
2025 stencilClearValue: 0
2026}
2027\endqml
2028
2029When a pass doesn't preserve contents (default), render targets are cleared to these values
2030before rendering. When \c PreserveColorContents or \c PreserveDepthStencilContents is set,
2031existing content is kept and clear values are ignored.
2032
2033\section2 Layer Organization Best Practices
2034
2035Organize 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
2044Document your layer usage in comments and be consistent across your application.
2045
2046\section2 Shader Compatibility
2047
2048Augment shaders and custom materials used in render passes must be compatible with Qt Quick
20493D'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
2060When 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
2071Transparent 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
2081For most cases, a separate forward pass for transparent objects is simplest.
2082
2083\section1 API Reference
2084
2085The 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*/