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 gráfico de cena, use as APIs do Jetpack
Compose para XR para criar interfaces espaciais (por exemplo, instâncias SpatialPanel
e
Orbiter
) no gráfico 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 entidade-componente 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 chamando setParent()
ou addChild()
.
As entidades têm alguns comportamentos padrão para coisas universais a todas elas, 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 mudar a visibilidade de um Entity
, use setHidden()
.
// Hide the entity entity.setHidden(true)
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. 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
.
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 = MovableComponent.create( session = session, systemMovable = false, scaleInZ = false, anchorPlacement = setOf(anchorPlacement) ) entity.addComponent(movableComponent)
À medida que o usuário move a entidade, o parâmetro scaleInZ
ajusta automaticamente a escala dela conforme ela 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 filhos.
Usar ResizableComponent
para permitir que o usuário redimensione uma entidade
O ResizableComponent
permite que os usuários redimensionem um Entity
. O
ResizableComponent
inclui indicadores visuais de interação 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 usar o ResizableComponent
, especifique um ResizeListener
para responder a eventos de redimensionamento específicos, como onResizeUpdate
ou
onResizeEnd
.
Confira um exemplo de como usar o ResizableComponent
com uma proporção fixa em um
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)
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
, é preciso 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 específicas 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_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)