Qt 3D 개요
Qt 3D 는 개발자가 필요한 모든 렌더링 파이프라인을 빠르게 구현할 수 있도록 완벽하게 구성 가능한 렌더러를 제공합니다. 또한 Qt 3D 에서는 렌더링을 넘어 실시간에 가까운 시뮬레이션을 위한 일반적인 프레임워크를 제공합니다.
Qt 3D 코어와 원하는 기능을 구현할 수 있는 여러 측면으로 깔끔하게 분리되어 있습니다. 각 측면은 컴포넌트 및 엔티티와 상호 작용하여 일부 기능을 제공합니다. 예를 들어 물리, 오디오, 충돌, 인공 지능(AI), 경로 찾기 등이 있습니다.
기본 3D 기능
Qt 3D 는 3D 도형을 그려서 이동하고 카메라를 움직일 수 있게 해주는 3D 프레임워크입니다. 다음과 같은 기본 기능을 지원합니다:
- C++ 및 Qt Quick 애플리케이션용 2D 및 3D rendering
- Meshes 및 지오메트리
- Materials
- 셰이더
- 섀도 매핑
- Ambient occlusion
- 높은 다이내믹 레인지
- 디퍼드 렌더링
- 멀티텍스처링
- 인스턴스 렌더링
- 유니폼 버퍼 오브젝트
- RHI로 포팅
- 프로 팁
머티리얼
Qt 3D 에는 여러 수준의 커스터마이징이 가능한 강력하고 매우 유연한 머티리얼 시스템이 있습니다. 다양한 플랫폼 또는 OpenGL 버전에서 다양한 렌더링 접근 방식을 지원하고, 다양한 상태 세트로 여러 렌더링 패스를 사용할 수 있으며, 다양한 레벨에서 파라미터를 재정의할 수 있는 메커니즘을 제공하고, 셰이더를 쉽게 전환할 수 있습니다. 이 모든 것이 C++ 또는 QML 프로퍼티 바인딩을 통해 가능합니다.
Material 유형의 프로퍼티는 참조된 효과 프로퍼티 자체에 지정된 GLSL 셰이더 프로그램의 균일 변수에 쉽게 매핑할 수 있습니다.
머티리얼 사용 예제는 다음 예제를 참조하십시오:
셰이더
Qt 3D 는 버텍스, 테셀레이션 제어, 테셀레이션 평가, 지오메트리, 프래그먼트 셰이더 등 모든 OpenGL 프로그래밍 가능 렌더링 파이프라인 단계를 지원합니다. 컴퓨트 셰이더는 향후 릴리스에 추가될 예정입니다.
셰이더 사용 예제는 Qt 3D: 와이어프레임 QML 예제를 참조하세요.
섀도 매핑
그림자는 OpenGL에서 직접 지원하지는 않지만 그림자를 생성하는 데 사용할 수 있는 기법은 무수히 많습니다. 섀도 매핑은 성능 비용이 매우 적으면서도 멋진 그림자를 생성하는 데 간단하게 사용할 수 있습니다.
섀도 매핑은 일반적으로 투 패스 렌더링을 사용하여 구현됩니다. 첫 번째 패스에서는 그림자 정보를 생성합니다. 두 번째 패스에서는 특정 렌더링 기법을 사용하여 장면을 생성하는 동시에 첫 번째 패스에서 수집한 정보를 사용하여 그림자를 그립니다.
섀도 매핑의 기본 개념은 빛에 가장 가까운 조각에만 조명을 비춘다는 것입니다. 다른 조각 뒤에 있는 조각은 가려져서 그림자가 됩니다.
따라서 첫 번째 패스에서는 빛의 관점에서 장면을 그립니다. 저장되는 정보는 단순히 이 조명 공간에서 가장 가까운 조각의 거리입니다. OpenGL 용어로 이는 뎁스 텍스처가 첨부된 프레임버퍼 오브젝트(FBO)가 있는 것과 같습니다. 실제로 눈으로부터의 거리가 깊이의 정의이며, OpenGL에서 수행하는 기본 깊이 테스트는 실제로 가장 가까운 조각에 대한 깊이만 저장합니다.
조각을 음영 처리할 필요가 없고 깊이만 계산하기 때문에 컬러 텍스처를 첨부할 필요도 없습니다.
다음 이미지는 셀프 섀도잉 평면과 트레포일 매듭이 있는 장면을 표시합니다:
다음 이미지는 장면의 과장된 섀도 맵 텍스처를 보여줍니다:
이 이미지는 라이트 관점에서 씬을 렌더링할 때 저장된 깊이를 나타냅니다. 어두운 색은 깊이가 얕음을 나타냅니다(즉, 카메라에 가까울수록). 이 씬에서 조명은 씬의 오브젝트 위, 메인 카메라를 기준으로 오른쪽에 배치되어 있습니다(첫 번째 스크린샷과 비교). 이는 장난감 비행기가 다른 오브젝트보다 카메라에 더 가깝다는 사실과 일치합니다.
섀도 맵이 생성되면 두 번째 렌더링 패스가 완료됩니다. 이 두 번째 패스에서는 일반 씬의 카메라를 사용하여 렌더링이 수행됩니다. 여기에는 퐁 셰이딩과 같은 모든 효과를 사용할 수 있습니다. 섀도 맵 알고리즘이 조각 셰이더에 적용되는 것이 중요합니다. 즉, 빛에 가장 가까운 조각은 밝게 그려지고 다른 조각은 그림자로 그려집니다.
첫 번째 패스에서 생성된 섀도 맵은 조각과 빛의 거리에 대한 필요한 정보를 제공합니다. 그런 다음 조명 공간에서 조각을 다시 매핑하여 조명 관점에서의 깊이와 섀도 맵 텍스처에서 해당 좌표의 위치를 계산하면 충분합니다. 그런 다음 주어진 좌표에서 섀도 맵 텍스처를 샘플링하고 샘플링 결과와 조각의 깊이를 비교할 수 있습니다. 조각이 더 멀리 있으면 그림자 상태이고, 그렇지 않으면 조명이 켜집니다.
인스턴스 렌더링
인스턴싱은 GPU가 기본 오브젝트의 여러 복사본(인스턴스)을 그리도록 하는 방법으로, 각 복사본마다 어떤 방식으로든 달라집니다. 종종 위치, 방향, 색상, 재질 속성, 스케일 등에서 Qt 3D Qt Quick Repeater 요소와 유사한 API를 제공합니다. 이 경우 델리게이트는 기본 객체이고 모델은 인스턴스별 데이터를 제공합니다. 따라서 Mesh 컴포넌트가 연결된 엔티티는 결국 glDrawElements 호출로 변환되지만, 인스턴스화된 컴포넌트가 있는 엔티티는 glDrawElementsInstanced 호출로 변환됩니다.
인스턴스화된 렌더링은 향후 릴리스에 추가될 예정입니다.
유니폼 버퍼 오브젝트
유니폼 버퍼 오브젝트(UBO)는 OpenGL 셰이더 프로그램에 바인딩하여 많은 양의 데이터를 쉽게 사용할 수 있도록 합니다. UBO의 일반적인 사용 사례는 머티리얼 또는 조명 파라미터 세트입니다.
유용한 팁
이 페이지에서 3D 렌더링에 매우 유용한 프로그래밍 팁을 확인할 수 있습니다: Qt 3D Render Pro 팁.
구성 가능한 렌더러
C++ 및 QML API에 대한 지원과 완전한 구성 가능한 렌더러를 결합하기 위해 프레임그래프라는 개념이 도입되었습니다. 시나리오그래프가 렌더링할 내용에 대한 데이터 기반 설명이라면 프레임그래프는 렌더링 방법에 대한 데이터 기반 설명입니다.
프레임그래프를 사용하면 개발자는 z-필 패스를 포함한 단순한 포워드 렌더러를 사용할지, 아니면 디퍼드 렌더러를 사용할지 선택할 수 있습니다. 또한 투명한 오브젝트를 렌더링할 시기 등을 제어할 수 있습니다. 이 모든 것이 순전히 데이터로만 구성되기 때문에 C++ 코드를 건드리지 않고 런타임에 동적으로 수정하는 것도 매우 쉽습니다. 사용자 지정 렌더링 알고리즘을 구현하는 자체 프레임그래프를 생성하여 Qt 3D 을 확장할 수 있습니다.
3D 확장
Qt 3D 은 3D 콘텐츠를 화면에 표시하는 필수 기능 외에도 3D 객체와 관련된 다음 유형의 확장 기능을 위한 호스트 역할을 할 수 있을 만큼 확장성과 유연성을 갖추고 있습니다:
- 물리 시뮬레이션
- 충돌 감지
- 3D 위치 오디오
- 리지드 바디, 스켈레탈 및 모프 타겟 애니메이션
- 경로 찾기 및 기타 AI
- 피킹
- 파티클
- 오브젝트 스폰
퍼포먼스
Qt 3D 은 사용 가능한 CPU 코어 수에 따라 성능이 향상되고 확장되도록 설계되었습니다. 최신 하드웨어는 기본 클럭 속도보다는 코어 수를 늘림으로써 성능을 향상시키기 때문입니다. 많은 작업이 서로 독립적이기 때문에 여러 코어를 사용하는 것이 효과적입니다. 예를 들어 경로 찾기 모듈이 수행하는 작업은 디버그 정보나 통계를 렌더링할 때를 제외하고는 렌더러가 수행하는 작업과 크게 겹치지 않습니다.
Qt 3D 아키텍처
Qt 3D 의 주요 사용 사례는 거의 실시간으로 오브젝트를 시뮬레이션하고 해당 오브젝트의 상태를 화면에 렌더링하는 것입니다. 스페이스 인베이더 예시에는 다음과 같은 오브젝트가 포함되어 있습니다:
- 플레이어의 지상 대포
- 지면
- 방어 블록
- 적 우주 침략자 우주선
- 적 보스 비행 접시
- 적과 플레이어가 쏘는 총알
전통적인 C++ 디자인에서 이러한 유형의 오브젝트는 일반적으로 일종의 상속 트리에 배열된 클래스로 구현됩니다. 상속 트리의 다양한 분기는 다음과 같은 기능을 위해 루트 클래스에 추가 기능을 추가할 수 있습니다:
- 사용자 입력 받기
- 사운드 재생
- 애니메이션 적용
- 다른 객체와 충돌한다
- 화면에 그려짐
스페이스 인베이더 예제의 유형은 이러한 기능에 따라 분류할 수 있습니다. 하지만 이렇게 간단한 예제에서도 우아한 상속 트리를 설계하는 것은 쉽지 않습니다.
이 접근 방식과 상속의 다른 변형에는 여러 가지 문제가 있습니다:
- 깊고 넓은 상속 계층 구조는 이해, 유지 및 확장이 어렵습니다.
- 상속 분류 체계는 컴파일 시점에 고정되어 있습니다.
- 클래스 상속 트리의 각 레벨은 단일 기준 또는 축을 기준으로만 분류할 수 있습니다.
- 공유 기능은 시간이 지남에 따라 클래스 계층 구조에 거품을 일으키는 경향이 있습니다.
- 개발자가 무엇을 하고 싶어할지 예측하는 것은 불가능합니다.
상속 트리를 깊고 넓게 확장하려면 일반적으로 원저자가 사용한 분류법을 이해하고 이에 동의해야 합니다. 따라서 Qt 3D 에서는 객체의 인스턴스에 기능을 부여하는 수단으로 상속 대신 집계에 중점을 두고 있습니다. 특히 Qt 3D 은 엔티티 컴포넌트 시스템(ECS)을 구현합니다.
ECS 사용
ECS에서 엔티티는 시뮬레이션된 객체를 나타내지만 그 자체로는 특정 동작이나 특성이 없습니다. 엔티티가 하나 이상의 컴포넌트를 집계하도록 하여 엔티티에 추가 동작을 접목할 수 있습니다. 각 컴포넌트는 오브젝트 유형의 동작을 수직으로 분할한 것입니다.
스페이스 인베이더 예시에서 땅은 엔티티에 렌더링이 필요하고 어떤 종류의 렌더링이 필요한지 시스템에 알려주는 컴포넌트가 부착된 엔티티입니다. 적 우주 침략자 우주선은 우주선을 렌더링할 뿐만 아니라 소리를 내고, 충돌하고, 애니메이션을 적용하고, 간단한 AI로 제어할 수 있도록 하는 컴포넌트가 부착된 또 다른 엔티티입니다.
플레이어의 지상 대포 엔티티는 AI 컴포넌트가 없다는 점을 제외하면 적 우주 침략자 우주선과 대부분 유사한 컴포넌트를 가지고 있습니다. 대신 대포에는 플레이어가 대포를 움직이고 총알을 발사할 수 있는 입력 컴포넌트가 있습니다.
ECS 백엔드
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 코드를 지정합니다.
Qt 3D 의 컴포넌트는 Qt3DCore::QComponent 을 서브클래싱하고 해당 컴포넌트가 작업을 수행하는 데 필요한 데이터를 추가하여 구현됩니다. 예를 들어, 메쉬 컴포넌트는 렌더러 측면에서 OpenGL 파이프라인을 통해 전송해야 하는 버텍스별 데이터를 검색하는 데 사용됩니다.
마지막으로 Qt3DCore::QEntity 은 단순히 0개 이상의 Qt3DCore::QComponent 인스턴스를 집계할 수 있는 객체입니다.
확장하기 Qt 3D
멀티 스레드 백엔드의 이점을 활용하기 위해 Qt의 일부로 또는 자체 애플리케이션에 특정 기능을 Qt 3D 에 추가하는 작업은 다음 작업으로 구성됩니다:
- 필요한 컴포넌트와 지원 데이터를 식별하고 구현합니다.
- QML 엔진에 컴포넌트를 등록합니다(QML API를 사용하는 경우에만).
- QAbstractAspect 서브클래스를 생성하고 서브시스템 기능을 구현합니다.
Qt 3D 작업 기반 엔진
Qt 3D 에서는 각 프레임에서 실행할 태스크 세트와 태스크 간의 종속성을 요청합니다. 이 작업은 스케줄러에 의해 구성된 모든 코어에 분산되어 성능을 향상시킵니다.
Qt 3D의 측면
기본적으로 Qt 3D 은 Qt3DRender 및 Qt3DInput 측면을 제공합니다. 이러한 측면이 제공하는 컴포넌트 및 기타 지원 클래스는 해당 모듈의 문서에서 설명합니다.
더 많은 기능을 제공하는 추가 측면은 Qt 3D 의 향후 버전에 추가될 예정입니다.
© 2025 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.