이 페이지에서는

Balsam의 사용자 정의 렌더 패스는 Qt Quick 3D

Qt Quick 3D 는 대부분의 렌더링 세부 사항을 자동으로 처리하는 3D 렌더링용 고수준 API를 제공합니다. 그러나 고급 사용 사례의 경우, 애플리케이션에서 렌더링 파이프라인을 완전히 제어해야 할 수도 있습니다. 사용자 정의 렌더 패스는 애플리케이션이 내부 렌더링 파이프라인을 비활성화하고 자체적인 사용자 지정 패스를 정의할 수 있도록 하여 이를 가능하게 합니다.

사용자 렌더 패스를 통해 다음과 같은 고급 렌더링 기법을 구현할 수 있습니다:

  • 지연 셰이딩 및 라이팅
  • 다중 패스 렌더링 효과
  • 사용자 정의 후처리 파이프라인
  • 레이어 기반 필터링을 활용한 선택적 렌더링
  • 스크린 스페이스 효과(앰비언트 오클루전, 반사 등)
  • 사용자 정의 섀도 매핑 기법
  • 디버그 시각화 패스

사용자 지정 수준

Qt Quick 3D 서로 보완적인 세 가지 수준의 렌더링 사용자 지정을 제공하며, 각 수준은 서로 다른 사용 사례에 적합합니다:

레벨범위사용 사례
Effect후처리씬 렌더링 후 효과 적용 (블러, 컬러 그레이딩 등)
CustomMaterial머티리얼별 셰이더개별 머티리얼에 대한 사용자 정의 버텍스 및 프래그먼트 셰이더
RenderPass (사용자 렌더 패스)파이프라인에 대한 완전한 제어디퍼드 렌더링, 다중 패스, 사용자 정의 렌더 타겟

사용자 렌더 패스(RenderPass)는 가장 광범위한 제어 기능을 제공하여, 기본 렌더링 파이프라인을 보완하거나 완전히 대체할 수 있게 해줍니다. 이는 사용자 렌더링( CustomMaterial ) 및 사용자 렌더링 패스( Effect)를 보완합니다: CustomMaterial 개별 오브젝트의 렌더링 방식을 사용자 정의하는 반면, 사용자 렌더 패스는 전반적인 렌더링 전략과 아키텍처를 제어합니다.

사용자 렌더 패스 사용

사용자 렌더 패스는 다음 두 가지 방식으로 사용할 수 있습니다:

내부 렌더링 패스 보완

내부 렌더링 패스를 비활성화하지 않고도 기본 렌더링 파이프라인과 함께 사용자 정의 렌더링 패스( RenderPass ) 객체를 추가할 수 있습니다. 이는 Effect 또는 CustomMaterial 에서 사용될 텍스처로 렌더링하거나, 보조 렌더 타깃을 생성할 때 유용합니다.

View3D {
    // Internal passes still run normally

    RenderPassTexture { id: customTexture; format: RenderPassTexture.RGBA16F }

    RenderPass {
        // Custom pass renders to texture
        commands: [
            ColorAttachment { target: customTexture },
            DepthStencilAttachment { }
        ]
    }

    // Use customTexture in an Effect or material
}

내부 패스 대체

렌더링 파이프라인을 완전히 제어하려면 renderOverrides 속성을 설정하여 Qt Quick 3D 의 내부 렌더링을 비활성화하십시오:

View3D {
    renderOverrides: View3D.DisableInternalPasses

    // Your custom render passes go here
}

내부 패스가 비활성화되면 Qt Quick 3D 는 기본 렌더링을 수행하지 않습니다. 즉, 다음을 수행해야 합니다:

  • 씬을 렌더링할 RenderPass 를 적어도 하나 정의해야 합니다
  • SimpleQuadRenderer 또는 이와 유사한 메커니즘을 통해 표시할 최종 출력 텍스처를 제공해야 합니다
  • 깊이 버퍼, 투명도 등을 포함한 모든 렌더링 측면을 직접 처리해야 합니다.

참고: 내부 패스를비활성화하면 모든 제어권을 갖게 되지만, 그에 따른 모든 책임도 져야 합니다. 자동 그림자 렌더링, 투명도 정렬, 환경 반사 등의 기능은 필요한 경우 사용자 정의 패스에서 구현해야 합니다.

핵심 개념

사용자 정의 렌더 패스는 다음과 같은 몇 가지 핵심 구성 요소로 이루어집니다:

RenderPass

RenderPass 타입은 주요 구성 요소입니다. 이 타입은 렌더링 대상과 방식을 제어하는 일련의 명령어로 구성된 단일 렌더링 작업을 정의합니다. 각 패스는 다음을 수행할 수 있습니다:

  • 하나 이상의 컬러 텍스처로 렌더링(최대 4개의 동시 렌더 타겟)
  • 깊이 및 스텐실 정보를 기록
  • 레이어를 기반으로 렌더링할 오브젝트를 필터링
  • 그래픽 파이프라인 상태(블렌딩, 컬링 등) 재정의
  • 원본 머티리얼을 사용하거나, 사용자 정의 셰이더로 보강하거나, 완전히 재정의할 수 있습니다

RenderPassTexture

RenderPassTexture 유형은 렌더 타겟 역할을 하는 텍스처를 정의합니다. 이는 다양한 형식(RGBA8, RGBA16F, RGBA32F 등)의 컬러 텍스처이거나 깊이/스텐실 텍스처일 수 있습니다. 렌더 패스 텍스처는 한 패스의 출력값으로 사용되며, 후속 패스의 텍스처 입력값으로 사용될 수 있습니다.

RenderOutputProvider

RenderOutputProvider 유형은 한 패스의 출력 텍스처를 머티리얼이나 다른 패스에서 사용할 수 있는 텍스처 입력으로 노출함으로써 렌더 패스들을 연결합니다. 이는 후속 패스가 이전 패스의 결과를 읽어야 하는 멀티패스 렌더링에 필수적입니다.

ContentLayer

ContentLayer 싱글톤은 어떤 패스에서 어떤 오브젝트가 렌더링될지 필터링하는 데 사용되는 레이어 상수(Layer0부터 Layer23까지)를 제공합니다. 오브젝트를 특정 레이어에 할당하고 패스에서 ` RenderablesFilter `를 사용하면, 각 패스에서 렌더링될 내용을 정밀하게 제어할 수 있습니다.

렌더링 명령어

각 RenderPass 에는 해당 레이어의 동작을 구성하는 명령어 목록이 포함되어 있습니다:

머티리얼 모드

각 RenderPass 에는 렌더링 중 머티리얼이 처리되는 방식을 제어하는 ` materialMode ` 속성이 있습니다. 다음 세 가지 모드는 각기 다른 수준의 머티리얼 제어 기능을 제공합니다:

OriginalMaterial 모드

이 모드는 오브젝트에 할당된 머티리얼을 변경하지 않고 렌더링합니다. 렌더링 파이프라인 구조(다중 패스, 사용자 정의 렌더 타겟)를 제어하되 머티리얼 동작은 표준으로 유지하고 싶을 때 유용합니다.

RenderPass {
    materialMode: RenderPass.OriginalMaterial
    commands: [
        ColorAttachment { target: myColorTexture },
        DepthStencilAttachment { }
    ]
}

AugmentMaterial 모드

이 모드는 기존 머티리얼 파이프라인에 사용자 정의 셰이더 코드를 삽입합니다. 이는 머티리얼의 기본 동작을 유지하면서 추가 데이터(노멀, 위치 등)를 여러 렌더 타깃으로 출력해야 하는 디퍼드 렌더링에서 특히 유용합니다.

RenderPass {
    materialMode: RenderPass.AugmentMaterial
    augmentShader: "my_augment.glsl"
    commands: [
        ColorAttachment { target: gbuffer0; name: "GBUFFER0" },
        ColorAttachment { target: gbuffer1; name: "GBUFFER1" },
        DepthStencilAttachment { }
    ]
}

증강 셰이더 파일에는 ` MAIN_FRAGMENT_AUGMENT() ` 함수가 포함되어 있습니다:

void MAIN_FRAGMENT_AUGMENT()
{
    // Access material properties
    vec3 color = BASE_COLOR.rgb;
    float metal = METALNESS;
    float rough = ROUGHNESS;
    vec3 normal = normalize(WORLD_NORMAL);

    // Write to multiple render targets
    GBUFFER0 = vec4(color, metal);
    GBUFFER1 = vec4(normal * 0.5 + 0.5, rough);
}

자세한 내용은 ‘다중 렌더 타겟용 Augment 셰이더’를 참조하십시오.

OverrideMaterial 모드

