Tworzenie, kontrolowanie i zarządzanie elementami

Pakiet SDK Jetpack XR umożliwia korzystanie z Jetpack SceneCore do tworzenia, kontrolowania i zarządzania instancjami Entity, takimi jak modele 3D, filmy stereoskopowePanelEntity za pomocą Jetpack SceneCore.

Jetpack SceneCore korzysta z 2 popularnych wzorów architektonicznych, aby obsługiwać tworzenie grafiki 3D: graf scenysystem obiektów i komponentów (ECS).

Tworzenie i sterowanie elementami za pomocą grafu sceny

Aby tworzyć obiekty w przestrzeni 3D i nimi zarządzać, możesz użyć interfejsu Session API Jetpack SceneCore, aby uzyskać dostęp do grafu sceny. Graf scen jest zgodny ze światem rzeczywistym użytkownika i pozwala na organizowanie obiektów 3D, takich jak panele i modele 3D, w strukturze hierarchicznej oraz przechowywanie stanu tych obiektów.

Po uzyskaniu dostępu do grafu sceny możesz używać interfejsów API w Jetpack Compose for XR do tworzenia interfejsu 3D (np. SpatialPanelOrbiter) w grafie sceny. W przypadku treści 3D, takich jak modele 3D, możesz uzyskać dostęp do sesji bezpośrednio. Więcej informacji znajdziesz na tej stronie w sekcji Informacje o ActivitySpace.

System komponentów encji

System obiektów i komponentów stosuje zasadę kompozycji zamiast dziedziczenia. Możesz rozszerzyć działanie elementów, dołączając komponenty definiujące zachowanie, co pozwoli Ci stosować to samo zachowanie do różnych typów elementów. Więcej informacji znajdziesz na tej stronie w sekcji Dodawanie typowych zachowań do jednostek.

Informacje o ActivitySpace

Każdy Session ma ActivitySpace, który jest automatycznie tworzony wraz z Session. ActivitySpace to najwyższy poziom Entity w grafice sceny.

ActivitySpace reprezentuje przestrzeń trójwymiarową z prawoskrętnym układem współrzędnych (oś X skierowana w prawo, oś Y skierowana w górę, a oś Z skierowana do tyłu względem punktu wyjścia) i z jednostkami odpowiadającymi rzeczywistemu światu. Początek ActivitySpace jest nieco arbitralny (użytkownicy mogą zresetować pozycję ActivitySpace w rzeczywistym świecie), dlatego zalecamy, aby umieszczać treści względem siebie, a nie względem początku.

Praca z elementami

Encje są kluczowe dla SceneCore. Większość elementów, które użytkownik widzi i z którymi wchodzi w interakcje, to elementy reprezentujące panele, modele 3D itp.

Ponieważ węzeł ActivitySpace jest węzłem najwyższego poziomu w grafu sceny, domyślnie wszystkie nowe elementy są umieszczane bezpośrednio w węźle ActivitySpace. Możesz przenosić elementy w grafice sceny, wywołując metodę setParent lub addChild.

Elementy mają pewne domyślne zachowania, które są uniwersalne dla wszystkich elementów, takie jak zmiana pozycji, obrotu lub widoczności. Niektóre podklasy Entity, np. GltfEntity, mają dodatkowe zachowania, które je obsługują.

Manipulowanie elementami

Gdy wprowadzisz zmianę w usłudze Entity należącej do podstawowej klasy Entity, zmiana zostanie zastosowana do wszystkich jej podrzędnych usług. Na przykład zmiana Pose w elemencie nadrzędnym Entity powoduje zmianę wszystkich jego elementów podrzędnych. Zmiana w elementach podrzędnych Entitynie ma wpływu na element nadrzędny.

Pose reprezentuje lokalizację i obrót elementu w przestrzeni 3D. Lokalizacja jest Vector3, która składa się z wartości liczbowych x, y, z. Obrót jest reprezentowany przez Quaternion. Pozycja Entity jest zawsze określana względem jego nadrzędnego elementu. Innymi słowy, Entity o pozycji (0, 0, 0) zostanie umieszczony w początku układu współrzędnych elementu nadrzędnego.

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

