VR開発メモトップ

Unity+Oculus Rift開発メモ

最終更新日:2016年08月15日

UnityでOculus Rift対応ソフトを開発する方法やTipsをまとめています。

更新履歴

(2016年8月15日)開発以外の情報を「Oculus Riftについて」ページに分離
(2016年8月6日)Unityの推奨バージョンを更新
(2016年7月25日)Unityのフォーラムのリンクを修正
(2016年7月12日)Oculus Utilitiesのリンクを変更
(2016年7月7日)Unityのフォーラムのリンクを変更

目次


UnityでOculus Rift対応ソフトを作るには

Unityは標準でVRサポートが組み込まれており、Oculus Riftにも対応しています。Oculus VRがUnityの推奨バージョンを公開しています。2016年8月15日現在、安定版のUnity 5.4.0f3および、パッチリリースのUnity 5.3.6p1が推奨バージョンのようです。

自作のソフトをOculus Riftで動かすには、Oculusソフトウェアの設定を変更する必要があります。

Oculusソフトウェアを起動して右上の歯車アイコンをクリック、Settingsを選択、左のGeneralを選択してUnknown Sourcesをオンにします。

UnityのプロジェクトをOculus Riftに対応させるには、Player SettingsのOther Settingsにある「Virtual Reality Supported」をチェックしてオンにしてください。エディタの再生ボタンを押すか、Standaloneでビルドして実行し、Oculus Riftを被って表示されれば成功です。警告画面でゲームコントローラーのボタンを押すか、画面下のメッセージを2秒間注視するとスタートします。

ビルドして実行する際、Riftの画面がPlease wait …の表示で止まっている場合は、Unityの起動ダイアログでPlayをクリックします(Oculusソフトウェアのウィンドウの下に隠れていることがあります)。

また、Unity公式からVR Samplesというサンプルプロジェクトが提供されています。とりあえずこれをビルドしてみるのがおすすめです。同じくUnity公式のVRのチュートリアルは英語ですが非常に分かりやすい内容になっています。

さらに、Oculus VRのダウンロードページにあるOculus Utilities for Unity 5をインポートすることで、Oculus Rift固有の機能が使えるようになります(「Oculus Utilitiesは何をするの?」を参照)。

動かない/スムーズに動かない

上手く行けば、ビルドしたものがスムーズに動いてヘッドトラッキングもぴったりついてくるはずですが、そうでない場合、何かがおかしいです。

以下のようなことを試してみてください。

エディタで再生するとカクつくんだけど

GameビューのMaximize on Playをオンにしておくと、いくらかカクつきが減るかもしれません。

「HEALTH & SAFETY WARNING」の警告メッセージはなくせないの?

DK2では消せたのですが、製品版のOculusソフトウェアでは消せないようです。ただ、起動して一度消すと再表示されなくなるようですので、あまり邪魔になることはないかもしれません。

Windows 10でも大丈夫?

対応しています。Windows 10は64ビット版が必要です。


開発Tips

Virtual Reality Supportedをオンにすると何が起きるの?

ビルドするとOculusのプラグインが出力ファイルに同梱され、Oculus Riftが接続されていると自動的にOculus Riftにも出力するようになります。Render Textureの設定されていないカメラが自動的にステレオレンダリングになり、左右両画面のカリングやシャドウマップの共通化などの最適化が行われます。

また、実行時にカメラのField of ViewがHMDにあわせて変更され、PositionとRotationがトラッキングの動きで上書きされるようになります。このため、スクリプトなどでカメラを動かす場合には、他のオブジェクトの子オブジェクトにする必要があります。

Oculus Riftが接続されていなければ通常通りPCに表示されます。これによって、Oculus Riftと非Oculus Rift両対応のソフトを作ることができます。

Oculus Utilitiesは何をするの?

Oculus VRのダウンロードページにあるOculus Utilities for Unity 5をインポートすると、UnityのVRサポート機能にはない、以下のようなOculus Rift固有の機能を使用できるようになります。

