エンティティの作成、制御、管理

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(SpatialPanelOrbiter など)を作成できます。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 プロパティを変更すると、その変更はすべての子にカスケードされます。たとえば、親 EntityPose を調整すると、すべての子に同じ調整が適用されます。子 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 定数の一覧については、リファレンス ドキュメントをご覧ください。

次のコード スニペットは、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)