Creare, controllare e gestire entità

L'SDK Jetpack XR ti consente di utilizzare Jetpack SceneCore per creare, controllare e gestire istanze Entity come modelli 3D, video stereoscopici e PanelEntity utilizzando Jetpack SceneCore.

Jetpack SceneCore adotta due pattern architetturali comuni per supportare lo sviluppo 3D: un grafo della scena e un sistema entità-componente (ECS).

Utilizzare il grafico della scena per creare e controllare le entità

Per creare e controllare gli oggetti nello spazio 3D, puoi utilizzare l'API Session di Jetpack SceneCore per accedere al grafico della scena. Il grafico della scena si allinea al mondo reale dell'utente e ti consente di organizzare entità 3D come pannelli e modelli 3D in una struttura gerarchica e di conservare lo stato di queste entità.

Una volta ottenuto l'accesso al grafico della scena, puoi utilizzare le API in Jetpack Compose per XR per creare un'interfaccia utente spaziale (ad esempio, istanze SpatialPanel e Orbiter) all'interno del grafico della scena. Per i contenuti 3D come i modelli 3D, puoi accedere direttamente alla sessione. Per saperne di più, consulta la sezione Informazioni su ActivitySpace in questa pagina.

Sistema a componenti di entità

Un sistema di componenti di entità segue il principio della composizione rispetto all'ereditarietà. Puoi espandere il comportamento delle entità collegando componenti che definiscono il comportamento, il che ti consente di applicare lo stesso comportamento a diversi tipi di entità. Per saperne di più, consulta la sezione Aggiungere un comportamento comune alle entità in questa pagina.

Informazioni su ActivitySpace

Ogni Session ha un ActivitySpace creato automaticamente con il Session. ActivitySpace è il Entity di primo livello nel grafico della scena.

ActivitySpace rappresenta uno spazio tridimensionale con un sistema di coordinate destrorso (l'asse x punta a destra, l'asse y punta verso l'alto e l'asse z punta all'indietro rispetto all'origine) e con unità di misura in metri che corrispondono al mondo reale. L'origine di ActivitySpace è in qualche modo arbitraria (in quanto gli utenti possono reimpostare la posizione di ActivitySpace nel mondo reale), pertanto è consigliabile posizionare i contenuti in relazione tra loro anziché in relazione all'origine.

Utilizzare le entità

Le entità sono fondamentali per SceneCore. Quasi tutto ciò che l'utente vede e con cui interagisce sono entità che rappresentano pannelli, modelli 3D e altro ancora.

Poiché ActivitySpace è il nodo di primo livello del grafico della scena, per impostazione predefinita, tutte le nuove entità vengono inserite direttamente in ActivitySpace. Puoi riposizionare le entità lungo il grafico della scena chiamando setParent() o addChild().

Le entità hanno alcuni comportamenti predefiniti per elementi universali per tutte le entità, come la modifica di posizione, rotazione o visibilità. Sottoclassi Entity specifiche, come GltfModelEntity, hanno comportamenti aggiuntivi che supportano la sottoclasse.

Manipolare le entità

Quando apporti una modifica a una proprietà Entity che appartiene alla classe Entity di base, la modifica viene applicata a tutti i relativi elementi secondari. Ad esempio, se modifichi il Pose di un Entity principale, tutti i relativi elementi secondari avranno lo stesso aggiustamento. Una modifica apportata a un Entity secondario non influisce su quello principale.

Un Pose rappresenta la posizione e la rotazione dell'entità nello spazio 3D. La posizione è un Vector3 costituito da posizioni numeriche x, y e z. La rotazione è rappresentata da un Quaternion. La posizione di un Entity è sempre relativa alla sua entità principale. In altre parole, un Entity la cui posizione è (0, 0, 0) verrà posizionato all'origine della relativa entità principale.

// 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))

Per modificare la visibilità di un Entity, utilizza setHidden().

// Hide the entity
entity.setHidden(true)

Per ridimensionare un Entity mantenendone la forma complessiva, utilizza setScale().

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

Aggiungere un comportamento comune alle entità

Puoi utilizzare i seguenti componenti per aggiungere un comportamento comune alle entità:

L'istanza dei componenti deve essere creata tramite il metodo di creazione appropriato nella classe Session. Ad esempio, per creare un ResizableComponent, chiama ResizableComponent.create().

Per aggiungere il comportamento specifico del componente a un Entity, utilizza il metodo addComponent().

Utilizzare MovableComponent per rendere un'entità spostabile dall'utente

Il MovableComponent consente all'utente di spostare un Entity. Puoi anche specificare se l'entità può essere ancorata a un tipo di superficie come superfici orizzontali o verticali oppure a superfici semantiche specifiche come tavolo, parete o soffitto. Per specificare le opzioni di ancoraggio, specifica un insieme di AnchorPlacement quando crei MovableComponent.

Ecco un esempio di entità che può essere spostata e ancorata a qualsiasi superficie verticale e solo alle superfici orizzontali del pavimento e del soffitto.

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)

Man mano che l'utente sposta l'entità, il parametro scaleInZ regola automaticamente la scala dell'entità man mano che si allontana dall'utente in modo simile a come i pannelli vengono scalati dal sistema nello spazio della casa. A causa della natura "a cascata" del sistema di componenti delle entità, la scala dell'elemento principale influirà su tutti i relativi elementi secondari.

Utilizza ResizableComponent per rendere ridimensionabile un'entità

Il ResizableComponent consente agli utenti di ridimensionare un Entity. ResizableComponent include segnali visivi di interazione che invitano l'utente a ridimensionare un Entity. Quando crei il ResizableComponent, puoi specificare una dimensione minima o massima (in metri). Hai anche la possibilità di specificare proporzioni fisse durante il ridimensionamento, in modo che la larghezza e l'altezza vengano ridimensionate in modo proporzionale tra loro.

Quando utilizzi ResizableComponent, devi specificare un ResizeListener per rispondere a eventi di ridimensionamento specifici come onResizeUpdate o onResizeEnd.

Ecco un esempio di utilizzo di ResizableComponent con proporzioni fisse su un 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)

Utilizzare InteractableComponent per acquisire gli eventi di input dell'utente

InteractableComponent consente di acquisire gli eventi di input dell'utente, ad esempio quando l'utente interagisce o passa il mouse sopra un Entity. Quando crei un InteractableComponent, devi specificare un InputEventListener per ricevere gli eventi di input. Quando l'utente esegue un'azione di input, viene chiamato il metodo onInputEvent con le informazioni di input specifiche fornite nel parametro InputEvent.

Per un elenco completo di tutte le costanti InputEvent, consulta la documentazione di riferimento.

Il seguente snippet di codice mostra un esempio di utilizzo di un InteractableComponent per aumentare le dimensioni di un'entità con la mano destra e diminuirle con la mano sinistra.

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)