Cómo trabajar con ARCore para Jetpack XR

ARCore para Jetpack XR permite que las apps funcionen con conceptos básicos de la realidad aumentada (RA), a través de primitivas de comprensión de escenas de bajo nivel y seguimiento de movimiento. Usa ARCore para Jetpack XR cuando crees experiencias de RA y necesites usar datos planares o fijar contenido a una ubicación fija en el espacio.

Comprende el ciclo de vida de una sesión

Se debe acceder a todos los objetos a los que ARCore hace un seguimiento para Jetpack XR a través de una sesión. Al igual que el ciclo de vida de una actividad, los objetos de sesión también tienen un ciclo de vida que se debe mantener según el uso que haga tu app de las funciones de un objeto de sesión. Si tu app contiene una sola actividad habilitada para XR, considera controlar el ciclo de vida de la sesión con un componente que priorice el ciclo de vida.

Crea una sesión

Se debe crear una sesión antes de poder usarla. Para crear una sesión, se requiere que el usuario haya otorgado el permiso android.permission.SCENE_UNDERSTANDING a tu app.

Para crear una sesión, sigue estos pasos:

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

Consulta SessionCreateResult para conocer los motivos por los que no se puede crear una sesión.

Cómo reanudar una sesión

Se debe reanudar una sesión cuando tu app esté lista para controlar los cambios de estado de ARCore para Jetpack XR. En muchos casos, esto se hace en la devolución de llamada onResume() de tu actividad, pero es posible que tu app desee retrasar el procesamiento hasta que el usuario interactúe.

En el siguiente fragmento de código, se muestra un ejemplo de cómo reanudar una sesión.

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

Consulta SessionResumeResult para conocer los motivos por los que una sesión podría no reanudarse.

Cómo pausar una sesión

Cuando tu actividad pase a segundo plano, pausa la sesión con Session.pause(). Si pausas una sesión, se detiene temporalmente el seguimiento hasta que se reanuda la sesión, lo que mantiene el estado del sistema de percepción.

Cómo destruir una sesión

Para descartar una sesión de forma permanente, usa Session.destroy(). Esto libera los recursos que usa la sesión y destruye todos sus estados.

Cómo recuperar el estado de los planos percibidos

ARCore para Jetpack XR proporciona el estado de los planos a través de un StateFlow que emite el estado de los planos. Si te suscribes a planes en una sesión, se notificará a tu app cuando se agreguen, se actualicen o se quiten planes.

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

Un plano tiene las siguientes propiedades:

  • label: Es una descripción semántica de un Plane determinado. Puede ser un Wall, Floor, Ceiling o Table.
  • centerPose: Es la posición del centro del plano detectado.
  • extents: Son las dimensiones del plano detectado, en metros.
  • vertices: Es una lista de vértices de un polígono convexo que se aproxima al plano.

Realiza una prueba de posicionamiento en planos

Una prueba de posicionamiento es un método para calcular la intersección de un rayo con los objetos a los que hace un seguimiento la sesión. Una aplicación común de una prueba de posicionamiento es apuntar a una tabla y colocar un objeto en esa ubicación. Realizar una prueba de posicionamiento genera una lista de objetos de hit. En otras palabras, una prueba de hit no se detiene en el primer objeto que se golpea. Sin embargo, a menudo, es posible que solo te interese el primer objeto que se encuentra de un tipo determinado.

Para realizar una prueba de posicionamiento, usa Interaction.hitTest() con un 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
}

Cómo fijar contenido a una ubicación fija en el espacio

Para asignar una posición en el mundo real a los objetos virtuales, usa un Anchor. Un objeto Anchor ayuda a tu app a hacer un seguimiento de una ubicación fija en el espacio físico.

Se crea un ancla con un Pose, que se puede interpretar en relación con un Trackable existente o no.

Crea un ancla en relación con un elemento rastreable

Cuando se crea un ancla en relación con un Trackable, como un Plane, que hace que el ancla siga el Trackable adjunto cuando se mueve por el espacio.

val anchor = trackable.createAnchor(pose)

Crea un ancla sin un elemento rastreable

Para crear un ancla que no esté unida a un Trackable, haz lo siguiente:

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

Cómo adjuntar una entidad a un ancla

Para renderizar un modelo en esta ubicación, crea un GltfModel y establece su pose en la pose del ancla. Asegúrate de que el modelo esté oculto cuando el TrackingState del ancla sea 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)
  }
}

Información sobre TrackingState

Cada Trackable tiene un TrackingState que se debe verificar antes de usarlo. Un Trackable que tiene un TrackableState de Tracking tiene su Pose actualizado de forma activa por el sistema. Un Trackable que es Paused puede convertirse en Tracking en el futuro, mientras que uno que es Stopped nunca se convertirá en Tracking.

Cómo conservar un ancla en todas las sesiones

Un ancla que no se conserva desaparece después de que se destruye una sesión. Cuando persistes un ancla, tu app recuerda la posición de esa ancla en sus datos privados de app. Este ancla se puede recuperar en una sesión posterior y se ancla en la misma ubicación del mundo.

Para conservar un ancla, usa anchor.persist() como se muestra a continuación:

val uuid = anchor.persist()

Tu app puede recuperar el ancla con UUID en una sesión futura:

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

Cuando ya no necesites un ancla, llama a unpersist(). Esto quita el ancla del almacenamiento de tu app y hace que el UUID determinado no se pueda recuperar para las llamadas a Anchor.load().

Anchor.unpersist(session, uuid)

Tu app también puede solicitar una lista de todos los anclajes que se conservaron y que aún están presentes en el almacenamiento de tu app:

val uuids = Anchor.getPersistedAnchorUuids(session)