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, instâncias SpatialPanel
e
Orbiter
) no gráfico de cena. Para conteúdo 3D, como modelos
3D, você pode acessar a sessão diretamente. Para saber mais, consulte Sobre o
ActivitySpace nesta página.
Sistema de componentes de entidade
Um sistema de componente de entidade 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
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. A maioria dos elementos com que o usuário 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 que são universais para todas
as entidades, como mudar a posição, a rotação ou a visibilidade. Especificações Entity
específicas, 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
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
com posição (0, 0, 0) será colocado na origem da entidade pai.
// 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))
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:
MovableComponent
: permite que o usuário mova entidades.ResizableComponent
: permite que o usuário redimensione entidades com padrões de IU consistentes.InteractableComponent
: permite capturar eventos de entrada para interações personalizadas.
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
ResizableComponent.create()
.
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. Você
também pode 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 = 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 da entidade à medida que ela se afasta do usuário, de forma semelhante à maneira como
os painéis são dimensionados pelo sistema no espaço de início. Devido à natureza "cascata"
do sistema de componentes de entidade, a escala da entidade pai vai afetar todas as
filhas.
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 a ResizeableComponent
, você pode 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
uma à outra.
Ao usar o ResieableComponent
, é necessário especificar um ResizeListener
para responder a eventos específicos de redimensionamento, 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 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
.
InputEvent.action
especifica o tipo de entrada, como pairar ou tocar em uma entidade.InputEvent.source
especifica de onde a entrada veio, como 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 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.
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)