Jetpack XR SDK позволяет использовать Jetpack SceneCore для создания, управления и контроля экземпляров Entity , таких как 3D-модели , стереоскопическое видео и PanelEntity , с помощью Jetpack SceneCore.
Jetpack SceneCore использует два распространенных архитектурных шаблона для поддержки 3D-разработки: граф сцены и систему «сущность-компонент» (ECS).
Используйте граф сцены для создания и управления объектами.
Для создания и управления объектами в трехмерном пространстве можно использовать API сессий Jetpack SceneCore, чтобы получить доступ к графу сцены. Граф сцены соответствует реальному миру пользователя и позволяет организовывать трехмерные объекты, такие как панели и трехмерные модели, в иерархическую структуру и хранить состояние этих объектов.
Получив доступ к графу сцены, вы можете использовать API Jetpack Compose for XR для создания пространственного пользовательского интерфейса (например, экземпляров SpatialPanel и Orbiter ) внутри графа сцены. Для 3D-контента, такого как 3D-модели, вы можете получить прямой доступ к сессии. Для получения дополнительной информации см. раздел «О пространстве активности» на этой странице.
Система компонентов сущности
Система компонентов сущностей следует принципу композиции, а не наследования. Вы можете расширить поведение сущностей, присоединяя компоненты, определяющие поведение, что позволяет применять одно и то же поведение к различным типам сущностей. Для получения дополнительной информации см. раздел «Добавление общего поведения к сущностям» на этой странице.
О пространстве для активного отдыха
Каждая 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.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.RIGHT) { entity.setScale(1.5f) } else if (it.pointerType == InputEvent.Pointer.LEFT) { entity.setScale(0.5f) } } } entity.addComponent(interactableComponent)
Создавайте пользовательские 3D-модели во время выполнения.
API пользовательских сеток позволяет программно генерировать 3D-фигуры непосредственно в коде, вместо загрузки статических ресурсов, таких как файлы glTF. Создавая пользовательскую геометрию на лету, вы можете отображать процедурные данные, динамические пользовательские формы и, казалось бы, бесконечное количество 3D-сред, таких как ландшафт, который непрерывно генерируется по мере исследования пользователями. Кроме того, генерация сеток во время выполнения способствует уменьшению размера бинарных файлов, устраняя необходимость упаковки бесчисленных вариантов одного и того же 3D-ресурса.