使用 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 modelPosition = 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
,請呼叫 session.createResizableComponent()
。
如要將特定元件行為新增至 Entity
,請使用 addComponent()
方法。
使用 MovableComponent 讓實體可供使用者移動
MovableComponent
可讓使用者移動 Entity
。您也可以指定實體是否可以錨定至水平或垂直表面等表面類型,或是桌子、牆壁或天花板等特定語意表面。如要指定錨點選項,請在建立 MovableComponent
時指定一組 AnchorPlacement
。
以下是實體的範例,可移動並固定在任何垂直表面,以及地板和天花板的水平表面。
val anchorPlacement = AnchorPlacement.createForPlanes(
planeTypeFilter = setOf(PlaneSemantic.FLOOR, PlaneSemantic.TABLE),
planeSemanticFilter = setOf(PlaneType.VERTICAL))
val movableComponent = xrSession.createMovableComponent(
systemMovable = false,
scaleInZ = false,
anchorPlacement = setOf(anchorPlacement)
)
entity.addComponent(movableComponent)
使用 ResizableComponent 讓實體可供使用者調整大小
ResizableComponent
可讓使用者調整 Entity
大小。ResizableComponent
包含視覺互動提示,可邀請使用者調整 Entity
大小。建立 ResizeableComponent
時,您可以指定最小或最大尺寸 (以公尺為單位)。您也可以在調整大小時指定固定顯示比例,讓寬度和高度以相同比例調整大小。
以下是使用 ResizableComponent
和固定顯示比例的範例:
val resizableComponent = xrSession.createResizableComponent()
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
會指定輸入類型,例如對實體懸停或輕觸(ACTION_DOWN)InputEvent.source
會指定輸入內容的來源,例如手勢或控制器輸入內容InputEvent.pointerType
可指定輸入內容來自右手或左手
如需所有 InputEvent
常數的完整清單,請參閱參考文件。
下列程式碼片段示範如何使用 InteractableComponent
,以右手增加實體大小,以左手減少實體大小。
private val executor by lazy { Executors.newSingleThreadExecutor() }
val interactableComponent = xrSession.createInteractableComponent(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)