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.action
указывает тип ввода, например наведение курсора или нажатие на объект. -
InputEvent.source
указывает, откуда поступил входной сигнал, например, от руки или с контроллера . -
InputEvent.pointerType
указывает, поступил ли ввод с правой или с левой руки.
Полный список всех констант 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)