Créer, contrôler et gérer des entités

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és
  • ResizableComponent: permet à l'utilisateur de redimensionner des entités avec des modèles d'UI cohérents
  • InteractableComponent: 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.

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)