なお、Oculus Utilitiesの機能を使用すると、当然ながらOculus Rift依存のアプリケーションになります。他のヘッドセットへの移植を考慮する場合、できるだけUnity本体の機能のみで作り、依存箇所を何らかの方法で吸収することを考えたほうがいいかもしれません。

位置トラッキングの合わせ方を教えて

まず、シーン内のカメラをプレイヤーの頭の位置(正確には両目の中間)に配置してください。その上で、実行中にちょうどいい場所に立つ、椅子に深く座るなどして、キーなどでトラッキングのリセットをかけます。以下のようなスクリプトを適当なゲームオブジェクトにアタッチして使います。

using UnityEngine;
using UnityEngine.VR;

public class RKeyToRecenter : MonoBehaviour
{
    void Update()
    {
        // Rキーで位置トラッキングをリセットする
        if (Input.GetKeyDown(KeyCode.R)) {
            InputTracking.Recenter();
        }
    }
}

Riftが位置トラッキングカメラの視界に入ってさえいれば、位置・向きとも比較的自由にトラッキングされます。

なお、位置トラッキングカメラを動かしたときは、Oculusソフトウェアでリセットする必要があります。右上の歯車>Settings>Devices>右上のConfigure Rift>Configure Riftで目の高さを入力し、「Set Your View in VR」の表示が出たらRiftをかぶって、正面を向いてXboxコントローラーのAボタンを押します。

Sceneビューのカメラアイコンが大きくて位置がよく分からない

SceneビューのバーにあるGizmosをクリックして、3D Gizmosのスライダーを左に動かしてみてください。

スケール(縮尺)の合わせかたを教えて

Riftの左右の映像はUnityのシーン内で左右の目の間隔(デフォルトでは6.4cm)ぶんずらした位置からレンダリングされ、この両眼視差によってVR空間の物体が現実的な大きさに感じられるようになっています。Unityは1ユニット=1メートルになっていますので、特に実写系のコンテンツではこれに従うのが基本です。例えば、身長170cmのキャラクターを出すときは、Unity上で頭頂まで縦1.7になるようにサイズを調整します。

オブジェクトのサイズを調整する際には、エディタ上でCubeオブジェクトを作って適当なスケールを入力して、定規代わりにすると便利です。

また、普段の生活で大きさをよく知っているものをVR空間に出してスケール感の手がかりにするのも良いかと思います。

Unity GUIを使うには?

Canvasを作成しRender ModeをWorld Spaceにして、Scaleを0.01などに設定して小さくしてシーンに配置します。

UIをカメラの向きに追随させて常に同じ位置に表示する場合は、Render ModeをScreen Space - CameraにしてRender Cameraにカメラを割り当て、Plane Distanceに表示する距離(メートル)を設定します。

なお、Oculusのベストプラクティスでは、UIは3D空間の構成要素として作成し、視点から2~3メートル=ユニットの距離に表示することが推奨されています。

UIとのインタラクションについては、Unity公式のVR Samplesに含まれているスクリプトを使用するのが簡単です。使い方や、VRでのUIの考え方については、チュートリアルのInteraction in VRおよびUser Interfaces for VRで解説されています(手抜きですいません。そのうち詳しく……)。

描画設定やアンチエイリアスについて

アンチエイリアスについては、Oculus VR社のvrdaveb氏のコメントによれば、Player SettingsでRendering PathをForwardにして、Quality SettingsのAnti AliasingでMulti Sampling(MSAA)をかけることが推奨されています。Deferredは帯域コストが高く、MSAAが使えないため不利になります。MSAAはイメージエフェクトのアンチエイリアス(FXAA)よりも軽量で、ポリゴンのエッジが綺麗です。ただし、HDRレンダリングをする場合はMSAAが使えないため、FXAAを使うことになります。

同じくPlayer SettingsのColor SpaceをGammaではなくLinearにすることが推奨されています。シェーディングが正確になるだけでなく、樽型変形のエイリアシングが大幅に減るとのことです。

レンダリング解像度を変更するには?

GPUの描画負荷は、描画するピクセル数と、ピクセルあたりのシェーダの複雑さに比例することが多いです。パフォーマンスが出ない場合、VRSettings.renderScaleでレンダリング解像度を下げると効果がある場合があります。

