Edited at

Oculus Goでレーザーポインターを表示する

More than 1 year has passed since last update.

Oculus Go でコントローラーからレーザーポインター的なガイドを表示する方法を調べたので備忘録として。

out.gif


参考

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 以下にそれぞれ配置すると、右手左手の設定に応じていい具合に表示を切り替えてれます。

ovrcamerarig.png

あとはこの位置からRay を飛ばしてレーザーを表示すればOK。


コード


LaserPointer.cs

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);
}
}
}


lp.png


まとめ

ポインター操作にGaze を使うゲームは分かりやすいんですが首が疲れるので、せっかくなのでコントローラーを使っていきたいと思います。