Revision control
++ // Copyright (C) 2025 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
++
++ /*!
++ \example userpasses
++ \ingroup quick3d-examples
++ \title Qt Quick 3D - User Passes Example
++ \examplecategory {3D}
++ \brief Demonstrates creating custom render passes in Qt Quick 3D.
++ \image userpasses.webp
++ {A 3D scene rendered using custom user passes}}
++
++ The \e {User Passes} example demonstrates how to create custom render passes
++ in Qt Quick 3D. It implements a deferred lighting rendering pipeline using
++ multiple user-defined render passes and shows how to handle the complete
++ rendering sequence: opaque geometry, skybox, 2D items embedded in the scene,
++ and transparent geometry.
++
++ \section1 Disabling internal render passes
++
++ By default, Qt Quick 3D uses a set of internal render passes to render the
++ 3D scene. Sometimes you may want to disable these internal passes and
++ implement your own rendering pipeline using user-defined render passes.
++
++ To disable the internal render passes, set the \l {QtQuick3D::View3D::renderOverrides}{renderOverrides}
++ property of the \l {QtQuick3D::View3D}{View3D} to \c View3D.DisableInternalPasses.
++
++ \snippet userpasses/Main.qml disable internal passes
++
++ If you disable the internal render passes, you will need to provide the result
++ of the main color pass for the View3D to be able to display anything on the screen.
++
++ \section1 Geometry Buffer Pass
++
++ In this example, the first custom render pass is a geometry buffer (G-buffer) pass
++ that renders the scene geometry into multiple render targets, storing different
++ material properties in each target. The provided example is a subset of the full
++ material properties provided by Qt Quick 3D materials, focusing on the properties
++ needed for a basic deferred lighting implementation.
++
++ Our RenderPass is defined in \c GBufferPass.qml:
++
++ \snippet userpasses/GBufferPass.qml gbuffer pass
++
++ It defines 3 color attachments and 1 depth attachment. The pass requires 3 textures
++ which are defined as \l {QtQuick3D::RenderPassTexture}{RenderPassTexture} objects inside the RenderPass.
++ These 3 RenderPassTextures are used as the targets for the color attachments of the pass, and the depth
++ attachment uses a depth texture provided from outside the pass.
++
++ The RenderPass itself is set to \c AugmentMaterial mode, which means that it will augment the materials
++ of the rendered objects with additional shader code. The augment shader is provided
++ in the \c gbuffer_augment.glsl file, which outputs the required material properties
++ to the multiple render targets.
++
++ \snippet userpasses/gbuffer_augment.glsl gbuffer augment shader
++
++ Here you see how the base color, metalness, worldNormal, roughness and world position are
++ stored into the 3 color attachments of the G-buffer.
++
++ To actually use the G-buffer pass in the rendering pipeline, we need to create an instance
++ of it in \c Main.qml, and provide the required depth texture:
++
++ \snippet userpasses/Main.qml depth texture
++
++ \snippet userpasses/Main.qml GBufferPass usage
++
++ The G-buffer pass is declared as a child of the main color pass, its consumer.
++ Nesting a RenderPass inside another RenderPass makes the nested pass render
++ first, so the lighting stage always samples G-buffers produced in the same frame.
++
++ Three \l {QtQuick3D.Helpers::}{RenderOutputProvider} instances are created to provide
++ references to the rendered G-buffer textures, which will be used in the subsequent lighting pass.
++
++ \snippet userpasses/Main.qml gbuffer providers
++
++ The \c layerMask property of the G-buffer pass is set to only render objects
++ that are on ContentLayer.Layer0 and ContentLayer.Layer1. This allows us to control
++ which objects are rendered in the G-buffer pass by setting their \l {QtQuick3D::Model::layers}{layers}
++ property accordingly.
++
++ \section1 Main Color Pass and SubRenderPasses
++
++ Rather than a single flat render pass, this example uses a composite \c mainColorPass
++ that owns the main color and depth textures and orchestrates all rendering through
++ a sequence of \l {QtQuick3D::SubRenderPass}{SubRenderPass} children.
++
++ Each SubRenderPass shares the same render targets as the outer pass and executes
++ in order. This makes it straightforward to build a layered rendering pipeline where
++ each stage adds to the result of the previous one.
++
++ \snippet userpasses/Main.qml main color pass
++
++ The outer pass sets \c renderableTypes: RenderablesFilter.None so that nothing
++ renders directly in the parent pass — all rendering is delegated to the
++ sub-passes. The \c PreserveDepthStencilContents flag ensures that depth values
++ written by the G-buffer pass are available to every sub-pass.
++
++ \section2 Deferred Lighting SubPass
++
++ The first sub-pass runs the deferred lighting computation. It renders
++ the full-screen \c deferredLightingQuad model which samples the G-buffer
++ textures and evaluates lighting for every pixel.
++
++ \snippet userpasses/Main.qml deferred lighting quad
++
++ The \c deferredLightingQuad is placed on \c ContentLayer.Layer13 so that it is
++ invisible to the G-buffer pass and only rendered by this sub-pass.
++
++ A \l {QtQuick3D::PipelineStateOverride}{PipelineStateOverride} disables both
++ depth writes and depth tests for the quad. The G-buffer pass already wrote correct
++ depth for the scene geometry, so the full-screen quad must not alter or test depth.
++
++ \section2 Skybox SubPass
++
++ The second sub-pass renders the scene environment skybox using the special
++ \c RenderPass.SkyboxPass pass mode. Qt Quick 3D takes care of drawing the
++ skybox geometry using the \l {QtQuick3D::SceneEnvironment::skyMaterial}{skyMaterial}
++ and \l {QtQuick3D::SceneEnvironment::backgroundMode}{backgroundMode} settings from
++ the \l {QtQuick3D::SceneEnvironment}{SceneEnvironment}.
++
++ A PipelineStateOverride enables depth testing so the skybox is correctly hidden
++ behind scene geometry, while depth writes are disabled because the skybox sits "at
++ infinity" and must never occlude geometry.
++
++ \section2 Transparent Objects SubPass
++
++ Transparent objects cannot be stored in the G-buffer because they require
++ back-to-front sorted blending. Instead they are rendered last using their
++ original materials via a dedicated sub-pass.
++
++ The transparent cone in the scene is declared as follows:
++
++ \snippet userpasses/Main.qml transparent cone
++
++ The transparent sub-pass uses a \l {QtQuick3D::RenderablesFilter}{RenderablesFilter}
++ to select only transparent renderables on the matching layers, and a
++ PipelineStateOverride enables alpha blending while keeping depth testing active
++ so transparent objects sort correctly against opaque geometry.
++
++ Transparent objects must be rendered \e after all opaque passes so that the
++ depth buffer is fully populated before blending occurs.
++
++ \section2 2D Items in 3D SubPass
++
++ Qt Quick 3D can embed standard Qt Quick 2D items inside the 3D scene using
++ \l {QtQuick3D::Node}{Node} as a container. To include these items in a custom
++ render pipeline, add a sub-pass with \c passMode: RenderPass.Item2DPass.
++
++ \snippet userpasses/Main.qml item2d node
++
++ The \c Item2DPass mode instructs Qt Quick 3D to render all Qt Quick items
++ that are children of 3D nodes into the current render target, composited with
++ the 3D content already present.
++
++ \section1 Rendering to the screen
++
++ Finally, to display the result of our custom render passes on the screen,
++ we need to ensure that the View3D's main color texture is updated with the
++ result of the main color pass.
++
++ \snippet userpasses/Main.qml main texture
++
++ The \l {QtQuick3D.Helpers::}{SimpleQuadRenderer} is used to blit the
++ main color texture produced by the \c mainColorPass to the View3D's framebuffer.
++ The \l {QtQuick3D.Helpers::}{RenderOutputProvider} exposes the first
++ color attachment of \c mainColorPass as a texture the SimpleQuadRenderer can
++ sample.
++ */