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

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

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

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

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

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

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

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

О ActivitySpace

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

ActivitySpace представляет собой трехмерное пространство с правосторонней системой координат (ось x указывает вправо, ось y указывает вверх, а ось z — назад относительно начала координат) и с метрами в качестве единиц, соответствующих реальному миру. Начало координат для ActivitySpace несколько произвольно (поскольку пользователи могут сбросить положение ActivitySpace в реальном мире), поэтому рекомендуется размещать контент относительно друг друга, а не относительно начала координат.

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

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

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

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

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

Когда вы вносите изменение в свойство 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, чтобы сделать Entity доступным для изменения размера пользователем

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

При использовании ResieableComponent необходимо указать 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)