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 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 entité-composant (ECS, Entity-Component System).
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 les entités 3D telles que les panneaux et les 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 UI spatiale (par exemple, des instances SpatialPanel
et Orbiter
) dans le graphique 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 À propos d'ActivitySpace sur cette page.
Système de composants d'entités
Un système 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 qui définissent le comportement. Cela vous permet d'appliquer le même comportement à différents types d'entités. Pour en savoir plus, consultez Ajouter un comportement commun aux entités sur cette page.
À propos d'ActivitySpace
Chaque Session
possède un ActivitySpace
qui est créé automatiquement avec le Session
. ActivitySpace
est le Entity
de premier niveau 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 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 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, par défaut, toutes les nouvelles entités sont placées directement dans ActivitySpace
. Vous pouvez déplacer des entités le long du graphique de scène en appelant setParent()
ou addChild()
.
Les entités ont des comportements par défaut pour les éléments universels à toutes les entités, comme la modification de la position, de la rotation ou de la visibilité. Certaines sous-classes Entity
, 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. Si vous apportez une modification à un Entity
enfant, cela n'aura 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 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 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 courant aux entités :
MovableComponent
: permet à l'utilisateur de déplacer des entités.ResizableComponent
: permet à l'utilisateur de redimensionner les entités avec des modèles d'UI cohérents.InteractableComponent
: vous permet de capturer des événements d'entrée pour des interactions personnalisées.
L'instanciation des composants doit être effectuée à l'aide de 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 méthode addComponent()
.
Utiliser MovableComponent
pour rendre une entité déplaçable par l'utilisateur
Le 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 une surface horizontale ou verticale, ou à des surfaces sémantiques spécifiques, comme une table, un mur ou un plafond. Pour spécifier des options d'ancrage, indiquez un ensemble de AnchorPlacement
lors de la création de MovableComponent
.
Voici un exemple d'entité qui peut être déplacée et ancrée sur n'importe quelle surface verticale et uniquement sur les surfaces horizontales du sol et du plafond.
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)
Lorsque l'utilisateur déplace l'entité, le paramètre scaleInZ
ajuste automatiquement son échelle à mesure qu'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 personnel. En raison de la nature "en cascade" du système de composants d'entité, l'échelle du parent aura un impact sur tous ses enfants.
Utiliser ResizableComponent
pour redimensionner une entité
ResizableComponent
permet aux utilisateurs de redimensionner un Entity
. Le ResizableComponent
inclut des repères visuels d'interaction qui invitent l'utilisateur à redimensionner un Entity
. Lorsque vous créez le ResizableComponent
, 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 par rapport à l'autre.
Lorsque vous utilisez ResizableComponent
, vous devez spécifier un ResizeListener
pour répondre à des événements de redimensionnement spécifiques tels que onResizeUpdate
ou onResizeEnd
.
Voici un exemple d'utilisation de ResizableComponent
avec un format fixe sur 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)
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 survoler ou appuyer sur une entité.InputEvent.source
spécifie la source de l'entrée, par exemple l'entrée manuelle ou avec la manette.InputEvent.pointerType
spé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 comment utiliser 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_TYPE_RIGHT) { entity.setScale(1.5f) } else if (it.pointerType == InputEvent.POINTER_TYPE_LEFT) { entity.setScale(0.5f) } } } entity.addComponent(interactableComponent)