Le SDK Jetpack XR vous permet d'utiliser Jetpack SceneCore pour créer, contrôler et gérer des instances Entity
telles que des modèles 3D, des vidéos stéréoscopiques et des PanelEntity
à l'aide de Jetpack SceneCore.
Jetpack SceneCore adopte deux modèles d'architecture courants pour prendre en charge le développement 3D: un graphique de scène et un système d'entité-composant (ECS).
Utiliser le graphisme de scène pour créer et contrôler des entités
Pour créer et contrôler des objets dans l'espace 3D, vous devez utiliser l'API Session de Jetpack SceneCore pour accéder au graphe de scène. Le graphique de scène s'aligne sur le monde réel de l'utilisateur et vous permet d'organiser des entités 3D telles que des panneaux et des modèles 3D dans une structure hiérarchique, et de conserver l'état de ces entités.
Une fois que vous avez accédé au graphisme de scène, vous pouvez utiliser les API de Jetpack Compose pour XR pour créer une UI spatiale (par exemple, SpatialPanel
et Orbiter
) dans le graphisme de scène. Pour les contenus 3D tels que les modèles 3D, vous pouvez accéder directement à la session. Pour en savoir plus, consultez la section À propos d'ActivitySpace sur cette page.
Système de composants d'entités
Un système d'entité-composant suit le principe de composition plutôt que d'héritage. Vous pouvez étendre le comportement des entités en y associant des composants définissant le comportement, ce qui vous permet d'appliquer le même comportement à différents types d'entités. Pour en savoir plus, consultez la section Ajouter un comportement commun aux entités sur cette page.
À propos d'ActivitySpace
Chaque Session
possède un ActivitySpace
créé automatiquement avec le Session
. ActivitySpace
est le Entity
de niveau supérieur dans le graphique de scène.
ActivitySpace représente un espace tridimensionnel avec un système de coordonnées "main droite" (l'axe X pointe vers la droite, l'axe Y pointe vers le haut et l'axe Z vers l'arrière par rapport à l'origine) et avec des mètres pour les unités correspondant au monde réel. L'origine de ActivitySpace
est quelque peu arbitraire (car les utilisateurs peuvent réinitialiser la position de ActivitySpace
dans le monde réel). Il est donc recommandé de positionner le contenu les uns par rapport aux autres plutôt que par rapport à l'origine.
Utiliser des entités
Les entités sont au cœur de SceneCore. La plupart des éléments que l'utilisateur voit et avec lesquels il interagit sont des entités représentant des panneaux, des modèles 3D, etc.
Étant donné que ActivitySpace
est le nœud de premier niveau du graphique de scène, toutes les nouvelles entités sont placées directement dans ActivitySpace
par défaut. Vous pouvez déplacer des entités le long du graphique de scène en appelant setParent
ou addChild
.
Les entités présentent certains comportements par défaut pour des éléments universels pour toutes les entités, tels que le changement de position, de rotation ou de visibilité. Des sous-classes Entity
spécifiques, comme GltfEntity
, présentent des comportements supplémentaires compatibles avec la sous-classe.
Manipuler des entités
Lorsque vous modifiez une propriété Entity
appartenant à la classe Entity
de base, le changement est appliqué en cascade à tous ses enfants. Par exemple, si vous ajustez le Pose
d'un Entity
parent, tous ses enfants subiront le même ajustement. Modifier un Entity
enfant n'a aucune incidence sur son parent.
Un Pose
représente l'emplacement et la rotation de l'entité dans l'espace 3D. L'emplacement est un Vector3
composé de positions numériques X, Y et Z. La rotation est représentée par un Quaternion
. La position d'un Entity
est toujours relative à son entité parente. En d'autres termes, un Entity
dont la position est (0, 0, 0) sera placé à l'origine de son entité parente.
//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))
Entity
Pour modifier la visibilité d'un Entity
, utilisez setHidden
.
//hide the entity
entity.setHidden(true)
Pour redimensionner un Entity
tout en conservant sa forme globale, utilisez setScale
.
//double the size of the entity
entity.setScale(2f)
Ajouter un comportement commun aux entités
Vous pouvez utiliser les composants suivants pour ajouter un comportement commun aux entités:
MovableComponent
: permet à l'utilisateur de déplacer des entitésResizableComponent
: permet à l'utilisateur de redimensionner des entités avec des modèles d'UI cohérentsInteractableComponent
: permet de capturer des événements d'entrée pour les interactions personnalisées
L'instanciation des composants doit être effectuée via la méthode de création appropriée dans la classe Session
. Par exemple, pour créer un ResizableComponent
, appelez session.createResizableComponent()
.
Pour ajouter le comportement spécifique du composant à un Entity
, utilisez la méthode addComponent()
.
Utiliser MovableComponent pour permettre à l'utilisateur de déplacer une entité
MovableComponent
permet à l'utilisateur de déplacer un Entity
. Vous pouvez également spécifier si l'entité peut être ancrée à un type de surface, comme des surfaces horizontales ou verticales, ou à des surfaces sémantiques spécifiques, comme une table, un mur ou un plafond. Pour spécifier des options d'ancrage, spécifiez un ensemble de AnchorPlacement
lors de la création de l'MovableComponent
.
Voici un exemple d'entité pouvant être déplacée et ancrée à n'importe quelle surface verticale, et uniquement aux surfaces horizontales du sol et du plafond.
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)
Utiliser ResizableComponent pour permettre à l'utilisateur de redimensionner une entité
ResizableComponent
permet aux utilisateurs de redimensionner un Entity
. ResizableComponent
inclut des indices d'interaction visuelle qui invitent l'utilisateur à redimensionner un Entity
. Lorsque vous créez le ResizeableComponent
, vous pouvez spécifier une taille minimale ou maximale (en mètres). Vous pouvez également spécifier un format fixe lors du redimensionnement afin que la largeur et la hauteur soient redimensionnées proportionnellement l'une à l'autre.
Voici un exemple d'utilisation de ResizableComponent
avec un format fixe:
val resizableComponent = xrSession.createResizableComponent()
resizableComponent.minimumSize = Dimensions(177f, 100f, 1f )
resizableComponent.fixedAspectRatio = 16f / 9f //Specify a 16:9 aspect ratio
entity.addComponent(resizableComponent)
Utiliser InteractableComponent pour capturer les événements d'entrée utilisateur
InteractableComponent
vous permet de capturer les événements d'entrée de l'utilisateur, par exemple lorsqu'il interagit avec un Entity
ou le survole.
Lorsque vous créez un InteractableComponent
, vous devez spécifier un InputEventListener
pour recevoir les événements d'entrée. Lorsque l'utilisateur effectue une action d'entrée, la méthode onInputEvent
est appelée avec les informations d'entrée spécifiques fournies dans le paramètre InputEvent
.
InputEvent.action
spécifie le type d'entrée, comme le pointage ou le tapotement(ACTION_DOWN) sur une entité.InputEvent.source
spécifie la source de l'entrée, par exemple une entrée manuelle ou contrôleur.InputEvent.pointerType
indique si l'entrée provient de la main droite ou de la main gauche.
Pour obtenir la liste complète de toutes les constantes InputEvent
, consultez la documentation de référence.
L'extrait de code suivant montre comment utiliser un InteractableComponent
pour augmenter la taille d'une entité avec la main droite et la réduire avec la main gauche.
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)