Le SDK Jetpack XR vous permet d'utiliser Jetpack SceneCore pour créer, contrôler et gérer
Entity instances, telles que des modèles 3D, des vidéos stéréoscopiques et
PanelEntity à l'aide de Jetpack SceneCore.
Jetpack SceneCore adopte deux modèles architecturaux courants pour prendre en charge le développement 3D : un graphique de scène et un système composant d'entité (ECS).
Utiliser le graphique de scène pour créer et contrôler des entités
Pour créer et contrôler des objets dans un espace 3D, vous pouvez utiliser l'API Session de Jetpack SceneCore pour accéder au graphique 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ès au graphique de scène, vous pouvez utiliser les API de Jetpack
Compose pour XR afin de créer une interface utilisateur spatiale (par exemple, SpatialPanel et
Orbiter instances) dans le graphique de scène. Pour le contenu 3D tel que les modèles 3D, vous pouvez accéder directement à la session. Pour en savoir plus, consultez la section À propos de l'
ActivitySpace sur cette page.
Système composant d'entité
Un système composant d'entité suit le principe de composition par rapport à l'héritage. Vous pouvez étendre le comportement des entités en associant des composants de définition du 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 de l'ActivitySpace
Chaque Session possède un ActivitySpace qui est créé automatiquement
avec la Session. ActivitySpace est l'Entity de premier niveau dans le graphique de scène.
L'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 vers le haut et l'axe Z vers l'arrière par rapport à l'origine) et avec des mètres pour les unités qui correspondent au monde réel. L'origine de ActivitySpace est quelque peu arbitraire (car les utilisateurs peuvent réinitialiser la position de l'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 essentielles à 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 l'ActivitySpace est le nœud de premier niveau du graphique de scène, toutes les nouvelles entités sont placées directement dans l'ActivitySpace par défaut. Vous pouvez déplacer
des entités le long du graphique de scène en définissant leur parent ou en utilisant
addChild().
Les entités ont des comportements par défaut pour les éléments universels à toutes les entités, tels que le changement de position, de rotation ou de visibilité. Les Entity
sous-classes spécifiques, comme GltfModelEntity, ont des comportements supplémentaires qui
prennent en charge la sous-classe.
Manipuler des entités
Lorsque vous modifiez une propriété Entity appartenant à la classe Entity de base, la modification est répercutée sur tous ses enfants. Par exemple,
si vous ajustez le Pose d'un Entity parent, tous ses enfants
auront le même ajustement. Une modification apportée à une Entity enfant n'a pas d'incidence sur son parent.
Une 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'une Entity est toujours relative à son entité parente. En d'autres termes, une Entity dont la position est (0, 0, 0) sera placée à l'origine de son entité parente.
// 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))
Pour désactiver un Entity, utilisez setEnabled(). Elle devient invisible et arrête tout traitement effectué sur elle.
// Disable the entity. entity.setEnabled(false)
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: vous permet de capturer des événements d'entrée pour des 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
ResizableComponent.create().
Pour ajouter le comportement spécifique du composant à un Entity utilisez la
addComponent() méthode.
Utiliser MovableComponent pour rendre une entité déplaçable par l'utilisateur
Le MovableComponent permet à une Entity d'être déplaçable par l'utilisateur.
Les événements de mouvement sont envoyés au composant lorsque l'utilisateur interagit avec les décorations. Le comportement par défaut du système, créé avec
MovableComponent.createSystemMovable(), déplace votre Entity lorsque les
décorations sont déplacées :
val movableComponent = MovableComponent.createSystemMovable(session) entity.addComponent(movableComponent)
Le paramètre facultatif scaleInZ (défini sur true par défaut) permet à l'entité
d'ajuster automatiquement son échelle lorsqu'elle s'éloigne de l'utilisateur,
de la même manière que les panneaux sont mis à l'échelle par le système dans l'espace d'accueil.
En raison de la nature "en cascade" du système composant d'entité, l'échelle du parent aura une incidence sur tous ses enfants.
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 les options d'ancrage, spécifiez un ensemble de AnchorPlacement
lors de la création du MovableComponent. Dans cet exemple, l'entité peut être déplacée et ancrée sur n'importe quelle surface horizontale de sol ou de table :
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)
Utiliser ResizableComponent pour rendre une entité redimensionnable par l'utilisateur
Le ResizableComponent permet aux utilisateurs de redimensionner une Entity. Le ResizableComponent inclut des repères d'interaction visuels qui invitent l'utilisateur à redimensionner une Entity. Lorsque vous créez le ResizableComponent, vous pouvez spécifier une taille minimale ou maximale (en mètres). Vous avez également la possibilité de spécifier un format d'image fixe lors du redimensionnement afin que la largeur et la hauteur soient redimensionnées proportionnellement l'une à l'autre.
Lorsque vous créez un ResizableComponent, spécifiez un resizeEventListener qui gère les événements de mise à jour. Vous pouvez répondre à différents ResizeState
événements, tels que RESIZE_STATE_ONGOING ou RESIZE_STATE_END.
Voici un exemple d'utilisation du ResizableComponent avec un format d'image fixe sur une 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)
Utiliser InteractableComponent pour capturer les événements d'entrée utilisateur
Le InteractableComponent vous permet de capturer les événements d'entrée de l'utilisateur,
par exemple lorsque l'utilisateur interagit avec un Entity ou le survole. Lorsque vous créez un InteractableComponent, spécifiez un écouteur qui reçoit les événements d'entrée.
Lorsque l'utilisateur effectue une action d'entrée, l'écouteur est appelé avec les
informations d'entrée fournies dans le InputEvent paramètre.
InputEvent.actionspécifie le type d'entrée, par exemple le survol ou l'appui sur une entité.InputEvent.sourcespécifie la source de l'entrée, par exemple une entrée manuelle ou un contrôleur.InputEvent.pointerTypespécifie 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 un exemple d'utilisation d'un InteractableComponent pour augmenter la taille d'une entité avec la main droite et la diminuer avec la main gauche.
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)
Créer des modèles 3D personnalisés au moment de l'exécution
L'API Custom Mesh vous permet de générer des formes 3D par programmation directement dans votre code, au lieu de charger des assets statiques tels que des fichiers glTF. En créant une géométrie personnalisée à la volée, vous pouvez afficher des données procédurales, des formes personnalisées dynamiques et des environnements 3D apparemment infinis, tels que des terrains qui se génèrent en continu lorsque vos utilisateurs les explorent. De plus, la génération de maillages au moment de l'exécution contribue à réduire la taille des binaires en éliminant la nécessité d'empaqueter d'innombrables variations d'un seul asset 3D.