Oculus Unity Integrationクロスプラットフォーム開発ドキュメンテーション 私家訳版


この記事はOculus Rift Advent Calendar 2018の4日目です。

はじめに

先日11月15日、Oculus SDKの一部であり、Oculus公式のUnity統合であるOculus Integration (Oculus Utilities for Unity)の最新版1.31が公開されました。このバージョンの大きな新機能が、Oculus Integrationを使ったままHTC Viveの動作がサポートされる、クロスプラットフォーム開発機能です。

以前からSteamVR SDKはViveにネイティブ対応しているのに加えRiftをサポートしていましたが、今回の対応により、Oculus側のSDKを使用した場合も、両方のヘッドセットに向けた開発が(少なくともUnityにおいては)可能になります。

前述の通りSteamVR SDKはViveとRift両方に対応していますが、問題なのが、SteamVR SDKを使用した場合はそのままではOculus Storeへの提出ができないという点です(その逆、つまり今回のOculus SDKのクロスプラットフォーム機能を使って実装したアプリをSteamに出すのは問題ないはず)。また、注目度の高いOculus Goや今後登場するOculus QuestはOculus SDKでしか動作しないため、これらにも対応したい場合いずれにしてもOculus SDKを避けて通ることはできません。もちろん、移植は色々な要素が絡むため、こういった機能があってもボタン一発とまではいきません。しかし、なるべく同じ機能の再実装を避けながら、PC・スタンドアローンを含む多くのプラットフォームに対応するという点においては、本機能は便利に使えるのではないでしょうか。

以下はOculusデベロッパードキュメンテーションのクロスプラットフォーム開発についてのページの私家版翻訳となります。


Unityでのクロスプラットフォーム開発について

※クロスプラットフォーム開発は現在試験的機能です。機能は変更または削除される場合があります。

開発者が複数のプラットフォームやデバイスをターゲットしたい場合、Oculus Integration (Oculus Utilities for Unity)を使ってOpenVR向けのビルドを作成する事ができます。本記事では、クロスプラットフォーム開発で使用できるAPIについて、また通常のOculus向け開発と異なる点について解説します。APIの通常の使用方法や開発プロセスについてはドキュメンテーションの別ページで解説されていますので、本記事ではカバーしません。

開発者はクロスプラットフォーム開発機能を使うことで、OculusまたはSteamVRプラットフォームに向けて、追加工数を最低限に抑えながらそのまま動作するアプリを開発することができます。クロスプラットフォーム機能は、入力周りでは、6自由度のヘッドマウントディスプレイとコントローラー、即ちOculus Rift+Touchや、HTC Viveとそのコントローラーに対応しています。現時点では、この2つのみがサポートされています。

カメラ – OVRCameraRig

基本的にはOculus Utilities for Unityガイドに書かれた手順通りに進めます。既存のアプリをアップデートする場合、OpenVR HMDおよびそのコントローラーをトラッキングするには、既にあるカメラを削除し、改めてOVRCameraRigのPrefabをシーンにドラッグして入れる必要があります。

OVRCameraRig Prefabをシーンに入れる際、Tracking Originは必ずFloorLevelに設定してください。クロスプラットフォーム開発時は、EyeLevelはサポートされていません。

クロスプラットフォーム開発時は、コントローラーの動きに追随するオブジェクトはLControllerAnchorまたはRControllerAnchorの子になっている必要があります。

HMDトラッキング – OVRDisplay

以下のAPIで、トラッキング空間内でのHMDの加速度を取得することができます。これらのAPIはクロスプラットフォーム開発に対応しています。

  • OVRDisplay.velocity()
  • OVRDisplay.angularvelocity()

入力 – OVRInput

Oculusコントローラー使用時の使用方法はOVRInputのガイドページをご覧ください。クロスプラットフォーム開発時には、以下のAPIを使うことができます。

個別のボタン

