Создание, контроль и управление сущностями

Jetpack XR SDK позволяет использовать Jetpack SceneCore для создания, контроля и управления экземплярами Entity , такими как 3D-модели , стереоскопическое видео и PanelEntity , с помощью Jetpack SceneCore.

Jetpack SceneCore использует два распространенных архитектурных шаблона для поддержки 3D-разработки: граф сцены и систему «сущность-компонент» (ECS).

Используйте граф сцены для создания и управления сущностями

Для создания и управления объектами в трёхмерном пространстве можно использовать Session API Jetpack SceneCore, чтобы получить доступ к графу сцены. Граф сцены соответствует реальному миру пользователя и позволяет организовывать трёхмерные объекты, такие как панели и 3D-модели, в иерархическую структуру и сохранять состояние этих объектов.

Получив доступ к графу сцены, вы можете использовать API Jetpack Compose для XR для создания пространственного пользовательского интерфейса (например, экземпляров SpatialPanel и Orbiter ) в графе сцены. Для трёхмерного контента, например, 3D-моделей, вы можете получить прямой доступ к сеансу. Подробнее см. в разделе «О ActivitySpace» на этой странице.

Система компонентов сущностей

Система «сущность-компонент» следует принципу композиции, а не наследования. Вы можете расширить поведение сущностей, присоединив компоненты, определяющие их поведение, что позволит применять одно и то же поведение к разным типам сущностей. Подробнее см. в разделе Добавление общего поведения к сущностям на этой странице.

О ActivitySpace

У каждого Session есть ActivitySpace , автоматически создаваемое вместе с Session . ActivitySpace — это Entity верхнего уровня в графе сцены.

ActivitySpace представляет собой трёхмерное пространство с правосторонней системой координат (ось X направлена ​​вправо, ось Y — вверх, а ось Z — назад относительно начала координат) и метрами в качестве единиц измерения, соответствующих реальному миру. Начало координат ActivitySpace в некоторой степени произвольно (поскольку пользователи могут изменять положение ActivitySpace в реальном мире), поэтому рекомендуется размещать контент относительно друг друга, а не относительно начала координат.

Работа с сущностями

Сущности играют центральную роль в SceneCore. Практически всё, что видит и с чем взаимодействует пользователь, — это сущности, представляющие панели, 3D-модели и многое другое.

Поскольку ActivitySpace является узлом верхнего уровня графа сцены, по умолчанию все новые сущности помещаются непосредственно в ActivitySpace . Вы можете перемещать сущности по графу сцены, вызывая setParent() или addChild() .

У сущностей есть некоторые стандартные поведения, универсальные для всех сущностей, такие как изменение положения, поворот или видимость. У отдельных подклассов Entity , например, GltfModelEntity , есть дополнительные поведения, поддерживающие подкласс.

Манипулировать сущностями

При изменении свойства Entity , принадлежащей базовому классу Entity , это изменение будет применено ко всем её дочерним объектам. Например, изменение Pose родительской Entity приведёт к такому же изменению всех её дочерних объектов. Внесение изменений в дочернюю Entity не влияет на её родительскую сущность.

Pose определяет положение и поворот сущности в трёхмерном пространстве. Положение — это Vector3 , состоящий из числовых координат x, y, z. Поворот представлен Quaternion . Положение Entity всегда определяется относительно её родительской сущности. Другими словами, Entity с позицией (0, 0, 0) будет помещена в начало координат своей родительской сущности.

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

Чтобы изменить видимость Entity , используйте setHidden() .

// Hide the entity
entity.setHidden(true)

Чтобы изменить размер Entity , сохранив ее общую форму, используйте setScale() .

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

Добавить общее поведение к сущностям

Для добавления общего поведения сущностям можно использовать следующие компоненты:

  • MovableComponent : позволяет пользователю перемещать объекты.
  • ResizableComponent : позволяет пользователю изменять размер объектов с использованием согласованных шаблонов пользовательского интерфейса.
  • InteractableComponent : позволяет захватывать события ввода для пользовательских взаимодействий.

Создание экземпляров компонентов должно осуществляться через соответствующий метод создания в классе Session . Например, чтобы создать ResizableComponent , вызовите ResizableComponent.create() .

Чтобы добавить определенное поведение компонента к Entity , используйте метод addComponent() .

Используйте MovableComponent , чтобы сделать сущность перемещаемой пользователем

MovableComponent позволяет пользователю перемещать Entity . Вы также можете указать, может ли сущность быть прикреплена к поверхности, например, к горизонтальной или вертикальной, или к определенным семантическим поверхностям, например, к столу, стене или потолку. Чтобы задать параметры привязки, укажите набор AnchorPlacement при создании MovableComponent .

Вот пример объекта, который можно перемещать и закреплять на любой вертикальной поверхности, а также на горизонтальных поверхностях пола и потолка.

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)

При перемещении объекта пользователем параметр scaleInZ автоматически корректирует масштаб объекта по мере его удаления от пользователя, аналогично тому, как система масштабирует панели в домашнем пространстве . В связи с «каскадной» природой системы компонентов объекта масштаб родительского объекта будет влиять на все его дочерние элементы.

Используйте ResizableComponent , чтобы сделать сущность изменяемой пользователем

ResizableComponent позволяет пользователям изменять размер Entity . ResizableComponent включает визуальные подсказки, приглашающие пользователя изменить размер Entity . При создании ResizableComponent можно указать минимальный или максимальный размер (в метрах). Также можно указать фиксированное соотношение сторон при изменении размера, чтобы ширина и высота изменялись пропорционально друг другу.

При использовании ResizableComponent необходимо указать ResizeListener для реагирования на определенные события изменения размера, такие как onResizeUpdate или onResizeEnd .

Вот пример использования ResizableComponent с фиксированным соотношением сторон на 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 для захвата событий пользовательского ввода

InteractableComponent позволяет перехватывать события ввода от пользователя, например, когда пользователь взаимодействует с объектом Entity или наводит на него курсор. При создании компонента InteractableComponent необходимо указать InputEventListener для получения событий ввода. Когда пользователь выполняет любое действие ввода, будет вызван метод onInputEvent с указанной в параметре InputEvent информацией о вводе.

Полный список всех констант InputEvent см. в справочной документации .

В следующем фрагменте кода показан пример использования InteractableComponent для увеличения размера объекта с правой стороны и уменьшения с левой.

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)