UnityEngine.VR.VRSettings.renderScale = 0.5f; // デフォルトは1.0f

Oculus Riftの位置・向きを取得するには?

Oculus Riftの位置・向きによってカメラのtransformが変化しますので、これを参照できます。

もしくは、InputTracking.GetLocalPosition/GetLocalRotationでカメラオブジェクトを基点にしたローカル座標と向きが取得できます。

using UnityEngine.VR;
...
Vector3 position = InputTracking.GetLocalPosition(VRNode.CenterEye);
Quaternion rotation = InputTracking.GetLocalRotation(VRNode.CenterEye);

VRNode.LeftEye/RightEye/CenterEye/Headでそれぞれ左右の目と、目の中間、頭部の位置・向きが取得できます。CenterEyeとHeadは同じ値が戻ってくるようです。

Oculus Riftの接続チェックをするには?

Riftが接続されていれば、VRDevice.isPresentがtrueになります。

using UnityEngine.VR;
...
if (VRDevice.isPresent) { /* Riftあり */ }

接続しているデバイスの種類を知るには?

VRDevice.family/modelを使用します。

using UnityEngine.VR;
...
Debug.Log("VRDevice.family = " + VRDevice.family);
Debug.Log("VRDevice.model = " + VRDevice.model);

このような出力が得られます。

VRDevice.family = oculus
VRDevice.model = Oculus Rift DK2

PCの画面に別視点の映像を表示するには?

カメラをシーンに追加し、Target Eyeを「None (Main Display)」に設定してください。また、どちらかのカメラから余分なAudio Listenerを削除してください。ビルドして実行すると別視点の画面がPC側に表示されます。

PC側のカメラのDepthの数値をRift側のカメラより大きくしておく必要があります。もしくは、VRSettings.showDeviceViewでRift側のカメラのミラー表示を無効にしてください(こちらのほうがより軽量なのではと思います)。

using UnityEngine;

public class HideRiftView : MonoBehaviour
{
    void Start()
    {
        UnityEngine.VR.VRSettings.showDeviceView = false;
    }
}

なお当然ですが、一画面余分にレンダリングしますので、そのぶん負荷が増えます。フレーム落ちする場合は、起動ダイアログの解像度設定を下げてみてください。

別のPCでプログラムをもう1つ動かして、ネットゲームの要領で同期表示することを検討してもいいかもしれません。

シーンにカメラを複数設置して同時描画できる?

通常のプロジェクトと同じようにカメラを複数使用してレイヤー表示できます。後から描画する方のカメラのClear FlagsをDepth OnlyもしくはDon’t Clearに、Depthを1以上に変更してください。また、余分なAudio Listenerを削除してください。

Oculus Utilitiesを使用している場合、OVRCameraRigが複数あると警告が出ます。Unityの通常のカメラを追加してください。

キャラクターのスケールを変更したい

既存のプロジェクトが1ユニット=1メートルになっていない場合や、巨人の視界などを表現したいというような場合があります。

カメラを別のオブジェクトの子にして、親オブジェクトのScaleを変更すれば実現できます。カメラ自身のScaleを変更しても反応しないので注意です。

サウンドに関する注意

ヘッドホンとスピーカーでは音声の定位が異なります。ヘッドホンは頭を動かすと一緒に回りますが、スピーカーは回りません。スピーカーで音声を出力する場合は、カメラからAudio Listenerを削除して別のオブジェクトにアタッチする必要があります。

Xbox Oneコントローラーの入力を取るには?

Unity本体で取得する場合、Input Managerにおけるジョイスティックの軸とボタンのマッピングは以下のようになっています。

