Jetpack XR SDK를 사용하면 Jetpack SceneCore를 사용하여 3D 모델, 3D 동영상, PanelEntity
과 같은 Entity
인스턴스를 만들고 제어하고 관리할 수 있습니다.
Jetpack SceneCore는 3D 개발을 지원하기 위해 두 가지 일반적인 아키텍처 패턴, 즉 장면 그래프와 엔티티-구성요소 시스템 (ECS)을 채택합니다.
장면 그래프를 사용하여 엔티티 만들기 및 제어
3D 공간에서 객체를 만들고 제어하려면 Jetpack SceneCore의 Session API를 사용하여 장면 그래프에 액세스하면 됩니다. 장면 그래프는 사용자의 실제 세계와 일치하며 패널 및 3D 모델과 같은 3D 항목을 계층 구조로 구성하고 이러한 항목의 상태를 유지할 수 있습니다.
장면 그래프에 액세스한 후 XR용 Jetpack Compose의 API를 사용하여 장면 그래프 내에 공간 UI (예: SpatialPanel
및 Orbiter
)를 만들 수 있습니다. 3D 모델과 같은 3D 콘텐츠의 경우 세션에 직접 액세스할 수 있습니다. 자세한 내용은 이 페이지의 ActivitySpace 정보를 참고하세요.
항목 구성요소 시스템
항목-구성요소 시스템은 상속보다 컴포지션의 원칙을 따릅니다. 동작 정의 구성요소를 연결하여 항목의 동작을 확장할 수 있으므로 동일한 동작을 여러 유형의 항목에 적용할 수 있습니다. 자세한 내용은 이 페이지의 항목에 공통 동작 추가를 참고하세요.
ActivitySpace 정보
각 Session
에는 Session
와 함께 자동으로 생성되는 ActivitySpace
가 있습니다. ActivitySpace
는 장면 그래프의 최상위 Entity
입니다.
ActivitySpace는 오른손잡이 좌표계 (x축은 오른쪽을, y축은 위쪽을, z축은 원점을 기준으로 뒤쪽을 가리킴)와 실제 세계와 일치하는 단위인 미터로 3차원 공간을 나타냅니다. ActivitySpace
의 원점은 다소 임의적입니다 (사용자가 실제 세계에서 ActivitySpace
의 위치를 재설정할 수 있음). 따라서 원점을 기준으로 하는 대신 콘텐츠를 서로 상대적으로 배치하는 것이 좋습니다.
항목 작업
항목은 SceneCore의 핵심입니다. 사용자가 보고 상호작용하는 대부분의 항목은 패널, 3D 모델 등을 나타내는 항목입니다.
ActivitySpace
는 장면 그래프의 최상위 노드이므로 기본적으로 모든 새 항목은 ActivitySpace
에 직접 배치됩니다. setParent
또는 addChild
를 호출하여 장면 그래프를 따라 항목을 재배치할 수 있습니다.
항목에는 위치, 회전, 표시 여부 변경과 같이 모든 항목에 공통적인 사항에 관한 몇 가지 기본 동작이 있습니다. GltfEntity
와 같은 특정 Entity
서브클래스에는 서브클래스를 지원하는 추가 동작이 있습니다.
항목 조작
기본 Entity
클래스에 속한 Entity
속성을 변경하면 변경사항이 모든 하위 요소로 계단식 방식으로 적용됩니다. 예를 들어 상위 요소 Entity
의 Pose
를 조정하면 모든 하위 요소가 동일하게 조정됩니다. 하위 Entity
를 변경해도 상위 요소에는 영향을 미치지 않습니다.
Pose
는 3D 공간 내에서 엔티티의 위치와 회전을 나타냅니다. 위치는 x, y, z 숫자 위치로 구성된 Vector3
입니다. 회전은 Quaternion
로 표현됩니다. Entity
의 위치는 항상 상위 항목을 기준으로 합니다. 즉, 위치가 (0, 0, 0)인 Entity
는 상위 항목의 원점에 배치됩니다.
// Place the entity forward 2 meters val newPosition = Vector3(0f, 0f, -2f) // Rotate the entity by 180 degrees on the up axis (upside-down) val newOrientation = Quaternion.fromEulerAngles(0f, 0f, 180f) // Update the position and rotation on the entity entity.setPose(Pose(newPosition, newOrientation))
Entity
의 공개 상태를 변경하려면 setHidden
를 사용합니다.
// Hide the entity entity.setHidden(true)
전체 도형을 유지하면서 Entity
의 크기를 조절하려면 setScale
를 사용합니다.
// Double the size of the entity entity.setScale(2f)
항목에 공통 동작 추가
다음 구성요소를 사용하여 항목에 일반적인 동작을 추가할 수 있습니다.
MovableComponent
: 사용자가 항목을 이동할 수 있습니다.ResizableComponent
: 사용자가 일관된 UI 패턴으로 항목의 크기를 조절할 수 있습니다.InteractableComponent
: 맞춤 상호작용의 입력 이벤트를 캡처할 수 있습니다.
구성요소를 인스턴스화하려면 Session
클래스의 적절한 생성 메서드를 통해야 합니다. 예를 들어 ResizableComponent
를 만들려면 ResizableComponent.create()
를 호출합니다.
Entity
에 특정 구성요소 동작을 추가하려면 addComponent()
메서드를 사용하세요.
MovableComponent를 사용하여 사용자가 엔티티를 이동할 수 있도록 만들기
MovableComponent
를 사용하면 사용자가 Entity
를 이동할 수 있습니다. 또한 항목을 가로 또는 세로 표면과 같은 표면 유형이나 테이블, 벽, 천장과 같은 특정 시맨틱 표면에 고정할 수 있는지 지정할 수 있습니다. 앵커 옵션을 지정하려면 MovableComponent
를 만들 때 AnchorPlacement
집합을 지정합니다.
다음은 모든 수직 표면과 바닥 및 천장 수평 표면으로만 이동하고 고정할 수 있는 항목의 예입니다.
val anchorPlacement = AnchorPlacement.createForPlanes( planeTypeFilter = setOf(PlaneSemantic.FLOOR, PlaneSemantic.TABLE), planeSemanticFilter = setOf(PlaneType.VERTICAL) ) val movableComponent = MovableComponent.create( session = session, systemMovable = false, scaleInZ = false, anchorPlacement = setOf(anchorPlacement) ) entity.addComponent(movableComponent)
사용자가 항목을 이동하면 scaleInZ
매개변수는 홈 공간에서 시스템이 패널의 크기를 조절하는 것과 비슷한 방식으로 항목이 사용자로부터 멀어지면서 항목의 크기를 자동으로 조정합니다. 항목 구성요소 시스템의 '캐스캐이딩' 특성으로 인해 상위 항목의 크기는 모든 하위 항목에 영향을 미칩니다.
ResizableComponent를 사용하여 사용자가 크기를 조절할 수 있는 항목 만들기
ResizableComponent
를 사용하면 사용자가 Entity
의 크기를 조절할 수 있습니다. ResizableComponent
에는 사용자가 Entity
의 크기를 조절하도록 유도하는 시각적 상호작용 신호가 포함되어 있습니다. ResizeableComponent
를 만들 때 최소 또는 최대 크기 (미터)를 지정할 수 있습니다. 너비와 높이가 서로 비례하여 크기가 조절되도록 크기를 조절할 때 고정 가로세로 비율을 지정할 수도 있습니다.
ResieableComponent
를 사용할 때는 onResizeUpdate
또는 onResizeEnd
와 같은 특정 크기 조절 이벤트에 응답하도록 ResizeListener
를 지정해야 합니다.
다음은 SurfaceEntity
에서 고정 가로세로 비율로 ResizableComponent
를 사용하는 예입니다.
val resizableComponent = ResizableComponent.create(session) resizableComponent.minimumSize = Dimensions(177f, 100f, 1f) resizableComponent.fixedAspectRatio = 16f / 9f // Specify a 16:9 aspect ratio resizableComponent.addResizeListener( executor, object : ResizeListener { override fun onResizeEnd(entity: Entity, finalSize: Dimensions) { // update the size in the component resizableComponent.size = finalSize // update the Entity to reflect the new size (entity as SurfaceEntity).canvasShape = SurfaceEntity.CanvasShape.Quad(finalSize.width, finalSize.height) } }, ) entity.addComponent(resizableComponent)
InteractableComponent를 사용하여 사용자 입력 이벤트 캡처
InteractableComponent
를 사용하면 사용자가 Entity
에 참여하거나 마우스를 가져갈 때와 같이 사용자의 입력 이벤트를 캡처할 수 있습니다.
InteractableComponent
를 만들 때 입력 이벤트를 수신할 InputEventListener
를 지정해야 합니다. 사용자가 입력 작업을 실행하면 onInputEvent
메서드가 InputEvent
매개변수에 제공된 특정 입력 정보와 함께 호출됩니다.
InputEvent.action
: 항목에 대한 마우스 오버 또는 탭과 같은 입력 유형을 지정합니다.InputEvent.source
: 입력의 출처(예: 손 또는 컨트롤러 입력)를 지정합니다.InputEvent.pointerType
: 입력이 오른손에서 들어왔는지 왼손에서 들어왔는지 지정합니다.
모든 InputEvent
상수의 전체 목록은 참조 문서를 참고하세요.
다음 코드 스니펫은 InteractableComponent
를 사용하여 오른손으로 항목의 크기를 늘리고 왼손으로 줄이는 예를 보여줍니다.
val executor = Executors.newSingleThreadExecutor() val interactableComponent = InteractableComponent.create(session, executor) { // when the user disengages with the entity with their hands if (it.source == InputEvent.SOURCE_HANDS && it.action == InputEvent.ACTION_UP) { // increase size with right hand and decrease with left if (it.pointerType == InputEvent.POINTER_TYPE_RIGHT) { entity.setScale(1.5f) } else if (it.pointerType == InputEvent.POINTER_TYPE_LEFT) { entity.setScale(0.5f) } } } entity.addComponent(interactableComponent)