Creare, controllare e gestire entità

Dispositivi XR applicabili
Queste indicazioni ti aiutano a creare esperienze per questi tipi di dispositivi XR.
Visori XR
Occhiali XR con cavo

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

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

Utilizzare il grafo di 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 grafo di scena. Il grafo di scena si allinea al mondo reale dell'utente e ti consente di organizzare le entità 3D, come pannelli e modelli 3D, in una struttura gerarchica e di mantenerne lo stato.

Una volta ottenuto l'accesso al grafo di scena, puoi utilizzare le API in Jetpack Compose per XR per creare un'interfaccia utente spaziale (ad esempio, SpatialPanel e Orbiter istanze) all'interno del grafo di 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 di 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 Aggiungere un comportamento comune alle entità in questa pagina.

Informazioni su ActivitySpace

Ogni Session ha un ActivitySpace che viene creato automaticamente con il Session. ActivitySpace è l'Entity di primo livello nel grafo di scena.

ActivitySpace rappresenta uno spazio tridimensionale con un sistema di coordinate destrorso (l'asse x punta a destra, l'asse y verso l'alto e l'asse z 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 l'uno rispetto all'altro anziché rispetto 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 grafo di scena, per impostazione predefinita tutte le nuove entità vengono inserite direttamente in ActivitySpace. Puoi spostare le entità lungo il grafo di scena impostando il relativo parent o utilizzando addChild().

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

Manipolare le entità

Quando modifichi una proprietà Entity appartenente alla classe Entity di base, la modifica viene applicata a tutti i relativi elementi secondari. Ad esempio, la regolazione di Pose di un Entity principale comporta la stessa regolazione per tutti i relativi elementi secondari. La modifica di un Entity secondario non influisce sul relativo elemento principale.

Pose rappresenta la posizione e la rotazione dell'entità nello spazio 3D. La posizione è un Vector3 composto da posizioni numeriche x, y, z. La rotazione è rappresentata da un Quaternion. La posizione di un Entity è sempre relativa alla relativa 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 disattivare un Entity, utilizza setEnabled(). In questo modo, l'entità diventa invisibile e viene interrotta tutta l'elaborazione eseguita su di essa.

// Disable the entity.
entity.setEnabled(false)

Per ridimensionare un Entity mantenendo 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 eseguita tramite il metodo di creazione appropriato nella classe Session. Ad esempio, per creare un ResizableComponent, chiama ResizableComponent.create().

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

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

Il MovableComponent consente all'utente di spostare un Entity.

Gli eventi di movimento vengono inviati al componente quando si interagisce con le decorazioni. Il comportamento predefinito del sistema, creato con MovableComponent.createSystemMovable(), sposta il tuo Entity quando le decorazioni vengono trascinate:

val movableComponent = MovableComponent.createSystemMovable(session)
entity.addComponent(movableComponent)

Il parametro facoltativo scaleInZ (per impostazione predefinita impostato su true) fa sì che l'entità regoli automaticamente la sua scala quando viene allontanata dall'utente, in modo simile a come i pannelli vengono scalati dal sistema nello spazio Home. A causa della natura "a cascata" del sistema di componenti di entità, la scala dell'elemento principale influirà su tutti i relativi elementi secondari.

Puoi anche specificare se l'entità può essere ancorata a un tipo di superficie, ad esempio superfici orizzontali o verticali, o a superfici semantiche specifiche, come tavoli, pareti o soffitti. Per specificare le opzioni di ancoraggio, specifica un insieme di AnchorPlacement durante la creazione di MovableComponent. In questo esempio, l'entità può essere spostata e ancorata a qualsiasi superficie orizzontale del pavimento o del tavolo:

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)

Utilizzare ResizableComponent per rendere un'entità ridimensionabile dall'utente

The ResizableComponent consente agli utenti di ridimensionare un Entity. ResizableComponent include segnali di interazione visiva che invitano l'utente a ridimensionare un Entity. Quando crei 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 proporzionalmente l'una all'altra.

Quando crei un ResizableComponent, specifica un resizeEventListener che gestisca gli eventi di aggiornamento. Puoi rispondere a diversi ResizeState eventi, come RESIZE_STATE_ONGOING o RESIZE_STATE_END.

Ecco un esempio di utilizzo di ResizableComponent con proporzioni fisse su un SurfaceEntity:

val resizableComponent = ResizableComponent.create(session) { event ->
    if (event.resizeState == ResizeEvent.ResizeState.END) {
        // update the Entity to reflect the new size
        surfaceEntity.shape = SurfaceEntity.Shape.Quad(FloatSize2d(event.newSize.width, event.newSize.height))
    }
}
resizableComponent.minimumEntitySize = FloatSize3d(177f, 100f, 1f)
resizableComponent.isFixedAspectRatioEnabled = true // Maintain a fixed aspect ratio when resizing

surfaceEntity.addComponent(resizableComponent)

Utilizzare InteractableComponent per acquisire eventi di input dell'utente

Il InteractableComponent consente di acquisire eventi di input dell'utente, ad esempio quando l'utente interagisce con un Entity o passa il mouse sopra di esso. Quando crei un InteractableComponent, specifica un listener che riceva gli eventi di input. Quando l'utente esegue un'azione di input, il listener viene chiamato con le informazioni di input fornite nel InputEvent parametro.

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 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.RIGHT) {
            entity.setScale(1.5f)
        } else if (it.pointerType == InputEvent.Pointer.LEFT) {
            entity.setScale(0.5f)
        }
    }
}
entity.addComponent(interactableComponent)

Creare modelli 3D personalizzati in fase di runtime

L'API Mesh personalizzata consente di generare forme 3D in modo programmatico direttamente nel codice, anziché caricare asset statici come i file glTF. Creando una geometria personalizzata al volo, puoi eseguire il rendering di dati procedurali, forme personalizzate dinamiche e ambienti 3D apparentemente infiniti, come rilievi che vengono generati continuamente man mano che gli utenti esplorano. Inoltre, la generazione di mesh in fase di runtime contribuisce a ridurre le dimensioni dei file binari eliminando la necessità di pacchettizzare innumerevoli varianti di un singolo asset 3D.