Pakiet Jetpack XR SDK umożliwia tworzenie, kontrolowanie i zarządzanie instancjami Entity
, takimi jak modele 3D, filmy stereoskopowe i PanelEntity
, za pomocą pakietu Jetpack SceneCore.
Jetpack SceneCore wykorzystuje 2 popularne wzorce architektoniczne, aby obsługiwać tworzenie aplikacji 3D: graf sceny i system komponentów jednostek (ECS).
Tworzenie i kontrolowanie obiektów za pomocą wykresu sceny
Aby tworzyć obiekty w przestrzeni 3D i nimi sterować, możesz użyć interfejsu Session API z Jetpack SceneCore, aby uzyskać dostęp do wykresu sceny. Graf sceny jest zgodny ze światem rzeczywistym użytkownika i umożliwia organizowanie obiektów 3D, takich jak panele i modele 3D, w strukturę hierarchiczną oraz przechowywanie stanu tych obiektów.
Po uzyskaniu dostępu do wykresu sceny możesz używać interfejsów API w Jetpack Compose for XR do tworzenia interfejsu przestrzennego (np. instancji SpatialPanel
i Orbiter
) w ramach wykresu 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 przestrzeni aktywności na tej stronie.
System komponentów encji
System komponentów i encji jest zgodny z zasadą kompozycji zamiast dziedziczenia. Możesz rozszerzyć działanie elementów, dołączając komponenty definiujące zachowanie, co pozwala stosować to samo zachowanie do różnych typów elementów. Więcej informacji znajdziesz w sekcji Dodawanie do encji wspólnych zachowań na tej stronie.
Informacje o ActivitySpace
Każdy Session
ma ActivitySpace
, który jest tworzony automatycznie wraz z Session
. ActivitySpace
to element Entity
najwyższego poziomu w grafie sceny.
ActivitySpace to przestrzeń trójwymiarowa z prawoskrętnym układem współrzędnych (oś X jest skierowana w prawo, oś Y w górę, a oś Z do tyłu względem początku układu współrzędnych) i jednostkami w metrach, które odpowiadają rzeczywistym wymiarom. Początek układu współrzędnych ActivitySpace
jest nieco arbitralny (użytkownicy mogą zresetować położenie ActivitySpace
w rzeczywistym świecie), dlatego zalecamy pozycjonowanie treści względem siebie, a nie względem początku układu współrzędnych.
Praca z encjami
Encje są kluczowym elementem SceneCore. Większość elementów, które użytkownik widzi i z którymi wchodzi w interakcję, to obiekty reprezentujące panele, modele 3D i inne elementy.
Ponieważ ActivitySpace
jest węzłem najwyższego poziomu w grafie sceny, domyślnie wszystkie nowe elementy są umieszczane bezpośrednio w ActivitySpace
. Możesz przenieść elementy wzdłuż wykresu sceny, wywołując funkcję setParent()
lub addChild()
.
Obiekty mają pewne domyślne zachowania w przypadku elementów uniwersalnych dla wszystkich obiektów, takich jak zmiana pozycji, obrotu lub widoczności. Poszczególne Entity
podklasy, takie jak GltfModelEntity
, mają dodatkowe zachowania, które obsługują podklasę.
Manipulowanie encjami
Jeśli wprowadzisz zmianę we właściwości Entity
należącej do klasy bazowej Entity
, zostanie ona zastosowana do wszystkich jej elementów podrzędnych. Na przykład zmiana Pose
elementu nadrzędnego Entity
powoduje, że wszystkie elementy podrzędne
mają taką samą zmianę. Zmiana w podrzędnym elemencie Entity
nie ma wpływu na element nadrzędny.
Symbol Pose
reprezentuje lokalizację i obrót jednostki w przestrzeni 3D. Lokalizacja to Vector3
składający się z wartości liczbowych x, y i z. Obrót jest oznaczony symbolem Quaternion
. Położenie Entity
jest zawsze względne w stosunku do elementu nadrzędnego. Innymi słowy, Entity
, którego pozycja to (0, 0, 0), zostanie umieszczony w punkcie początkowym jednostki nadrzędnej.
// 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 do encji typowych zachowań
Aby dodać do obiektów typowe zachowania, 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 wzorców interfejsu.InteractableComponent
: umożliwia rejestrowanie zdarzeń wejściowych w przypadku interakcji niestandardowych.
Tworzenie instancji komponentów musi odbywać się za pomocą odpowiedniej metody tworzenia w klasie Session
. Na przykład aby utworzyć ResizableComponent
, wywołaj
ResizableComponent.create()
.
Aby dodać do elementu Entity
określone działanie komponentu, użyj metody addComponent()
.
Używanie MovableComponent
, aby umożliwić użytkownikowi przesuwanie obiektu
MovableComponent
umożliwia użytkownikowi przesuwanie Entity
. Możesz też określić, czy element może być przytwierdzony do określonego typu powierzchni, np. poziomej lub pionowej, albo do konkretnych powierzchni semantycznych, takich jak stół, ściana lub sufit. Aby określić opcje kotwicy, podczas tworzenia elementu MovableComponent
podaj zestaw AnchorPlacement
.
Oto przykład obiektu, który można przesuwać i przytwierdzać 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 przesuwa element, parametr scaleInZ
automatycznie dostosowuje jego skalę, gdy oddala się od użytkownika, podobnie jak system skaluje panele w przestrzeni domowej. 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 kodu ResizableComponent
, aby umożliwić zmianę rozmiaru jednostki przez użytkownika
ResizableComponent
umożliwia użytkownikom zmianę rozmiaru Entity
. ResizableComponent
zawiera wizualne wskazówki dotyczące interakcji, które zachęcają użytkownika do zmiany rozmiaru Entity
. Podczas tworzenia ResizableComponent
możesz określić minimalny lub maksymalny rozmiar (w metrach). Podczas zmiany rozmiaru możesz też określić stały współczynnik proporcji, aby szerokość i wysokość zmieniały się proporcjonalnie względem siebie.
Gdy używasz ResizableComponent
, musisz określić ResizeListener
, aby odpowiadać na konkretne zdarzenia zmiany rozmiaru, takie jak onResizeUpdate
lub onResizeEnd
.
Oto przykład użycia właściwości ResizableComponent
ze stałymi proporcjami na urządzeniu 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)
Używaj InteractableComponent
do rejestrowania zdarzeń związanych z działaniami użytkownika
InteractableComponent
umożliwia rejestrowanie zdarzeń wejściowych od użytkownika, takich jak interakcja z elementem Entity
lub najechanie na niego kursorem. Podczas tworzenia InteractableComponent
musisz określić InputEventListener
, aby odbierać zdarzenia wejściowe. Gdy użytkownik wykona dowolną czynność związaną z wprowadzaniem danych, zostanie wywołana metoda onInputEvent
z informacjami o wprowadzonych danych podanymi w parametrze InputEvent
.
InputEvent.action
określa typ działania, np. najechanie lub kliknięcie elementu.InputEvent.source
określa, skąd pochodzi dane wejściowe, np. z ręki lub kontrolera.InputEvent.pointerType
określa, czy dane wejściowe pochodzą z prawej czy lewej ręki.
Pełną listę wszystkich stałych InputEvent
znajdziesz w dokumentacji.
Poniższy fragment kodu pokazuje przykład użycia InteractableComponent
do powiększania obiektu prawą ręką i zmniejszania go 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)