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 에는 해당 레이어의 동작을 구성하는 명령어 목록이 포함되어 있습니다:
- ColorAttachment: 색상 렌더 타깃을 지정합니다
- DepthStencilAttachment: 깊이/스텐실 처리를 지정합니다
- DepthTextureAttachment: 깊이 출력에 텍스처를 사용합니다
- RenderablesFilter: 레이어 및 유형(불투명/투명)별로 오브젝트를 필터링합니다
- PipelineStateOverride: 그래픽 파이프라인 상태를 제어합니다
SubRenderPass: 이 렌더 패스 내에서 다른 렌더 패스를 실행합니다- AddDefine: 셰이더 전처리기 정의 추가
머티리얼 모드
각 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 automaticallyDepthTextureAttachment 깊이 출력을 위해 명시적 텍스처를 사용하는 방법:
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
}
}
}이 예제는:
- 내부 패스를 비활성화합니다
- 렌더 타겟 텍스처(colorTarget)를 생성합니다
- 해당 텍스처로 렌더링하는 렌더 패스를 정의합니다
- RenderOutputProvider 를 사용하여 텍스처를 노출합니다
- 다음과 같이 결과를 표시합니다. SimpleQuadRenderer
- 표준 머티리얼을 적용한 구체를 렌더링합니다
레이어 작업
ContentLayer 싱글톤은 오브젝트를 레이어로 구성하기 위한 상수를 제공하여, 각 패스에서 렌더링되는 내용을 세밀하게 제어할 수 있게 해줍니다.
레이어 상수
Qt Quick 3D xml-ph-0000@deepl.internal는 사용자가 할당할 수 있는 24개의 레이어를 제공합니다:
ContentLayer.Layer0ContentLayer.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비트 | 표준 색상 출력, 메모리 사용량 감소 |
| RGBA16F | 16비트 부동 소수점 | HDR 렌더링, 중간 버퍼 |
| RGBA32F | 32비트 부동 소수점 | 고정밀도 계산 |
| R8, R16, R16F, R32F | 단일 채널 변형 | 그레이스케일 데이터, 전용 버퍼 |
심도 형식:
| 포맷 | 설명 |
|---|---|
| 심도 16 | 16비트 색심도 |
| Depth24 | 24비트 색심도 |
| Depth32 | 32비트 색심도 |
| Depth24Stencil8 | 24비트 심도 + 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,LessOrEqualGreater,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_COLOR | vec4 | 머티리얼 기본 색상(선형 색상 공간, 머티리얼 처리 후). |
METALNESS | float | 0.0에서 1.0 사이의 머티리얼 메탈니스. |
ROUGHNESS | float | 0.0에서 1.0 사이의 머티리얼 거칠기 값입니다. |
WORLD_NORMAL | vec3 | 월드 스페이스 표면 법선(노멀 매핑 후). |
WORLD_TANGENT | vec3 | 월드 공간 접선 벡터. |
WORLD_BINORMAL | vec3 | 월드 공간의 바이노멀 벡터. |
DIFFUSE_LIGHT | vec3 | 누적된 확산광 기여도. |
SPECULAR_LIGHT | vec3 | 누적된 스페큘러 광 기여도. |
EMISSIVE_LIGHT | vec3 | 머티리얼의 발광 기여도. |
F0 | vec3 | 법선 입사 시의 프레넬 반사율. |
F90 | vec3 | 접선 입사 시의 프레넬 반사율. |
참고: 일부 예제(아래의 디퍼드 렌더링 예제 포함)는 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-버퍼 또는 지오메트리 버퍼라고 함)에 렌더링하고, 두 번째 패스에서 저장된 지오메트리 데이터를 사용하여 조명 계산을 수행하는 기술입니다. 이 방식은 조명 수가 많을 때 특히 효율적입니다. 조명 수와 관계없이 각 픽셀은 한 번만 셰이딩되기 때문입니다.
지연 렌더링 아키텍처
디퍼드 렌더링 파이프라인은 두 가지 주요 패스로 구성됩니다:
- 지오메트리 패스(G-버퍼 패스): 씬의 지오메트리를 여러 렌더 타깃에 렌더링하여 알베도, 노멀, 거칠기, 금속성, 월드 위치와 같은 머티리얼 속성을 저장합니다.
- 조명 패스: 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 }
}렌더링 흐름
렌더링은 다음과 같이 진행됩니다:
- G-버퍼 패스: Layer0 및 Layer1에 있는 씬 오브젝트가 렌더링됩니다. 각 오브젝트에 대해 어거먼트 셰이더는 알베도, 노멀, 러프니스, 메탈니스 및 위치를 세 개의 컬러 어태치먼트에 기록합니다. 깊이는 공유 깊이 텍스처에 기록됩니다.
- 라이팅 패스: Layer13의 전체 화면 쿼드가 렌더링됩니다. 이 쿼드의 커스텀 머티리얼은 3개의 G-버퍼 텍스처와 깊이 텍스처를 샘플링하여 씬 정보를 재구성한 후, 라이팅 계산(방향성 조명, 이미지 기반 라이팅 등)을 수행하여 최종 조명 적용 색상을 생성합니다.
- 표시: 라이팅 패스의 결과는 ` 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: 다음에서 환경 스카이박스를 렌더링합니다 SceneEnvironmentRenderPass.Item2DPass: 3D 씬에 삽입된 2D Qt Quick 콘텐츠를 렌더링합니다
렌더링 순서:
- 불투명 지오메트리를 G-버퍼에 렌더링
- 전체 화면 쿼드에 디퍼드 라이팅 적용
- 지오메트리 뒤에 스카이박스 렌더링 (깊이 테스트 활성화, 깊이 쓰기 비활성화)
- 2D UI 오버레이가 가장 위에 렌더링됨
- 투명한 오브젝트는 블렌딩과 함께 마지막에 렌더링됨
깊이 버퍼 공유:
PreserveDepthStencilContents 를 사용하여 패스 간에 mainDepthStencilTexture 를 공유합니다. 이를 통해 스카이박스가 지오메트리 뒤에서 렌더링되고, 투명 오브젝트가 불투명 지오메트리에 대해 올바르게 테스트되도록 보장합니다.
Item2D 콘텐츠:
Qt Quick Node 객체에 배치된 2D 항목(버튼, 사각형, 텍스트 등)은 를 통해 렌더링됩니다. 이러한 항목은 3D 공간에 배치되지만, 마우스/터치 입력을 받을 수 있는 2D 오버레이로 렌더링됩니다. RenderPass.Item2DPass
성능 고려 사항
사용자 정의 렌더링 패스는 최대의 제어력을 제공하지만, 성능에 미치는 영향을 신중하게 고려해야 합니다.
텍스처 형식 선택
필요에 따라 텍스처 형식을 선택하십시오:
| 형식 | 픽셀당 크기 | 사용 사례 |
|---|---|---|
| RGBA8 | 4바이트 | 최종 출력, 간단한 색상 버퍼 |
| RGBA16F | 8바이트 | HDR 콘텐츠, 중간 버퍼, 노멀 |
| RGBA32F | 16바이트 | 고정밀도 계산, 위치 |
| R16F | 2바이트 | 단일 채널 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 | 셰이더 전처리기 정의 추가 |
| 타깃별 블렌드 상태 | renderTargetBlend | MRT용 블렌드 구성 |
| 디스플레이 헬퍼 | SimpleQuadRenderer | 최종 출력을 다음 위치로 렌더링합니다. View3D |
관련 유형
| 유형 | 설명 |
|---|---|
| CustomMaterial | 버텍스/프래그먼트 셰이더가 포함된 사용자 정의 머티리얼 |
| Effect | 후처리 효과 |
| View3D | renderOverrides 속성이 있는 3D 뷰 |
| Model | layers 속성이 있는 3D 모델 |
예제
- Qt Quick 3D - User Passes 예제: 완전한 디퍼드 렌더링 예제
참조
- 프로그래밍 가능한 머티리얼, 이펙트, 지오메트리 및 텍스처 데이터: Qt Quick 3D 사용자 지정 기능 개요
- Qt Quick 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.