UnityでOculus Riftの接続状態によって処理を切り替える


Oculus Riftについて

 はもう説明不要ですよね?
2012年E3で最初のプロトタイプが披露され、
同年8月のKickstarterでは30日で240万ドルを集め、
2013年のE3ではPlaystation 4とXbox Oneを抑えてBEST HARDWARE賞を受賞し、
2014年中に性能を大幅に向上させた「完成版」が発売する予定の「ゲーム用」ヘッドマウントディスプレイです。

 注目度が高すぎてフォーラム投稿やらメディアインタビューやら情報が既に錯綜しているので、経緯と公式情報は現状Wikipediaが最も綺麗にまとまっています。

 Windows/Mac/Linux、DirectX/OpenGL対応のOVR SDK(C++)があり、
Unity、Unreal Engine(UDK含む)用のインテグレーションSDKも公式で配布されています。
オープンソースゲームエンジンのTorque3Dも既に対応しているのでこちらもおススメです。

 無料・無期限で全機能を使えるUDKやオープンソースのTorque3Dでも良いんですが、
私は2010年から触っているのと、2012年からMacをメインマシンにした関係でUnityを使っています。

 Oculus RiftはネイティブDLLで動作するのでUnity Proが必須ですが、Oculus Riftを購入するとUnity Pro体験版の4ヶ月延長コードが付いてくるのでソフトを有償頒布しない限りこれで十分だと思います。期限が切れたらUnity Proを買うか他のゲームエンジンに乗り換えましょう。
 
 Unityではカメラやキャラクターコントローラ等を公式SDKで用意されているスクリプトやPrefabに準拠して作成すればOculus Riftに対応することが出来ます。

UnityでOculus Riftを使いたい…けど

 さて、UnityでOculus Riftを使うにあたって問題になるのがUnity製アプリのファイル形式です。
Unityでビルドされたアプリは実行ファイルとリソースファイルがセットになっています。
そのため、単純に

  • Oculus Rift対応バージョン
  • 通常バージョン

を両方作成するとリソースファイルがダブって無駄になってしまいます。
ビルド2回、容量が2倍と悪いことづくめなので何とかこれを解決しましょう。

Oculus Riftが使用可能か設定ファイルで判別する

 Oculus Riftが付いていても通常のモニタでプレイしたい場合はこれだけでいいでしょう。しかし、もしOculus Riftで表示する設定が有効になっていた場合、Oculus Riftが無い環境でもあの樽型シェーダで画面を表示しますか?

正気ですか?

Oculus Riftが使用可能かプログラムで判別する

 ということでこちらを実装しましょう。
幸い、Oculus RiftのSDKには次のクラスメソッドが用意されています。

OVRDevice
// 表示デバイスがHMDかどうか(ミラーリング含む)
bool OVRDevice.IsHMDPresent();

 このメソッドを実行するとPCとOculus Riftが映像ケーブル(DVI/HDMI)で接続されているかどうかをtrue/falseで返してくれます。これを用いて条件分岐を行い通常ディスプレイ用のカメラオブジェクトとOculus Rift用のカメラオブジェクトを切り替えれば一つの実行ファイルで手動のコンフィグだけに頼らないユニバーサルアプリを作成することが出来ます。

 また、OVRDeviceクラスではセンサーの情報も取ることが出来ます。
映像ケーブルが挿してあってもOculus Riftのヘッドトラッキングを行っているUSBケーブルが抜けていたらOculus Riftモードにはしないと言った処理も可能です。

OVRDevice
// Oculus Riftのセンサー数
int OVRDevice.SensorCount;

// Oculus Riftのn番目のセンサーが有効か
bool OVRDevice.IsSensorPresent(int);

 OVRDeviceはMonoBehaviourクラスを継承しており、これらの値は基本的にAwake関数(GameObjectコンストラクタ)内で実行されます。

そのため、OVRDeviceをGameObjectに割り当てなければ上記のコードは動作しません。

