Oculus Go でコントローラーからレーザーポインター的なガイドを表示する方法を調べたので備忘録として。
参考
Use GearVrController with Selection Ray - Unity
基本的にここに書かれている通りにやればOK。
使用中のコントローラー(左右どちら?)を取得する
Oculus Go では左右どちらの手でコントローラーを使うか設定できるので、アプリ内での表示もこの設定に沿う必要があります。現在コントローラーを左右どちらの手で使っているかはOVRInput.GetActiveController で取得できます。
// 現在アクティブなコントローラーを取得
var controller = OVRInput.GetActiveController();
if (controller == OVRInput.Controller.RTrackedRemote)
{
// 右手
return _RightHandAnchor;
}
else if (controller == OVRInput.Controller.LTrackedRemote)
{
// 左手
return _LeftHandAnchor;
}
OVRInput.GetActiveController はStart やAwake のタイミングでは取得できなかった(OVRInput.Controller.None が返ってくる)ので、Update 中で取得しています(ちょっとハマった。素直に参考記事のとおりにすればよかった)。
Oculus 公式のOVRInput ドキュメントによると、OVRInput.IsControllerConnected でも判定できる模様。
コントローラー位置の取得する
コントローラー(手)の位置そのものはOVRCameraRig に付いているLeftHandAnchor/RightHandAnchor から取得できます。
コントローラーのモデルを表示したい場合はOculus Integration に付属のPrefav、TrackedRemote をLeftHandAnchor/RightHandAnchor 以下にそれぞれ配置すると、右手左手の設定に応じていい具合に表示を切り替えてれます。
あとはこの位置からRay を飛ばしてレーザーを表示すればOK。
コード
public class LaserPointer : MonoBehaviour
{
[SerializeField]
private Transform _RightHandAnchor;
[SerializeField]
private Transform _LeftHandAnchor;
[SerializeField]
private Transform _CenterEyeAnchor;
[SerializeField]
private float _MaxDistance = 100.0f;
[SerializeField]
private LineRenderer _LaserPointerRenderer;
private Transform Pointer
{
get
{
// 現在アクティブなコントローラーを取得
var controller = OVRInput.GetActiveController();
if (controller == OVRInput.Controller.RTrackedRemote)
{
return _RightHandAnchor;
}
else if (controller == OVRInput.Controller.LTrackedRemote)
{
return _LeftHandAnchor;
}
// どちらも取れなければ目の間からビームが出る
return _CenterEyeAnchor;
}
}
void Update ()
{
var pointer = Pointer;
if (pointer == null || _LaserPointerRenderer == null)
{
return;
}
// コントローラー位置からRayを飛ばす
Ray pointerRay = new Ray(pointer.position, pointer.forward);
// レーザーの起点
_LaserPointerRenderer.SetPosition(0, pointerRay.origin);
RaycastHit hitInfo;
if (Physics.Raycast(pointerRay, out hitInfo, _MaxDistance))
{
// Rayがヒットしたらそこまで
_LaserPointerRenderer.SetPosition(1, hitInfo.point);
}
else
{
// Rayがヒットしなかったら向いている方向にMaxDistance伸ばす
_LaserPointerRenderer.SetPosition(1, pointerRay.origin + pointerRay.direction * _MaxDistance);
}
}
}
まとめ
ポインター操作にGaze を使うゲームは分かりやすいんですが首が疲れるので、せっかくなのでコントローラーを使っていきたいと思います。