Godot에서 Spatial Containers 사용하기

적용 가능한 XR 기기
이 가이드는 이러한 유형의 XR 기기를 위한 환경을 빌드하는 데 도움이 됩니다.
XR 헤드셋
유선 XR 글라스

공간 컨테이너를 사용하면 앱이 전체 공간 모드에서 시스템 관리 3D 볼륨 경계 상자 내에 3D OpenXR 콘텐츠를 렌더링하거나 런타임에 전체 화면 무제한 환경으로 전환할 수 있습니다.

이 가이드에 따라 프로젝트에서 공간 컨테이너를 구성하고 사용하세요.

Android XR에서 전체 공간 모드로 실행되는 여러 공간 컨테이너
그림 1. 전체 공간 모드의 공간 컨테이너(바닥에 고정된 3D 지형 컨테이너와 2D UI와 페어링된 3D 모델 포함)

공간 컨테이너 작동 방식

프로젝트 설정에서 공간 컨테이너를 사용 설정하면 다음이 적용됩니다.

  • 전체 활성 3D 장면은 장면 원점 (0, 0, 0)을 중심으로 하는 단일 기본 공간 컨테이너 내에 배치됩니다. 개별 Node3D 노드를 컨테이너 내부에 배치하기 위해 태그를 지정하거나 할당할 필요가 없습니다.
  • 앱은 프로젝트 설정에서 구성된 경계 모드(Bounded 또는 Immersive)와 초기 경계 크기를 사용하여 관리형 전체 공간 모드로 실행됩니다. 제한 모드에서 시스템은 경계 상자의 크기를 벗어나는 장면의 3D 도형을 자동으로 클립합니다.
  • 기본적으로 Android XR 시스템은 사용자가 3D 공간에서 경계가 지정된 컨테이너를 잡고, 이동하고, 위치를 변경하거나, 최소화하고 닫을 수 있도록 창 컨트롤을 제공합니다. 런타임 시 앱은 컨테이너 크기를 조절하고, 제한 모드 (OpenXRSpatialContainerState.BOUNDED)와 전체 화면 몰입형 모드 (OpenXRSpatialContainerState.IMMERSIVE) 간에 전환하며, OpenXRSpatialContainerExtension 싱글톤을 사용하여 경계 및 상태 변경에 반응할 수 있습니다.

기본 요건

시작하기 전에 개발 환경과 대상 기기가 다음 요구사항을 충족하는지 확인하세요.

  • Godot 버전: Godot 4.8-dev 이상
  • 프로젝트 설정: Godot Engine 프로젝트 설정 가이드의 모든 단계를 완료합니다.
  • Godot OpenXR Vendors 플러그인: Android XR 관련 확장 프로그램 지원을 사용 설정하는 Godot OpenXR Vendors 플러그인 버전 5.2 이상을 설치합니다.
  • 대상 기기: Spatial API 수준 4 이상을 지원하는 Android XR 기기 런타임 시 OpenXRSpatialContainerExtension.is_enabled()를 호출하여 기기에서 확장 프로그램을 사용할 수 있는지 확인합니다.

프로젝트 설정에서 공간 컨테이너 사용 설정

OpenXR, 공간 컨테이너, 자동 런타임 권한, 알파 블렌딩 패스 스루를 사용 설정하도록 프로젝트 설정을 구성합니다.

  1. 프로젝트 > 프로젝트 설정을 엽니다.
  2. 프로젝트 설정 창의 오른쪽 상단에서 고급 설정 전환을 사용 설정합니다.
  3. General(일반) > XR > Shaders(셰이더)로 이동하여 Enabled(사용 설정됨)를 선택합니다.
  4. General(일반) > XR > OpenXR로 이동하여 다음 설정을 구성합니다.
    • 사용 설정됨을 선택하여 프로젝트에 OpenXR을 사용 설정합니다.
    • Environment Blend Mode를 Alpha Blend로 설정합니다.
  5. OpenXR에서 Extensions 섹션으로 이동하여 다음 설정을 구성합니다.
    • Automatically Request Runtime Permissions를 선택하면 앱이 시작 시 Android 매니페스트에 선언된 XR 런타임 권한을 사용자에게 자동으로 요청합니다.
    • 공간 컨테이너 하위 섹션에서 사용 설정됨을 선택합니다.
    • Bounds Mode를 Bounded로 설정하여 3D 경계 상자에서 실행하거나 Immersive로 설정하여 전체 화면 몰입형 모드에서 실행합니다.
    • 경계를 초기 너비, 높이, 깊이 측정기준(미터 단위)으로 설정합니다(예: Vector3(1.0, 1.0, 1.0)).
  6. General > Rendering > Viewport로 이동하여 Transparent Background를 선택합니다.

