借助 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
用于指定输入类型,例如对实体进行悬停或点按(ACTION_DOWN)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)