はじめに
Vision Proが発売されて1ヶ月程が経ちました。
Vision Proの開発について、できること、できないことがわかってきたので、記事にしようと思います。
今回は導入編として、開発環境の構築と簡単なアプリの作成方法について書いていきます。
※この記事は2024/3/1時点までの調査結果を元に作成しました。
Vision Proの概念的な説明は↓の記事を見てください。
用語
PolySpatial 特有の用語がいくつかあるので、最初に書いておきます。
- Bounded Volume
Shared Space
のこと- 複数のアプリを同時に開くことができる
- Unbounded Volume
Full Space
のこと- 1つのアプリが画面を占有し、他のアプリは非表示になる
開発環境
- Unity 2022.3.18f1
- PolySpatial 1.0.3
- VisionOS 1.0.3
- macOS Sonoma 14.2
- Xcode 15.2
環境構築
Unityをインストール
PolySpatialの動作環境は1.0.3時点でUnity 2022.3.18f1以降となっています。
合わせて、 iOS Build Support
と visionOS Build Support
のモジュールもインストールします。
テンプレートプロジェクトをダウンロード
https://discussions.unity.com/t/visionos-template-update/335386
↑のリンクからテンプレートプロジェクトをダウンロードできます。
自分でプロジェクトを作成してセットアップしていくこともできますが、テンプレートプロジェクトから始めた方が簡単です。
新規プロジェクトのセットアップ
一応、新規プロジェクトのセットアップについても書いておきます。
まず、プロジェクトを新規作成します。
3D(URP)で始めるのが良いと思います。
プロジェクトが開いたら、 XR Plugin Manager
をインストールします。
Project Settings/XR Plug-in Management
から Apple visionOS
を有効化します。
有効化すると、AR Foundation
, Apple visionOS XR Plugin
などのパッケージがインポートされます。
その後、エディタの再起動が要求されるので、再起動します。
再起動が完了したら、Apple visionOS
の App Mode
を Mixed Reality - Volume or Immersive Space
に変更します。
変更すると、 PolySpatial
関連のパッケージがインポートされます。
パッケージのインポートが完了したら、
最後に Player/Splash Image
の Show Splash Screen
を無効化します。
ビルドターゲットを変更
プロジェクトのセットアップが完了したらビルドターゲットを visionOS
に変更します。
これで環境構築は完了です。
ビルド
シミュレータへビルド
テンプレートプロジェクトではビルド設定に最初からSampleSceneが設定されているので、このシーンをビルドしてみます。
Target SDK を Simulator SDK
に変更してビルドします。
通常のiOSアプリのビルドと同様にXcodeプロジェクトができるので、Xcodeプロジェクトを開いて、シミュレータを対象にビルドします。
ビルドが正常に完了したらシミュレータ上で↓のようなBoundedのシーンが表示されます。
Macと実機をペアリング
今度はVision Pro実機にビルドしてみます。
Target SDK を Device SDK
に変更してビルドします。
VisionProはDeveloper StrapがないとMacと有線接続できないので、今回はWiFi経由でインストールします。
WiFi経由でインストールするにはVision ProとMacをペアリングする必要があります。
ペアリングに関しては↓の記事が参考になりました。(同じiCloudアカウントでログインする必要はなさそうです。)
https://www.techno-edge.net/article/2024/02/05/2756.html
Copying shared cache symbols from Vision Pro
https://forums.developer.apple.com/forums/thread/746905
↑のスレッドで話されている、VisionProからXcodeへのShared Cacheのコピーが全然進まない問題が、自分の環境でも発生し、完了するのに1時間半くらいかかってしまいました。
弊社では複数のエンジニアがVisionProの開発を行っており、全員が1時間半待つのは効率が悪すぎるということで、なんとかならないか色々な方法を試しました。
その結果、誰か一人がコピーを完了したら、そのキャッシュを他の人にそのまま渡せば良いことがわかりました。
↓のパスにコピーしたキャッシュがあるので、他の人はキャッシュをもらって、同じパスに配置すればOKです。/Users/{ユーザー名}/Library/Developer/Xcode/visionOS DeviceSupport
複数人での開発で同じ問題にぶつかっている人はぜひ試してみてください。
実機にビルド
実機にビルドすると↓のようになります。
コンテンツ作成
サンプルを動かすことができたので、自分でも簡単なアプリを作ってみます。
シーンを新規作成
Main Camera
と Directional Light
が置かれた新規シーンを作りました。
ここに必要なものを追加していきます。
Volume Camera を配置
XR/Setupの Volume Camera
をシーン上に配置します。
このオブジェクトがコンテンツの中心となるので、PositionとRotationを全て0にしておいた方が作りやすいと思います。
VolumeCameraWindowConfiguration を作成
次に Volume Window Configration
を作成します。Volume Window Configration
はコンテンツの表示方法の設定ファイルです。
Volume Window Configration
の Mode
を Bounded
にすると、 Output Dimensions (meters)
に設定した大きさのボリュームとしてコンテンツが表示されます。
Mode
を Unbounded
にすると、大きさに制限のないImmersiveなコンテンツとして表示されます。
今回は1m四方のBoundedに設定しました。Volume Window Configration
が作成できたら、 Volume Camera
コンポーネントの Volume Window Configration
に設定します。
Volume Camera
の Dimensions
はエディタ上での大きさです。
そのままでも良いですが、 Output Dimensions (meters)
と同じ値に設定しておくと作りやすいと思います。
シーン上に設定した大きさのボリュームが表示されます。
この範囲内にコンテンツを配置していきます。
モデルの配置
これでシーンの準備は完了したので、コンテンツの作成に入っていきます。
今回はボリュームの中にカワセミのモデルを配置してみました。
ピンチ入力の検知
ピンチ入力(親指と人差し指を一瞬くっつけて離す)を検知したら、カワセミの羽ばたくアニメーションが再生されるようにしてみます。
まずモデルのルートオブジェクトに Collider
(今回は BoxCollider
)と VisionOSHoverEffect
コンポーネントをアタッチします。
これでカワセミに視線を向けた時に白く光るようになりました。
※現状だと、Vision ProのMRアプリで視線のホバーエフェクトを自作することはできず、 VisionOSHoverEffect
コンポーネントに頼ることになると思います。
次にカワセミのアニメーション周りの設定をします。
基本的にはいつも通りに作ればいいのですが、 Animator
コンポーネントの Culling Mode
だけは Always Animate
に設定する必要があるようです。
↓参考URL
https://discussions.unity.com/t/culled-animation-wont-play-in-mr-scene/320077
シミュレータで見ると↓のようになります。
視線(マウス)をホバーさせている時だけモデルが白く光っています。
ピンチを検出するスクリプトを作成します。
カワセミのアニメーション制御のスクリプト BirdController
は今回の記事には関係ないので割愛します。
using Unity.PolySpatial.InputDevices;
using UnityEngine;
using UnityEngine.InputSystem.EnhancedTouch;
using UnityEngine.InputSystem.LowLevel;
using Touch = UnityEngine.InputSystem.EnhancedTouch.Touch; // 使用するTouchクラスはUnityEngine.Touchではない
namespace Gaprot.Behaviours
{
/// <summary>
/// サンプル管理クラス
/// </summary>
public class SampleManager : MonoBehaviour
{
/// <summary>
/// Awake
/// </summary>
private void Awake()
{
EnhancedTouchSupport.Enable(); // EnhancedTouchSupport を有効化
}
/// <summary>
/// OnDestroy
/// </summary>
private void OnDestroy()
{
EnhancedTouchSupport.Disable(); // EnhancedTouchSupport を無効化
}
/// <summary>
/// Update
/// </summary>
private void Update()
{
var activeTouches = Touch.activeTouches; // 現在有効な入力を取得
if(activeTouches.Count <= 0) return; // 有効な入力がない場合は処理終了
if (!EnhancedSpatialPointerSupport.TryGetPointerState(activeTouches[0], out SpatialPointerState state)) return; // SpatialPointerState が取得できない場合処理終了
if (state.phase is not SpatialPointerPhase.Began) return; // ピンチ入力開始時以外は処理終了(ここはコンテンツに合わせてカスタム)
var target = state.targetObject; // ピンチ入力の対象オブジェクトを取得
if(!target.TryGetComponent(out BirdController bird)) return; // BirdController コンポーネントを取得
bird.OnPinch(); // ピンチ時の処理を実行
}
}
}
空オブジェクト Sample Manager
を作成し、↑のスクリプトをアタッチします。
あとはカワセミ側にアニメーション制御用のスクリプトをアタッチすれば完成です。
実機にビルドすると↓のようになります。
おわりに
今回のような簡単なコンテンツなら、 Volume Camera を置くだけで作ることができるので、これからもいろいろなアプリを作っていこうと思っています。
次回は応用編として、Unbounded(Immersive)でハンドトラッキングなどを使うコンテンツを作る記事を執筆予定です。