Axis/Button
X axis 左アナログスティック X軸(左-1~右1)
Y axis 左アナログスティック Y軸(上-1~下1)
4th axis 右アナログスティック X軸(左-1~右1)
5th axis 右アナログスティック Y軸(上-1~下1)
7th axis 方向キー X軸(左-1、右1)
8th axis 方向キー Y軸(下-1、上1)※アナログスティックと逆
3rd / 9th axis LT(リリース-1~最大1)
6th / 10th axis RT(リリース-1~最大1)
joystick button 0 Aボタン
joystick button 1 Bボタン
joystick button 2 Xボタン
joystick button 3 Yボタン
joystick button 4 LB
joystick button 5 RB
joystick button 6 ビューボタン(中央左のボタン)
joystick button 7 メニューボタン(中央右のボタン)
joystick button 8 左アナログスティック押し込み
joystick button 9 右アナログスティック押し込み
joystick button 10 Xboxボタン

または、Oculus UtilitiesのOVRInputで取得します。

Oculus Remoteの入力を取るには?

Unity本体では、ベータリリースのUnity 5.4.0b22以降でジョイスティック入力として取得できます。Input Managerにおける軸とボタンのマッピングは以下のようになっています。Xbox Oneコントローラーの方向キーおよびA/Bボタンと同一になっています。

Axis/Button
7th axis 方向キー X軸(左-1、右1)
8th axis 方向キー Y軸(下-1、上1)
joystick button 0 Selectボタン
joystick button 1 Backボタン

Oculusボタンと2つのボリュームボタンにはアクセスできません。

また、Input.GetJoystickNames()で取得できる文字列の配列に”Oculus Remote”が入っています。

Oculus UtilitiesのOVRInputでも取得できます。

Oculus Homeに戻るには?

Application.Quit()で終了します。または、Universal MenuでいつでもExit to Homeできます。終了時にOnApplicationQuit()が呼ばれますので、ここでデータの保存処理などを行います。

unsupported graphics APIと怒られる

VRサポートを有効にしても、

[Compositor] ERROR: Cannot start with unsupported graphics API.
Bad config or LibOVR not found. VR disabled.

と表示されてVRモードにならない場合、Player SettingsのGraphics APIs for WindowsでDirect3D9が使用されている可能性があります。すぐ上のAutomatic Graphics APIをチェックしDirect3D11が使用されるようにして、Unityを再起動してください。


不具合など

個人的に遭遇・把握している不具合を載せます。


Oculus Touchについて

Oculus VRは、Oculus Riftとは別に、Oculus Touchという両手に握って操作する入力コントローラを2016年後半に発売予定とのことです。

Oculus Touchはヘッドセット同様、主に外周リング部に埋め込まれた赤外線LEDと位置トラッキングカメラでトラッキングされます。精度の向上と、手や身体でLEDが隠れて位置をロストする問題の軽減のために、少なくとも2つの位置トラッキングカメラを使用することになっており、Oculus Touchを購入するともう1つの位置トラッキングカメラがついてくるようです。カメラの配置は比較的自由なようです。

Oculus TouchのAPIはOculus Utilitiesに含まれています。公開されているドキュメント(Oculus Touch ControllersOVRInput)から、以下のような仕様が伺えます。

また、Oculus Touchの位置はOVRCameraRigの子のTransformとして読めるほか、OVRInput.GetLocalControllerPosition/GetLocalControllerRotationで取得できるようです。

Oculus Touchとの無線通信についてはOculus Rift(ヘッドセット)に受信機が入っており、展示でたくさん並べて使用しても電波干渉の心配はないとのことです。


番外編

Oculus Rift製品版のランタイムでは(DK2と異なり)非同期タイムワープがサポートされ、フレームレートが低くても頭の回転ではカクつきません。ただ、これにあまり頼らないようにとのことです。

Oculus Platform SDKで、ストア向けアプリにおいて、リーダーボード、マルチプレイヤーマッチメイキング、P2Pネットワーキングなどがサポートされるようです。Oculus SDK for WindowsのPlatformSDK¥UnityにUnity用のパッケージが入っています。

製品版のOculusソフトウェア向けにビルドするとOculus Rift DK2の画面が旧Oculus Runtimeと比べ明るくなりますが、仕様とのことです。輝度を上げてガンマを正確にしたとのことです。

Leap MotionのOculus Rift製品版についてのFAQが公開されています。


参考リンク

書いた人:こりん(@k0rin
リンク切れや間違いなどございましたらメールやTwitterでご指摘ください。
VR開発メモトップ RSS