이 모드는 모든 오브젝트 머티리얼을 단일 머티리얼로 대체합니다. 섀도우 매핑, 깊이 프리패스, 디버그 시각화 같은 특수한 렌더링 패스에 유용합니다.

RenderPass {
    materialMode: RenderPass.OverrideMaterial
    overrideMaterial: CustomMaterial {
        fragmentShader: "depth_only.frag"
        // All objects will use this material
    }
    commands: [
        DepthTextureAttachment { target: depthTexture }
    ]
}

렌더 패스 명령어

명령은 ` commands ` 속성에 지정되며, 정의된 순서대로 실행됩니다.

컬러 어태치먼트

ColorAttachment 명령어는 컬러 렌더 타겟을 지정합니다. name 속성은 어거스트 셰이더에서 해당 어태치먼트에 접근하는 방식을 정의합니다.

ColorAttachment {
    target: myTexture      // RenderPassTexture to render to
    name: "GBUFFER0"      // Name for shader access (optional)
}

패스당 최대 4개의 컬러 어태치먼트(여러 렌더 타깃용)를 가질 수 있습니다.

깊이 어태치먼트

깊이 처리는 두 가지 방법으로 수행할 수 있습니다:

DepthStencilAttachment 암시적 깊이/스텐실 버퍼를 사용합니다:

DepthStencilAttachment { }  // Creates depth/stencil buffer automatically

DepthTextureAttachment 깊이 출력을 위해 명시적 텍스처를 사용하는 방법:

RenderPassTexture {
    id: depthTex
    format: RenderPassTexture.Depth24Stencil8
}

DepthTextureAttachment {
    target: depthTex  // Explicit depth texture
}

여러 패스 간에 깊이 버퍼를 공유해야 하거나 셰이더에서 텍스처 입력으로 사용해야 할 때는 ` DepthTextureAttachment `를 사용하십시오.

렌더러블 필터

RenderablesFilter 명령은 레이어 할당 및 렌더러블 유형에 따라 어떤 오브젝트가 렌더링될지 제어합니다.

RenderablesFilter {
    layerMask: ContentLayer.Layer0 | ContentLayer.Layer1
    renderableTypes: RenderablesFilter.Opaque
}

layerMask 속성은 비트별 OR 연산을 사용하여 레이어를 결합합니다. renderableTypes 속성의 값은 다음과 같을 수 있습니다:

  • RenderablesFilter.Opaque: 불투명한 오브젝트만 렌더링
  • RenderablesFilter.Transparent: 투명한 오브젝트만 렌더링
  • RenderablesFilter.Opaque | RenderablesFilter.Transparent: 둘 다 렌더링

파이프라인 상태 재정의

PipelineStateOverride 명령어는 그래픽 파이프라인 상태를 세밀하게 제어할 수 있게 해줍니다. 이 명령어를 사용하면 깊이 검사, 블렌딩, 컬링, 폴리곤 모드 등을 재정의할 수 있습니다.

PipelineStateOverride {
    depthTestEnabled: true
    depthWriteEnabled: false
    blendEnabled: true
    cullMode: PipelineStateOverride.Back
    polygonMode: PipelineStateOverride.Fill
}

더 많은 예제는 ‘파이프라인 상태 제어’를 참조하십시오.

서브 렌더 패스

SubRenderPass 명령어는 현재 렌더 패스 내에서 다른 렌더 패스를 실행함으로써 렌더 패스를 계층적으로 구성할 수 있게 해줍니다.

RenderPass {
    id: parentPass
    commands: [
        ColorAttachment { target: colorTex },
        SubRenderPass { renderPass: childPass },
        // More commands after child pass
    ]
}

RenderPass {
    id: childPass
    // This pass executes within parentPass
}

정의 추가

AddDefine 명령어는 셰이더 컴파일에 영향을 미치는 셰이더 전처리기 정의(define)를 추가합니다.

AddDefine {
    name: "USE_SPECIAL_MODE"
    value: 1
}

간단한 예제: 단일 패스 렌더링

다음은 사용자 정의 렌더 패스를 보여주는 최소한의 예제입니다:

import QtQuick
import QtQuick3D
import QtQuick3D.Helpers

View3D {
    anchors.fill: parent
    renderOverrides: View3D.DisableInternalPasses

    // Camera and lights
    PerspectiveCamera { z: 300 }
    DirectionalLight { }

    // Define render target texture
    RenderPassTexture {
        id: colorTarget
        format: RenderPassTexture.RGBA16F
    }

    // Define the render pass
    RenderPass {
        id: mainPass
        materialMode: RenderPass.OriginalMaterial
        clearColor: "skyblue"

        commands: [
            ColorAttachment { target: colorTarget },
            DepthStencilAttachment { }
        ]
    }

    // Display the result
    SimpleQuadRenderer {
        texture: Texture {
            textureProvider: RenderOutputProvider {
                textureSource: RenderOutputProvider.UserPassTexture
                renderPass: mainPass
                attachmentSelector: RenderOutputProvider.Attachment0
            }
        }
    }

    // Scene content
    Model {
        source: "#Sphere"
        materials: PrincipledMaterial {
            baseColor: "red"
            metalness: 0.0
            roughness: 0.3
        }
    }
}

이 예제는:

  1. 내부 패스를 비활성화합니다
  2. 렌더 타겟 텍스처(colorTarget)를 생성합니다
  3. 해당 텍스처로 렌더링하는 렌더 패스를 정의합니다
  4. RenderOutputProvider 를 사용하여 텍스처를 노출합니다
  5. 다음과 같이 결과를 표시합니다. SimpleQuadRenderer
  6. 표준 머티리얼을 적용한 구체를 렌더링합니다

레이어 작업

ContentLayer 싱글톤은 오브젝트를 레이어로 구성하기 위한 상수를 제공하여, 각 패스에서 렌더링되는 내용을 세밀하게 제어할 수 있게 해줍니다.

레이어 상수

Qt Quick 3D xml-ph-0000@deepl.internal는 사용자가 할당할 수 있는 24개의 레이어를 제공합니다:

  • ContentLayer.Layer0 ContentLayer.Layer23 를 통해 : 개별 레이어
  • ContentLayer.LayerAll: 모든 사용자 레이어를 합친 것
  • ContentLayer.LayerNone: 레이어 없음

참고: 레이어 24~31은 내부 용도로 예약되어 있습니다.

레이어에 개체 할당

layers 속성을 사용하여 객체를 레이어에 할당합니다:

Model {
    source: "#Cube"
    layers: ContentLayer.Layer0
    materials: PrincipledMaterial { baseColor: "red" }
}

Model {
    source: "#Sphere"
    layers: ContentLayer.Layer1 | ContentLayer.Layer2
    materials: PrincipledMaterial { baseColor: "blue" }
}

비트별 OR 연산을 사용하여 객체를 여러 레이어에 동시에 할당할 수 있습니다.

레이어별 필터링

렌더링 단계에서 ` RenderablesFilter `를 사용하여 렌더링할 레이어를 선택합니다:

RenderPass {
    id: pass1
    commands: [
        ColorAttachment { target: texture1 },
        RenderablesFilter {
            layerMask: ContentLayer.Layer0
        }
    ]
    // Only renders objects on Layer0 (red cube)
}

RenderPass {
    id: pass2
    commands: [
        ColorAttachment { target: texture2 },
        RenderablesFilter {
            layerMask: ContentLayer.Layer1 | ContentLayer.Layer2
        }
    ]
    // Only renders objects on Layer1 or Layer2 (blue sphere)
}

사용 사례: 선택적 렌더링

실제 예시로는 특정 오브젝트를 와이어프레임 오버레이로 렌더링하는 것입니다:

View3D {
    renderOverrides: View3D.DisableInternalPasses

    RenderPassTexture { id: colorTex; format: RenderPassTexture.RGBA16F }
    RenderPassTexture { id: depthTex; format: RenderPassTexture.Depth24Stencil8 }

    // Pass 1: Render solid objects
    RenderPass {
        id: solidPass
        commands: [
            ColorAttachment { target: colorTex },
            DepthTextureAttachment { target: depthTex },
            RenderablesFilter { layerMask: ContentLayer.Layer0 }
        ]
    }

    // Pass 2: Render wireframe overlay
    RenderPass {
        id: wireframePass
        commands: [
            ColorAttachment { target: colorTex },
            DepthTextureAttachment { target: depthTex },
            PipelineStateOverride {
                polygonMode: PipelineStateOverride.Line
                depthTestEnabled: true
                depthWriteEnabled: false
            },
            RenderablesFilter { layerMask: ContentLayer.Layer1 }
        ]
    }

    SimpleQuadRenderer {
        texture: Texture {
            textureProvider: RenderOutputProvider {
                textureSource: RenderOutputProvider.UserPassTexture
                renderPass: wireframePass
                attachmentSelector: RenderOutputProvider.Attachment0
            }
        }
    }

    Model {
        source: "#Sphere"
        layers: ContentLayer.Layer0  // Rendered solid
        materials: PrincipledMaterial { baseColor: "blue" }
    }

    Model {
        source: "#Sphere"
        layers: ContentLayer.Layer1  // Rendered as wireframe
        materials: PrincipledMaterial { baseColor: "yellow" }
    }
}

