이 페이지에서

Qt 3D 개요

Qt 3D 는 개발자가 필요한 모든 렌더링 파이프라인을 신속하게 구현할 수 있도록 지원하는, 완전히 구성 가능한 렌더러를 제공합니다. 또한, Qt 3D 는 렌더링을 넘어선 준실시간 시뮬레이션을 위한 범용 프레임워크를 제공합니다.

Qt 3D 는 코어와 원하는 기능을 구현할 수 있는 여러 ‘어스펙트(aspect) ’로 명확하게 분리되어 있습니다. 어스펙트는 컴포넌트 및 엔티티와 상호작용하여 특정 기능을 제공합니다. 어스펙트의 예로는 물리, 오디오, 충돌, 인공 지능(AI), 경로 탐색 등이 있습니다.

기본 3D 기능

Qt 3D 는 3D 도형을 그리거나 이동시키고, 카메라를 이동시킬 수 있게 해주는 3D 프레임워크입니다. 이 프레임워크는 다음과 같은 기본 기능을 지원합니다:

머티리얼

Qt 3D 는 다단계 맞춤 설정이 가능한 강력하고 매우 유연한 머티리얼 시스템을 갖추고 있습니다. 이 시스템은 다양한 플랫폼이나 OpenGL 버전에 따른 서로 다른 렌더링 방식을 지원하며, 서로 다른 상태 집합을 사용한 다중 렌더링 패스를 가능하게 하고, 다양한 수준에서 매개변수를 재정의할 수 있는 메커니즘을 제공하며, 셰이더를 손쉽게 전환할 수 있게 해줍니다. 이 모든 기능은 C++ 또는 QML 속성 바인딩을 통해 구현됩니다.

Material 유형의 속성은 참조된 효과 속성에서 지정된 GLSL 셰이더 프로그램 내의 유니폼 변수에 쉽게 매핑될 수 있습니다.

머티리얼 사용 예제는 다음 예제를 참조하십시오:

셰이더

Qt 3D 는 OpenGL의 모든 프로그래밍 가능한 렌더링 파이프라인 단계, 즉 버텍스, 테셀레이션 제어, 테셀레이션 평가, 지오메트리 및 프래그먼트 셰이더를 모두 지원합니다. 컴퓨트 셰이더는 향후 릴리스에서 지원될 예정입니다.

셰이더 사용 예제는 ‘Qt 3D: 와이어프레임 QML 예제’를 참조하십시오.

섀도 매핑

OpenGL은 그림자를 직접 지원하지 않지만, 그림자를 생성하는 데 활용할 수 있는 기술은 무수히 많습니다. 섀도 매핑은 성능 저하가 매우 적으면서도 멋진 그림자를 생성하는 데 사용하기 간편합니다.

섀도 매핑은 일반적으로 2패스 렌더링을 사용하여 구현됩니다. 첫 번째 패스에서는 섀도 정보가 생성됩니다. 두 번째 패스에서는 특정 렌더링 기법을 사용하여 씬을 생성하는 동시에, 첫 번째 패스에서 수집된 정보를 활용하여 섀도를 그립니다.

섀도우 매핑의 기본 원리는 광원에 가장 가까운 프래그먼트만 조명을 받는다는 것입니다. 다른 프래그먼트 뒤에 있는 프래그먼트는 가려지므로 그림자 속에 있게 됩니다.

따라서 첫 번째 패스에서는 광원의 시점에서 씬을 렌더링합니다. 저장되는 정보는 단순히 이 광원 공간에서 가장 가까운 프래그먼트의 거리입니다. OpenGL 용어로 말하자면, 이는 깊이 텍스처가 부착된 프레임버퍼 객체(FBO)를 갖는 것과 같습니다. 사실, 눈으로부터의 거리가 깊이의 정의이며, OpenGL이 수행하는 기본 깊이 테스트는 실제로 가장 가까운 프래그먼트의 깊이만 저장합니다.

프래그먼트에 음영을 적용할 필요가 없고 깊이만 계산하면 되므로, 컬러 텍스처 부착은 필요하지 않습니다.

다음 이미지는 자체 그림자가 드리워진 평면과 삼엽 매듭이 있는 장면을 보여줍니다:

초록색 비행기 위로 금속성 매듭이 떠 있고, 배경에서는 주황색 비행기가 날고 있는 모습을 보여주는 3D 렌더링 장면

다음 이미지는 해당 장면의 과장된 섀도우 맵 텍스처를 보여줍니다:

3D 매듭과 비행기의 그레이스케일 뎁스 맵

