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 de arquitectura comunes para admitir el desarrollo en 3D: un grafo de escenas y un sistema de componentes de entidades (ECS).
Usa el grafo de escenas para crear y controlar entidades
Para crear y controlar objetos en el espacio 3D, debes usar la API de Session de Jetpack SceneCore para obtener acceso al grafo de escenas. El grafo de escenas 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 hayas obtenido acceso al grafo de escenas, puedes usar las APIs de Jetpack Compose para XR para crear una IU espacial (por ejemplo, SpatialPanel
y Orbiter
) dentro del grafo de escenas. En el caso del contenido 3D, como los modelos 3D, puedes acceder directamente a la sesión. Para obtener más información, consulta Acerca de ActivitySpace en esta página.
Sistema de componentes de entidades
Un sistema de componentes de entidad sigue el principio de composición en lugar de la herencia. Puedes expandir el comportamiento de las entidades si adjuntas 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.
Información 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 escena.
ActivitySpace representa un espacio tridimensional con un sistema de coordenadas de mano derecha (el eje x apunta a la derecha, el eje y apunta hacia arriba y el eje z hacia atrás en relación con el origen) y con metros para 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 los demás en lugar de hacerlo en relación con el origen.
Cómo trabajar 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.
Como ActivitySpace
es el nodo de nivel superior del grafo de escena, de forma predeterminada, todas las entidades nuevas se colocan directamente en ActivitySpace
. Para reubicar entidades a lo largo del grafo de escenas, llama 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 específicas de Entity
, como GltfEntity
, tienen comportamientos adicionales que admiten la subclase.
Cómo manipular entidades
Cuando realices un cambio en una propiedad Entity
que pertenezca a la clase Entity
base, el cambio se aplicará en cascada a todos sus elementos secundarios. Por ejemplo, ajustar el Pose
de un Entity
superior hace que todos sus elementos secundarios tengan el mismo ajuste. Hacer un cambio en un Entity
secundario no afecta a su elemento superior.
Un Pose
representa la ubicación y la rotación de la entidad en el espacio 3D. La ubicación es un Vector3
que consta de posiciones numéricas x, y, z. La rotación se representa con un elemento Quaternion
. La posición de un Entity
siempre es relativa a su entidad superior. En otras palabras, un Entity
cuya posición es (0, 0, 0) se colocará en el origen de su entidad superior.
//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))
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 un comportamiento común a las entidades
Puedes usar los siguientes componentes para agregar un comportamiento común a las entidades:
MovableComponent
: Permite que el usuario mueva entidades.ResizableComponent
: Permite al usuario cambiar el tamaño de las entidades con patrones de IU coherentes.InteractableComponent
: Te permite capturar eventos de entrada para interacciones personalizadas.
La creación de instancias de componentes debe realizarse a través del método de creación apropiado en la clase Session
. Por ejemplo, para crear un ResizableComponent
, llama a session.createResizableComponent()
.
Para agregar el comportamiento específico del componente a un Entity
, usa el método addComponent()
.
Usa MovableComponent para que el usuario pueda mover una entidad
El MovableComponent
permite que el usuario mueva un Entity
. También puedes especificar si la entidad se puede fijar 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 ancla, especifica un conjunto de AnchorPlacement
cuando crees el MovableComponent
.
Este es un ejemplo de una entidad que se puede mover y fijar a cualquier superficie vertical y solo a las superficies horizontales del piso y el techo.
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)
Usa ResizableComponent para que el usuario pueda cambiar el tamaño de una entidad
ResizableComponent
permite a los usuarios cambiar el tamaño de un Entity
. El ResizableComponent
incluye indicadores de interacción visual que invitan al usuario a cambiar el tamaño de un Entity
. Cuando creas el ResizeableComponent
, 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 cambien de tamaño de forma proporcional entre sí.
Este es un ejemplo del uso de ResizableComponent
con una relación de aspecto fija:
val resizableComponent = xrSession.createResizableComponent()
resizableComponent.minimumSize = Dimensions(177f, 100f, 1f )
resizableComponent.fixedAspectRatio = 16f / 9f //Specify a 16:9 aspect ratio
entity.addComponent(resizableComponent)
Usa InteractableComponent para capturar eventos de entrada del usuario
InteractableComponent
te permite capturar eventos de entrada del usuario, como cuando interactúa con un Entity
o coloca el cursor sobre él.
Cuando creas un InteractableComponent
, debes especificar un InputEventListener
para recibir los eventos de entrada. Cuando el usuario realice 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
.
InputEvent.action
especifica el tipo de entrada, como colocar el cursor sobre o presionar una entidad.InputEvent.source
especifica de dónde proviene la entrada, como la entrada de mano o controlador.InputEvent.pointerType
especifica si la entrada provino de la mano derecha o izquierda.
Para obtener una lista completa de todas las constantes 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.
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)