Jetpack XR SDK を使用すると、Jetpack SceneCore を使用して、3D モデル、立体視動画、PanelEntity
などの Entity
インスタンスを作成、制御、管理できます。
Jetpack SceneCore は、3D 開発をサポートするために、シーングラフとエンティティ コンポーネント システム(ECS)という 2 つの一般的なアーキテクチャ パターンを採用しています。
シーングラフを使用してエンティティを作成、制御する
3D 空間でオブジェクトを作成して制御するには、Jetpack SceneCore の Session API を使用してシーングラフにアクセスする必要があります。シーングラフはユーザーの現実世界と連動しており、パネルや 3D モデルなどの 3D エンティティを階層構造に整理し、それらのエンティティの状態を保持できます。
シーングラフにアクセスしたら、Jetpack Compose for XR の API を使用して、シーングラフ内に空間 UI(SpatialPanel
や Orbiter
など)を作成できます。3D モデルなどの 3D コンテンツの場合は、セッションに直接アクセスできます。詳細については、このページのActivitySpace についてをご覧ください。
エンティティ コンポーネント システム
エンティティ コンポーネント システムは、継承よりもコンポジションの原則に従います。動作を定義するコンポーネントを接続することで、エンティティの動作を拡張できます。これにより、同じ動作を異なるタイプのエンティティに適用できます。詳細については、このページのエンティティに一般的な動作を追加するをご覧ください。
ActivitySpace について
各 Session
には、Session
とともに自動的に作成される ActivitySpace
があります。ActivitySpace
は、シーングラフの最上位の Entity
です。
ActivitySpace は、右手系の座標系(x 軸は右、y 軸は上、z 軸は原点から後ろ)の 3 次元空間を表します。単位はメートルで、現実世界に対応しています。ActivitySpace
の原点は任意です(ユーザーは現実世界で ActivitySpace
の位置をリセットできるため)。そのため、コンテンツは原点ではなく、互いに対して配置することをおすすめします。
エンティティを操作する
エンティティは SceneCore の中核です。ユーザーが表示、操作するほとんどのものは、パネルや 3D モデルなどを表すエンティティです。
ActivitySpace
はシーングラフの最上位ノードであるため、デフォルトでは、すべての新しいエンティティが ActivitySpace
に直接配置されます。シーングラフに沿ってエンティティを再配置するには、setParent
または addChild
を呼び出します。
エンティティには、位置、回転、可視性の変更など、すべてのエンティティに共通するデフォルトの動作があります。GltfEntity
などの特定の Entity
サブクラスには、サブクラスをサポートする追加の動作があります。
エンティティの操作
ベースの Entity
クラスに属する Entity
プロパティを変更すると、その変更はすべての子にカスケードされます。たとえば、親 Entity
の Pose
を調整すると、すべての子に同じ調整が適用されます。子 Entity
を変更しても、親には影響しません。
Pose
は、3D 空間内のエンティティの位置と回転を表します。位置は、x、y、z の数字の位置で構成される Vector3
です。回転は 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
: ユーザーが UI パターンを統一してエンティティのサイズを変更できるようにします。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
を指定する必要があります。ユーザーが入力アクションを実行すると、InputEvent
パラメータで指定された特定の入力情報とともに onInputEvent
メソッドが呼び出されます。
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)