Jetpack XR SDK 可讓您使用 Jetpack SceneCore 建立、控制及管理 Entity
執行個體,例如 3D 模型、立體影片和 PanelEntity
。
Jetpack SceneCore 採用兩種常見的架構模式,支援 3D 開發:場景圖和實體元件系統 (ECS)。
使用場景圖建立及控制實體
如要在 3D 空間中建立及控制物件,可以使用 Jetpack SceneCore 的 Session API 存取場景圖。場景圖會與使用者的現實世界對齊,方便您將面板和 3D 模型等 3D 實體整理成階層式結構,並保留這些實體的狀態。
存取場景圖後,您可以使用 Jetpack Compose for XR 中的 API,在場景圖中建立空間 UI (例如 SpatialPanel
和 Orbiter
執行個體)。如果是 3D 模型等 3D 內容,可以直接存取工作階段。詳情請參閱本頁的「關於 ActivitySpace」一文。
實體元件系統
實體元件系統遵循組合而非繼承的原則。您可以附加定義行為的元件來擴充實體的行為,以便將相同行為套用至不同類型的實體。詳情請參閱本頁的「為實體新增常見行為」。
關於 ActivitySpace
每個 Session
都有一個 ActivitySpace
,會隨著 Session
自動建立。ActivitySpace
是場景圖中的頂層 Entity
。
ActivitySpace 代表 3 維空間,採用右手座標系統 (x 軸指向右側、y 軸指向上方,而 z 軸則相對於原點指向後方),單位為公尺,與現實世界相符。ActivitySpace
的原點有些任意 (因為使用者可以在現實世界中重設 ActivitySpace
的位置),因此建議您以彼此相對的方式放置內容,而非以原點相對的方式放置。
使用實體
實體是 SceneCore 的核心。使用者看到及互動的大多數內容,都是代表面板、3D 模型等的實體。
由於 ActivitySpace
是場景圖的頂層節點,因此根據預設,所有新實體都會直接放置在 ActivitySpace
中。您可以呼叫 setParent()
或 addChild()
,沿著場景圖重新放置實體。
實體有一些預設行為,適用於所有實體,例如變更位置、旋轉角度或可見度。特定 Entity
子類別 (例如 GltfModelEntity
) 具有支援子類別的其他行為。
操控實體
如果您變更屬於基本 Entity
類別的 Entity
屬性,變更會向下層疊加至所有子項。舉例來說,調整父項 Entity
的 Pose
會導致所有子項都進行相同的調整。在子項 Entity
中進行變更不會影響上層項目。
Pose
代表實體在 3D 空間中的位置和旋轉角度。位置是 Vector3
,由 x、y、z 數值位置組成。旋轉角度以 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
將 Entity 設為可供使用者移動
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
的大小。建立 ResizableComponent
時,您可以指定最小或最大尺寸 (以公尺為單位)。您也可以在調整大小時指定固定顯示比例,讓寬度和高度按比例調整。
使用 ResizableComponent
時,您必須指定 ResizeListener
,才能回應特定大小調整事件,例如 onResizeUpdate
或 onResizeEnd
。
以下範例說明如何在 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
互動或將游標懸停在 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)