Entitäten erstellen, steuern und verwalten

Mit dem Jetpack XR SDK können Sie mit Jetpack SceneCore Entity-Instanzen wie 3D-Modelle, stereoskopische Videos und PanelEntity erstellen, steuern und verwalten.

Jetpack SceneCore verwendet zwei gängige Architekturmuster zur Unterstützung der 3D-Entwicklung: einen Szenengraphen und ein Entity-Component-System (ECS).

Szenengraph zum Erstellen und Steuern von Entitäten verwenden

Wenn Sie Objekte im 3D-Raum erstellen und steuern möchten, können Sie mit der Session API von Jetpack SceneCore auf den Szenengraphen zugreifen. Der Szenengraph entspricht der realen Welt des Nutzers und ermöglicht es Ihnen, 3D-Objekte wie Panels und 3D-Modelle in einer hierarchischen Struktur zu organisieren und den Status dieser Objekte zu speichern.

Sobald Sie Zugriff auf den Szenengraphen haben, können Sie die APIs in Jetpack Compose für XR verwenden, um räumliche Benutzeroberflächen zu erstellen, z. B. SpatialPanel- und Orbiter-Instanzen im Szenengraphen. Bei 3D-Inhalten wie 3D-Modellen können Sie direkt auf die Sitzung zugreifen. Weitere Informationen finden Sie auf dieser Seite unter ActivitySpace.

Entitätskomponentensystem

Ein Entity-Component-System folgt dem Prinzip der Komposition über Vererbung. Sie können das Verhalten von Entitäten erweitern, indem Sie verhaltensdefinierende Komponenten anhängen. So können Sie dasselbe Verhalten auf verschiedene Arten von Entitäten anwenden. Weitere Informationen finden Sie auf dieser Seite unter Gemeinsames Verhalten für Entitäten hinzufügen.

Informationen zum ActivitySpace

Jede Session hat eine ActivitySpace, die automatisch mit der Session erstellt wird. Die ActivitySpace ist die Entity der obersten Ebene im Szenengraphen.

Der ActivitySpace ist ein dreidimensionaler Raum mit einem rechtshändigen Koordinatensystem (die x-Achse zeigt nach rechts, die y-Achse nach oben und die z-Achse nach hinten relativ zum Ursprung) und mit Metern als Einheiten, die der realen Welt entsprechen. Der Ursprung für ActivitySpace ist etwas willkürlich, da Nutzer die Position von ActivitySpace in der realen Welt zurücksetzen können. Daher empfiehlt es sich, Inhalte relativ zueinander statt relativ zum Ursprung zu positionieren.

Mit Entitäten arbeiten

Entitäten sind ein zentraler Bestandteil von SceneCore. Fast alles, was der Nutzer sieht und mit dem er interagiert, sind Einheiten, die Bereiche, 3D-Modelle und mehr darstellen.

Da ActivitySpace der Knoten der obersten Ebene des Szenengraphen ist, werden standardmäßig alle neuen Entitäten direkt in ActivitySpace platziert. Sie können Objekte im Szenengraphen verschieben, indem Sie setParent() oder addChild() aufrufen.

Für Entitäten gibt es einige Standardverhalten für Dinge, die für alle Entitäten universell sind, z. B. das Ändern von Position, Drehung oder Sichtbarkeit. Bestimmte Entity-Unterklassen wie GltfModelEntity haben zusätzliches Verhalten, das die Unterklasse unterstützt.

Entitäten bearbeiten

Wenn Sie eine Änderung an einer Entity-Property vornehmen, die zur Basisklasse Entity gehört, wird die Änderung auf alle untergeordneten Elemente übertragen. Wenn Sie beispielsweise die Pose eines übergeordneten Entity anpassen, wird die Anpassung auf alle untergeordneten Elemente angewendet. Wenn Sie eine Änderung in einem untergeordneten Entity vornehmen, hat das keine Auswirkungen auf das übergeordnete Entity.

Ein Pose-Element stellt die Position und Rotation der Entität im 3D-Raum dar. Der Ort ist ein Vector3, der aus numerischen X-, Y- und Z-Positionen besteht. Die Rotation wird durch eine Quaternion dargestellt. Die Position eines Entity ist immer relativ zur übergeordneten Entität. Ein Entity mit der Position (0, 0, 0) wird also am Ursprung seiner übergeordneten Entität platziert.

