visionOS 2.0から追加された RoomTrackingを利用した公式サンプルを触ってみました。
RoomTrackingは、ARKitの中のRoomTrackingProviderを利用して部屋をトラッキングすることができる機能です。この機能を利用して、部屋を移動したことを検知してそれぞれの部屋で演出を行ったり、現在の部屋の中に配置したオブジェクトがあるかを確認したりすることができます。
公式資料のURL
関係するApple公式動画:ARKitを活用したより高度な空間コンピューティング体験の創出
Apple公式サンプル:Building local experiences with room tracking
利用可能な開発環境
RoomTrackingを利用したアプリはvisionOS 2.0以降での動作となるため、対応したビルド環境が必要となります。また、RoomTrackingはARKitを利用するため、ImmersiveSpace上でしか利用できません。
| visionOS | 2.0以上 |
| Xcode | 16.0以上 |
サンプルの概要
サンプルとして、以下の三つの要素が存在します。
- 球のオブジェクトを配置して、そのオブジェクトをWorldAnchorで位置固定する。
- RoomTrackingで検知した部屋のジオメトリから部屋の壁にメッシュを貼り付け、視線に合わせたメッシュの色を変更する。
- 自分のいる部屋を検知し、自分のいる部屋と同じ部屋に存在する球オブジェクトに他の球と違う演出を加える。
これらの要素があるため、球のオブジェクトを異なる部屋に配置し、部屋をトラッキングしながら部屋を移動することで、部屋移動の演出(球の色の変更)を見ることができます。
球の色変更が起こるまでのフロー
球の色変更が起こるまでのフローとして、サンプル内では以下のようなフローが起こっています。

サンプルの主要なコード
それぞれの主要なコードが前述したフローに関係しているので、このフローを中心に主要コードを解説します。
RoomAnchorのアップデート
SwiftUIのARKitにおいて、Providerの更新のコードは下記のようなフォーマットになっており、RoomTrackingProviderにおいてもそれは同じようです。RoomAnchorが追加される場合は、.added,更新される場合は.updated,削除される場合は.removedが呼ばれます。サンプルでは、.addedと.updatedが起こった際に、自身(デバイス)の存在している部屋の位置や球の位置がどの部屋にあるかを確認しているコードが入っています。
for await update in roomTracking.anchorUpdates {
let roomAnchor = update.anchor
switch update.event {
case .removed:
~~~
case .added, .updated:
~~~
}
}デバイスがいる部屋を特定する
RoomAnchor.isCurrentRoomで自身が部屋の中にいるかどうかを確認できます。.updatedで更新を確認し、RoomAnchorのidを保存して現在自身がいる部屋にすぐアクセスできるようにしておくのがセオリーのようで、サンプルでもそのようになっていました。その他にもRoomTrackingProviderにcurrentRoomAnchorというパラメータがあるので、そこからも現在のデバイスのある部屋を特定できます。
オブジェクトがどの部屋の中にあるかを特定する
オブジェクトの位置が部屋の中にあるかは、roomAnchor.contains(_ point: SIMD3<Float>)で特定できます。細かく言うと、値として渡すのがEntityではないのでオブジェクトでなくてもある場所のポジションが部屋の中にあるかを特定する関数です。下記が、サンプル内で球が現在のデバイスのある部屋に存在するかどうかを特定しているコード部分です。
guard let currentRoom = roomTracking.currentRoomAnchor else {
return false
}
let spherePosition = sphere.originFromAnchorTransform.columns.3.xyz
return currentRoom.contains(spherePosition)トラッキングした部屋のジオメトリを利用する
部屋をトラッキングした時に得られるRoomAnchorはgeometryのプロパティを持っており、このgeometryに対してメッシュを貼ることができます。また、RoomAnchor.geometries(of: MeshAnchor.MeshClassification)を利用すると、メッシュの種類ごとに別々のメッシュを取得することができます。サンプル内では壁だけにMeshを貼るコードを利用しています。もし、すべてのメッシュを取得したい場合はRoomAnchor.geometryですべてのメッシュを取得できるのでこちらを利用したら問題ないです。
let wallGeometries = roomAnchor.geometries(of: .wall)
for wallGeometry in wallGeometries {
~~~
}RoomTrackingを応用して出来そうなこと
サンプルを使ってみて、この機能を利用すると出来そうなことをあげておきたいと思います。
自身のいる部屋のオブジェクトのみ表示する
部屋を跨いでアプリを利用することが想定されることはあまりないかもしれませんが、例えばアプリ上で部屋のジオメトリに合わせてメッシュを表示していた場合メッシュのない部屋からみた場合壁を突き抜けてメッシュが存在しているように見えて没入感がなくなることが考えられます。 RoomTrackingを利用すれば、自身がいる部屋のものだけを表示することができるのでこのような没入感が削がれる問題を解消できると思います。
追従するオブジェクトやUIを、部屋毎に出し分ける
ImmersiveSpaceを利用する場合、頭に追従するUIやオブジェクトなどを作成する場合があります。そのようなオブジェクトがある場合、部屋が変わるタイミングでオブジェクトを変更したり、その部屋特有のUIに変更することで特別感のある演出ができると思います。例えば、謎解きゲームなどでその部屋だけでしかできないアクションが常に追従しているUIに出現するなどを想像すると分かり良いかもしれません。
終わりに
いかがだったでしょうか。RoomTrackingを利用するタイミングというのは普通の開発ではあまりないかもしれませんが、この機能を中心に据えたゲームなどは考えると尖ったものができそうです。また、部屋のメッシュ自体は通常の平面検出よりも部屋の壁や床に特化しているような気がする(詳細不明)ので、壁や床に対してメッシュをつけるような演出の場合はPlaneDetectionではなく RoomTrackingの方が利用しやすい場面があるかもしれません。visionOSはまだまだ発展途上かと思うので、今後のアップデートと開発者のアイディアで面白い機能になったらいいですね。