Aby zmienić widoczność Entity, użyj setHidden.

// Hide the entity
entity.setHidden(true)

Aby zmienić rozmiar Entity, zachowując jego ogólny kształt, użyj setScale.

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

Dodawanie typowego zachowania do elementów

Aby dodać do elementów wspólne zachowanie, możesz użyć tych komponentów:

  • MovableComponent: umożliwia użytkownikowi przenoszenie elementów
  • ResizableComponent: umożliwia użytkownikowi zmianę rozmiaru elementów za pomocą spójnych wzorów interfejsu.
  • InteractableComponent: umożliwia rejestrowanie zdarzeń wejściowych w przypadku niestandardowych interakcji.

Tworzenie wystąpienia komponentów musi odbywać się za pomocą odpowiedniej metody tworzenia w klasie Session. Na przykład, aby utworzyć element ResizableComponent, wywołaj funkcję ResizableComponent.create().

Aby dodać do Entity określone zachowanie komponentu, użyj metody addComponent().

Użycie komponentu MovableComponent, aby umożliwić użytkownikom przenoszenie elementu.

MovableComponent pozwala użytkownikowi przenosić Entity. Możesz też określić, czy element może być zakotwiczony do typu powierzchni, np. poziomej lub pionowej, czy też do konkretnych powierzchni semantycznych, takich jak stół, ściana czy sufit. Aby określić opcje kotwicy, podczas tworzenia MovableComponent podaj zestaw AnchorPlacement.

Oto przykład obiektu, który można przesuwać i kotwić do dowolnej powierzchni pionowej oraz tylko do poziomych powierzchni podłogi i sufitu.

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)

Gdy użytkownik przenosi element, parametr scaleInZ automatycznie dostosowuje jego skalę, gdy oddala się on od użytkownika, podobnie jak panele są skalowane przez system w pokoju domowym. Ze względu na „kaskadowy” charakter systemu komponentów, skala komponentu nadrzędnego będzie miała wpływ na wszystkie jego komponenty podrzędne.

Użyj komponentu ResizableComponent, aby umożliwić użytkownikom zmianę rozmiaru elementu.

ResizableComponent pozwala użytkownikom zmieniać rozmiar elementu Entity. ResizableComponent zawiera wizualne wskazówki, które zachęcają użytkownika do zmiany rozmiaru Entity. Podczas tworzenia ResizeableComponent możesz określić minimalny lub maksymalny rozmiar (w metrach). Możesz też określić stały współczynnik proporcji podczas zmiany rozmiaru, aby szerokość i wysokość zmieniały się proporcjonalnie do siebie.

Gdy używasz funkcji ResieableComponent, musisz podać parametr ResizeListener, aby reagować na określone zdarzenia zmiany rozmiaru, takie jak onResizeUpdate lub onResizeEnd.

Oto przykład użycia ResizableComponent z ustawionymi proporcjami w przypadku 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)

Wykorzystanie klasy InteractableComponent do rejestrowania zdarzeń wprowadzania danych przez użytkownika

InteractableComponent pozwala rejestrować zdarzenia wprowadzania danych przez użytkownika, np. gdy użytkownik klika lub najeżdża kursorem na element Entity. Podczas tworzenia InteractableComponent musisz podać parametr InputEventListener, aby otrzymywać zdarzenia wejściowe. Gdy użytkownik wykona jakieś działanie związane z wprowadzaniem danych, zostanie wywołana metoda onInputEvent z określonymi informacjami o danych podanymi w parametrze InputEvent.

Pełną listę wszystkich stałych InputEvent znajdziesz w dokumentacji.

Poniższy fragment kodu pokazuje przykład użycia InteractableComponent do zwiększania rozmiaru elementu prawą ręką i zmniejszania lewą ręką.

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)