텍스처 관리

사용자 렌더 패스는 렌더 타겟으로서뿐만 아니라 후속 패스나 머티리얼의 입력으로서도 텍스처에 크게 의존합니다.

렌더 패스 텍스처 형식

RenderPassTexture 다양한 사용 사례에 맞춰 다음과 같은 여러 형식을 지원합니다:

색상 형식:

형식설명사용 사례
RGBA8채널당 8비트표준 색상 출력, 메모리 사용량 감소
RGBA16F16비트 부동 소수점HDR 렌더링, 중간 버퍼
RGBA32F32비트 부동 소수점고정밀도 계산
R8, R16, R16F, R32F단일 채널 변형그레이스케일 데이터, 전용 버퍼

심도 형식:

포맷설명
심도 1616비트 색심도
Depth2424비트 색심도
Depth3232비트 색심도
Depth24Stencil824비트 심도 + 8비트 스텐실

텍스처 정의 예시:

RenderPassTexture {
    id: hdrColorBuffer
    format: RenderPassTexture.RGBA16F  // HDR color
}

RenderPassTexture {
    id: depthBuffer
    format: RenderPassTexture.Depth24Stencil8  // Depth + stencil
}

RenderPassTexture {
    id: normalBuffer
    format: RenderPassTexture.RGBA16F  // Store normals
}

패스 간 텍스처 공유

여러 패스가 동일한 깊이 텍스처를 공유할 수 있어, 패스 간 깊이 테스트가 가능합니다:

RenderPassTexture {
    id: sharedDepth
    format: RenderPassTexture.Depth24Stencil8
}

RenderPass {
    id: geometryPass
    commands: [
        ColorAttachment { target: colorTex1 },
        DepthTextureAttachment { target: sharedDepth }
    ]
}

RenderPass {
    id: transparentPass
    renderTargetFlags: RenderPass.PreserveDepthStencilContents
    commands: [
        ColorAttachment { target: colorTex2 },
        DepthTextureAttachment { target: sharedDepth }
        // Uses depth from geometryPass for depth testing
    ]
}

렌더 출력 프로바이더

RenderOutputProvider 는 렌더 패스 출력을 Texture 입력으로 노출합니다:

// Define a render pass with color output
RenderPass {
    id: firstPass
    commands: [
        ColorAttachment { target: intermediateTexture }
    ]
}

// Expose its output
RenderOutputProvider {
    id: intermediateProvider
    textureSource: RenderOutputProvider.UserPassTexture
    renderPass: firstPass
    attachmentSelector: RenderOutputProvider.Attachment0
}

// Use in a material
CustomMaterial {
    property TextureInput inputTex: TextureInput {
        texture: Texture { textureProvider: intermediateProvider }
    }
    fragmentShader: "process.frag"
}

attachmentSelector 속성은 패스에 여러 렌더 타겟이 있을 때 사용할 색상 어태치먼트를 지정합니다:

  • RenderOutputProvider.Attachment0: 첫 번째 색상 어태치먼트
  • RenderOutputProvider.Attachment1: 두 번째 색상 어태치먼트
  • RenderOutputProvider.Attachment2: 세 번째 색상 어태치먼트
  • RenderOutputProvider.Attachment3: 네 번째 색상 어태치먼트

패스 연쇄 예시

여러 패스를 연쇄적으로 연결할 수 있으며, 각 패스는 이전 패스의 출력을 처리합니다:

View3D {
    renderOverrides: View3D.DisableInternalPasses

    // Intermediate textures
    RenderPassTexture { id: tex0; format: RenderPassTexture.RGBA16F }
    RenderPassTexture { id: tex1; format: RenderPassTexture.RGBA16F }
    RenderPassTexture { id: tex2; format: RenderPassTexture.RGBA16F }

    // Pass 1: Render scene
    RenderPass {
        id: scenePass
        commands: [
            ColorAttachment { target: tex0 },
            DepthStencilAttachment { }
        ]
    }

    // Pass 2: Process tex0 -> tex1
    RenderPass {
        id: process1
        materialMode: RenderPass.OriginalMaterial
        commands: [
            ColorAttachment { target: tex1 }
        ]
    }

    Model {
        layers: ContentLayer.Layer10
        geometry: PlaneGeometry { }
        materials: CustomMaterial {
            property TextureInput input: TextureInput {
                texture: Texture {
                    textureProvider: RenderOutputProvider {
                        textureSource: RenderOutputProvider.UserPassTexture
                        renderPass: scenePass
                    }
                }
            }
            fragmentShader: "effect1.frag"
        }
    }

    // Pass 3: Process tex1 -> tex2
    RenderPass {
        id: process2
        commands: [
            ColorAttachment { target: tex2 },
            RenderablesFilter { layerMask: ContentLayer.Layer11 }
        ]
    }

    Model {
        layers: ContentLayer.Layer11
        geometry: PlaneGeometry { }
        materials: CustomMaterial {
            property TextureInput input: TextureInput {
                texture: Texture {
                    textureProvider: RenderOutputProvider {
                        textureSource: RenderOutputProvider.UserPassTexture
                        renderPass: process1
                    }
                }
            }
            fragmentShader: "effect2.frag"
        }
    }

    // Display final result
    SimpleQuadRenderer {
        texture: Texture {
            textureProvider: RenderOutputProvider {
                textureSource: RenderOutputProvider.UserPassTexture
                renderPass: process2
            }
        }
    }
}

파이프라인 상태 제어

PipelineStateOverride 명령어는 그래픽 파이프라인 상태를 세밀하게 제어하여, 깊이 검사, 블렌딩, 컬링 등을 사용자 정의할 수 있게 해줍니다.

깊이 테스트 및 기록

깊이 값의 테스트 및 기록 방식을 제어합니다:

PipelineStateOverride {
    depthTestEnabled: true
    depthWriteEnabled: true
    depthFunction: PipelineStateOverride.LessOrEqual
}

depthFunction 속성의 값은 다음과 같을 수 있습니다:

  • Never, Less, Equal, LessOrEqual
  • Greater, NotEqual, GreaterOrEqual, Always

블렌딩

투명도를 위한 블렌딩을 활성화하고 구성합니다:

PipelineStateOverride {
    blendEnabled: true
    // Uses default blend mode (source alpha blending)
}

렌더 타깃이 여러 개인 경우, 타깃별 블렌드 상태를 사용합니다. ` PipelineStateOverride `은 ` targetBlend0 `부터 ` targetBlend7 `까지( renderTargetBlend 유형)의 부착물별 값 유형 속성을 노출하며, 블렌드 계수 및 연산 열거형은 ` RenderTargetBlend ` 네임스페이스에 있습니다:

PipelineStateOverride {
    targetBlend0.enable: true
    targetBlend0.srcColor: RenderTargetBlend.SrcAlpha
    targetBlend0.dstColor: RenderTargetBlend.OneMinusSrcAlpha
    targetBlend0.opColor:  RenderTargetBlend.Add

    targetBlend1.enable: false  // No blending for attachment 1
}

컬링

면 켈링 제어:

PipelineStateOverride {
    cullMode: PipelineStateOverride.Back   // Override material's cull mode to Back
}

여기에서 ‘ cullMode ’을 설정하면, 이 패스에 대해 머티리얼이 원래 지정했을 값이 재정의됩니다. 옵션: None (컬링 없음), Front (전면 면 컬링), Back (후면 면 컬링).

와이어프레임 렌더링

지오메트리를 와이어프레임으로 렌더링:

PipelineStateOverride {
    polygonMode: PipelineStateOverride.Line
    cullMode: PipelineStateOverride.None  // Show both sides
}

polygonMode 는 Fill (기본값) 또는 Line (와이어프레임)일 수 있습니다.

직사각형 잘라내기

렌더링을 직사각형 영역으로 제한합니다:

PipelineStateOverride {
    usesScissor: true
    scissor: Qt.rect(100, 100, 400, 300)  // x, y, width, height
}

뷰포트 제어

뷰포트 재정의:

PipelineStateOverride {
    viewport: Qt.rect(0, 0, 800, 600)
}

전체 예제: 와이어프레임 오버레이

