O SDK do Jetpack XR permite usar o Jetpack SceneCore para criar, controlar e gerenciar
instâncias Entity
, como modelos 3D, vídeos estereoscópicos e
PanelEntity
usando o Jetpack SceneCore.
O Jetpack SceneCore adota dois padrões de arquitetura comuns para oferecer suporte ao desenvolvimento 3D: um grafo de cena e um sistema de entidade-componente (ECS, na sigla em inglês).
Usar o grafo de cena para criar e controlar entidades
Para criar e controlar objetos no espaço 3D, use a API Session do Jetpack SceneCore para acessar o grafo de cena. O gráfico de cena se alinha com o 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 acessar o grafo de cena, use as APIs do Jetpack
Compose para XR e crie uma interface espacial (por exemplo, instâncias SpatialPanel
e
Orbiter
) no grafo de cena. Para conteúdo 3D, como modelos 3D, acesse a sessão diretamente. Para saber mais, consulte Sobre o
ActivitySpace nesta página.
Sistema de componentes de entidade
Um sistema de componentes de entidade segue o princípio da composição em vez de 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
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 orientado para a direita (o eixo x aponta para a direita, o eixo y 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 pouco arbitrária, já que os usuários podem redefinir a posição de ActivitySpace
no mundo real. Por isso, é recomendável posicionar o conteúdo em relação um ao outro, em vez de em relação à origem.
Trabalhar com entidades
As entidades são fundamentais para o 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 ao longo do gráfico de cena definindo o parent
ou usando addChild()
.
As entidades têm alguns comportamentos padrão para coisas universais a todas as entidades, como mudança de posição, rotação ou visibilidade. Subclasses Entity
específicas, como GltfModelEntity
, têm comportamentos adicionais que oferecem suporte a elas.
Manipular entidades
Quando você faz uma mudança em uma propriedade Entity
que pertence à classe base Entity
, a mudança é transmitida a todos os filhos dela. 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 a mãe.
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 mãe. Em outras palavras, um Entity
cuja posição seja (0, 0, 0) será colocado na origem da entidade mãe.
// 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 desativar um Entity
, use setEnabled()
. Isso o torna invisível e
interrompe todo o processamento feito nele.
// Disable the entity. entity.setEnabled(false)
Para redimensionar um Entity
sem alterar o formato geral, use setScale()
.
// Double the size of the entity entity.setScale(2f)
Adicionar comportamento comum a entidades
Você pode usar os seguintes componentes para adicionar comportamentos comuns às entidades:
MovableComponent
: permite que o usuário mova entidades.ResizableComponent
: permite que o usuário redimensione entidades com padrões de UI consistentes.InteractableComponent
: permite capturar eventos de entrada para interações personalizadas.
A instanciação de componentes precisa ser feita usando o método de criação adequado na classe Session
. Por exemplo, para criar um ResizableComponent
, chame
ResizableComponent.create()
.
Para adicionar o comportamento específico do componente a um Entity
, use o método addComponent()
.
Usar MovableComponent
para tornar uma entidade móvel para o usuário
O MovableComponent
permite que um Entity
seja movido pelo usuário.
Os eventos de movimento são enviados ao componente quando há interação com as
decorações. O comportamento padrão do sistema, criado com
MovableComponent.createSystemMovable()
, move seu Entity
quando as
decorações são arrastadas:
val movableComponent = MovableComponent.createSystemMovable(session) entity.addComponent(movableComponent)
O parâmetro opcional scaleInZ
(por padrão, definido como true
) faz com que a entidade ajuste automaticamente a escala à medida que se afasta do usuário, de maneira semelhante a como os painéis são dimensionados pelo sistema no espaço inicial.
Devido à natureza "em cascata" do sistema de componentes de entidade, a escala do elemento pai afeta todos os elementos filhos.
Você também pode especificar se a entidade pode ser ancorada a um tipo de superfície, como horizontal ou vertical, ou a 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
. Neste exemplo, a entidade que pode ser movida e ancorada em qualquer superfície horizontal de piso ou mesa:
val anchorPlacement = AnchorPlacement.createForPlanes( anchorablePlaneOrientations = setOf(PlaneOrientation.VERTICAL), anchorablePlaneSemanticTypes = setOf(PlaneSemanticType.FLOOR, PlaneSemanticType.TABLE) ) val movableComponent = MovableComponent.createAnchorable( session = session, anchorPlacement = setOf(anchorPlacement) ) entity.addComponent(movableComponent)
Usar ResizableComponent
para permitir que o usuário redimensione uma entidade
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 ResizableComponent
, é possível especificar um tamanho mínimo ou máximo (em metros). Você também pode especificar uma proporção fixa ao redimensionar para que a largura e a altura sejam redimensionadas proporcionalmente entre si.
Ao criar um ResizableComponent
, especifique um resizeEventListener
que
processe os eventos de atualização. Você pode responder a diferentes eventos de ResizeState
, como RESIZE_STATE_ONGOING
ou RESIZE_STATE_END
.
Confira um exemplo de como usar o ResizableComponent
com uma proporção fixa em um
SurfaceEntity
:
val resizableComponent = ResizableComponent.create(session) { event -> if (event.resizeState == ResizeEvent.ResizeState.RESIZE_STATE_END) { // update the Entity to reflect the new size surfaceEntity.canvasShape = SurfaceEntity.CanvasShape.Quad(event.newSize.width, event.newSize.height) } } resizableComponent.minimumEntitySize = FloatSize3d(177f, 100f, 1f) resizableComponent.fixedAspectRatio = 16f / 9f // Specify a 16:9 aspect ratio surfaceEntity.addComponent(resizableComponent)
Usar InteractableComponent
para capturar eventos de entrada do usuário
O InteractableComponent
permite capturar eventos de entrada do usuário,
como quando ele interage ou passa o cursor sobre um Entity
. Ao criar um
InteractableComponent
, especifique um listener que receba os eventos de entrada.
Quando o usuário realiza qualquer ação de entrada, o listener é chamado com as informações de entrada fornecidas no parâmetro InputEvent
.
InputEvent.action
especifica o tipo de entrada, como passar o cursor ou tocar em uma entidade.InputEvent.source
especifica de onde veio a entrada, como entrada de mão ou controlador.InputEvent.pointerType
especifica se a entrada veio da mão direita ou esquerda.
Para uma lista completa de todas as constantes InputEvent
, consulte a documentação de referência.
O snippet de código a seguir mostra um exemplo de como usar um InteractableComponent
para aumentar o tamanho de uma entidade com a mão direita e diminuir com a
esquerda.
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.SOURCE_HANDS && it.action == InputEvent.Action.ACTION_UP) { // increase size with right hand and decrease with left if (it.pointerType == InputEvent.Pointer.POINTER_TYPE_RIGHT) { entity.setScale(1.5f) } else if (it.pointerType == InputEvent.Pointer.POINTER_TYPE_LEFT) { entity.setScale(0.5f) } } } entity.addComponent(interactableComponent)