カメラ切り替え等の初期化処理を行うGameObjectにOVRDeviceスクリプトも割り当てておきましょう。

※OVRDevice.IsHMDPresentが接続状態に関わらずtrueになってしまう環境もあるという報告もあるのでセンサー情報と&&で有無判定を行った方が無難です。

シーン切替え時に前のシーンのトラッキング情報を引き継ぐ

 何じゃそりゃ?と思うかもしれませんが、OVRDeviceの値はDestroy→Awakeを繰り返すごとにリセットされてしまいます。

「そんなの当たり前だろう」と思うかも知れませんが、Oculus Riftの場合は「リセット時に初期方向の位置がセットされる」ので、単純にシーン切替時の頭の向きが次のシーンの初期位置になってしまいます。

 これは場所を広く取って立ちながらプレイできる環境なら問題ありませんが、椅子に座ってプレイするゲームの場合は首を捻った位置でもホームポジションにされてしまうので、体を捻るかシーン切り替えの度に頭を元の位置に戻さなければならなくなり、非常に不便です。

 この問題を直接解決する機能は以前の公式SDKには存在しなかったのですが、SDK Ver0.2.4でOVRDeviceに追加されました。

OVRDevice
// トラッカーをリセットするか
bool OVRDevice.ResetTracker;

 ResetTrackerをUnityのインスペクタやスクリプトなどでfalseに設定しておくと、
OVRDeviceはOnDestroy時にトラッキング情報を破棄せず、次のシーンのOVRDeviceは前のシーンのトラッキング情報をそのまま引き継ぎます。
これでプレイヤーはシーン切替時の自分の首の角度を意識せずに済みます。

Oculus Rift対応のゲームを作ってみた

 もう先々月の話になりますが、このOculus RiftとLEAP Motionに対応しつつ通常のモニタにも対応したゲーム「Perilous Dimension」をコミックマーケット84で頒布しました。

 上記の処理を用いて起動時に自動でOculus Riftと通常表示を切り替える仕様になっています。
しかし、Oculus RiftとLEAP Motion前提にシンプルなゲームデザインにしているので、通常表示で遊ぶとボリュームも少なく微妙に感じられてしまう方が多いかと思います。
面白いゲームを遊びたい方はメロンブックス専売の天壌のテンペストを買いましょう。

 開発の動機としてはアメリカでは企業も個人もエロもOculus Rift対応ソフトをバンバン出している中で日本では一向にOculus Rift対応のゲームが出てこないことに焦りを感じて作ったわけですが、コミックマーケットやINDIE STREAMに展示して100名近くの方に遊んで頂いた結果、多くの方に満足して頂けたのでOculus Riftの魅力を伝えるという当初の目的は果たせたのかなと思います。

コミックマーケット84(Game Spark)
コミックマーケット84(電撃オンライン)
INDIE STREAM(R30ゲーム)

 制作時の予想を遥かに上回る好評だったので、現在は年内中の委託頒布を目処にクオリティアップとボリュームアップ作業を行っています。
11月9日の東京ロケテゲームショウにもPerilous Dimensionを展示予定ですし、
11月17日のデジゲー博にも展示と頒布を行うので興味のある方は是非お越しください。

終わりに

 Oculus Riftはまだ 発 売 前 のデバイスで、需要に対してソフトの供給が全く追い付いていない状況です。
そのためUnityでもUnrealEngineでもTorque3Dでも自作エンジンでも良いので、Oculus Rift対応ソフトを作ることは大いに意義があることです。
皆さんも是非Oculus Rift対応のゲームやアプリを開発して、
一緒に最高のHMDにしようぜ

関連リンク

Oculus VR Developer Center : 公式開発者向けサイト

Oculus VR Share(Beta) : 公式アプリ投稿プラットフォーム

VirtualReality.io : 非公式アプリプラットフォーム(UIもOculus前提)