이 예제는 씬을 정상적으로 렌더링한 후, 와이어프레임 버전을 오버레이합니다:

View3D {
    renderOverrides: View3D.DisableInternalPasses

    RenderPassTexture { id: color; format: RenderPassTexture.RGBA16F }
    RenderPassTexture { id: depth; format: RenderPassTexture.Depth24Stencil8 }

    // Solid pass
    RenderPass {
        id: solidPass
        clearColor: "black"
        commands: [
            ColorAttachment { target: color },
            DepthTextureAttachment { target: depth },
            RenderablesFilter {
                layerMask: ContentLayer.Layer0
                renderableTypes: RenderablesFilter.Opaque
            }
        ]
    }

    // Wireframe overlay
    RenderPass {
        id: wirePass
        renderTargetFlags: RenderPass.PreserveColorContents |
                          RenderPass.PreserveDepthStencilContents
        commands: [
            ColorAttachment { target: color },
            DepthTextureAttachment { target: depth },
            PipelineStateOverride {
                polygonMode: PipelineStateOverride.Line
                depthTestEnabled: true
                depthWriteEnabled: false
                blendEnabled: true
            },
            RenderablesFilter { layerMask: ContentLayer.Layer0 }
        ]
    }

    SimpleQuadRenderer {
        texture: Texture {
            textureProvider: RenderOutputProvider {
                textureSource: RenderOutputProvider.UserPassTexture
                renderPass: wirePass
            }
        }
    }

    PerspectiveCamera { z: 300 }
    DirectionalLight { }

    Model {
        source: "#Sphere"
        layers: ContentLayer.Layer0
        materials: PrincipledMaterial {
            baseColor: "blue"
            metalness: 0.5
            roughness: 0.3
        }
    }
}

다중 렌더 타겟용 증강 셰이더

RenderPass.AugmentMaterial 모드를 사용할 때는 머티리얼의 프래그먼트 셰이더에 사용자 정의 코드를 삽입하는 증강 셰이더를 제공해야 합니다. 이는 머티리얼 데이터를 여러 렌더 타깃(MRT)으로 출력해야 하는 디퍼드 렌더링에서 특히 유용합니다.

MAIN_FRAGMENT_AUGMENT 함수

증강 셰이더 파일에는 MAIN_FRAGMENT_AUGMENT() 함수가 정의되어 있어야 합니다:

void MAIN_FRAGMENT_AUGMENT()
{
    // Your custom shader code here
}

이 함수는 프래그먼트 셰이더에서 머티리얼 계산이 완료된 후 호출되며, 이를 통해 머티리얼 속성에 접근하고 사용자 정의 출력값을 작성할 수 있습니다.

사용 가능한 내장 변수

MAIN_FRAGMENT_AUGMENT() 내부에서 엔진은 머티리얼 파이프라인 데이터를 노출하는 일련의 매크로를 대입합니다. 아래에 나열된 매크로만이 어거먼트 셰이더 API의 일부입니다:

매크로유형설명
BASE_COLORvec4머티리얼 기본 색상(선형 색상 공간, 머티리얼 처리 후).
METALNESSfloat0.0에서 1.0 사이의 머티리얼 메탈니스.
ROUGHNESSfloat0.0에서 1.0 사이의 머티리얼 거칠기 값입니다.
WORLD_NORMALvec3월드 스페이스 표면 법선(노멀 매핑 후).
WORLD_TANGENTvec3월드 공간 접선 벡터.
WORLD_BINORMALvec3월드 공간의 바이노멀 벡터.
DIFFUSE_LIGHTvec3누적된 확산광 기여도.
SPECULAR_LIGHTvec3누적된 스페큘러 광 기여도.
EMISSIVE_LIGHTvec3머티리얼의 발광 기여도.
F0vec3법선 입사 시의 프레넬 반사율.
F90vec3접선 입사 시의 프레넬 반사율.

참고: 일부 예제(아래의 디퍼드 렌더링 예제 포함)는 qt_varWorldPos 를 통해 월드 스페이스 프래그먼트 위치를 읽습니다. 이는 엔진의 기본 변수 이름이며, 어거먼트 셰이더 매크로가 아니며, ‘내장 셰이더 기능’에서 설명한 .glsllib 파일과 마찬가지로 준공개 범주에 속합니다. 즉, 실제로는 작동하지만 릴리스 간 안정성이 보장되지는 않습니다.

명명된 출력에 쓰기

렌더 패스의 컬러 어태치먼트는 셰이더의 출력 변수와 일치하는 이름을 가질 수 있습니다:

RenderPass {
    commands: [
        ColorAttachment { target: tex0; name: "GBUFFER0" },
        ColorAttachment { target: tex1; name: "GBUFFER1" },
        ColorAttachment { target: tex2; name: "GBUFFER2" }
    ]
}

증강 셰이더에서:

void MAIN_FRAGMENT_AUGMENT()
{
    GBUFFER0 = vec4(...);  // Writes to first attachment
    GBUFFER1 = vec4(...);  // Writes to second attachment
    GBUFFER2 = vec4(...);  // Writes to third attachment
}

Qt Quick 3D 최대 4개의 컬러 어태치먼트(GBUFFER0부터 GBUFFER3까지)를 동시에 지원합니다.

완전한 어거먼트 셰이더 예제

다음은 디퍼드 렌더링 G-버퍼 패스에 대한 완전한 예제입니다:

// gbuffer_augment.glsl
void MAIN_FRAGMENT_AUGMENT()
{
    // Get material properties
    vec3 baseColor = BASE_COLOR.rgb;
    float metalness = METALNESS;
    float roughness = ROUGHNESS;
    vec3 worldNormal = normalize(WORLD_NORMAL);
    vec3 worldPos = qt_varWorldPos;

    // GBuffer 0: Albedo (RGB) + Metalness (A)
    GBUFFER0 = vec4(baseColor, metalness);

    // GBuffer 1: World Normal (RGB) + Roughness (A)
    // Encode normal from [-1,1] to [0,1] for storage
    GBUFFER1 = vec4(worldNormal * 0.5 + 0.5, roughness);

    // GBuffer 2: World Position
    GBUFFER2 = vec4(worldPos, 1.0);
}

렌더 패스(RenderPassTexture 와 함께 사용되며, 인스턴스는 외곽의 View3D 의 직접 자식으로 선언되고 ID를 통해 참조됩니다):

View3D {
    RenderPassTexture { id: gbuffer0; format: RenderPassTexture.RGBA16F }
    RenderPassTexture { id: gbuffer1; format: RenderPassTexture.RGBA16F }
    RenderPassTexture { id: gbuffer2; format: RenderPassTexture.RGBA16F }

    RenderPass {
        id: gbufferPass
        materialMode: RenderPass.AugmentMaterial
        augmentShader: "gbuffer_augment.glsl"
        commands: [
            ColorAttachment { target: gbuffer0; name: "GBUFFER0" },
            ColorAttachment { target: gbuffer1; name: "GBUFFER1" },
            ColorAttachment { target: gbuffer2; name: "GBUFFER2" },
            DepthStencilAttachment { }
        ]
    }
}

머티리얼 동작 유지

오거먼트 셰이더는 일반 머티리얼 파이프라인을 대체하는 것이 아니라, 그와 병행하여 실행됩니다. 즉,

  • 머티리얼의 텍스처, 속성 및 계산은 여전히 정상적으로 수행됩니다
  • 주 색상 출력을 대체하는 것이 아니라 추가적인 출력을 더하는 것입니다
  • 재정의되지 않는 한, 원래 머티리얼의 RGBA 출력은 여전히 첫 번째 색상 어태치먼트에 기록됩니다

사용자 정의 데이터만 출력해야 하고 표준 머티리얼 계산이 필요하지 않은 경우, 대신 ‘ RenderPass.OverrideMaterial ’를 사용하는 것을 고려해 보십시오.

Augment와 Override의 사용 시나리오

다음과 같은 경우에는 ‘ AugmentMaterial ’를 사용하십시오:

  • G-버퍼에 필요한 머티리얼 속성(메탈니스, 러프니스, 노멀)이 필요한 경우
  • 텍스처 매핑과 같은 기존 머티리얼 기능을 활용하려는 경우
  • 머티리얼 데이터가 포함된 여러 개의 렌더 타깃이 필요한 경우

다음과 같은 경우에는 ‘ OverrideMaterial ’를 사용하십시오:

  • 모든 오브젝트에 대해 동일한 동작(깊이 프리패스, 섀도우 맵 등)이 필요한 경우
  • 머티리얼별 속성이 필요하지 않은 경우
  • 머티리얼 계산을 우회하여 최대 성능을 확보하고자 할 때

내장 셰이더 기능

