借助 Jetpack XR SDK,您可以使用 Jetpack SceneCore 创建、控制和管理
Entity实例,例如 3D 模型、立体视频和
PanelEntity。
Jetpack SceneCore 采用两种常见的架构模式来支持 3D 开发:场景图和实体组件 系统 (ECS)。
使用场景图创建和控制实体
如需在 3D 空间中创建和控制对象,您可以使用 Jetpack SceneCore's 会话 API 来访问场景图。场景图与用户的真实世界保持一致,可让您将面板和 3D 模型等 3D 实体整理到分层结构中,并保留这些实体的状态。
访问场景图后,您可以使用 Jetpack
Compose for XR 中的 API 在场景图中创建空间界面(例如 SpatialPanel 和
Orbiter 实例)。对于 3D 模型等 3D 内容,您可以直接访问会话。如需了解详情,请参阅本页面的 ActivitySpace
简介。
实体组件系统
实体组件系统遵循组合优于继承的原则。您可以通过附加行为定义组件来扩展实体的行为,这样您就可以将相同的行为应用于不同类型的实体。如需了解详情,请查看本页面的向实体添加常见 行为。
ActivitySpace 简介
每个 Session 都有一个 ActivitySpace,该 ActivitySpace 会与 Session 一起自动创建
。ActivitySpace 是场景图中的顶级 Entity。
ActivitySpace 表示一个具有右手坐标系(x 轴指向右侧,y 轴指向上方,z 轴相对于原点指向后方)的 3 维空间,其单位为米,与真实世界相符。ActivitySpace 的原点在某种程度上是任意的(因为用户可以重置 ActivitySpace 在真实世界中的位置),因此建议将内容彼此相对定位,而不是相对于原点定位。
使用实体
实体是 SceneCore 的核心。用户看到和互动的大部分内容都是表示面板、3D 模型等的实体。
由于 ActivitySpace 是场景图的顶级节点,因此默认情况下,所有新实体都直接放置在 ActivitySpace 中。您可以沿场景图重新定位
实体,方法是设置其 parent 或使用
addChild()。
实体具有一些默认行为,适用于所有实体通用的内容,例如更改位置、旋转或可见性。特定的 Entity
子类(例如 GltfModelEntity)具有支持该子类的其他行为。
操控实体
当您对属于基本 Entity 类的 Entity 属性进行更改时,该更改将级联到其所有子项。例如,
调整父级 Entity 的 Pose 会导致其所有子项
进行相同的调整。在子级 Entity 中进行更改不会影响其父级。
Pose 表示实体在 3D 空间中的位置和旋转。位置是一个 Vector3,由 x、y、z 数值位置组成。旋转由 Quaternion表示。Entity 的位置始终相对于其父实体。换句话说,位置为 (0, 0, 0) 的 Entity 将放置在其父实体原点。
// 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)使实体
在远离用户时自动调整其比例,
类似于系统在 主空间中缩放面板的方式。
由于实体组件系统的“级联”特性,父级的比例会影响其所有子项。
您还可以指定实体是否可以锚定到水平或垂直表面等表面类型,或锚定到表、墙壁或天花板等特定语义表面。如需指定锚定选项,请在创建 MovableComponent 时指定一组 AnchorPlacement
。在此示例中,实体可以移动并锚定到任何地板或桌面水平表面:
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。
以下示例展示了如何在 SurfaceEntity 上使用具有固定宽高比的 ResizableComponent:
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 互动或将鼠标悬停在 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 模型
借助 Custom Mesh API,您可以直接在代码中以编程方式生成 3D 形状,而不是加载 glTF 文件等静态资源。通过即时构建自定义几何图形,您可以渲染程序化数据、动态自定义形状和看似无限的 3D 环境,例如随着用户探索而不断生成的地形。此外,在运行时生成网格还有助于缩小二进制文件大小,因为无需打包单个 3D 资源的无数变体。