이 이미지는 광원의 관점에서 장면을 렌더링할 때 저장된 깊이를 나타냅니다. 어두운 색상은 얕은 깊이(즉, 카메라에 더 가까운 위치)를 나타냅니다. 이 장면에서 광원은 장면 내 오브젝트들 위쪽 어딘가, 메인 카메라를 기준으로 오른쪽에 위치해 있습니다(첫 번째 스크린샷과 비교해 보세요). 이는 장난감 평면이 다른 오브젝트들보다 카메라에 더 가깝다는 사실과 일치합니다.

섀도우 맵이 생성되면 두 번째 렌더링 패스가 수행됩니다. 이 두 번째 패스에서는 일반적인 장면의 카메라를 사용하여 렌더링이 이루어집니다. 여기서는 퐁 셰이딩(Phong shading)과 같은 어떤 효과든 사용할 수 있습니다. 중요한 점은 섀도우 맵 알고리즘이 프래그먼트 셰이더에서 적용되어야 한다는 것입니다. 즉, 광원에 가장 가까운 프래그먼트는 조명이 비친 상태로 그려지는 반면, 다른 프래그먼트들은 그림자 상태로 그려집니다.

첫 번째 패스에서 생성된 섀도우 맵은 프래그먼트와 광원 간의 거리에 대한 필수 정보를 제공합니다. 그러면 프래그먼트를 광원 좌표계로 재매핑하기만 하면 되며, 이를 통해 광원의 관점에서 프래그먼트의 깊이를 계산하고, 섀도우 맵 텍스처 상에서 해당 프래그먼트의 좌표가 어디에 위치하는지도 파악할 수 있습니다. 그런 다음 지정된 좌표에서 섀도우 맵 텍스처를 샘플링하고, 프래그먼트의 깊이를 샘플링 결과와 비교할 수 있습니다. 프래그먼트가 더 멀리 떨어져 있다면 그림자 속에 있는 것이고, 그렇지 않으면 빛이 비치는 것입니다.

인스턴스 렌더링

인스턴싱(Instancing )은 GPU가 기본 오브젝트의 여러 복사본(인스턴스)을 그리도록 하는 방식으로, 각 복사본마다 위치, 방향, 색상, 재질 속성, 스케일 등과 같은 측면에서 차이가 있습니다. Qt 3D 는 Qt Quick Repeater 요소와 유사한 API를 제공합니다. 이 경우, 델리게이트는 기본 오브젝트이며 모델은 인스턴스별 데이터를 제공합니다. 따라서 Mesh 컴포넌트가 부착된 엔티티는 결국 glDrawElements 호출로 변환되는 반면, instanced 컴포넌트가 부착된 엔티티는 glDrawElementsInstanced 호출로 변환됩니다.

인스턴스화된 렌더링 기능은 향후 릴리스에서 제공될 예정입니다.

유니폼 버퍼 객체

UBO(Uniform Buffer Object)를 OpenGL 셰이더 프로그램에 바인딩하여 대량의 데이터를 즉시 사용할 수 있게 할 수 있습니다. UBO의 일반적인 사용 사례는 머티리얼 또는 라이팅 매개변수 세트입니다.

유용한 팁

3D 렌더링에 대한 매우 유용한 프로그래밍 팁은 다음 페이지에서 확인할 수 있습니다: Qt 3D Render Pro Tips.

구성 가능한 렌더러

C++ 및 QML API에 대한 지원을 모두 제공하면서 완전히 구성 가능한 렌더러를 구현하기 위해 프레임그래프 ( framegraph ) 개념이 도입되었습니다. 씬그래프(scenegraph )가 렌더링할 대상을 데이터 기반으로 기술하는 것인 반면, 프레임그래프는 렌더링 방법을 데이터 기반으로 기술합니다.

프레임그래프를 통해 개발자는 z-fill 패스를 포함하는 간단한 포워드 렌더러를 사용할지, 아니면 디퍼드 렌더러를 사용할지 선택할 수 있습니다. 또한 투명한 오브젝트를 언제 렌더링할지 등을 제어할 수도 있습니다. 이 모든 것이 순전히 데이터를 통해 구성되므로, C++ 코드를 건드리지 않고도 런타임 중에 동적으로 수정하기가 매우 쉽습니다. 사용자 정의 렌더링 알고리즘을 구현하는 자체 프레임그래프를 생성하여 Qt 3D 을 확장할 수도 있습니다.

3D 확장 기능

화면에 3D 콘텐츠를 표시하는 기본 기능 외에도, Qt 3D 는 3D 객체와 관련된 다음과 같은 유형의 확장을 수용할 수 있을 만큼 확장성이 뛰어나고 유연합니다:

  • 물리 시뮬레이션
  • 충돌 감지
  • 3D 위치 기반 오디오
  • 강체, 스켈레탈, 모프 타겟 애니메이션
  • 경로 탐색 및 기타 AI
  • 피킹
  • 파티클
  • 오브젝트 스폰