렌더 패스에서 사용되는 Augment 셰이더와 사용자 정의 머티리얼은 인클루드 시스템을 통해 Qt Quick 3D 의 내장 셰이더 인프라에 접근할 수 있습니다. 이러한 셰이더 라이브러리 파일(.glsllib)은 조명, 그림자, 톤 매핑 등의 기능을 제공합니다.

포함 구문:

셰이더 코드에서 \#include 지시어를 사용하여 기능을 가져옵니다:

#include "tonemapping.glsllib"
#include "lightsData.glsllib"
#include "shadowMapping.glsllib"
#include "funcprocessPunctualLighting.glsllib"

void MAIN()
{
    // Use included functions
    vec3 color = qt_tonemap(hdrColor);
}

사용 가능한 셰이더 라이브러리:

이러한 셰이더 라이브러리는 엔진 내 src/runtimerender/res/effectlib/ 에 위치하며, 준공개(semi-public)로 간주됩니다. 즉, 사용자 셰이더에서 사용할 수 있지만 Qt의 다른 공개 API와 동일한 바이너리 호환성이 보장되지는 않습니다.

라이브러리설명
tonemapping.glsllib내장된 톤 매핑 알고리즘을 사용하여 HDR을 LDR로 변환하는 qt_tonemap() 함수를 제공합니다.
lightsData.glsllib사용자 정의 조명 계산 시 활용할 수 있는 장면 조명 정보(광원 위치, 색상, 방향 등)를 포함합니다
shadowMapping.glsllib기본 섀도 맵에서 샘플링하는 함수를 제공하여 사용자 정의 머티리얼이 그림자를 받을 수 있도록 합니다.
funcprocessPunctualLighting.glsllib표준 PBR 조명 계산을 위한 qt_processPunctualLighting() 및 기타 내장 조명 함수를 포함합니다.
sampleProbe.glsllib이미지 기반 조명 프로브를 샘플링하는 함수(qt_sampleDiffuse(), qt_sampleGlossyPrincipled())

예제: 내장 함수를 사용한 사용자 정의 조명

다음은 내장 조명 기능을 사용하는 프래그먼트 셰이더의 예시입니다:

#include "lightsData.glsllib"
#include "funcprocessPunctualLighting.glsllib"
#include "tonemapping.glsllib"
#include "sampleProbe.glsllib"

void MAIN()
{
    vec3 worldPos = ...; // From G-buffer or varying
    vec3 normal = ...;
    vec3 viewDir = normalize(CAMERA_POSITION - worldPos);
    vec3 baseColor = ...;
    float roughness = ...;
    float metalness = ...;

    vec3 F0 = mix(vec3(0.04), baseColor, metalness);

    vec3 diffuseAccum = vec3(0.0);
    vec3 specAccum = vec3(0.0);

    // Use built-in punctual lighting (directional, point, spot lights)
    qt_processPunctualLighting(diffuseAccum,
                               specAccum,
                               baseColor,
                               worldPos,
                               normal,
                               viewDir,
                               vec3(1.0), // specularAmount
                               vec3(1.0), // specularTint
                               roughness,
                               metalness,
                               F0,
                               vec3(1.0)); // F90

    // Add image-based lighting
    vec4 probeDiffuse = vec4(baseColor, 1.0) * qt_sampleDiffuse(normal);
    vec4 probeSpecular = qt_sampleGlossyPrincipled(normal, viewDir, F0, roughness);
    diffuseAccum += probeDiffuse.rgb;
    specAccum += probeSpecular.rgb;

    vec3 color = diffuseAccum + specAccum;

    // Apply tonemapping
    FRAGCOLOR = vec4(qt_tonemap(color), 1.0);
}

참고: 이러한 셰이더 라이브러리는 반공개(semi-public) API입니다. 이 라이브러리는 안정적이며 사용자 정의 셰이더에서 사용하도록 설계되었지만, Qt는 릴리스 간에 내부 구현이나 사용 가능한 함수가 변경되지 않을 것이라고 보장하지 않습니다. 다만, qt_tonemap() 및 qt_processPunctualLighting() 과 같이 일반적으로 사용되는 함수는 크게 변경될 가능성이 낮습니다.

고급 예제: 지연 렌더링

지연 렌더링(Deferred Rendering)은 첫 번째 패스에서 지오메트리 정보를 여러 텍스처(G-버퍼 또는 지오메트리 버퍼라고 함)에 렌더링하고, 두 번째 패스에서 저장된 지오메트리 데이터를 사용하여 조명 계산을 수행하는 기술입니다. 이 방식은 조명 수가 많을 때 특히 효율적입니다. 조명 수와 관계없이 각 픽셀은 한 번만 셰이딩되기 때문입니다.

지연 렌더링 아키텍처

디퍼드 렌더링 파이프라인은 두 가지 주요 패스로 구성됩니다:

  1. 지오메트리 패스(G-버퍼 패스): 씬의 지오메트리를 여러 렌더 타깃에 렌더링하여 알베도, 노멀, 거칠기, 금속성, 월드 위치와 같은 머티리얼 속성을 저장합니다.
  2. 조명 패스: G-버퍼를 샘플링하는 전체 화면 쿼드를 렌더링하고, 저장된 지오메트리 데이터를 기반으로 각 픽셀에 대한 조명 계산을 수행합니다.

G-버퍼 패스 구현

먼저, 머티리얼 데이터를 여러 렌더 타깃으로 출력하는 G-버퍼 패스를 정의합니다:

GBufferPass.qml: G-버퍼 렌더 타겟은 필수 속성으로 노출되므로, 이를 감싸는 ` View3D `가 해당 타겟을 제공하고 그 출력을 읽을 수 있습니다:

import QtQuick
import QtQuick3D

RenderPass {
    id: gbufferPass
    clearColor: Qt.rgba(0.0, 0.0, 0.0, 0.0)

    property alias layerMask: filter.layerMask

    // Provided by the View3D that uses this pass
    required property RenderPassTexture gbuffer0   // rgb: baseColor, a: metalness
    required property RenderPassTexture gbuffer1   // rgb: normal,    a: roughness
    required property RenderPassTexture gbuffer2   // rgb: world pos, a: spare
    required property RenderPassTexture depthTexture

    materialMode: RenderPass.AugmentMaterial
    augmentShader: "gbuffer_augment.glsl"

    commands: [
        ColorAttachment { target: gbufferPass.gbuffer0; name: "GBUFFER0" },
        ColorAttachment { target: gbufferPass.gbuffer1; name: "GBUFFER1" },
        ColorAttachment { target: gbufferPass.gbuffer2; name: "GBUFFER2" },
        DepthTextureAttachment { target: gbufferPass.depthTexture },
        RenderablesFilter {
            id: filter
            renderableTypes: RenderablesFilter.Opaque
        }
    ]
}

gbuffer_augment.glsl:

void MAIN_FRAGMENT_AUGMENT()
{
    vec3 baseColor   = BASE_COLOR.rgb;
    float metalness  = METALNESS;
    float roughness  = ROUGHNESS;
    vec3 worldNormal = normalize(WORLD_NORMAL);

    // GBuffer 0: albedo + metalness
    GBUFFER0 = vec4(baseColor, metalness);

    // GBuffer 1: normal (encoded to 0..1) + roughness
    GBUFFER1 = vec4(worldNormal * 0.5 + 0.5, roughness);

    // GBuffer 2: world position
    GBUFFER2 = vec4(qt_varWorldPos, 1.0);
}

증강 셰이더는 머티리얼 파이프라인에서 계산된 머티리얼 속성에 접근하여 이를 세 개의 G-버퍼 어태치먼트에 기록합니다. 노멀은 저장을 위해 [-1,1] 범위에서 [0,1] 범위로 인코딩됩니다.

라이팅 패스 구현

라이팅 패스는 G-버퍼를 샘플링하여 라이팅을 계산하는 전체 화면 사각형을 렌더링합니다:

// Lighting pass model (full-screen quad)
Model {
    id: deferredLightingQuad
    layers: ContentLayer.Layer13  // Dedicated layer for lighting quad

    geometry: PlaneGeometry {
        plane: PlaneGeometry.XY  // Quad in screen space
    }

    materials: CustomMaterial {
        // Texture inputs for G-buffers
        property TextureInput gbuffer0: TextureInput {
            enabled: true
            texture: Texture { textureProvider: gbuffer0Provider }
        }
        property TextureInput gbuffer1: TextureInput {
            enabled: true
            texture: Texture { textureProvider: gbuffer1Provider }
        }
        property TextureInput gbuffer2: TextureInput {
            enabled: true
            texture: Texture { textureProvider: gbuffer2Provider }
        }

        shadingMode: CustomMaterial.Unshaded
        fragmentShader: "lighting.frag"
        vertexShader: "lighting.vert"
    }
}

