使用 Jetpack XR 的 ARCore

ARCore for Jetpack XR 可讓應用程式使用低階場景理解原語元和動作追蹤,運用擴增實境 (AR) 的基本概念。建構 AR 體驗時,如果需要使用平面資料或將內容錨定至空間中的固定位置,請使用 ARCore for Jetpack XR。

瞭解工作階段的生命週期

所有由 ARCore for Jetpack XR 追蹤的物件,都必須透過工作階段存取。與活動生命週期類似,工作階段物件也有生命週期,必須根據應用程式對工作階段物件功能的使用方式進行維護。如果應用程式包含單一支援 XR 的活動,請考慮使用生命週期感知元件處理工作階段的生命週期。

建立工作階段

您必須先建立工作階段,才能使用。如要建立工作階段,使用者必須android.permission.SCENE_UNDERSTANDING 權限授予您的應用程式

如要建立工作階段,請按照下列步驟操作:

when (val result = Session.create(owner)) {
  is SessionCreateSuccess -> {
    session = result.session
  }
  is SessionCreatePermissionsNotGranted -> {
   // Request android.permission.SCENE_UNDERSTANDING.
  }
}

如要瞭解無法建立工作階段的原因,請參閱 SessionCreateResult

繼續執行工作階段

當應用程式準備好處理 ARCore for Jetpack XR 的狀態變更時,應恢復工作階段。在許多情況下,這項作業會在活動的 onResume() 回呼中執行,但應用程式可能會延遲處理,直到使用者互動為止。

以下程式碼片段為繼續工作階段的範例。

when (val result = session.resume()) {
  is SessionResumeSuccess -> {
    // Session has been created successfully.
    // Attach any successful handlers here.
  }
  is SessionResumePermissionsNotGranted -> {
    // Request android.permission.SCENE_UNDERSTANDING.
}

如要瞭解工作階段無法繼續的原因,請參閱 SessionResumeResult

暫停工作階段

當活動進入背景時,請使用 Session.pause() 暫停工作階段。暫停工作階段會暫時停止追蹤,直到工作階段恢復為止,以維持感知系統的狀態。

摧毀工作階段

如要永久處置工作階段,請使用 Session.destroy()。這麼做可釋放工作階段使用的資源,並銷毀所有工作階段狀態。

擷取感知平面的狀態

ARCore for Jetpack XR 會透過發出平面狀態的 StateFlow,提供平面狀態。在工作階段中訂閱平面,可在平面新增、更新或移除時通知您的應用程式。

Plane.subscribe(session).collect { planes ->
 // Planes have changed; update plane rendering
}

平面具有下列屬性:

對平面執行命中測試

命中測試是一種方法,可計算光線與工作階段追蹤的物件交集。命中測試的常見應用方式是指向資料表,並在該位置放置物件。執行命中測試會產生命中物件清單。換句話說,命中測試不會在第一個命中物件時停止。不過,您通常只會對特定類型的首個命中物件感興趣。

如要執行命中測試,請使用 Interaction.hitTest() 搭配 Ray

val results = Interaction.hitTest(session, ray)
// When interested in the first Table hit:
val tableHit = results.firstOrNull {
  val trackable = it.trackable
  trackable is Plane && trackable.state.value.label == Plane.Label.Table
}

將內容固定在聊天室中固定的位置

如要為虛擬物件指定實際位置,請使用 Anchor。錨定物件可協助應用程式追蹤實體空間中的固定位置。

錨點是使用 Pose 建立,可根據現有的 Trackable 進行解讀,也可以不依據現有的 Trackable 進行解讀。

建立相對於可追蹤項目的錨點

錨點建立於 Trackable (例如 Plane) 時,錨點會在附加的 Trackable 移動時,追隨附加的 Trackable

val anchor = trackable.createAnchor(pose)

在不使用 Trackable 的情況下建立錨點

如要建立未連結至 Trackable 的錨點,請按照下列步驟操作:

when (val result = Anchor.create(session, pose)) {
  is AnchorCreateSuccess -> // ...
  else -> // handle failure
}

將實體附加至錨點

如要在這個位置算繪模型,請建立 GltfModel,並將其姿勢設為錨點的姿勢。確認模型在 Anchor 的 TrackingStateStopped 時會隱藏。

// renderSession is androidx.xr.core.Session
anchor.state.collect { state ->
  if (state.trackingState == TrackingState.Tracking) {
    gltfEntity.setPose(
      renderSession.perceptionSpace.transformPoseTo(state.pose, renderSession.activitySpace)
    )
  } else if (state.trackingState == TrackingState.Stopped) {
    entity.setHidden(true)
  }
}

瞭解 TrackingState

每個 Trackable 都有一個 TrackingState,應在使用前先檢查。TrackableTrackableStateTracking 時,系統會主動更新其 PosePausedTrackable 日後可能會變成 Tracking,但 Stopped 則永遠不會變成 Tracking

在整個工作階段中保留錨點

未儲存的錨點會在工作階段結束後消失。透過錨點持久化,應用程式會記住錨點在私人應用程式資料中的相對位置。這個錨點可在後續工作階段中擷取,並且會錨定在地球上的同一個位置。

如要保留錨點,請使用 anchor.persist(),如下所示:

val uuid = anchor.persist()

應用程式可以在日後的工作階段中使用 UUID 擷取錨點:

when (val result = Anchor.load(session, uuid)) {
  is AnchorCreateSuccess -> // Loading was successful. The anchor is stored in result.anchor.
  else -> // handle failure
}

當您不再需要錨點時,請呼叫 unpersist()。這會從應用程式儲存空間中移除錨點,並讓指定的 UUID 無法擷取,以便呼叫 Anchor.load()

Anchor.unpersist(session, uuid)

應用程式也可以要求所有已儲存且仍存在應用程式儲存空間中的錨點清單:

val uuids = Anchor.getPersistedAnchorUuids(session)