성능

Qt 3D 은 현대 하드웨어가 기본 클럭 속도보다는 코어 수를 늘려 성능을 향상시키기 때문에, 우수한 성능을 발휘하고 사용 가능한 CPU 코어 수에 따라 확장되도록 설계되었습니다. 많은 작업이 서로 독립적이기 때문에 다중 코어를 사용하는 것이 효과적입니다. 예를 들어, 경로 탐색 모듈이 수행하는 작업은 디버그 정보나 통계를 렌더링하는 경우를 제외하고는 렌더러가 수행하는 작업과 크게 겹치지 않습니다.

Qt 3D 아키텍처

Qt 3D 의 주요 사용 사례는 오브젝트를 준실시간으로 시뮬레이션하고, 해당 오브젝트의 상태를 화면에 렌더링하는 것입니다. ‘스페이스 인베이더(Space Invaders)’ 예제에는 다음과 같은 오브젝트가 포함되어 있습니다:

스페이스 인베이더 게임 플레이 스크린샷

  • 플레이어의 지상 대포
  • 지면
  • 방어용 블록
  • 적 스페이스 인베이더 우주선
  • 적 보스인 비행접시
  • 적과 플레이어가 발사하는 탄환

전통적인 C++ 설계에서는 이러한 유형의 객체들이 일반적으로 일종의 상속 트리로 구성된 클래스로 구현됩니다. 상속 트리의 다양한 분기들은 다음과 같은 기능을 위해 루트 클래스에 추가 기능을 제공할 수 있습니다:

  • 사용자 입력 수신
  • 소리 재생
  • 애니메이션 재생
  • 다른 객체와 충돌
  • 화면에 표시됨

'스페이스 인베이더' 예제의 타입들은 이러한 특징에 따라 분류할 수 있습니다. 하지만 이처럼 단순한 예제라 할지라도 우아한 상속 트리를 설계하는 것은 쉽지 않습니다.

이러한 접근 방식과 상속의 다른 변형 방식들은 다음과 같은 여러 가지 문제를 야기합니다:

  • 깊고 넓은 상속 계층 구조는 이해하고, 유지 관리하며, 확장하기가 어렵습니다.
  • 상속 분류 체계는 컴파일 시점에 고정됩니다.
  • 클래스 상속 트리의 각 레벨은 단일 기준이나 축에 대해서만 분류할 수 있습니다.
  • 공통 기능은 시간이 지남에 따라 클래스 계층 구조 상위로 올라오는 경향이 있습니다.
  • 개발자들이 무엇을 하고 싶어 할지 예측하는 것은 불가능합니다.

깊고 넓은 상속 트리를 확장하려면 대개 원작자가 사용한 분류 체계를 이해하고 이에 동의해야 합니다. 따라서 ‘ Qt 3D ’는 객체 인스턴스에 기능을 부여하는 수단으로 상속 대신 집합에 중점을 둡니다. 구체적으로, ‘ Qt 3D ’는 엔티티 컴포넌트 시스템(ECS)을 구현합니다.

ECS 사용

ECS에서 엔티티는 시뮬레이션된 객체를 나타내지만, 그 자체로는 특정 행동이나 특성을 전혀 가지고 있지 않습니다. 엔티티가 하나 이상의 컴포넌트를 집합화(aggregate)함으로써 추가적인 행동을 부여받을 수 있습니다. 각 컴포넌트는 객체 유형의 행동에 대한 수직적 단면입니다.

'스페이스 인베이더' 예시에서 지면은 엔티티이며, 이 엔티티에는 시스템에 렌더링이 필요하다는 사실과 어떤 종류의 렌더링이 필요한지를 알려주는 컴포넌트가 부착되어 있습니다. 적 우주 침략자 함선은 또 다른 엔티티로, 이 함선이 렌더링되도록 하는 컴포넌트가 부착되어 있을 뿐만 아니라, 소리를 내고, 충돌을 감지하며, 애니메이션을 적용받고, 간단한 AI에 의해 제어될 수 있게 해줍니다.

플레이어의 지상 대포 엔티티는 AI 컴포넌트가 없다는 점을 제외하면, 적 우주 침략자 함선과 대체로 유사한 컴포넌트를 가지고 있습니다. 대신 대포에는 플레이어가 대포를 이동시키고 탄환을 발사할 수 있도록 하는 입력 컴포넌트가 있습니다.

ECS 백엔드

QEntity의 구성 요소를 보여주는 다이어그램

Qt 3D 의 백엔드는 ECS 패러다임의 시스템 부분을 어스펙트 형태로 구현합니다. 어스펙트는 하나 이상의 집계된 컴포넌트의 조합을 통해 엔티티에 제공되는 기능 중 특정 수직 슬라이스를 구현합니다.

