借助适用于 Jetpack XR 的 ARCore,应用可以使用低级场景理解基元和动作跟踪来处理增强现实 (AR) 的基本概念。在构建 AR 体验时,如果您需要使用平面数据或将内容锚定到空间中的固定位置,请使用适用于 Jetpack XR 的 ARCore。
了解会话的生命周期
必须通过会话访问 ARCore for Jetpack XR 跟踪的所有对象。与 activity 的生命周期类似,会话对象也具有生命周期,必须根据应用对会话对象功能的使用情况进行维护。如果您的应用包含一个支持 XR 的 activity,请考虑使用生命周期感知型组件处理会话的生命周期。
创建会话
必须先创建会话,然后才能使用。若要创建会话,用户必须已向您的应用授予 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 的状态更改时,应恢复会话。在许多情况下,这可以在 activity 的 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
。
暂停会话
当 activity 进入后台时,使用 Session.pause()
暂停会话。暂停会话会暂时停止跟踪,直到会话恢复为止,同时会保持感知系统的状态。
销毁会话
如需永久处置会话,请使用 Session.destroy()
。这会释放会话使用的资源,并销毁所有会话状态。
检索感知平面的状态
适用于 Jetpack XR 的 ARCore 通过发射平面状态的 StateFlow
提供平面状态。在会话中订阅航线后,系统会在添加、更新或移除航线时通知您的应用。
Plane.subscribe(session).collect { planes ->
// Planes have changed; update plane rendering
}
平面具有以下属性:
label
:给定Plane
的语义说明。可以是Wall
、Floor
、Ceiling
或Table
。centerPose
:检测到的平面中心的姿势。extents
:检测到的平面的尺寸(以米为单位)。vertices
:近似于平面的凸多边形的顶点列表。
对平面执行点击测试
点击测试是一种计算光线与会话跟踪的对象的交点的方法。点击测试的常见应用是指向表格并在该位置放置对象。执行点击测试会产生一个点击对象列表。换句话说,碰撞测试不会在命中第一个对象时停止。不过,您通常可能只对命中的第一个对象感兴趣。
如需执行点击测试,请将 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
。Anchor 对象可帮助您的应用跟踪物理空间中的固定位置。
锚点是使用 Pose
创建的,可以相对于现有的 Trackable
进行解读,也可以不进行解读。
创建相对于可跟踪对象的锚点
相对于 Trackable
(例如 Plane
)创建锚点时,锚点会在附加的 Trackable
在空间中移动时跟随该 Trackable
。
val anchor = trackable.createAnchor(pose)
创建不含可跟踪的锚点
如需创建未附加到 Trackable
的锚点,请执行以下操作:
when (val result = Anchor.create(session, pose)) {
is AnchorCreateSuccess -> // ...
else -> // handle failure
}
将实体附加到锚点
如需在此位置渲染模型,请创建 GltfModel
并将其姿势设置为锚点的姿势。确保当锚点的 TrackingState
为 Stopped
时,模型处于隐藏状态。
// 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
,应先检查该 TrackingState
,然后再使用。如果 Trackable
的 TrackableState
为 Tracking
,系统会主动更新其 Pose
。Paused
的 Trackable
将来可能会变为 Tracking
,而 Stopped
的 Trackable
永远不会变为 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)