Pakiet Jetpack XR SDK umożliwia tworzenie, kontrolowanie i zarządzanie instancjami Entity
, takimi jak modele 3D, filmy stereoskopowe i PanelEntity
, za pomocą Jetpack SceneCore.
Jetpack SceneCore korzysta z 2 popularnych wzorów architektonicznych, aby obsługiwać tworzenie grafiki 3D: graf sceny i system 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, aby tworzyć interfejs 3D (np. instancje SpatialPanel
i Orbiter
) 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 w sekcji Informacje o ActivitySpace na tej stronie.
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 z Session
. ActivitySpace
to najwyższy poziom Entity
w scenie.
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 Entity
podklasy, np. GltfEntity
, mają dodatkowe zachowania, które obsługują tę podklasę.
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 dostosowanie Pose
w elemencie nadrzędnym Entity
powoduje, że wszystkie jego podrzędne elementy Entity
zostaną dostosowane w ten sam sposób. Wprowadzenie zmiany w poziomie podrzędnym Entity
nie ma wpływu na jego jednostkę nadrzędną.
Pose
reprezentuje lokalizację i obrót elementu w przestrzeni 3D. Lokalizacja jest obiektem Vector3
, który zawiera współrzędne x, y i z. Rotacja jest oznaczona symbolem Quaternion
. Pozycja Entity
jest zawsze określana względem elementu nadrzędnego. 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 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ówResizableComponent
: pozwala użytkownikowi zmieniać rozmiary elementów przy zachowaniu spójności w wzorze interfejsu.InteractableComponent
: umożliwia rejestrowanie zdarzeń związanych z danymi wejściowymi 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 na określonym typie powierzchni, np. poziomej lub pionowej, albo na konkretnej powierzchni semantycznej, np. na stole, ścianie lub suficie. 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 jednostek skala elementu nadrzędnego będzie miała wpływ na wszystkie jego elementy podrzędne.
Użyj komponentu ResizableComponent, aby umożliwić użytkownikom zmianę rozmiaru elementu.
ResizableComponent
pozwala użytkownikom zmieniać rozmiar Entity
. ResizableComponent
zawiera wizualne wskazówki dotyczące interakcji, 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 tagu ResieableComponent
, musisz podać wartość 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
Parametr InteractableComponent
umożliwia rejestrowanie zdarzeń związanych z działaniami użytkownika, np. gdy ten klika lub najeżdża kursorem na element Entity
. Podczas tworzenia InteractableComponent
musisz podać InputEventListener
, aby odbierać zdarzenia wejściowe. Gdy użytkownik wykona jakiekolwiek działanie związane z wprowadzaniem danych, zostanie wywołana metoda onInputEvent
z konkretnymi informacjami o danych, które są dostępne w parametrze InputEvent
.
InputEvent.action
określa typ danych wejściowych, np. najechanie kursorem lub kliknięcie elementu.InputEvent.source
określa, skąd pochodzą dane wejściowe, np. ruchy ręki lub sterownika.InputEvent.pointerType
określa, czy dane wejściowe pochodzą z prawej czy z lewej ręki.
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)