// Lighting pass renders the quad to main output
RenderPass {
    id: deferredLightingPass
    materialMode: RenderPass.OriginalMaterial

    commands: [
        ColorAttachment { target: mainColorTexture },
        DepthStencilAttachment { },
        RenderablesFilter { layerMask: ContentLayer.Layer13 }
    ]
}

라이팅 버텍스 셰이더(lighting.vert)는 정규화된 장치 좌표계에서 전체 화면 쿼드를 생성하고, 프래그먼트 셰이더(lighting.frag)는 G-버퍼를 샘플링하여 라이팅 계산을 수행합니다.

완전한 통합

다음은 View3D 에서 두 패스를 통합하는 방법입니다:

View3D {
    renderOverrides: View3D.DisableInternalPasses

    // Main output texture
    RenderPassTexture { id: mainColorTexture; format: RenderPassTexture.RGBA16F }

    // Shared depth texture
    RenderPassTexture { id: mainDepthStencilTexture; format: RenderPassTexture.Depth24Stencil8 }

    // G-buffer render targets
    RenderPassTexture { id: gbuffer0Tex; format: RenderPassTexture.RGBA16F }
    RenderPassTexture { id: gbuffer1Tex; format: RenderPassTexture.RGBA16F }
    RenderPassTexture { id: gbuffer2Tex; format: RenderPassTexture.RGBA16F }

    // G-buffer pass
    GBufferPass {
        id: gbufferPass
        layerMask: ContentLayer.Layer0 | ContentLayer.Layer1
        gbuffer0: gbuffer0Tex
        gbuffer1: gbuffer1Tex
        gbuffer2: gbuffer2Tex
        depthTexture: mainDepthStencilTexture
    }

    // Expose G-buffer outputs
    RenderOutputProvider {
        id: gbuffer0Provider
        textureSource: RenderOutputProvider.UserPassTexture
        renderPass: gbufferPass
        attachmentSelector: RenderOutputProvider.Attachment0
    }

    RenderOutputProvider {
        id: gbuffer1Provider
        textureSource: RenderOutputProvider.UserPassTexture
        renderPass: gbufferPass
        attachmentSelector: RenderOutputProvider.Attachment1
    }

    RenderOutputProvider {
        id: gbuffer2Provider
        textureSource: RenderOutputProvider.UserPassTexture
        renderPass: gbufferPass
        attachmentSelector: RenderOutputProvider.Attachment2
    }

    // Lighting pass (defined above)

    // Display final result
    SimpleQuadRenderer {
        texture: Texture {
            textureProvider: RenderOutputProvider {
                textureSource: RenderOutputProvider.UserPassTexture
                renderPass: deferredLightingPass
                attachmentSelector: RenderOutputProvider.Attachment0
            }
        }
    }

    // Scene objects
    Model {
        layers: ContentLayer.Layer0
        source: "#Sphere"
        materials: PrincipledMaterial {
            baseColor: "red"
            metalness: 0.5
            roughness: 0.3
        }
    }

    // Camera and lights
    PerspectiveCamera { z: 300 }
    DirectionalLight { eulerRotation.x: -45 }
}

렌더링 흐름

렌더링은 다음과 같이 진행됩니다:

  1. G-버퍼 패스: Layer0 및 Layer1에 있는 씬 오브젝트가 렌더링됩니다. 각 오브젝트에 대해 어거먼트 셰이더는 알베도, 노멀, 러프니스, 메탈니스 및 위치를 세 개의 컬러 어태치먼트에 기록합니다. 깊이는 공유 깊이 텍스처에 기록됩니다.
  2. 라이팅 패스: Layer13의 전체 화면 쿼드가 렌더링됩니다. 이 쿼드의 커스텀 머티리얼은 3개의 G-버퍼 텍스처와 깊이 텍스처를 샘플링하여 씬 정보를 재구성한 후, 라이팅 계산(방향성 조명, 이미지 기반 라이팅 등)을 수행하여 최종 조명 적용 색상을 생성합니다.
  3. 표시: 라이팅 패스의 결과는 ` SimpleQuadRenderer`를 통해 표시됩니다.

장점 및 한계

장점:

  • 조명이 많은 경우에도 효율적(각 픽셀당 한 번만 조명 처리)
  • 장면의 복잡성과 무관하게 조명 계산이 단순함
  • 스크린 스페이스 효과를 구현하기 쉬움
  • 지오메트리 패스와 라이팅 패스를 분리

한계:

  • G-버퍼 읽기/쓰기로 인해 메모리 대역폭 요구량이 높음
  • 하드웨어 MSAA 미지원 (대체 앤티앨리어싱 필요)
  • 투명도를 구현하려면 별도의 포워드 패스가 필요함
  • 설정 및 유지 관리가 더 복잡한 파이프라인

완전한 작동 예제는 Qt Quick 3D - User Passes Example을 참조하십시오.

완전한 렌더링 파이프라인 예제

현실감 있는 사용자 정의 렌더링 파이프라인을 구현하려면 불투명 지오메트리, 스카이박스 배경, 2D 오버레이, 투명 오브젝트 등 여러 종류의 패스를 결합해야 하는 경우가 많습니다. 다음은 SubRenderPass 를 사용하여 계층적 합성을 통해 이러한 요소들을 구성하는 방법을 보여주는 완전한 예제입니다:

View3D {
    renderOverrides: View3D.DisableInternalPasses

    environment: SceneEnvironment {
        backgroundMode: SceneEnvironment.SkyBox
        lightProbe: Texture {
            textureData: ProceduralSkyTextureData { }
        }
    }

    RenderPassTexture {
        id: mainColorTexture
        format: RenderPassTexture.RGBA16F
    }

    RenderPassTexture {
        id: mainDepthStencilTexture
        format: RenderPassTexture.Depth24Stencil8
    }

    // Main pass orchestrates the complete render path:
    // 1. Opaque geometry (deferred)
    // 2. Skybox background
    // 3. 2D UI overlays
    // 4. Transparent objects (forward)
    RenderPass {
        id: mainColorPass
        clearColor: "black"
        renderTargetFlags: RenderPass.PreserveDepthStencilContents

        commands: [
            ColorAttachment { target: mainColorTexture },
            DepthTextureAttachment { target: mainDepthStencilTexture },
            RenderablesFilter {
                renderableTypes: RenderablesFilter.None  // Parent doesn't render
            },

            // Sub-pass 1: Deferred lighting
            SubRenderPass {
                renderPass: RenderPass {
                    id: deferredLightingPass
                    materialMode: RenderPass.OriginalMaterial
                    commands: [
                        PipelineStateOverride {
                            depthWriteEnabled: false
                            depthTestEnabled: false
                        },
                        RenderablesFilter { layerMask: ContentLayer.Layer13 }
                    ]
                }
            },

            // Sub-pass 2: Skybox (behind everything)
            SubRenderPass {
                renderPass: RenderPass {
                    passMode: RenderPass.SkyboxPass
                    commands: [
                        PipelineStateOverride {
                            depthTestEnabled: true
                            depthWriteEnabled: false
                        }
                    ]
                }
            },

            // Sub-pass 3: 2D Qt Quick content
            SubRenderPass {
                renderPass: RenderPass {
                    passMode: RenderPass.Item2DPass
                }
            },

            // Sub-pass 4: Transparent objects (forward rendering)
            SubRenderPass {
                renderPass: RenderPass {
                    materialMode: RenderPass.OriginalMaterial
                    commands: [
                        RenderablesFilter {
                            renderableTypes: RenderablesFilter.Transparent
                            layerMask: ContentLayer.Layer0 | ContentLayer.Layer1
                        },
                        PipelineStateOverride {
                            blendEnabled: true
                            depthTestEnabled: true
                            depthWriteEnabled: false
                        }
                    ]
                }
            }
        ]
    }

    // G-buffer pass (referenced by deferred lighting)
    GBufferPass {
        id: gbufferPass
        layerMask: ContentLayer.Layer0 | ContentLayer.Layer1
        depthTexture: mainDepthStencilTexture
    }

    // Full-screen quad for deferred lighting
    Model {
        layers: ContentLayer.Layer13
        geometry: PlaneGeometry { plane: PlaneGeometry.XY }
        materials: CustomMaterial {
            property TextureInput gbuffer0: TextureInput {
                texture: Texture {
                    textureProvider: RenderOutputProvider {
                        textureSource: RenderOutputProvider.UserPassTexture
                        renderPass: gbufferPass
                        attachmentSelector: RenderOutputProvider.Attachment0
                    }
                }
            }
            // ... other G-buffer inputs
            shadingMode: CustomMaterial.Unshaded
            fragmentShader: "lighting.frag"
            vertexShader: "lighting.vert"
        }
    }

    // Display final result
    SimpleQuadRenderer {
        texture: Texture {
            textureProvider: RenderOutputProvider {
                textureSource: RenderOutputProvider.UserPassTexture
                renderPass: mainColorPass
            }
        }
    }

    // Opaque 3D content
    Model {
        layers: ContentLayer.Layer0
        source: "#Sphere"
        materials: PrincipledMaterial { baseColor: "red" }
    }

    // Transparent 3D content
    Model {
        layers: ContentLayer.Layer1
        source: "#Cone"
        materials: PrincipledMaterial {
            baseColor: Qt.rgba(0.0, 1.0, 0.0, 0.5)
            alphaMode: PrincipledMaterial.Blend
        }
    }

    // 2D content in 3D space
    Node {
        x: -200
        y: 100
        Item {
            Button { text: "Click Me!" }
            Rectangle {
                color: "blue"
                width: 50; height: 50
            }
        }
    }

    PerspectiveCamera { z: 300 }
    DirectionalLight { eulerRotation.x: -45 }
}

