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