Crea, controla y administra entidades

El SDK de Jetpack XR te permite usar Jetpack SceneCore para crear, controlar y administrar instancias de Entity, como modelos 3D, video estereoscópico y PanelEntity con Jetpack SceneCore.

Jetpack SceneCore adopta dos patrones arquitectónicos comunes para admitir el desarrollo en 3D: un gráfico de escena y un sistema de componentes de entidades (ECS).

Usa el grafo de la escena para crear y controlar entidades

Para crear y controlar objetos en el espacio 3D, puedes usar la API de Session de Jetpack SceneCore para acceder al gráfico de la escena. El gráfico de la escena se alinea con el mundo real del usuario y te permite organizar entidades 3D, como paneles y modelos 3D, en una estructura jerárquica, y mantener el estado de esas entidades.

Una vez que obtengas acceso al gráfico de la escena, podrás usar las APIs de Jetpack Compose para XR y crear una IU espacial (por ejemplo, instancias de SpatialPanel y Orbiter) dentro del gráfico de la escena. En el caso del contenido en 3D, como los modelos en 3D, puedes acceder a la sesión directamente. Para obtener más información, consulta Acerca de ActivitySpace en esta página.

Sistema de componentes de entidades

Un sistema de componentes de entidades sigue el principio de composición sobre herencia. Puedes expandir el comportamiento de las entidades adjuntando componentes que definen el comportamiento, lo que te permite aplicar el mismo comportamiento a diferentes tipos de entidades. Para obtener más información, consulta Cómo agregar comportamiento común a las entidades en esta página.

Acerca de ActivitySpace

Cada Session tiene un ActivitySpace que se crea automáticamente con el Session. El ActivitySpace es el Entity de nivel superior en el gráfico de la escena.

El objeto ActivitySpace representa un espacio tridimensional con un sistema de coordenadas a la derecha (el eje X apunta hacia la derecha, el eje Y apunta hacia arriba y el eje Z hacia atrás en relación con el origen) y con metros como unidades que coinciden con el mundo real. El origen de ActivitySpace es algo arbitrario (ya que los usuarios pueden restablecer la posición de ActivitySpace en el mundo real), por lo que se recomienda posicionar el contenido en relación con otro contenido en lugar de hacerlo en relación con el origen.

Trabaja con entidades

Las entidades son fundamentales para SceneCore. Casi todo lo que el usuario ve y con lo que interactúa son entidades que representan paneles, modelos 3D y mucho más.

Dado que ActivitySpace es el nodo de nivel superior del grafo de la escena, de forma predeterminada, todas las entidades nuevas se colocan directamente en ActivitySpace. Puedes reubicar entidades a lo largo del grafo de la escena llamando a setParent() o addChild().

Las entidades tienen algunos comportamientos predeterminados para elementos que son universales para todas las entidades, como cambiar la posición, la rotación o la visibilidad. Las subclases Entity específicas, como GltfModelEntity, tienen comportamientos adicionales que admiten la subclase.

Manipula entidades

Cuando realizas un cambio en una propiedad Entity que pertenece a la clase Entity base, el cambio se propagará a todos sus elementos secundarios. Por ejemplo, ajustar el Pose de un Entity principal hace que todos sus elementos secundarios tengan el mismo ajuste. Realizar un cambio en un Entity secundario no afecta a su principal.

Un Pose representa la ubicación y la rotación de la entidad dentro del espacio 3D. La ubicación es un Vector3 que consta de posiciones numéricas x, y y z. La rotación se representa con un Quaternion. La posición de un Entity siempre es relativa a su entidad principal. En otras palabras, un Entity cuya posición es (0, 0, 0) se colocará en el origen de su entidad principal.

// 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

Para cambiar la visibilidad de un Entity, usa setHidden().

// Hide the entity
entity.setHidden(true)

Para cambiar el tamaño de un Entity y mantener su forma general, usa setScale().

// Double the size of the entity
entity.setScale(2f)

Agrega comportamiento común a las entidades

Puedes usar los siguientes componentes para agregar comportamiento común a las entidades:

Los componentes de instancias deben realizarse a través del método de creación adecuado en la clase Session. Por ejemplo, para crear un ResizableComponent, llama a ResizableComponent.create().

Para agregar el comportamiento específico del componente a un Entity, usa el método addComponent().

Usa MovableComponent para hacer que una entidad se pueda mover por el usuario

El MovableComponent permite que el usuario mueva el Entity. También puedes especificar si la entidad se puede anclar a un tipo de superficie, como superficies horizontales o verticales, o superficies semánticas específicas, como una mesa, una pared o un techo. Para especificar opciones de anclaje, especifica un conjunto de AnchorPlacement cuando crees el MovableComponent.

Este es un ejemplo de una entidad que se puede mover y anclar a cualquier superficie vertical y solo a superficies horizontales del piso y el techo.

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)

A medida que el usuario mueve la entidad, el parámetro scaleInZ ajusta automáticamente su escala a medida que se aleja del usuario de manera similar a cómo el sistema escala los paneles en el espacio principal. Debido a la naturaleza "en cascada" del sistema de componentes de entidades, la escala de la entidad principal afectará a todos sus elementos secundarios.

Usa ResizableComponent para hacer que una entidad se pueda cambiar de tamaño por el usuario

El ResizableComponent permite a los usuarios cambiar el tamaño de un Entity. El ResizableComponent incluye indicadores visuales de interacción que invitan al usuario a cambiar el tamaño de un Entity. Cuando creas el objeto ResizableComponent, puedes especificar un tamaño mínimo o máximo (en metros). También tienes la opción de especificar una relación de aspecto fija cuando cambias el tamaño para que el ancho y la altura se ajusten proporcionalmente entre sí.

Cuando uses ResizableComponent, debes especificar un ResizeListener para responder a eventos de cambio de tamaño específicos, como onResizeUpdate o onResizeEnd.

A continuación, se muestra un ejemplo del uso de ResizableComponent con una relación de aspecto fija en un SurfaceEntity:

val resizableComponent = ResizableComponent.create(session)
resizableComponent.minimumSize = Dimensions(177f, 100f, 1f)
resizableComponent.fixedAspectRatio = 16f / 9f // Specify a 16:9 aspect ratio

resizableComponent.addResizeListener(
    executor,
    object : ResizeListener {
        override fun onResizeEnd(entity: Entity, finalSize: Dimensions) {

            // update the size in the component
            resizableComponent.size = finalSize

            // update the Entity to reflect the new size
            (entity as SurfaceEntity).canvasShape = SurfaceEntity.CanvasShape.Quad(finalSize.width, finalSize.height)
        }
    },
)

entity.addComponent(resizableComponent)

Usa InteractableComponent para capturar eventos de entrada del usuario

El InteractableComponent te permite capturar eventos de entrada del usuario, como cuando el usuario interactúa con un Entity o coloca el cursor sobre él. Cuando creas un objeto InteractableComponent, debes especificar un InputEventListener para recibir los eventos de entrada. Cuando el usuario realiza cualquier acción de entrada, se llamará al método onInputEvent con la información de entrada específica proporcionada en el parámetro InputEvent.

Para obtener una lista completa de todas las constantes de InputEvent, consulta la documentación de referencia.

En el siguiente fragmento de código, se muestra un ejemplo del uso de un InteractableComponent para aumentar el tamaño de una entidad con la mano derecha y disminuirlo con la izquierda.

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)