예를 들어, 렌더러 어스펙트는 메시, 머티리얼, 그리고 선택적으로 변환 컴포넌트를 가진 엔티티를 찾습니다. 렌더러 어스펙트가 이러한 엔티티를 발견하면, 해당 데이터를 활용하여 멋진 그래픽을 렌더링하는 방법을 알고 있습니다. 엔티티에 이러한 컴포넌트가 없다면, 렌더러 어스펙트는 이를 무시합니다.

Qt 3D 추가 기능을 제공하는 컴포넌트를 집합하여 사용자 정의 엔티티를 생성합니다. Qt 3D 엔진은 어스펙트를 사용하여 특정 컴포넌트를 가진 엔티티를 처리하고 업데이트합니다.

예를 들어, 물리 어스펙트는 어떤 종류의 충돌 볼륨 컴포넌트를 가지고 있으며, 질량, 마찰 계수 등과 같이 해당 시뮬레이션에 필요한 다른 속성을 지정하는 또 다른 컴포넌트를 가진 엔티티를 찾습니다. 소리를 내는 엔티티는 자신이 소리 발생기임을 지정하는 컴포넌트를 가지고 있을 뿐만 아니라, 언제 어떤 소리를 재생할지 지정하는 컴포넌트도 가지고 있습니다.

ECS는 상속 대신 집합을 사용하기 때문에, 컴포넌트를 추가하거나 제거하는 것만으로도 런타임 중에 객체의 동작 방식을 동적으로 변경할 수 있습니다.

예를 들어, 플레이어가 파워업을 얻은 후 갑자기 벽을 뚫고 달릴 수 있게 하려면, 파워업 효과가 종료될 때까지 해당 엔티티의 충돌 볼륨 컴포넌트를 일시적으로 제거하면 됩니다. PlayerWhoRunsThroughWalls 을 위해 특별히 일회성 서브클래스를 생성할 필요가 없습니다.

Qt 3D ECS 구현

Qt 3D 는 ECS를 간단한 클래스 계층 구조로 구현합니다. Qt 3D 의 기본 클래스는 Qt3DCore::QNode이며, 이는 QObject 의 서브클래스입니다. Qt3DCore::QNode는 QObject 에 속성 변경 사항을 어스펙트에 자동으로 전달하는 기능과 애플리케이션 전체에서 고유한 ID를 추가합니다. 어스펙트는 별도의 스레드에서 실행되며, Qt3DCore::QNode는 사용자 대상 객체와 어스펙트 간의 데이터 전송을 간소화합니다.

일반적으로 Qt3DCore::QNode의 서브클래스는 컴포넌트가 참조하는 추가적인 지원 데이터를 제공합니다. 예를 들어, QShaderProgram 클래스는 일련의 엔티티를 렌더링할 때 사용될 GLSL 코드를 지정합니다.

QEntity, QComponent, QNode 및 QObject 간의 관계를 보여주는 다이어그램

Qt 3D 의 컴포넌트는 Qt3DCore::QComponent를 상속하여 구현되며, 해당 어스펙트가 작업을 수행하는 데 필요한 데이터를 추가합니다. 예를 들어, 메쉬 컴포넌트는 렌더러 어스펙트가 OpenGL 파이프라인으로 전송해야 하는 정점별 데이터를 가져오는 데 사용됩니다.

마지막으로, Qt3DCore::QEntity는 0개 이상의 Qt3DCore::QComponent 인스턴스를 집계할 수 있는 객체입니다.

확장 Qt 3D

Qt 3D 에 기능을 추가하여, Qt의 일부로 또는 멀티스레드 백엔드의 이점을 활용하기 위해 사용자 애플리케이션에 특화된 기능을 구현하려면 다음 작업을 수행해야 합니다:

  • 필요한 컴포넌트와 지원 데이터를 파악하고 구현합니다.
  • QML 엔진에 컴포넌트를 등록합니다(QML API를 사용하는 경우에만 해당).
  • QAbstractAspect를 상속하고 서브시스템 기능을 구현합니다.

Qt 3D 작업 기반 엔진

Qt 3D 에서는 각 프레임마다 어스펙트에 대해 실행할 작업 집합과 이들 간의 종속성을 요청합니다. 성능 향상을 위해 스케줄러가 설정된 모든 코어에 작업을 분배합니다.

Qt 3D의 어스펙트

기본적으로 Qt 3D 는 Qt3DRender 및 Qt3DInput 어스펙트를 제공합니다. 이러한 어스펙트가 제공하는 컴포넌트 및 기타 지원 클래스에 대해서는 해당 모듈의 문서에서 설명합니다.

향후 Qt 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.