以下のボタンは、Get(), GetUp(), GetDown()に対応しています。Get()はボタンの入力状態(押されていればtrue)、GetUp()はそのフレームにボタンが離されたかどうか(離されていればtrue)、GetDown()はそのフレームにボタンが押されたかどうか(押されていればtrue)を調べます。OculusコントローラーのマッピングについてはOVRInputページをご覧ください。

  • Button.PrimaryIndexTrigger
  • Button.SecondaryIndexTrigger
  • Button.PrimaryHandTrigger
  • Button.SecondaryHandTrigger
  • Button.PrimaryThumbstick
  • Button.SecondaryThumbstick
  • Button.Two
  • Button.Four
  • Axis1D.PrimaryIndexTrigger
  • Axis1D.PrimaryHandTrigger
  • Axis1D.SecondaryIndexTrigger
  • Axis1D.SecondaryHandTrigger
  • Axis2D.PrimaryThumbstick
  • Axis2D.SecondaryThumbstick

既存アプリとの下位互換性維持のため、これらのAPIのなかではOculus TouchとViveコントローラーの両方が“Touch”として扱われます。左のXRコントローラーはLTouch、右はRTouchとなります。

ボタンや各種入力の状態は、以下のいずれかに対して求めることができます。

  • Controller.LTouch
  • Controller.RTouch
  • Controller.Touch

[訳注: 上記API群は、原則的に(取得したいボタン名, 問い合わせたいコントローラー名)という引数の構造を持っています。OVRInputで指定できるボタン名には“Primary” “Secondary”という指定があり、左手か右手どちらに対する問い合わせなのかを明示的に指定せずにPrimaryボタンの状態を取得した場合、「左手コントローラーが有効であれば左手側についている方、無ければ右手側の方」に問い合わせる挙動となります。細かい対応関係一覧はOVRInput内のButton enumを確認してください。次の段落はこれを踏まえています]

クロスプラットフォーム開発でOVRInputを使う場合、第二引数で問い合わせ先のコントローラーを明示的に指定したうえで、第一引数でPrimaryのボタンを指定する事をお勧めします。第二引数のコントローラーの左右の指定は必須ではありませんが、多くの場合指定しておいた方が簡単になります。以下にいくつか例を示します。

  • OVRInput.Get(Button.PrimaryHandTrigger, Controller.LTouch) – 左手のXRコントローラーの「グリップ」トリガーまたはボタンが握り締められている間trueを返します。
  • OVRInput.GetDown(Button.Two, Controller.LTouch) – 左手のXRコントローラーの「上の方のボタン」が現フレームで押し込まれた場合trueを返します。これはOculus Touchの場合はYボタン、Viveコントローラーの場合は横棒が3つ入ったメニューボタンとなります。
  • OVRInput.Get(Axis1D.PrimaryIndexTrigger. Controller.RTouch) – 右手のXRコントローラーの人差し指トリガーが押し込まれている度合いを0.0-1.0の間で返します。

コントローラーの姿勢と加速度

以下のAPIでトラッキング空間内でのコントローラーの姿勢および加速度を取得することができます。これらのAPIはクロスプラットフォーム開発に対応しています。

  • GetLocalControllerPosition()
  • GetLocalControllerRotation()
  • GetLocalControllerVelocity()
  • GetLocalControllerAngularVelocity()

対応OpenVRコントローラーのボタンマッピング

HTC Viveコントローラーは、上記で紹介したOVRInputの各種APIにおいては、以下のボタン名に対応する形で扱われます。

  • Button.Two – メニューボタン
  • Axis2D.PrimaryThumbstick – 静電容量式トラックパッド
  • Button.PrimaryThumbstick – トラックパッドの押し込み
  • Axis1D.PrimaryIndexTrigger – トリガー
  • Axis1D.PrimaryHandTrigger – コントローラー側面のグリップボタン

ハプティクス(振動) – SetControllerVibration()

