使用 Jetpack XR SDK,您可以使用 Jetpack SceneCore 建立、控制及管理 Entity
執行個體,例如使用 Jetpack SceneCore 的 3D 模型、立體影片和 PanelEntity
。
Jetpack SceneCore 採用兩種常見的架構模式來支援 3D 開發:場景圖和實體元件系統 (ECS)。
使用場景圖表建立及控制實體
如要在 3D 空間中建立及控制物件,您可以使用 Jetpack SceneCore 的 Session API 存取場景圖表。場景圖表會與使用者的實際世界保持一致,讓您將面板和 3D 模型等 3D 實體組織成階層式結構,並保留這些實體的狀態。
取得場景群組存取權後,您就可以使用 Jetpack Compose for XR 中的 API,在場景群組中建立空間 UI (例如 SpatialPanel
和 Orbiter
)。對於 3D 模型等 3D 內容,您可以直接存取工作階段。詳情請參閱本頁的「活動空間簡介」一文。
實體元件系統
實體元件系統遵循組合優於繼承的原則。您可以透過附加行為定義元件來擴充實體的行為,這樣一來,您就能將相同的行為套用至不同類型的實體。詳情請參閱本頁的「為實體新增常用行為」。
關於 ActivitySpace
每個 Session
都有一個 ActivitySpace
,系統會自動使用 Session
建立這個 ActivitySpace
。ActivitySpace
是場景圖中的頂層 Entity
。
ActivitySpace 代表 3D 空間,採用右手定則的座標系統 (x 軸指向右邊、y 軸指向上方,z 軸則相對於原點向後),並以公尺為單位,以便與現實世界相符。ActivitySpace
的來源是隨機的 (因為使用者可以在現實世界中重設 ActivitySpace
的位置),因此建議您將內容彼此相對定位,而非相對於來源定位。
使用實體
實體是 SceneCore 的核心元素。使用者看到並互動的大部分內容,都是代表面板、3D 模型等實體。
由於 ActivitySpace
是場景圖的頂層節點,因此根據預設,所有新的實體都會直接放入 ActivitySpace
。您可以呼叫 setParent
或 addChild
,沿著場景圖表重新定位實體。
實體具有一些預設行為,適用於所有實體的通用行為,例如變更位置、旋轉或可見度。特定 Entity
子類別 (例如 GltfEntity
) 具有支援子類別的其他行為。
操控實體
當您變更屬於基本 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 讓實體可供使用者移動
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
時,您可以指定最小或最大尺寸 (以公尺為單位)。您也可以在調整大小時指定固定顯示比例,讓寬度和高度以相同比例調整大小。
以下是使用 ResizableComponent
和固定顯示比例的範例:
val resizableComponent = ResizableComponent.create(session) resizableComponent.minimumSize = Dimensions(177f, 100f, 1f) resizableComponent.fixedAspectRatio = 16f / 9f // Specify a 16:9 aspect ratio entity.addComponent(resizableComponent)
使用 InteractableComponent 擷取使用者輸入事件
InteractableComponent
可讓您擷取使用者的輸入事件,例如使用者與 Entity
互動或將滑鼠游標懸停在 Entity
上時。建立 InteractableComponent
時,您必須指定 InputEventListener
來接收輸入事件。使用者執行任何輸入動作時,系統會呼叫 onInputEvent
方法,並使用 InputEvent
參數中提供的特定輸入資訊。
InputEvent.action
可指定輸入類型,例如在實體上懸停或輕觸InputEvent.source
會指定輸入內容的來源,例如 hand 或 controller 輸入內容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)