
Full Spaceは本当に球体だった!
はじめに
今回はvisionOSの特徴の一つである空間をコントロールできるImmersive Spaceについてコードも交えて解説したいと思います。
Immersive Spaceとは
Immersive Spaceとは、空間上にアプリをどの様に表示するかの表現方法です。例えば、ImmersionStyleをmixedにすると他のアプリと混在することができます。fullを指定すれば1つのアプリで空間上を覆い隠すことができます。ただし、ユーザー体験で考えると複数のアプリを同時に使いたい場合が多いので、1つのアプリに集中したほうが良い場合のみFull Spaceを使うようにします。今回はこのFull Spaceの実装について見ていきます。
Full Spaceの実態
Full Spaceの実装はHello Worldのサンプルで確認することができます。サンプルを見る前のイメージはImmersiveSpaceにTextureを貼り付けて表現するのだと思っていました。
# Hello WorldのFull Spaceの実装
let entity = Entity()
entity.components.set(ModelComponent(
mesh: .generateSphere(radius: 1000),
materials: [material]
))
実態は、半径1000mの球体を作成して内側に宇宙空間のMaterialを指定しているだけでした。AppleがWWDCの動画でFull Spaceを表現する際に人間の周りを球体で囲っていましたが、あれは概念を説明するものではなくて実態でした!

出典:Immersive experiences
Materialの種類
Immersive Spaceで利用できるMaterialにはいくつかの種類があります。ここではImmersive Spaceで利用すると便利なMaterialについて見てみます。その他のMaterialについてはRealityKitのMaterials Shadersのドキュメントを参考にしてみてください。
UnlitMaterial

UnlitMaterialはHello WorldのThe Solar Systemで宇宙空間をImmersive Spaceとして表示する際に利用されています。UnlitMaterialはシーン内の光の影響を受けません。そのため、宇宙空間のように光の影響を受けたくないImmersive Spaceを利用する時に適しています。
VideoMaterial

VideoMaterialは動画をテクスチャとして利用することができるMaterialです。例えば四角いModel Componentを準備して正面のテクスチャにVideoMaterialを貼り付ければ、映画館を表現する様なImmersive Spaceを作ることもできそうです。
VideoMaterialで映像を表示
実際にVideoMaterialを表示する方法は簡単です。Hello Worldのコードを少し修正するだけで動画が再生されるImmersive Spaceを表現することができます。
# Hello WorldのコードをVideo Materialに変更
import SwiftUI
import RealityKit
import AVKit
struct Starfield: View {
var body: some View {
RealityView { content in
let url = Bundle.main.url(forResource: "movie", withExtension: "mp4")
let player = AVPlayer(url: url!)
let material = VideoMaterial(avPlayer: player)
player.play()
let entity = Entity()
entity.components.set(ModelComponent(
mesh: .generateBox(size: 10),
materials: [material]
))
entity.scale *= .init(x: -1, y: 1, z: 1)
content.add(entity)
}
}
}
コードを解説すると動画ファイルのパスをAVPlayerに渡して、VideoMaterialを生成します。ちなみに、動画形式はMOVファイルは再生できないのでMP4に変換して利用する必要があります。
let url = Bundle.main.url(forResource: "movie", withExtension: "mp4")
let player = AVPlayer(url: url!)
let material = VideoMaterial(avPlayer: player)
player.play()
後はModelComponentを生成してMaterialとしてVideoMaterialを渡しあげるだけです。ここでは、.generateBox(size: 10)で10mの正方形を生成して動画をTextureとして貼り付けています。最後にentity.scale *= .init(x: -1, y: 1, z: 1)としているのはTextureをそのまま貼り付けるとModel Componentの外側にTextureが適用されます。そこでx: -1とすることで内側にTextureが表示されるようにしています。
let entity = Entity()
entity.components.set(ModelComponent(
mesh: .generateBox(size: 10),
materials: [material]
))
entity.scale *= .init(x: -1, y: 1, z: 1)
content.add(entity)
おまけ:visionOS SimulatorでImmersive Spaceを快適にデバッグする方法
Immersive SpaceをSimulatorでデバッグする時に困るのが操作系です。Immersive Spaceの空間を見回したり、引いたり寄ったりしたくなります。キーボードとマウスを使えば操作することはできますが、トライ&エラーを繰り返している最中はとても不便です。実機でデバッグできれば確実で簡単ですが、日本で発売されていない現状を考えると難しいです。
そこでお勧めしたいのがMacにゲームコントローラーをつなげる方法です。USBで接続するだけで何もソフトウェアは不要です。これは非常に便利でSimulatorの操作が直感的になります。この方法はサンフランシスコ在住のソフトウェアエンジニアのバスケさんに教えてもらいました。

まとめ
Immersive SpaceはvisionOSの特徴的な機能のひとつなので効果的な場面では積極的に使っていきたいと思います。また、ModelComponentを使えばかなり自由度の高い特別なImmersive Spaceを表現できそうです。現在、作っている個人アプリもImmersive Spaceを使ったアプリなので視覚的な空間だけではなく、Spacial Audioを使って本当にその場にいるような表現をしたいと思います。