【Unity(C#)】Oculus Integration内の出来合いの物だけで少しリッチなレーザーポインターを実装する


Oculus Integration

2019/12/10 追記
サンプル上げました。Oculus Integrationもそのままで上げてるので少し重いです。
https://github.com/ForJobOk/OVR_SimpleLaserPointer

今回はOculus IntegrationのScriptを利用してレーザーポインターを実装します。
今回実装するレーザーポインターは
スライドショーなどで差し棒代わりに使用したり、メニュー画面でUIを選択したり、、、などの用途です。

実際に実装したものがこちらになります。

UIにかざした場合のみレーザーポインターが出現するようになってます。
※手はこちら


2019/11/25 追記

Githubにプロジェクトファイルをアップしました

OVRGazePointer

OVRGazePointerは本来は目線にポインターが追従するという用途で用意されています1が、
レーザーを実装してレーザーポインターとして使ってしまいます。

AwakeUpdateに書き加えます。
6までナンバリングしたコメントの部分です。
必要ない機能などを消したかったので元のScriptに直接書き加えずに新しいScriptを作成しています。
必要ない機能などを消したかったので元のScriptに直接書き加えずに
まるまるコピーして新しいScriptとして作成しています。

OVRGazePointerをコピーして書き換え

    //1.変数を宣言
    LineRenderer lineRenderer;

    [SerializeField]
    GameObject startPointObj,endPointObj;

    public void Awake()
    {
        //2.GetComponentします
        lineRenderer = this.gameObject.GetComponent<LineRenderer>();

        currentScale = 1;

        if (_instance != null && _instance != this)
        {
            enabled = false;
            DestroyImmediate(this);
            return;
        }

        _instance = this;

        //3.PointerIconはポインターアイコンのオブジェクト名が入る
        gazeIcon = transform.Find("PointerIcon");
        progressIndicator = transform.GetComponent<OVRProgressIndicator>();
    }

    void Update()
    {
        //4.レーザーの位置を決定
        lineRenderer.SetPosition(0, startPointObj.transform.position);
        lineRenderer.SetPosition(1, endPointObj.transform.position);

        if (rayTransform == null && Camera.main != null)
            rayTransform = Camera.main.transform;


        transform.position = rayTransform.position + rayTransform.forward * depth;


        if (visibilityStrength == 0 && !hidden)
        {
            Hide();
            //5.消す
            lineRenderer.enabled = false;
        }
        else if (visibilityStrength > 0 && hidden)
        {
            Show();
            //6.出す
            lineRenderer.enabled = true;
        }
    }

何回も使い回すようであれば、
LineRendererは必須なのでRequireComponentを使っておくといいと思います。

OVRGazePointerを元にコピーして新たに作成したOculusLaserPointer
[RequireComponent(typeof(LineRenderer))]
public class OculusLaserPointer: OVRCursor

レーザーの下準備

作成したScriptを適当なオブジェクトにアタッチします。

Inspectorの設定は画像の通りです。(※一部不要なパラメータを削除しています)


パラメータの説明

Hide By Default - True時はUIにRayがヒットした場合のみレーザーポインターが出現します。Falseだとずっと出てます。
Show Timeout Period - UIにヒットした場合にレーザーポインターが出現するまでの秒数です。
Hide Timeout Period - レーザーポインターがUIから離れた場合に消滅するまでの秒数です。
Dim On Hide Request - 外部からオンオフできます(たぶん)
Depth Scale Multiplier - ポインターのスケールです。
Ray Transform - 設定したオブジェクトの正面方向(Z軸正の方向)に向かってRayを飛ばします。手のアンカーの階層に入れるといい感じです。
Start Point Obj - レーザーポインターの発射位置です。基本的にRay Transformと同じです。
End Point Obj - レーザーポインター終了位置です。ポインターの表示されたポジションを利用しています。

アイコンの下準備

GazaPointerというMaterialを使います。

先ほど作成したレーザーポインターをアタッチしたオブジェクトの子にQuadを作成し、MeshColliderを削除します。
そして、OVROverlayというScriptをアタッチします。

Override Color Scaleでポインターの色を変えることができます。

OVR Raycaster

CanvasにOVR Raycasterをアタッチします。Graphic Raycasterは必要ありません。

EventSystem

既存のInput ModuleではNGなのでOVR Input Moduleを利用します。

必要な設定はここだけです。

Joy Pad Click Buttonに好きな選択キーを設定できます。(画像の場合、人差し指でボタンやトグルなどを選択可能)
キーについてはこちらの記事がとてもわかり易くまとまっております。

おまけ

コントローラーが手などの場合は、手から直接レーザーが出ていると違和感があります。
なので画像のようにだんだんと濃くなる感じのShaderを利用しました。

ドンピシャでほしいShader2を書いてる方がいらっしゃたので改良して使わせていただきました。

改良と言ってもuvの方向を変更しただけですが。。。

            fixed4 frag(v2f i) : COLOR{
              /*fixed amount = clamp(abs(_TopColorPos - i.uv.y) + (0.5 - _TopColorAmount), 0, 1);*/
                fixed amount = clamp(abs(_TopColorPos - i.uv.x) + (0.5 - _TopColorAmount), 0, 1);
                i.color = lerp(_TopColor, _ButtomColor, amount);
                return i.color;
               }

かなり遠回りですが、出来合いの物だけでいいかんじになったんじゃないでしょうか。

なんかOculusの権利関係ややこしそうなので、
コピーライティング書いときます。

Copyright © Facebook Technologies, LLC and
its affiliates. All rights reserved.