2016年05月21日
UnityでHTC Vive向けのアプリケーションを作る方法やTipsをまとめています(随時更新)。Unity 5.3.5、5.4.0b18時点の内容です。
更新履歴
(2016年5月21日)「トリガーの入力をアナログ値で取るには」を追加
(2016年5月6日)「Lighthouseのメモ」を追加、SteamVRプラグインがUnity 5.4に対応したので項目を削除
(2016年4月27日)「おまけ」にいろいろ追記
(2016年4月22日)「位置トラッキングとカメラの位置について」を追加
(2016年4月19日)Unity 5.4ベータについて更新
HTC Viveって何?
HTC Vive(エイチティーシー・バイブ)は、台湾HTC社が販売しているVRヘッドセットです。2016年4月5日に製品版が発売されました。公式サイトから979ドルで購入が可能です(送料別・納期注意)。Oculus Riftの競合機ですが、Oculus Riftと位置トラッキングの方式が異なること、最大4×3メートルの部屋サイズのプレイエリアを想定していること、2本のモーションコントローラが標準で付属していることが大きな特徴です。また、ソフトウェア面についてはValve社がサポートを行っており、Steamで対応ゲーム等を購入できます。
HTC Vive自体については以下の記事が詳しいです。
また、体験者とVR空間の映像をグリーンバックで合成したイメージ映像があり、雰囲気がつかめるかと思います。
PC環境について
HTC Viveの使用・アプリケーション開発に必要なPCのスペックとその理由については、ほぼOculus Riftと同様です。「Unity+Oculus Rift開発メモ」のPC環境についてを参照してください。違いとして、USBポートは1つで大丈夫です。
また、SteamVR Performance Testという検証ソフトが公開されています。これを実行して、PCが必要スペックを満たすかどうかを確認できます。
セットアップ
ケーブル類を一通り接続したのち、Vive Setupをダウンロードして実行します。セットアップソフトウェアが親切なので、ガイドに従っていれば大丈夫だと思います。詰まったら4Gamer等に詳しい記事がありますので、参考にするといいかと思います。
インストールにはネットワーク接続が必要で、合計1.5GBほどのダウンロードが必要になります(.NET Frameworkを除く)。
ちなみに、モーションコントローラのファームウェアをアップデートしないと認識しないことがあるようです。USBで接続してSteamVRソフトウェアで更新できます。
Unityで対応ソフトを作るには
UnityでHTC Vive対応ソフトを作るには、Asset StoreにあるSteamVRプラグインを使用します。新規のプロジェクトを作成し、SteamVRプラグインをインポートしてください。最新バージョンの1.1.0でUnity 5.4ベータにも対応しています。
SteamVRプラグインを使用せず、Unity本体のVRサポート機能のみでHTC Viveを使うこともできます。ただし、今のところヘッドセットのみの対応で、Viveコントローラが使用できません。UnityのVRサポートを使用する場合を参照してください。
プラグインをインポートすると、SteamVR_Settingsというウィンドウが開きます。これによって、Unityのプロジェクトの設定がSteamVRの推奨設定に変更されます(64ビットビルド、非フルスクリーン、起動ダイアログを出さない、カラースペースをリニアにする等)。問題ないようでしたら、左下の「Accept All」をクリックしてください。「You made the right choice!(正しい選択をしたね!)」というノリノリのメッセージウィンドウが出ますので閉じます。
試しにサンプルシーンを開きます。Projectビューで、SteamVR/Scenes/exampleシーンを開き、再生してください。上手くいけば、HTC Viveの画面にたくさんの立方体とモーションコントローラが表示されているはずです。
また、既存のプロジェクト・シーンをHTC Vive対応にするには、カメラを無効化して、ProjectビューのSteamVR/Prefabs/[CameraRig]プレハブをシーンに配置してください。
Viveコントローラの位置を取るには
[CameraRig]プレハブ下にコントローラのゲームオブジェクト(Controller (left)、Controller (right))があり、Transformで位置や向きを取得できます。
また、SteamVR/Extrasに、コントローラでオブジェクトを投げるSteamVR_TestThrowというサンプルがあります。
トリガーやボタンの入力を取るには
トリガーやボタンは、コントローラのゲームオブジェクトにアタッチされているSteamVR_TrackedObjectコンポーネントからデバイスを参照して、GetTouch / GetPress関数で状態を、GetTouchDown / GetTouchUp / GetPressDown / GetPressUp関数で状態変化を取得することができます。
以下にサンプルスクリプトを示します。ControllerExample.csという名前でController (left)またはController (right)にアタッチしてください。
using UnityEngine;
public class ControllerExample : MonoBehaviour
{
void Update()
{
SteamVR_TrackedObject trackedObject = GetComponent<SteamVR_TrackedObject>();
var device = SteamVR_Controller.Input((int) trackedObject.index);
if (device.GetTouchDown(SteamVR_Controller.ButtonMask.Trigger)) {
Debug.Log("トリガーを浅く引いた");
}
if (device.GetPressDown(SteamVR_Controller.ButtonMask.Trigger)) {
Debug.Log("トリガーを深く引いた");
}
if (device.GetTouchUp(SteamVR_Controller.ButtonMask.Trigger)) {
Debug.Log("トリガーを離した");
}
if (device.GetPressDown(SteamVR_Controller.ButtonMask.Touchpad)) {
Debug.Log("タッチパッドをクリックした");
}
if (device.GetPress(SteamVR_Controller.ButtonMask.Touchpad)) {
Debug.Log("タッチパッドをクリックしている");
}
if (device.GetPressUp(SteamVR_Controller.ButtonMask.Touchpad)) {
Debug.Log("タッチパッドをクリックして離した");
}
if (device.GetTouchDown(SteamVR_Controller.ButtonMask.Touchpad)) {
Debug.Log("タッチパッドに触った");
}
if (device.GetTouchUp(SteamVR_Controller.ButtonMask.Touchpad)) {
Debug.Log("タッチパッドを離した");
}
if (device.GetPressDown(SteamVR_Controller.ButtonMask.ApplicationMenu)) {
Debug.Log("メニューボタンをクリックした");
}
if (device.GetPressDown(SteamVR_Controller.ButtonMask.Grip)) {
Debug.Log("グリップボタンをクリックした");
}
if (device.GetTouch(SteamVR_Controller.ButtonMask.Trigger)) {
//Debug.Log("トリガーを浅く引いている");
}
if (device.GetPress(SteamVR_Controller.ButtonMask.Trigger)) {
//Debug.Log("トリガーを深く引いている");
}
if (device.GetTouch(SteamVR_Controller.ButtonMask.Touchpad)) {
//Debug.Log("タッチパッドに触っている");
}
}
}
トリガーの入力をアナログ値で取るには
GetAxis関数でトリガーのIDを指定して、戻り値のVector2のxで取得できます。サンプルスクリプトを示します。TriggerExample.csという名前でController (left)またはController (right)にアタッチしてください。
using UnityEngine;
public class TriggerExample : MonoBehaviour
{
void Update()
{
SteamVR_TrackedObject trackedObject = GetComponent<SteamVR_TrackedObject>();
var device = SteamVR_Controller.Input((int) trackedObject.index);
float value = device.GetAxis(Valve.VR.EVRButtonId.k_EButton_SteamVR_Trigger).x;
Debug.Log(value);
}
}
戻り値は0から1の範囲になります。トリガーをクリック直前まで引くと0.8強くらいまで上がり、カチッとクリックすると1にジャンプするようです。ただし、このクリック判定はコントローラによってあまり信頼できないという話があります。また、トリガーを離しても完全に0に戻らないことがあります。
タッチパッドのタッチ位置を取るには
GetAxis関数で取得できます。サンプルスクリプトを示します。TouchpadExample.csという名前でController (left)またはController (right)にアタッチしてください。
using UnityEngine;
public class TouchpadExample : MonoBehaviour
{
void Update()
{
SteamVR_TrackedObject trackedObject = GetComponent<SteamVR_TrackedObject>();
var device = SteamVR_Controller.Input((int) trackedObject.index);
Vector2 position = device.GetAxis();
Debug.Log("x: " + position.x + " y: " + position.y);
}
}
GetAxisの戻り値は、X軸が-1(左)から1(右)、Y軸が-1(下)から1(上)です。また、タッチパッドから指が離れていると(0, 0)が返ってきます。
GetPressDown (SteamVR_Controller.ButtonMask.Touchpad)と組み合わせて、どのあたりをクリックしたかを取ることもできます。端の方は取れないため注意です。
Viveコントローラの表示を消すには/違うオブジェクトを表示するには
コントローラのオブジェクトの子のModelにアタッチされているSteam VR Render Modelスクリプトのチェックを切って無効化します。
異なるオブジェクトを表示するには、Controller (left)またはController (right)に子オブジェクトをアタッチします。
Viveコントローラを振動させるには
TriggerHapticPulse関数を使います。引数で振動の大きさを指定します。最大3999まで機能しますが、100~2000ほどが有効範囲かなと思います(もう少し要調査)。
サンプルスクリプトを示します。HapticFeedbackExample.csという名前でController (left)またはController (right)にアタッチしてください。
using UnityEngine;
public class HapticFeedbackExample : MonoBehaviour
{
void Update()
{
SteamVR_TrackedObject trackedObject = GetComponent<SteamVR_TrackedObject>();
var device = SteamVR_Controller.Input((int) trackedObject.index);
if (device.GetTouchDown(SteamVR_Controller.ButtonMask.Touchpad)) {
// タッチパッドに触れた
device.TriggerHapticPulse(500);
}
if (device.GetPress(SteamVR_Controller.ButtonMask.Trigger)) {
// トリガーを深く引いている
device.TriggerHapticPulse(1000);
} else if (device.GetTouch(SteamVR_Controller.ButtonMask.Trigger)) {
// トリガーを浅く引いている
device.TriggerHapticPulse(100);
}
}
}
位置トラッキングとカメラの位置について
プロジェクト内で、ルームスケールもしくは着席状態のいずれかのトラッキングスペースを使用することができます。デフォルトではルームスケールになっています。
トラッキングスペースを変更するには、SteamVR/Prefabs/[SteamVR]プレハブをシーンにドロップしてください。[SteamVR]のTracking SpaceでTracking Universe StandingまたはTracking Universe Seatedを選択します。
Tracking Universe Standing(デフォルト)
ルームスケールのモードです。[CameraRig]を配置した場所が、HTC Viveのルームセットアップで設定したプレイエリアの中央の地面になります。
通例、[CameraRig]を(0, 0, 0)等に配置してその周辺にシーンを構築することになるかと思います。[CameraRig]のTransformを変更するとプレイエリアを移動できます。
Tracking Universe Seated
着席モードです。[CameraRig]をVR空間のプレイヤーの頭の位置に配置します。Oculus Riftと同じようなモードです。
位置をリセットするには、SteamVRを起動した状態でヘッドセットをかぶって、Viveコントローラのシステムボタン(電源ボタン)を押しダッシュボードを表示します。右下にある設定ボタン>「一般的なVR設定」>「座位のリセット」でヘッドセットの位置・向きが[CameraRig]の位置・向きとしてアプリケーション間で保存されます。
また、SteamVR.instance.hmd.ResetSeatedZeroPose関数を呼び出してリセットすることもできます。Valveの開発者が言うには、ダッシュボードでリセットできるので、キャリブレーション機能をゲームごとに自分で実装する必要はないとのことですが、そうもいかないケースがあるかと思います。サンプルスクリプトです。
using UnityEngine;
public class RKeyToRecenter : MonoBehaviour
{
void Update()
{
// SeatedモードでRキーで位置トラッキングをリセットする
if (Input.GetKeyDown(KeyCode.R)) {
SteamVR.instance.hmd.ResetSeatedZeroPose();
}
}
}
なお、Tracking Universe StandingではResetSeatedZeroPose関数は効果がありません。
UnityのVRサポートを使用する場合
SteamVRプラグインを使用せず、Unity本体のVRサポート機能のみでHTC Viveを使用することもできます。ただし、ヘッドセットだけで、モーションコントローラがまだサポートされていません。Unity 5.4が必要になりますので、Unityのベータ版のページからダウンロードしてインストールしてください。
プロジェクトを作成したら、Edit > Project Settings > PlayerでPlayer Settingsを開きます。Virtual Reality Supportedをチェックして、下に出てきたVirtual Reality SDKsの右下の+ボタンを押して、OpenVRを追加してください。
再生するか、ビルドして実行するとヘッドセットで見ることができます。
Lighthouseのメモ
ルームセットアップはViveコントローラ1本だけで可能です。立位のみのキャリブレーションはViveコントローラなしでも可能ですが、ダッシュボードが開けないのでどうしても1本は必要なようです。
ルームセットアップでは部屋の端に沿ってコントローラを動かしますが、安全そうなら「詳細モード」(部屋の四隅でトリガーを引く)のほうが速いです。
HTC ViveはLighthouseというテクノロジーで位置トラッキングをしています。ベースステーションはその名の通り灯台(lighthouse)の役目を果たし、赤外線を一定パターンで部屋中に照射して、それをヘッドセットやViveコントローラのセンサーで拾うタイミングで位置を推定するようになっています。つまり、トラッキングにはヘッドセットやViveコントローラのセンサーからベースステーションが見えている必要があります。
ベースステーションは、全灯をフラッシュしたのちレーザーを縦横にスキャンするというパターンを高速に繰り返します。赤外線の照射がどのように行われているかを示すイメージ動画があります。
ベースステーションは、部屋の端と端に配置することになっていますが、1つだけを正面に置くといった使い方も可能です。もちろんベースステーションが物や身体に隠れるとトラッキングが切れるので注意です。
ベースステーションを2台使用する場合はチャンネルをBとCに、1台の場合はAにする必要があります。
ベースステーションを設置するためのスタンドにはカメラ用やライト用の三脚などが使用できます。ベースステーションはモーターで振動し、またそばを歩くと揺れたりするため、安定度のやや高めのものを使ったほうがいいようです。
複数のHTC Viveを並べて使用するとき、ベースステーションの配置に注意が必要です。ヘッドセットやViveコントローラが無関係なベースステーションの赤外線を拾うとトラッキングが乱れてしまいます。黒いパーティションで区切る等の対策が必要です。
逆に、遮蔽されない限り、複数台のHTC Viveでベースステーションを共通して使用することもできます。
ベースステーションの電源がオンになっていると、赤外線を使用する家電等のリモコンが効きにくくなったりするようです。
おまけ
SteamVRのメニューの「ディスプレイ ミラー」でヘッドセット内の画面をPCにミラー表示できます。
Viveコントローラのバッテリーの持続時間は約4~6時間とのことです(使用状況にもよると思いますが、実使用で4時間ほどでバッテリーが切れました)。終日の展示などではこまめに充電する必要がありそうです。
Viveソフトウェアのセットアップには1.5GBほどのダウンロードを行います(.NET Frameworkを除く)。ネットワーク接続のない場所での展示ではあらかじめインストールしておく必要があります。
@izmさんがHTC Vive一式を持ち運ぶ方法について一案を講じています。他に、カメラ用のバッグなどがいいかもしれません。