借助 Jetpack XR SDK,您可以使用 Jetpack SceneCore 创建、控制和管理 Entity
实例,例如 3D 模型、立体视频和 PanelEntity
。
Jetpack SceneCore 采用了两种常见的架构模式来支持 3D 开发:场景图和实体-组件系统 (ECS)。
使用场景图创建和控制实体
如需在 3D 空间中创建和控制对象,您必须使用 Jetpack SceneCore 的 Session API 来获取对场景图的访问权限。场景图与用户的真实世界保持一致,可让您将面板和 3D 模型等 3D 实体整理成分层结构,并保留这些实体的状态。
获得对场景图的访问权限后,您就可以使用 Jetpack Compose for XR 中的 API 在场景图中创建空间界面(例如 SpatialPanel
和 Orbiter
)。对于 3D 内容(例如 3D 模型),您可以直接访问会话。如需了解详情,请参阅本页面上的 ActivitySpace 简介。
实体组件系统
实体-组件系统遵循“组合优于继承”的原则。您可以通过附加行为定义组件来扩展实体的行为,从而将相同的行为应用于不同类型的实体。如需了解详情,请参阅本页中的向实体添加常见行为。
ActivitySpace 简介
每个 Session
都有一个 ActivitySpace
,该 ActivitySpace
会随 Session
自动创建。ActivitySpace
是场景图中的顶级 Entity
。
ActivitySpace 表示采用右手坐标系(x 轴指向右侧,y 轴指向上方,z 轴相对于原点指向后方)的三维空间,并采用与现实世界相符的米为单位。ActivitySpace
的原点有点任意(因为用户可以在现实世界中重置 ActivitySpace
的位置),因此建议将内容相对于彼此定位,而不是相对于原点。
使用实体
实体是 SceneCore 的核心。用户看到的和与之互动的大多数内容都是代表面板、3D 模型等的实体。
由于 ActivitySpace
是场景图的顶级节点,因此默认情况下,所有新实体都会直接放入 ActivitySpace
。您可以通过调用 setParent
或 addChild
沿场景图重新定位实体。
实体针对所有实体通用的操作(例如更改位置、旋转或可见性)具有一些默认行为。特定的 Entity
子类(例如 GltfEntity
)具有支持该子类的其他行为。
操纵实体
当您更改属于基 Entity
类的 Entity
属性时,相应更改会向下级联动到其所有子项。例如,调整父级 Entity
的 Pose
会导致其所有子级都进行相同的调整。对子 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)
向实体添加常见行为
您可以使用以下组件为实体添加常见行为:
MovableComponent
:允许用户移动实体ResizableComponent
:允许用户使用一致的界面模式调整实体的大小InteractableComponent
:可让您捕获自定义互动所需的输入事件
必须通过 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.action
用于指定输入类型,例如对实体进行悬停或点按InputEvent.source
用于指定输入来源,例如手部或控制器输入InputEvent.pointerType
用于指定输入是来自右手还是左手
如需查看所有 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)