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 di architettura comuni per supportare lo sviluppo 3D: un grafo della scena e un sistema di componenti-entità (ECS).
Utilizzare la scena di grafo per creare e controllare le entità
Per creare e controllare gli oggetti nello spazio 3D, devi utilizzare l'API Session di Jetpack SceneCore per accedere al grafo della scena. La scena è in linea con il mondo reale dell'utente e ti consente di organizzare entità 3D come pannelli e modelli 3D in una struttura gerarchica e di mantenere lo stato di queste entità.
Dopo aver ottenuto l'accesso al grafo della scena, puoi utilizzare le API di Jetpack Compose per XR per creare un'interfaccia utente spaziale (ad esempio SpatialPanel
e Orbiter
) all'interno del grafo 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 di componenti delle entità
Un sistema di entità e componenti segue il principio della composizione rispetto all'eredità. Puoi espandere il comportamento delle entità collegando componenti che definiscono il comportamento, in modo da 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 Session
. ActivitySpace
è il Entity
di primo livello nel grafo della scena.
ActivitySpace rappresenta uno spazio tridimensionale con un sistema di coordinate destrorso (l'asse x punta verso destra, l'asse y verso l'alto e l'asse z all'indietro rispetto all'origine) e con metri per le unità corrispondenti al mondo reale. L'origine di ActivitySpace
è in qualche modo arbitraria (poiché gli utenti possono reimpostare la posizione di ActivitySpace
nel mondo reale), pertanto è consigliabile posizionare i contenuti in base a un punto di riferimento diverso dall'origine.
Lavorare con 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 della scena, per impostazione predefinita tutte le nuove entità vengono inserite direttamente in ActivitySpace
. Puoi spostare le entità lungo il grafo della scena chiamando setParent
o addChild
.
Le entità hanno alcuni comportamenti predefiniti per elementi universali per tutte le entità, ad esempio la modifica della posizione, della rotazione o della visibilità. Classi di Entity
particolari, come GltfEntity
, 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 verrà applicata a cascata a tutti i relativi elementi secondari. Ad esempio, se modifichi Pose
di un elemento principale Entity
, tutti i suoi elementi secondari avranno lo stesso aggiustamento. La modifica di 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, 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 sua entità principale.
//place the entity forward 2 meters
val modelPosition = 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 generale, utilizza
setScale
.
//double the size of the entity
entity.setScale(2f)
Aggiungere un comportamento comune alle entità
Per aggiungere un comportamento comune alle entità, puoi utilizzare i seguenti componenti:
MovableComponent
: consente all'utente di spostare le entitàResizableComponent
: consente all'utente di ridimensionare le entità con pattern di UI coerentiInteractableComponent
: consente di acquisire eventi di input per interazioni personalizzate
L'inizializzazione dei componenti deve essere eseguita tramite il metodo di creazione appropriato nella classe Session
. Ad esempio, per creare un ResizableComponent
, chiama
session.createResizableComponent()
.
Per aggiungere il comportamento specifico del componente a un Entity
, utilizza il metodo
addComponent()
.
Utilizza MovableComponent per rendere un'entità spostabile dall'utente
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, o a superfici semantiche specifiche come tavolo, parete o soffitto. Per specificare le opzioni di ancoraggio, specifica un insieme di
AnchorPlacement
durante la creazione del MovableComponent
.
Ecco un esempio di entità che può essere spostata e ancorata a qualsiasi superficie verticale e solo a quelle orizzontali del pavimento e del soffitto.
val anchorPlacement = AnchorPlacement.createForPlanes(
planeTypeFilter = setOf(PlaneSemantic.FLOOR, PlaneSemantic.TABLE),
planeSemanticFilter = setOf(PlaneType.VERTICAL))
val movableComponent = xrSession.createMovableComponent(
systemMovable = false,
scaleInZ = false,
anchorPlacement = setOf(anchorPlacement)
)
entity.addComponent(movableComponent)
Utilizza ResizableComponent per rendere un'entità ridimensionabile dall'utente
ResizableComponent
consente agli utenti di ridimensionare un
Entity
. Il ResizableComponent
include indicatori di interazione visiva che invitano
l'utente a ridimensionare un Entity
. Quando crei il ResizeableComponent
, puoi
specificare una dimensione minima o massima (in metri). Hai anche la possibilità di specificare un formato fisso durante il ridimensionamento in modo che la larghezza e l'altezza vengano ridimensionate proporzionalmente l'una all'altra.
Ecco un esempio di utilizzo di ResizableComponent
con un'area immagine fissa:
val resizableComponent = xrSession.createResizableComponent()
resizableComponent.minimumSize = Dimensions(177f, 100f, 1f )
resizableComponent.fixedAspectRatio = 16f / 9f //Specify a 16:9 aspect ratio
entity.addComponent(resizableComponent)
Utilizzare InteractableComponent per acquisire gli eventi di input utente
InteractableComponent
ti consente di acquisire gli eventi di input dell'utente, ad esempio quando interagisce con un Entity
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 inserimento, il metodo onInputEvent
viene chiamato con le informazioni specifiche sull'input fornite nel
parametro InputEvent
.
InputEvent.action
specifica il tipo di input, ad esempio passaggio del mouse o pulsante premuto(ACTION_DOWN) su un'entitàInputEvent.source
specifica la sorgente dell'input, ad esempio l'input con il tocco o con il controllerInputEvent.pointerType
specifica se l'input proviene dalla mano destra o dalla mano sinistra
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.
private val executor by lazy { Executors.newSingleThreadExecutor() }
val interactableComponent = xrSession.createInteractableComponent(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)