Criar, controlar e gerenciar entidades

O SDK do Jetpack XR permite usar o Jetpack SceneCore para criar, controlar e gerenciar instâncias de Entity, como modelos 3D, vídeo estereoscópico e PanelEntity usando o Jetpack SceneCore.

O Jetpack SceneCore adota dois padrões de arquitetura comuns para oferecer suporte ao desenvolvimento em 3D: um grafo de cena e um sistema de componentes de entidade (ECS).

Usar o gráfico de cena para criar e controlar entidades

Para criar e controlar objetos no espaço 3D, use a API Session do Jetpack SceneCore para ter acesso à cena. O gráfico de cena se alinha ao mundo real do usuário e permite organizar entidades 3D, como painéis e modelos 3D, em uma estrutura hierárquica e manter o estado dessas entidades.

Depois de ter acesso à cena, você pode usar as APIs do Jetpack Compose para XR para criar uma interface espacial (por exemplo, SpatialPanel e Orbiters) dentro da cena. Para conteúdo 3D, como modelos 3D, é possível acessar a sessão diretamente. Para saber mais, consulte Sobre o ActivitySpace nesta página.

Sistema de componentes de entidade

Um sistema de entidade-componente segue o princípio da composição sobre a herança. É possível expandir o comportamento das entidades anexando componentes que definem o comportamento, o que permite aplicar o mesmo comportamento a diferentes tipos de entidades. Para mais informações, consulte Adicionar comportamento comum a entidades nesta página.

Sobre o ActivitySpace

Cada Session tem um ActivitySpace que é criado automaticamente com o Session. O ActivitySpace é o Entity de nível superior no gráfico de cena.

O ActivitySpace representa um espaço tridimensional com um sistema de coordenadas direito (o eixo x aponta para a direita, o eixo y aponta para cima e o eixo z para trás em relação à origem) e com metros para unidades que correspondem ao mundo real. A origem de ActivitySpace é um tanto arbitrária (já que os usuários podem redefinir a posição do ActivitySpace no mundo real). Portanto, é recomendado posicionar o conteúdo em relação a cada um dos outros, em vez de relacionar à origem.

Trabalhar com entidades

As entidades são o centro do SceneCore. Quase tudo que o usuário vê e com que interage são entidades que representam painéis, modelos 3D e muito mais.

Como o ActivitySpace é o nó de nível superior do gráfico de cena, por padrão, todas as novas entidades são colocadas diretamente no ActivitySpace. É possível realocar entidades no gráfico de cena chamando setParent ou addChild.

As entidades têm alguns comportamentos padrão para coisas que são universais para todas as entidades, como mudar a posição, a rotação ou a visibilidade. Especificações Entity subclasses, como GltfEntity, têm outros comportamentos que oferecem suporte à subclasse.

Manipular entidades

Quando você faz uma mudança em uma propriedade Entity que pertence à classe Entity base, a mudança é transmitida em cascata para todas as filhas. Por exemplo, ajustar o Pose de um Entity pai faz com que todos os filhos tenham o mesmo ajuste. Fazer uma mudança em uma Entity filha não afeta o elemento pai.

Um Pose representa a localização e a rotação da entidade no espaço 3D. O local é um Vector3 que consiste em posições numéricas x, y e z. A rotação é representada por um Quaternion. A posição de um Entity é sempre relativa à entidade pai. Em outras palavras, um Entity com posição (0, 0, 0) será colocado na origem da entidade pai.

//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 mudar a visibilidade de um Entity, use setHidden.

//hide the entity
entity.setHidden(true)

Para redimensionar um Entity mantendo a forma geral, use setScale.

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

Adicionar comportamento comum a entidades

É possível usar os seguintes componentes para adicionar comportamentos comuns às entidades:

A instanciação de componentes precisa ser feita pelo método de criação apropriado na classe Session. Por exemplo, para criar um ResizableComponent, chame session.createResizableComponent().

Para adicionar o comportamento específico do componente a um Entity, use o método addComponent().

Usar o MovableComponent para permitir que o usuário mova uma entidade

O MovableComponent permite que um Entity seja movido pelo usuário. Também é possível especificar se a entidade pode ser ancorada a um tipo de superfície, como superfícies horizontais ou verticais, ou superfícies semânticas específicas, como mesa, parede ou teto. Para especificar opções de âncora, especifique um conjunto de AnchorPlacement ao criar o MovableComponent.

Confira um exemplo de entidade que pode ser movida e ancorada em qualquer superfície vertical e apenas em superfícies horizontais de piso e teto.

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)

Usar ResizableComponent para tornar uma entidade redimensionável pelo usuário

O ResizableComponent permite que os usuários redimensionem um Entity. O ResizableComponent inclui dicas de interação visual que convidam o usuário a redimensionar um Entity. Ao criar o ResizeableComponent, é possível especificar um tamanho mínimo ou máximo (em metros). Você também tem a opção de especificar uma proporção fixa ao redimensionar para que a largura e a altura sejam redimensionadas proporcionalmente.

Confira um exemplo de como usar ResizableComponent com uma proporção fixa:

val resizableComponent = xrSession.createResizableComponent()
resizableComponent.minimumSize = Dimensions(177f, 100f, 1f )
resizableComponent.fixedAspectRatio = 16f / 9f //Specify a 16:9 aspect ratio
entity.addComponent(resizableComponent)

Usar o InteractableComponent para capturar eventos de entrada do usuário

O InteractableComponent permite capturar eventos de entrada do usuário, como quando o usuário interage ou passa o cursor sobre um Entity. Ao criar um InteractableComponent, é necessário especificar um InputEventListener para receber os eventos de entrada. Quando o usuário realiza qualquer ação de entrada, o método onInputEvent é chamado com as informações de entrada específicas fornecidas no parâmetro InputEvent.

Para uma lista completa de todas as constantes InputEvent, consulte a documentação de referência.

O snippet de código abaixo mostra um exemplo de como usar um InteractableComponent para aumentar o tamanho de uma entidade com a mão direita e diminuir com a mão esquerda.

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)