はじめに
UnityでOculus Touchを用いるサンプルプロジェクトを作ったので、とりあえず公開してみました。
物をつかむための素朴な方法を実装しただけの物で、実用には耐えないと思いますが、
仕組みを学習する上で役立てて頂けると嬉しいです。
せっかくなので、何回かに分けてノウハウを共有したいと思っています。
今日はまず、全般的なことをまとめたあと、Touchの入力を受け取る処理について見ていきます。
とりあえずの完成品
Oculus Touch のサンプルプロジェクトを作ってみた https://t.co/m4CHsKkX8a @YouTubeさんから
— 三浦真人 (@miurror) 2017年1月10日
現時点のソースコードを公開しております。
github.com/miurror/TouchSample
参考サイト
以下の動画(英語)で解説されていることと、よく似た内容を説明する予定です。
Unity - Setting up the Oculus Touch
Unity - Grabbing & throwing objects with Oculus Touch
Oculusの中の人(mfmfさん)が提供して下さっているOculus Avatar SDKを用いたサンプルプロジェクト Avatar Grab sample は、非常に参考になります。(Oculus Avatar SDKとは、Oculusが提供するかっこいいアバターをUnityやC++で扱うためのソフトウェア開発キットのことです。)
以上の参考サイトは、きゅーこんさんの記事 Devel/OculusRift/OculusTouch で知りました。
フレームシンセシスさんの記事 Unity+Oculus Touch開発メモ も、繰り返し参考にしています。
開発環境
- Unity 5.5.0f3
- C#
- Oculus Utilities for Unity 5 V1.10.0 (インポートするのはOVR/Scripts のみ)
Oculus Utilitiesは、RiftやGear VR用アプリの開発者向けに、様々なasset, script, sample sceneなどを提供しているOculusの公式パッケージです。今回、明示的に用いるのは、入力方法を統合するAPIであるOVRInputになります(他にも裏で動くscriptが幾つかあります)。最新版のダウンロードはこちらから。
developer3.oculus.com/downloads
また、OVRInputに関する公式の手引きはこちらです。
developer3.oculus.com/documentation/game-engines/latest/concepts/unity-ovrinput
Touchの位置トラッキングでオブジェクトを動かす
TouchController.cs
TouchにはRift本体と同様に、赤外線LEDとカメラを用いた位置トラッキング機能があります。そこで、コントローラの位置と向きを、OVRInputの関数GetLocalControllerPosition()
と GetLocalControllerRotation()
で取得することにします。それぞれUnityEngineにおけるVector3とQuaternionの値を返します。
using UnityEngine;
public class TouchController : MonoBehaviour {
public OVRInput.Controller controller;
void Update () {
transform.localPosition = OVRInput.GetLocalControllerPosition(controller);
transform.localRotation = OVRInput.GetLocalControllerRotation(controller);
}
}
controllerの値をインスペクタからRTouch, LTouchに指定することで、Touchの動きに追従するオブジェクト(つまりバーチャル空間におけるプレイヤーの手)を作ることが出来ます。
tips
- 手が身体から大きく離れてしまわないために、空のオブジェクト(Player)を作っておいて、Main Cameraや左右の手(RightHand, LeftHand)の親オブジェクトにします。
- 顔に近づけると手が消えてしまう場合は、Main Cameraの
Camera.nearClipPlane
を小さな値(たとえば0.01)に設定して描画範囲を広げます。(インスペクタから設定できます。) - Unity 5.5 以降では、OVRInput を使わずにUnityEngine.VRの関数
InputTracking.GetLocalPosition()
,InputTracking.GetLocalRotation()
を用いても同じ結果が得られます。その場合、OVRInput.Controller
の代わりには、同じ列挙型のVRNode
を用いて、インスペクタからRightHand, LeftHandを指定します。
Touchのボタン入力でオブジェクトをつかむ(落とす)
Grab.cs
Grip Buttonからの入力を取得するために、OVRInputの関数Get()
を用います。
using UnityEngine;
public class Grab : MonoBehaviour {
public OVRInput.Controller controller;
// オブジェクトをつかむ(落とす)イベントが生じるための Trigger の閾値
public const float THRESH_GRAB = 0.55f;
public const float THRESH_DROP = 0.35f;
// オブジェクトをつかんでいるかどうか
private bool grabbing;
void Update () {
OVRInput.Update();
if(!grabbing && OVRInput.Get(OVRInput.Axis1D.PrimaryHandTrigger, controller) >= THRESH_GRAB) GrabObject();
if(grabbing && OVRInput.Get(OVRInput.Axis1D.PrimaryHandTrigger, controller) <= THRESH_DROP) DropObject();
}
}
controllerの値には先ほどと同様、RTouch, LTouchを指定します。
この際、左右のコントローラに対してボタン名Axis1D.PrimaryHandTrigger
を共通に使用することが出来ます。その他のボタンに対しても以下のように、左右共通の名前を使うことが出来ます。
これは、「様々なコントローラを統合して扱う」というOVRInputの哲学に関係しています。OVRInputでは、実質的な入力操作(Button, Touch, NearTouch, Axis1D, Axis2D)に列挙体が割り当てられていて(バーチャルマッピング)、その他の違いを重要視しない作りになっているのです。
tips
OVRInput.Update()
は、ボタンのマッピングを正しく受け取るために必ず呼び出す必要があります。ただし、代わりに次のような方法を採用することも出来ます。
- OVRManager.cs をMain Cameraにアタッチする。
- OVR/Prefabsもインポートして、Main Cameraの代わりにプレハブ OVRCameraRig を使う。(この場合、OVRManager.cs は予めアタッチされている。 Avatar Grab sampleで用いられている方法。)
- OVRInputを使わずに、以下のようなUnityのボタンマッピングを用いてUnityEngineの関数
Input.GetAxis()
でHandTriggerの状態を取得する(この場合、左右でボタン名を切り替える処理が必要になる。参考動画で用いられている方法)。
まとめ
本日は、Oculus UtilitiesのAPI, OVRInputを用いて、Touchの位置やボタン入力を受け取る方法を見ました。肝心の、物をつかむ処理GrabObject()
, 落とす処理DropObject()
についても、次回以降の記事で説明したいと思います。