핵심 개념

SubRenderPass 계층적 구성을 위한:

메인 패스는 ` SubRenderPass ` 명령어를 사용하여 자식 패스를 순차적으로 실행합니다. 부모 패스 자체는 아무것도 렌더링하지 않으며(`RenderablesFilter.None`), 단지 자식 패스들을 조정할 뿐입니다. 이를 통해 명확한 구조를 제공하며, 모든 하위 패스 간에 뎁스 버퍼를 공유할 수 있게 합니다.

패스 모드:

  • RenderPass.UserPass (기본값): 사용자 정의 지오메트리 및 머티리얼을 사용한 렌더링
  • RenderPass.SkyboxPass: 다음에서 환경 스카이박스를 렌더링합니다 SceneEnvironment
  • RenderPass.Item2DPass: 3D 씬에 삽입된 2D Qt Quick 콘텐츠를 렌더링합니다

렌더링 순서:

  1. 불투명 지오메트리를 G-버퍼에 렌더링
  2. 전체 화면 쿼드에 디퍼드 라이팅 적용
  3. 지오메트리 뒤에 스카이박스 렌더링 (깊이 테스트 활성화, 깊이 쓰기 비활성화)
  4. 2D UI 오버레이가 가장 위에 렌더링됨
  5. 투명한 오브젝트는 블렌딩과 함께 마지막에 렌더링됨

깊이 버퍼 공유:

PreserveDepthStencilContents 를 사용하여 패스 간에 mainDepthStencilTexture 를 공유합니다. 이를 통해 스카이박스가 지오메트리 뒤에서 렌더링되고, 투명 오브젝트가 불투명 지오메트리에 대해 올바르게 테스트되도록 보장합니다.

Item2D 콘텐츠:

Qt Quick Node 객체에 배치된 2D 항목(버튼, 사각형, 텍스트 등)은 를 통해 렌더링됩니다. 이러한 항목은 3D 공간에 배치되지만, 마우스/터치 입력을 받을 수 있는 2D 오버레이로 렌더링됩니다. RenderPass.Item2DPass

성능 고려 사항

사용자 정의 렌더링 패스는 최대의 제어력을 제공하지만, 성능에 미치는 영향을 신중하게 고려해야 합니다.

텍스처 형식 선택

필요에 따라 텍스처 형식을 선택하십시오:

형식픽셀당 크기사용 사례
RGBA84바이트최종 출력, 간단한 색상 버퍼
RGBA16F8바이트HDR 콘텐츠, 중간 버퍼, 노멀
RGBA32F16바이트고정밀도 계산, 위치
R16F2바이트단일 채널 HDR (깊이, AO 등)

1920x1080 프레임버퍼의 경우:

  • RGBA8: 약 8 MB
  • RGBA16F: 약 16 MB
  • RGBA32F: 약 32 MB
  • RGBA16F G-버퍼 3개: 약 48 MB

권장 사항: 중간 버퍼에는 RGBA16F를 사용하고, 충분한 경우 RGBA8 또는 R8을 사용하십시오.

지연 렌더링 대 포워드 렌더링

측면지연 렌더링포워드 렌더링
조명이 많은 경우효율적 (O(조명 수 + 픽셀 수))비용이 많이 듦 (O(조명 수 * 오브젝트 수))
메모리 대역폭높음 (G-버퍼 읽기/쓰기)낮음
투명도별도의 패스가 필요함기본 지원
MSAA직접 지원되지 않음하드웨어 MSAA 작동
설정 난이도더 복잡함더 간단함

다음과 같은 경우 디퍼드 렌더링을 사용하십시오:

  • 조명이 많은 경우 (10개 이상)
  • 스크린 스페이스 이펙트가 중요한 경우
  • 장면이 대부분 불투명한 경우

다음과 같은 경우에는 포워드 렌더링을 사용하세요:

  • 조명이 적은 경우(5개 미만)
  • 투명도가 높은 경우
  • 메모리 대역폭이 제한적인 경우
  • 더 단순한 파이프라인이 바람직할 때

패스 순서 최적화

렌더링 패스는 발견되는 순서대로 실행됩니다. 다음을 통해 최적화하십시오:

  • 투명한 지오메트리보다 불투명한 지오메트리를 먼저 렌더링
  • 유리한 경우 깊이 프리패스를 사용(복잡한 장면에서 오버드로우 감소)
  • 렌더 타겟 전환을 최소화
  • 가능한 경우 패스 간에 깊이 버퍼 재사용

렌더 타겟 플래그

renderTargetFlags 속성은 메모리 동작을 제어합니다:

RenderPass {
    // First pass: write new content
    renderTargetFlags: 0  // Default: clear render targets
}

RenderPass {
    // Second pass: add to existing content
    renderTargetFlags: RenderPass.PreserveColorContents |
                      RenderPass.PreserveDepthStencilContents
}

RenderPass {
    // Depth not needed after this pass
    renderTargetFlags: RenderPass.DoNotStoreDepthStencilContents
}

PreserveColorContents/PreserveDepthStencilContents: 기존 데이터를 유지합니다(예: 동일한 타깃에 대한 다중 패스 렌더링 시).

DoNotStoreDepthStencilContents: 깊이/스텐실 데이터를 버려도 된다는 힌트를 제공합니다(일부 하드웨어에서는 메모리 쓰기 작업을 피함으로써 성능이 향상될 수 있음).

사용자 패스를 사용할 때

다음과 같은 경우 사용자 렌더 패스 사용을 고려하십시오:

  • 지연 렌더링 구현 시
  • 복잡한 다중 패스 효과 생성 시
  • 렌더링 순서를 명시적으로 제어해야 할 때
  • 사용자 정의 렌더링 기법 구현 시
  • 지오메트리 데이터가 필요한 스크린 스페이스 이펙트를 구축할 때

다음과 같은 경우에는 사용자 패스를 피하십시오:

  • 기본 렌더링으로 요구 사항을 충족할 수 있는 경우
  • 오직 후처리만 필요한 경우 (대신 Effect 를 사용하십시오)
  • 사용자 정의 머티리얼 셰이더만 필요한 경우(대신 CustomMaterial 를 사용하세요)
  • 성능이 매우 중요하고 추가 패스가 자원 낭비가 될 경우

일반적인 패턴 및 사용 사례

사용자 렌더링 패스를 통해 다양한 고급 렌더링 기법을 구현할 수 있습니다. 다음은 몇 가지 일반적인 패턴입니다:

지연 셰이딩/라이팅

지오메트리 속성을 G-버퍼에 저장하고 스크린 공간에서 라이팅을 수행합니다. 자세한 내용은 ‘고급 예제: 디퍼드 렌더링’에서 다룹니다.

에지 감지 및 아웃라인 처리

씬을 정상적으로 렌더링한 후, 두 번째 패스에서 에지 감지를 적용합니다:

// Pass 1: Render scene with normals/depth
RenderPass {
    id: scenePass
    commands: [
        ColorAttachment { target: colorTex },
        DepthTextureAttachment { target: depthTex }
    ]
}

// Pass 2: Edge detection using depth discontinuities
RenderPass {
    id: edgePass
    commands: [
        ColorAttachment { target: outlineTex },
        RenderablesFilter { layerMask: ContentLayer.Layer10 }
    ]
}

Model {
    layers: ContentLayer.Layer10
    geometry: PlaneGeometry { }
    materials: CustomMaterial {
        property TextureInput depthInput: TextureInput {
            // depthProvider is the id of a RenderOutputProvider that exposes
            // depthTex as a sampleable texture (see "Render Output Provider"
            // earlier in this page).
            texture: Texture { textureProvider: depthProvider }
        }
        fragmentShader: "edge_detect.frag"
        // Shader samples depth, computes gradients, draws edges
    }
}