クロスプラットフォームでのコントローラーを振動させる場合は、SetControllerVibration APIを使用してください。OVRHapticsおよびOVRHapticsClip APIはクロスプラットフォーム開発に対応していません。
本APIの使用方法については、OVRInputガイドをご覧ください。クロスプラットフォーム開発デバイスの場合は、第一引数の周波数は1.0で固定、第二引数の振幅は0.0-1.0の範囲で指定する事が可能です。以下に例を示します。

  • OVRInput.SetControllerVibration(1.0f, 0.5f, Controller.RTouch) – ピーク振幅の半分で、右のXRコントローラーを振動させます。この振動は、新たに振動が指定されるか、0を指定されて停止するかするまで続きます。また、新たに振動を指定せずに2秒経過した場合はタイムアウトで自動的に停止します。
  • OVRInput.SetControllerVibration(1.0f, 0.0f, Controller.RTouch) – 右のXRコントローラーの振動を停止します。

境界線・プレイエリア – OVRBoundary

OVRBoundaryを使用する事で、ユーザーのプレイエリア情報を取得・設定する事ができます。詳しくはOVRBoundaryガイドをご覧ください。以下のAPIがクロスプラットフォーム開発に対応しています。

  • GetDimensions()
  • GetGeometry()
  • SetVisible()
  • GetVisible()
  • GetConfigured()

GetGeometry()は実行時に小規模なガベージコレクション割り当てが発生するため、毎フレーム実行するのではなく、一回実行して取得したものをキャッシュしてください。

クロスプラットフォームアバター

Unityにおいて、Oculusアバターはクロスプラットフォーム開発に対応しています。クロスプラットフォームでのアバター使用について詳しくは、Unityクロスプラットフォームアバターサンプルシーンの解説ページをご覧ください。

Oculus Rift/Gear VRアプリでローディング画面の視界端に見える黒枠を別の色にする


Oculus RiftやGear VRのVRアプリにおいて、ローディング画面などでレンダリングがリフレッシュレートに間に合わず、Asynchronous Timewarp (ATW)処理で擬似的に生成されたフレームが表示されることがあります。このような時、ATWが前の絵の位置をずらしているため、ずれた分だけ表示領域の端に黒い枠が見えてきます。

現状こちらの色を一発で変更する方法はないのですが、Compositor Layerという機能を応用することで色を変えることが可能です。Oculus Utilities for UnityではOVROverlayというコンポーネント名、Unreal EngineではStereo Layersという名前で組み込まれています。

「Compositor Layer (Timewarp Layer)」はOculus SDKに内蔵されている、一部のオブジェクトを通常のレンダリングと別枠で、出力直前に合成して表示することができる機能です。Compositor Layerを使って表示できるものは板ポリゴン(Quad)やキューブマップ、円筒など形状が限定されます1が、レンダリングのフレームレートではなくコンポジターのフレームレートで動作するため、通常のレンダリングが間に合っていない時であっても常時滑らかに表示されます。(名前が似ていますが、Unityのレイヤー機能とは無関係です。)