Android 내보내기, 권한, 전체 공간 모드 구성

다음으로, 앱이 공간 컨테이너가 사용 설정된 전체 공간 모드에서 실행되도록 Android 내보내기 사전 설정, 권한, 활동 시작 모드를 구성합니다.

Android 내보내기 사전 설정 구성

  1. Project(프로젝트) > Export…(내보내기…)로 이동하여 Android 내보내기 사전 설정을 선택합니다.
  2. Gradle Build에서 Use Gradle Build를 선택하고 Min SDK를 34 이상으로 설정합니다.

    사용 설정

  3. XR Features에서 XR Mode를 OpenXR로 설정하고 Enable AndroidXR Plugin을 선택합니다.

    제공된 양식에서 옵션을 구성합니다.

  4. Android XR 기능에서 실험 기능 사용을 선택합니다.

바닥 잠금을 위한 장면 이해 권한 추가

기본 공간 컨테이너를 만들고 렌더링하는 데는 위험한 런타임 권한이 필요하지 않습니다. 실험용 기능 사용이 사용 설정되면 android.permission.HEAD_TRACKING가 매니페스트에 자동으로 추가됩니다. 하지만 앱에서 공간 컨테이너를 실제 바닥에 고정하고 고정하는 등의 장면 이해 기능을 사용하는 경우 앱은 런타임에 android.permission.SCENE_UNDERSTANDING_COARSE 권한을 선언하고 요청해야 합니다.

Android XR 권한에 관한 자세한 내용은 XR 권한 이해를 참고하세요. 앱에서 바닥 잠금 또는 장면 이해를 사용하는 경우 android.permission.SCENE_UNDERSTANDING_COARSE를 선언하고 요청합니다.

  1. 프로젝트 > 내보내기… > Android에서 Permissions(권한) > Custom Permissions(맞춤 권한)로 이동하여 android.permission.SCENE_UNDERSTANDING_COARSE를 추가합니다.

  2. Project Settings > General > XR > OpenXR > Extensions에서 Automatically Request Runtime Permissions를 선택하면 OpenXR이 시작될 때 앱에서 자동으로 권한을 요청합니다. GDScript에서 권한을 수동으로 요청해야 하는 경우 OS.request_permission()를 호출합니다.

    if not OS.get_granted_permissions().has("android.permission.SCENE_UNDERSTANDING_COARSE"):
        OS.request_permission("android.permission.SCENE_UNDERSTANDING_COARSE")
    

전체 공간 모드 구성

Android XR의 공간 컨테이너는 전체 공간 모드(XR_ACTIVITY_START_MODE_FULL_SPACE_MANAGED)만 지원합니다. Android 활동이 커스텀 빌드 템플릿 (android/build/AndroidManifest.xml, Project > Install Android Build Template…을 사용하여 설치됨)에서 XR_ACTIVITY_START_MODE_FULL_SPACE_MANAGED를 선언하는지 확인합니다.

<manifest ...>
    <application ...>
        <property
            android:name="android.window.PROPERTY_XR_ACTIVITY_START_MODE"
            android:value="XR_ACTIVITY_START_MODE_FULL_SPACE_MANAGED"
            tools:replace="android:value" />
        ...
    </application>
</manifest>

GDScript에서 공간 컨테이너 작업

OpenXRSpatialContainerExtension 싱글톤과 OpenXRSpatialContainerState 클래스는 XR_EXT_spatial_container 및 XR_EXT_spatial_container_self_rendering 확장 프로그램을 GDScript에 노출합니다. 런타임 시 OpenXRSpatialContainerExtension를 사용하여 기본 공간 컨테이너의 상태와 경계를 검사하고, 컨테이너 신호를 수신 대기하고, BOUNDED 모드 (3D 경계 상자)와 IMMERSIVE 모드 (전체 화면 무제한 뷰) 간의 전환을 요청합니다.

