Создание объектов, управление ими и контроль над ними

Поддерживаемые XR-устройства
Это руководство поможет вам создавать контент для таких устройств.
XR-шлемы
Проводные XR-очки

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

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

Как создавать объекты и управлять ими с помощью графа сцены

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

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

Система компонентов объекта

Система компонентов сущностей следует принципу композиции вместо наследования. Вы можете расширить возможности объектов, добавив компоненты, определяющие поведение. Это позволит применять одинаковое поведение к разным типам объектов. Подробнее о том, как добавить общие свойства для объектов…

О ActivitySpace

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

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

Как работать с объектами

Объекты – это основа SceneCore. Почти все, что видит пользователь и с чем взаимодействует, – это объекты, представляющие панели, 3D-модели и т. д.

Поскольку ActivitySpace – это узел верхнего уровня графа сцены, по умолчанию все новые объекты помещаются непосредственно в ActivitySpace. Вы можете перемещать объекты в графе сцены, задав для них параметр parent или используя 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, используйте setEnabled(). Это сделает его невидимым и остановит все процессы, связанные с ним.

// Disable the entity.
entity.setEnabled(false)

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

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

Как добавить к объектам общее поведение

Чтобы добавить к объектам стандартное поведение, можно использовать следующие компоненты:

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

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

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

Как сделать объект перемещаемым пользователем с помощью MovableComponent

MovableComponent позволяет пользователю перемещать Entity.

События перемещения отправляются компоненту, когда пользователь взаимодействует с декорациями. Поведение системы по умолчанию, созданное с помощью MovableComponent.createSystemMovable(), перемещает Entity при перетаскивании декораций:

val movableComponent = MovableComponent.createSystemMovable(session)
entity.addComponent(movableComponent)

Необязательный параметр scaleInZ (по умолчанию задано значение true) позволяет объекту автоматически изменять масштаб при удалении от пользователя, как это происходит с панелями в домашнем пространстве. Из-за каскадного характера системы компонентов сущностей масштаб родительского объекта будет влиять на все его дочерние объекты.

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

val anchorPlacement = AnchorPlacement.createForPlanes(
    anchorablePlaneOrientations = setOf(PlaneOrientation.VERTICAL),
    anchorablePlaneSemanticTypes = setOf(PlaneSemanticType.FLOOR, PlaneSemanticType.TABLE)
)

val movableComponent = MovableComponent.createAnchorable(
    session = session,
    anchorPlacement = setOf(anchorPlacement)
)
entity.addComponent(movableComponent)

Как сделать объект изменяемым пользователем с помощью ResizableComponent

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

При создании ResizableComponent укажите resizeEventListener, который обрабатывает события обновления. Вы можете реагировать на различные ResizeState события, например RESIZE_STATE_ONGOING или RESIZE_STATE_END.

Вот пример использования элемента ResizableComponent с фиксированным соотношением сторон на элементе SurfaceEntity:

val resizableComponent = ResizableComponent.create(session) { event ->
    if (event.resizeState == ResizeEvent.ResizeState.END) {
        // update the Entity to reflect the new size
        surfaceEntity.shape = SurfaceEntity.Shape.Quad(FloatSize2d(event.newSize.width, event.newSize.height))
    }
}
resizableComponent.minimumEntitySize = FloatSize3d(177f, 100f, 1f)
resizableComponent.isFixedAspectRatioEnabled = true // Maintain a fixed aspect ratio when resizing

surfaceEntity.addComponent(resizableComponent)

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

Тег InteractableComponent позволяет регистрировать события ввода от пользователя, например когда он взаимодействует с элементом Entity или наводит на него указатель. При создании InteractableComponent укажите прослушиватель, который будет получать события ввода. Когда пользователь выполняет какое-либо действие, связанное с вводом данных, вызывается прослушиватель с информацией, указанной в параметре 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.RIGHT) {
            entity.setScale(1.5f)
        } else if (it.pointerType == InputEvent.Pointer.LEFT) {
            entity.setScale(0.5f)
        }
    }
}
entity.addComponent(interactableComponent)

Как создавать собственные 3D-модели во время выполнения

Custom Mesh API позволяет программно создавать 3D-объекты прямо в коде, а не загружать статические объекты, например файлы glTF. Создавая собственную геометрию на лету, вы можете отрисовывать процедурные данные, динамические фигуры и бесконечные 3D-среды, например рельеф, который постоянно генерируется по мере того, как пользователи исследуют его. Кроме того, создание сеток во время выполнения позволяет уменьшить размер двоичных файлов, поскольку нет необходимости упаковывать бесчисленные варианты одного и того же 3D-объекта.