例えばUnityでは以下のように:

  • Main Cameraの子としてQuadオブジェクトを作成(位置は0,0,0
  • Quadオブジェクトのマテリアルとして白一色の画像テクスチャ(ここではwhitesquare)を貼り付けたマテリアルを指定
  • QuadオブジェクトにOVROverlayコンポーネントを貼り付ける
  • OVROverlayCurrent Overlay TypeUnderlayCurrent Overlay ShapeQuadに指定。これにより、通常のレンダリングが行われていない(はみ出した)領域にのみ、このQuadが表示されます。
  • OVROverlayの中にあるTextures変数に先程と同じ白一色のテクスチャを2箇所とも指定する

こうすると、ATWで生成されたフレームが見えている間も、普段ならはみ出して黒い背景が表示されている部分に白いQuadが表示されるため、背景の色が白に見えるようになります。2
なお、挙動の確認のためにわざとレンダリングの処理落ちを起こすには、Update()内にSystem.Threading.Thread.Sleep(500);などを入れたコンポーネントをどこかに貼っておくと起こせます。

このほか、Compositor Layerは処理落ち中でもガタつかない注視カーソルの実装や、画質が高いことを活かしたUI/テキスト/画像などの表示、またそもそもローディング画面自体をCompositor Layerで作るといった使い方もできます。Compositor Layerについてより詳しくはこちら。

Unity: https://developer.oculus.com/documentation/unity/latest/concepts/unity-ovroverlay/
Unreal: https://developer.oculus.com/documentation/unreal/latest/concepts/unreal-overlay/


  1. 使える形状はPCとモバイルで多少異なります。QuadやCubemapは両方で利用可。 
  2. ただし、白色は人によってはチラツキを視認しやすくなるためお勧めしません。実際に変える場合は暗めの色をお勧めします。 

VPSをMondo Rescueでバックアップ


さくらのVPSで自分用Mastodonインスタンスを立てるまでのYak Shavingの記録…になるはずだが、まだ途中。

改めて見たらUbuntuのバージョンが14.04で古すぎたので、まず16.04にアップグレードするところから始める。
ディストリビューションアップグレード中にぶっ壊れるのは怖いので、まずはバックアップを取る。

これを参考にMondo Rescueでバックアップを取ることにする。
ただ、/etc/apt/sources.list.d/mondorescue.sources.listを追加してsudo apt-get updateしたところ、公開鍵が見つからないようで以下の警告が出る:

W: GPG error: ftp://ftp.mondorescue.org 14.04 Release: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 6BA8C2D220EBFB0E

検索してみたところ、Mondo Rescueメーリングリストで以下のやりとりを発見。
[Mondo-devel] [OT?] New keys for debian repository…

書かれている通り、以下の鍵を追加して解消。

gpg --recv-keys 8AB63AFD171EFF9E
gpg -a --export 8AB63AFD171EFF9E | sudo apt-key add -
gpg --recv-keys 6BA8C2D220EBFB0E
gpg -a --export 6BA8C2D220EBFB0E | sudo apt-key add -

無事Mondo Rescueがインストールできたので、早速バックアップを試みる。

sudo mkdir /backup
sudo mondoarchive -Oi -L -s 50G -d /backup -E /backup -S /tmp -T /tmp -p backup-20170417

途中で以下のエラーが出てバックアップが失敗する。

Mindi failed to create your boot+data disks.
Fatal error... Failed to generate boot+data disks
---FATALERROR--- Failed to generate boot+data disks
If you require technical support, please contact the mailing list.
See http://www.mondorescue.org for details.
The list's members can help you, if you attach that file to your e-mail.
Log file: /var/log/mondoarchive.log
Mondo has aborted.

ログファイル(/var/log/mondoarchive.log)を見たら、ディスクが足りない…?
HDD容量はまだガラガラのはずだけども。

$ df -h
Filesystem      Size  Used Avail Use% Mounted on
(略)
/dev/vda1        96G  7.3G   84G   9% /
(略)

調べたところ、足りてないのはHDD容量ではなく、MindiのRAMディスクの容量らしい。
[Mondo-devel] no space left on device error – mindi

Mindiの設定ファイル/etc/mindi/mindi.confで大きめのサイズを指定する。何回か失敗したが結局以下のサイズで成功。

EXTRA_SPACE=320152      # increase if you run out of ramdisk space
BOOT_SIZE=80960

先ほどと同じバックアップコマンドでバックアップが始まったが、長時間かかる中でSSH接続がタイムアウトしてしまい、接続切断に巻き込まれてmondoarchiveコマンドが終了させられてしまった。
改めて、途中で切れても大丈夫なようにtmuxでセッションを作り、その中で実行する。Ctrl-B dでセッションからdetach。数時間待って再度tmux attachでセッションに入って結果を確認。今回は成功。
Transmitで手元のMacにダウンロードする。

今日はここまで。

ErgoDox EZ カスタマイズ


ErgoDox EZを買ったので、早速カスタマイズしていきます。

Macには現在 ControllerMate および Karabiner/Seil がインストールされているので、実現したい機能をどれを使って実装するかを選んで考えていく必要があります。また、これまで使っていた DHARMAPOINT DRTCKB91UBK との兼ね合いも考えたいところです。

キートップの違いに注意

ErgoDox EZは購入時にキートップを刻印ありか刻印なしのものから選ぶことが出来ますが、この2つの違いは刻印の有無だけではない点に注意する必要があります。刻印なしのキートップは行ごとに傾斜が異なるスカルプチャーキー(DCS)となっていますが、刻印有りは配列を並べ替えられるよう全キーフラット(DSA)になっています。

深く考えずに刻印ありキートップを選んでしまいましたが、実際使い始めてみたら傾斜はある方がいい事に気づいたため、ErgoDox EZ販売サイトにメールして刻印なしキートップを新たに入手することに。気をつけましょう…

英数/かなキー

Macの日本語キーボードにはスペースバーの両隣に英数とかなキーがついており、これによりIMEを切り替える形になっています。現在いるモードを意識する必要が無いのでWindowsで標準的な全角/半角トグルキーよりも好きな仕組みですが、これは入れておきたいところ。

結論から言うと KC_LANG2 が英数キー、 KC_LANG1 がかなキーにあたるキー名なので、この2つを両手に割り当て。まだWindowsでは使ってないですが、Win側でもKarabinerみたいなツールでIME ON/OFFに割り当てることできるかな?

親指シフト

このキーボードを期に親指シフトに挑戦してみようかと考えているところですが、色々調べてみると今使われてる親指シフトの実装方法は大抵親指シフト用のキーが足りないのを補うために下の方のキーを潰してて、そのぶん既存のキーが不便になるっぽい様子。割当し放題なErgoDoxではそんな妥協をしなくてもいいはずなので、両方の親指シフトキーを変換に使えるように出来ないか考えてみます。

  • ErgoDox側で親指右キーの位置に普段まず使わないF16を割り当て
  • KarabinerでF16をスペースに割り当て直し
  • 更にKarabinerで親指シフトの右親指キーをF16に割り当てるバージョンをprivate.xmlに記述

private.xml
(Includeが絶対パスになっちゃってるのが気持ち悪い。もっと綺麗な指定の仕方はないものか)

これにより、左右両親指とも日本語入力時は親指シフトキー、英語入力時にはスペースとして振る舞わせることに成功。
まだ親指シフト配列自体の習得は全く出来てないので、これからですが…

キー配列

デフォルトではErgoDox EZはUSキーボードスタイルとなっていますが、色々割り当てなおしてJISキーボードスタイルに変更するかどうかは目下悩み中。DRTCKB91UBKがJIS配列なので揃えておいたほうが混乱は少ない気はするのですが(特に、Macでは配列の異なるキーボードを複数繋いでもそれぞれ異なる配列認識で共存できるのですが、Windowsでは出来ないっぽいので)。やるとしたら先人の知恵を参考にしながらやってみることとします。

しかしErgoDoxについて調べだして初めて知りましたが、簡単にUSBキーボードとして振る舞わせることが出来るうえにファームウェア書き換えも繋いだまま出来る Teensyマイコンボード とか、便利なものが出来てるんですね今時は。
どうりで自作キーボード作り出した人がやたら増えてるわけだ…

Oculus RiftとLiveViewRiftで全方位パノラマを再生する


2016/10追記: LiveViewRiftは現在更新されないまま大分古くなっており、現在のRift製品版やOculus Softwareに追随できていません。現在は全天球動画などを再生する場合、他のソフトの使用をお勧めします。

最近見つけたLiveViewRiftというソフトが非常に強力だったので紹介したいと思います。

LiveViewRiftはMac/Windows用の、Oculus Riftを使って動画や静止画、全方位・全天球映像等の再生ができるソフトです。

こういったソフトは他にも

等いくつかありますが、LiveViewRiftは非常に設定項目が柔軟で、およそどんな形式でデータが作られていても調整次第で表示が可能である点が大きな特徴です。RICOH THETA等で撮影された全天球画像はもちろんの事、例えば立体視でデータが左目と右目のファイルに分かれている場合や、パノラマが床・空・それ以外のファイルに分かれている場合であっても、複数のファイルをレイヤーとして同時に表示再生する事ができるので対応可能です。

なお、このソフトは現在Oculus RuntimeのExtendモードにのみ対応しています。Windowsの場合、Open Broadcaster Software等を併用しないと表示内容のミラーリングが出来ないので、ご注意ください。