사용자 정의 후처리 체인

RenderOutputProvider 를 통해 각 패스의 출력을 다음 패스로 전달함으로써 여러 후처리 효과를 연쇄적으로 연결합니다. 다단계 체인의 실제 예시는 ‘패스 체이닝 예제’를 참조하십시오(scenePass → process1 → process2 → display).

선택적 와이어프레임 오버레이

일부 객체는 솔리드로, 다른 객체는 와이어프레임 오버레이로 렌더링합니다. ‘레이어 작업’ 섹션의 예제를 참조하십시오.

디버그 시각화

법선, 깊이 또는 기타 데이터를 시각화하는 디버그 패스를 생성합니다:

// Normal visualization pass
RenderPass {
    materialMode: RenderPass.OverrideMaterial
    overrideMaterial: CustomMaterial {
        fragmentShader: "debug_normals.frag"
        // FRAGCOLOR = vec4(normalize(NORMAL) * 0.5 + 0.5, 1.0);
    }
    commands: [
        ColorAttachment { target: debugTex }
    ]
}

사용자 정의 섀도우 매핑

명시적인 제어를 통해 사용자 정의 섀도우 매핑을 구현할 수 있습니다:

// Shadow map pass (render from light's perspective)
RenderPass {
    id: shadowPass
    materialMode: RenderPass.OverrideMaterial
    overrideMaterial: CustomMaterial {
        fragmentShader: "depth_only.frag"
    }
    commands: [
        DepthTextureAttachment { target: shadowMapTex }
    ]
}

// Main pass using shadow map
RenderPass {
    id: mainPass
    commands: [
        ColorAttachment { target: colorTex },
        DepthStencilAttachment { }
    ]
}

// Materials in main pass sample shadowMapTex for shadow testing

중요 고려 사항

사용자 렌더 패스를 다룰 때는 다음의 중요한 사항을 유의하십시오:

그림자 처리

사용자 렌더 패스에는 Qt Quick 3D 의 내부 그림자 렌더링이 자동으로 포함 되지 않습니다. 내부 패스를 비활성화했으나 그림자가 필요한 경우, 다음을 수행해야 합니다:

  • 자체 섀도우 매핑 패스를 구현해야 합니다
  • 광원의 시점에서 씬을 렌더링하여 깊이 텍스처에 저장해야 합니다
  • 조명 계산 시 섀도우 맵을 샘플링해야 합니다

또는 더 간단한 경우에는 그림자가 필요하지 않거나 미리 구워진 그림자 맵을 사용할 수도 있습니다.

HDR 및 톤 매핑

부동 소수점 렌더 타겟(RGBA16F, RGBA32F)을 사용할 경우, 렌더링은 선형 HDR 공간에서 이루어집니다. 표시 가능한 LDR로 변환하려면 최종 디스플레이 패스에서 톤 매핑을 적용해야 합니다.

CustomMaterial {
    fragmentShader: "tonemap.frag"
}
// In tonemap.frag
vec3 tonemap(vec3 hdr) {
    // Simple Reinhard tonemapping
    return hdr / (hdr + vec3(1.0));
}

void MAIN() {
    vec3 hdrColor = texture(hdrInput, UV0).rgb;
    FRAGCOLOR = vec4(tonemap(hdrColor), 1.0);
}

Qt Quick 3D 이 목적을 위해 셰이더 내에서 ` qt_tonemap() ` 함수를 사용할 수 있습니다.

깊이 텍스처 생성

텍스처로 깊이가 필요한 경우(피사계 심도 같은 효과용), ` DepthStencilAttachment` 대신 ` DepthTextureAttachment `를 사용하십시오:

RenderPassTexture {
    id: depthTex
    format: RenderPassTexture.Depth24Stencil8
}

RenderPass {
    commands: [
        ColorAttachment { target: colorTex },
        DepthTextureAttachment { target: depthTex }
        // depthTex can now be sampled in shaders
    ]
}

클리어 값 및 렌더 타겟 관리

각 패스에서는 초기화 값을 지정할 수 있습니다:

RenderPass {
    clearColor: Qt.rgba(0.0, 0.0, 0.0, 0.0)
    depthClearValue: 1.0
    stencilClearValue: 0
}

패스가 내용을 보존하지 않는 경우(기본값), 렌더링 전에 렌더 타겟이 이 값들로 초기화됩니다. ` PreserveColorContents ` 또는 ` PreserveDepthStencilContents `가 설정되면 기존 내용이 유지되고 초기화 값은 무시됩니다.

레이어 구성 모범 사례

레이어를 논리적으로 구성하십시오:

  • 레이어 0-2: 메인 씬 오브젝트
  • 레이어 3-4: 투명 오브젝트(별도의 패스)
  • 레이어 10 이상: 후처리용 전체 화면 쿼드
  • 레이어 15 이상: UI/디버그 오버레이

주석에 레이어 사용 용도를 명확히 기록하고, 애플리케이션 전체에서 일관성을 유지하십시오.

셰이더 호환성

렌더 패스에서 사용되는 Augment 셰이더 및 사용자 정의 머티리얼은 Qt Quick 3D 의 셰이더 인프라와 호환되어야 합니다:

  • GLSL 호환 구문을 사용하십시오
  • Qt Quick 3D 함수에 대해 적절한 \#include 지시문을 포함하십시오
  • 사용 가능한 내장 변수를 숙지하십시오
  • 모든 대상 플랫폼(OpenGL, Vulkan, Metal, D3D)에서 테스트해야 합니다

다중 렌더 타겟(MRT)의 제한 사항

다중 렌더 타겟(MRT)을 사용할 때:

  • 색상 어태치먼트는 최대 4개까지 허용됩니다
  • 모든 어태치먼트의 크기는 동일해야 합니다
  • 블렌드 상태는 다음을 통해 어태치먼트별로 지정할 수 있습니다 PipelineStateOverride
  • 모든 하드웨어가 MRT를 지원하는 것은 아닙니다(장치 기능을 확인하십시오).

투명도

투명한 오브젝트는 디퍼드 렌더링에서 처리하기 어렵습니다. 일반적인 접근 방식:

  • 투명 객체에 대한 포워드 패스: 불투명 지오메트리는 디퍼드 방식으로 렌더링하고, 투명 지오메트리는 별도의 포워드 패스에서 렌더링
  • 별도의 투명 G-버퍼: 투명 지오메트리를 블렌딩이 활성화된 별도의 G-버퍼 세트에 렌더링
  • 가중치 적용 블렌딩을 이용한 순서 독립적 투명도(OIT): 특수한 OIT 기법을 사용

대부분의 경우, 투명 오브젝트를 위한 별도의 포워드 패스를 사용하는 것이 가장 간단합니다.

API 참조

다음 표는 사용자 렌더 패스와 관련된 모든 유형에 대한 전체 참조 정보를 제공합니다:

기능QML 유형설명
메인 렌더링 패스 정의RenderPass명령 및 머티리얼 모드를 사용하여 렌더링 패스를 정의합니다
렌더 타겟 텍스처RenderPassTexture렌더 타깃으로 사용되는 텍스처(색상 또는 깊이/스텐실)
텍스처 출력 제공자RenderOutputProvider렌더 패스 출력을 텍스처 입력으로 노출합니다
레이어 상수ContentLayer레이어 필터링 상수를 제공하는 싱글톤
색상 출력ColorAttachment색상 렌더 타겟을 지정합니다
깊이/스텐실 (기본값)DepthStencilAttachment암시적 깊이/스텐실 버퍼 사용
깊이/스텐실(텍스처)DepthTextureAttachment명시적 깊이 텍스처를 사용합니다
오브젝트 필터링RenderablesFilter레이어 및 유형별로 오브젝트를 필터링합니다
파이프라인 상태PipelineStateOverride그래픽 파이프라인 상태를 재정의합니다
중첩된 패스 실행SubRenderPass다른 렌더 패스를 실행합니다
셰이더 정의AddDefine셰이더 전처리기 정의 추가
타깃별 블렌드 상태renderTargetBlendMRT용 블렌드 구성
디스플레이 헬퍼SimpleQuadRenderer최종 출력을 다음 위치로 렌더링합니다. View3D
유형설명
CustomMaterial버텍스/프래그먼트 셰이더가 포함된 사용자 정의 머티리얼
Effect후처리 효과
View3DrenderOverrides 속성이 있는 3D 뷰
Modellayers 속성이 있는 3D 모델

예제

참조

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.