// 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))

Wenn Sie die Sichtbarkeit eines Entity ändern möchten, verwenden Sie setHidden().

// Hide the entity
entity.setHidden(true)

Wenn Sie die Größe eines Entity ändern möchten, ohne die Gesamtform zu verändern, verwenden Sie setScale().

// Double the size of the entity
entity.setScale(2f)

Entitäten gemeinsames Verhalten hinzufügen

Mit den folgenden Komponenten können Sie Entitäten häufig verwendete Verhaltensweisen hinzufügen:

  • MovableComponent: Ermöglicht dem Nutzer, Einheiten zu verschieben.
  • ResizableComponent: Ermöglicht dem Nutzer, die Größe von Einheiten mit einheitlichen UI-Mustern zu ändern.
  • InteractableComponent: Ermöglicht das Erfassen von Eingabeereignissen für benutzerdefinierte Interaktionen.

Das Instanziieren von Komponenten muss über die entsprechende Erstellungsmethode in der Klasse Session erfolgen. Wenn Sie beispielsweise ein ResizableComponent erstellen möchten, rufen Sie ResizableComponent.create() auf.

Verwenden Sie die Methode addComponent(), um einem Entity das spezifische Komponentenverhalten hinzuzufügen.

MovableComponent verwenden, um eine Entität für Nutzer verschiebbar zu machen

Mit dem MovableComponent kann der Nutzer das Entity verschieben. Sie können auch angeben, ob das Objekt an einem Oberflächentyp wie horizontalen oder vertikalen Oberflächen oder an bestimmten semantischen Oberflächen wie Tisch, Wand oder Decke verankert werden kann. Wenn Sie Ankeroptionen angeben möchten, geben Sie beim Erstellen von MovableComponent eine Reihe von AnchorPlacement an.

Hier ist ein Beispiel für ein Objekt, das verschoben und an einer beliebigen vertikalen Oberfläche sowie nur an horizontalen Oberflächen von Boden und Decke verankert werden kann.

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)

Wenn der Nutzer das Objekt bewegt, wird der scaleInZ-Parameter automatisch an die Größe des Objekts angepasst, wenn es sich vom Nutzer entfernt. Das ist ähnlich wie bei der Skalierung von Feldern durch das System im Home-Bereich. Aufgrund der „kaskadierenden“ Natur des Entity-Komponentensystems wirkt sich die Skalierung des übergeordneten Elements auf alle untergeordneten Elemente aus.

ResizableComponent verwenden, um die Größe einer Entität durch Nutzer anpassen zu lassen

Mit dem ResizableComponent können Nutzer die Größe eines Entity ändern. Die ResizableComponent enthält visuelle Hinweise, die den Nutzer auffordern, die Größe einer Entity zu ändern. Beim Erstellen der ResizableComponent können Sie eine Mindest- oder Maximalgröße (in Metern) angeben. Sie haben auch die Möglichkeit, beim Ändern der Größe ein festes Seitenverhältnis anzugeben, sodass Breite und Höhe proportional zueinander angepasst werden.

Wenn Sie die ResizableComponent verwenden, müssen Sie eine ResizeListener angeben, um auf bestimmte Größenänderungsereignisse wie onResizeUpdate oder onResizeEnd zu reagieren.

Hier ein Beispiel für die Verwendung von ResizableComponent mit einem festen Seitenverhältnis auf einem 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)

InteractableComponent verwenden, um Nutzer-Eingabeereignisse zu erfassen

Mit InteractableComponent können Sie Eingabeereignisse vom Nutzer erfassen, z. B. wenn er mit einem Entity interagiert oder den Mauszeiger darauf bewegt. Wenn Sie ein InteractableComponent erstellen, müssen Sie ein InputEventListener angeben, um die Eingabeereignisse zu empfangen. Wenn der Nutzer eine Eingabeaktion ausführt, wird die Methode onInputEvent mit den spezifischen Eingabeinformationen aufgerufen, die im Parameter InputEvent angegeben sind.

Eine vollständige Liste aller InputEvent-Konstanten finden Sie in der Referenzdokumentation.

Das folgende Code-Snippet zeigt ein Beispiel für die Verwendung eines InteractableComponent-Objekts, um die Größe eines Objekts mit der rechten Hand zu erhöhen und mit der linken Hand zu verringern.

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)