创建、控制和管理实体

借助 Jetpack XR SDK,您可以使用 Jetpack SceneCore 创建、控制和管理 Entity 实例,例如 3D 模型立体视频PanelEntity

Jetpack SceneCore 采用了两种常见的架构模式来支持 3D 开发:场景图实体-组件系统 (ECS)。

使用场景图创建和控制实体

如需在 3D 空间中创建和控制对象,您必须使用 Jetpack SceneCore 的 Session API 来获取对场景图的访问权限。场景图与用户的真实世界保持一致,可让您将面板和 3D 模型等 3D 实体整理成分层结构,并保留这些实体的状态。

获得对场景图的访问权限后,您就可以使用 Jetpack Compose for XR 中的 API 在场景图中创建空间界面(例如 SpatialPanelOrbiter)。对于 3D 内容(例如 3D 模型),您可以直接访问会话。如需了解详情,请参阅本页面上的 ActivitySpace 简介

实体组件系统

实体-组件系统遵循“组合优于继承”的原则。您可以通过附加行为定义组件来扩展实体的行为,从而将相同的行为应用于不同类型的实体。如需了解详情,请参阅本页中的向实体添加常见行为

ActivitySpace 简介

每个 Session 都有一个 ActivitySpace,该 ActivitySpace 会随 Session 自动创建。ActivitySpace 是场景图中的顶级 Entity

ActivitySpace 表示采用右手坐标系(x 轴指向右侧,y 轴指向上方,z 轴相对于原点指向后方)的三维空间,并采用与现实世界相符的米为单位。ActivitySpace 的原点有点任意(因为用户可以在现实世界中重置 ActivitySpace 的位置),因此建议将内容相对于彼此定位,而不是相对于原点。

使用实体

实体是 SceneCore 的核心。用户看到的和与之互动的大多数内容都是代表面板、3D 模型等的实体。

由于 ActivitySpace 是场景图的顶级节点,因此默认情况下,所有新实体都会直接放入 ActivitySpace。您可以通过调用 setParentaddChild 沿场景图重新定位实体。

实体针对所有实体通用的操作(例如更改位置、旋转或可见性)具有一些默认行为。特定的 Entity 子类(例如 GltfEntity)具有支持该子类的其他行为。

操纵实体

当您更改属于基 Entity 类的 Entity 属性时,相应更改会向下级联动到其所有子项。例如,调整父级 EntityPose 会导致其所有子级都进行相同的调整。对子 Entity 进行更改不会影响其父级。

Pose 表示实体在 3D 空间中的位置和旋转。位置是 Vector3,由 x、y、z 数值位置组成。旋转由 Quaternion 表示。Entity 的位置始终相对于其父实体。换句话说,位置为 (0, 0, 0) 的 Entity 将放置在其父实体的原点处。

//place the entity forward 2 meters
val modelPosition = 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)

向实体添加常见行为

您可以使用以下组件为实体添加常见行为:

必须通过 Session 类中的适当创建方法来实例化组件。例如,如需创建 ResizableComponent,请调用 session.createResizableComponent()

如需向 Entity 添加特定组件行为,请使用 addComponent() 方法。

使用 MovableComponent 使实体可供用户移动

MovableComponent 允许用户移动 Entity。您还可以指定实体是否可以锚定到表面类型(例如水平或垂直表面),或特定的语义表面(例如桌子、墙壁或天花板)。如需指定锚点选项,请在创建 MovableComponent 时指定一组 AnchorPlacement

下面是一个实体的示例,该实体可以移动并锚定到任何垂直表面,以及仅锚定到地板和天花板水平表面。

val anchorPlacement = AnchorPlacement.createForPlanes(
    planeTypeFilter = setOf(PlaneSemantic.FLOOR, PlaneSemantic.TABLE),
    planeSemanticFilter = setOf(PlaneType.VERTICAL))

val movableComponent = xrSession.createMovableComponent(
    systemMovable = false,
    scaleInZ = false,
    anchorPlacement = setOf(anchorPlacement)
)
entity.addComponent(movableComponent)

使用 ResizableComponent 使实体可供用户调整大小

借助 ResizableComponent,用户可以调整 Entity 的大小。ResizableComponent 包含视觉互动提示,提示用户调整 Entity 的大小。创建 ResizeableComponent 时,您可以指定最小或最大尺寸(以米为单位)。您还可以选择在调整大小时指定固定的宽高比,以便宽度和高度按比例调整。

下面是一个使用固定宽高比的 ResizableComponent 的示例:

val resizableComponent = xrSession.createResizableComponent()
resizableComponent.minimumSize = Dimensions(177f, 100f, 1f )
resizableComponent.fixedAspectRatio = 16f / 9f //Specify a 16:9 aspect ratio
entity.addComponent(resizableComponent)

使用 InteractableComponent 捕获用户输入事件

借助 InteractableComponent,您可以捕获来自用户的输入事件,例如用户与 Entity 互动或将鼠标悬停在 Entity 上时。创建 InteractableComponent 时,您必须指定 InputEventListener 来接收输入事件。当用户执行任何输入操作时,系统会调用 onInputEvent 方法,并使用 InputEvent 参数中提供的具体输入信息。

如需查看所有 InputEvent 常量的完整列表,请参阅参考文档

以下代码段展示了一个使用 InteractableComponent 的示例,其中右手用于增大实体的大小,而左手用于缩小实体的大小。

private val executor by lazy { Executors.newSingleThreadExecutor() }
val interactableComponent = xrSession.createInteractableComponent(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)