공간 컨테이너 신호에 연결

OpenXRSpatialContainerExtension.is_enabled()를 확인하여 현재 기기에서 Spatial Container 확장 프로그램이 지원되고 활성 상태인지 확인하고 _ready()에서 컨테이너 경계 및 상태 신호에 연결합니다.

OpenXRSpatialContainerExtension는 공간 컨테이너에 대해 다음 상태 신호를 내보냅니다.

  • spatial_container_visibility_changed: 컨테이너가 표시 (true)되거나 숨겨질 (false) 때 (spatial_container, is_visible)와 함께 전송됩니다. is_visible가 false인 경우 애니메이션, 오디오 또는 시뮬레이션 업데이트를 일시중지합니다.
  • spatial_container_interactability_changed: 컨테이너가 사용자 입력 포커스를 얻거나 (true) 잃을 때 (false) (spatial_container, is_interactive)와 함께 전송됩니다. 포커스가 변경될 때 대화형 하이라이트 및 입력 처리를 사용 설정하거나 사용 중지합니다.
  • spatial_container_bounds_mode_changed: 컨테이너가 OpenXRSpatialContainerState.BOUNDED와 OpenXRSpatialContainerState.IMMERSIVE 간에 전환될 때 (spatial_container, bounds_mode)와 함께 전송됩니다. 환경 시각 요소 (예: 스카이박스 또는 패스 스루)와 모드별 UI 컨트롤을 전환합니다.
func _ready() -> void:
    if OpenXRSpatialContainerExtension.is_enabled():
        OpenXRSpatialContainerExtension.spatial_container_bounds_changed.connect(
            _on_bounds_changed
        )
        OpenXRSpatialContainerExtension.spatial_container_bounds_mode_changed.connect(
            _on_bounds_mode_changed
        )
        OpenXRSpatialContainerExtension.spatial_container_visibility_changed.connect(
            _on_visibility_changed
        )
        OpenXRSpatialContainerExtension.spatial_container_interactability_changed.connect(
            _on_interactability_changed
        )

func _on_visibility_changed(_rid: RID, is_visible: bool) -> void:
    # Pause or resume simulation and audio based on visibility
    pass

func _on_interactability_changed(_rid: RID, is_interactive: bool) -> void:
    # Enable or disable input handling and focus highlights
    pass

컨테이너 경계에 맞게 3D 콘텐츠 크기 조정

BOUNDED 모드에서는 가로세로 비율을 유지하고 항상 컨테이너의 가장 작은 면에 맞도록 bounds의 가장 작은 크기로 3D 콘텐츠를 균일하게 조정합니다. IMMERSIVE 모드로 전환할 때 장면을 1:1 배율로 복원합니다.

func _on_bounds_changed(_rid: RID, bounds: Vector3) -> void:
    var uniform_scale: float = min(bounds.x, bounds.y, bounds.z)
    content_root.scale = Vector3.ONE * uniform_scale

func _on_bounds_mode_changed(
    _rid: RID, bounds_mode: OpenXRSpatialContainerState.BoundsMode
) -> void:
    if bounds_mode == OpenXRSpatialContainerState.IMMERSIVE:
        content_root.scale = Vector3.ONE

제한 모드와 몰입형 모드 간 전환

OpenXRSpatialContainerState.BOUNDED 또는 OpenXRSpatialContainerState.IMMERSIVE로 request_main_spatial_container_bounds_mode를 호출하여 경계가 있는 3D 볼륨과 전체 화면 몰입형 뷰 간에 전환합니다.

# Request transitioning to immersive mode (or pass BOUNDED to return)
OpenXRSpatialContainerExtension.request_main_spatial_container_bounds_mode(
    OpenXRSpatialContainerState.IMMERSIVE
)

참고 항목


OpenXR™ 및 OpenXR 로고는 The Khronos Group Inc. 소유의 상표이며 중국, 유럽 연합, 일본, 영국에서 상표로 등록되어 있습니다.