helloworlds

not a noun, it's a verb

【VR】Oculus Go Unityでコントローラーを追加し移動してみる

さて、前回は、Unityのプロジェクトを作成しました。

o21o21.hatenablog.jp

続いてOculus Goに付属しているコントローラー(Replacement Controller)をUnityへimportしてみます。 そして、一人称で動けるようにします。

f:id:o21o21:20180612161059p:plain

アセットのインポート

アセットのインポートを最小限に済ませたい方は、UnityのAsset Storeから直接アセットをインポートしましょう。 まとめてUtilitiesをインポートしたい方は、こちらからダウンロード。 ダウンロードしたら、UnityのメニューAssets > Import Package > Custom *Package ... からダウンロードして解凍したファイルをインポートします。

以下、Asset Storeからの手順。 UnityのAsset StoreOculus Integrationというアセットがあります。

  1. UnityのAsset Storeにアクセス
  2. 検索フォームに"Oculus Integration"とタイプ f:id:o21o21:20180611222450p:plain
  3. "DOWNLOAD"を押下(無料です!) f:id:o21o21:20180611222723p:plain
  4. ダウンロードが完了したら、"Import"を押下
  5. ポップアップウィンドウが表示され、全てにチェックボックスが入っていることを確認し、"Import"。 f:id:o21o21:20180611223038p:plain
  6. versionの確認(Yes or No)
  7. Unityのrestartの確認(→ Yes)
  8. 再起動後、Asettsフォルダに存在を確認 f:id:o21o21:20180611223849p:plain

これでアセットのインポートを完了です!

OVRCameraRigを追加

インポートしてきたOculusフォルダを確認してみます。

Assets > Oculus > VR > Prefabs > OVRCameraRig

OVRCameraRigを、Hierarchyに追加します。 デフォルトのプロジェクトでは、Main Cameraがあると思います。 こちらは不要になるので、削除するか、Inspectorの方でチェックを外します。

f:id:o21o21:20180612121337p:plain

これでSceneからMain Cameraが消えたと思います。

OVRCameraRigの位置ですが、任意で大丈夫ですが、 私はUnityの三人称キャラ、Ethanをシーンに追加して目線を合わせてみました。 ※Ethanのインポートは、メニューAsetts > Import Package > Characters、全てをインポートすると、 Assets/Standard Assets/Characters/ThirdPersonCharacter/Prefabs/配下にEthanがいます。

Ethanの身長は、約168cmとされているようですが、ちゃんと調べるには自分で立方体を設置して測ってみるとよさそうですw

f:id:o21o21:20180612123347p:plain

コントローラーの設定

いよいよコントローラーの設定をしていきます。

1. コントローラーを追加

Oculus/VR/Prefabs/TrackedRemote.prefab

こちらをOVRCameraRigのLeftHandAnchorRightHandAnchorドラッグ&ドロップします。

f:id:o21o21:20180612123750p:plain

そうすると、以下のようにOculus Goのコントローラーが確認できるかと思います。

/RightHandAnchor/TrackedRemote/OculusGoControllerModel
/LeftHandAnchor/TrackedRemote/OculusGoControllerModel

f:id:o21o21:20180612124256p:plain

2. ポインタを設定する

何か操作をするときにどこをコントローラーが指しているか知る必要があります。

まず、Hierarchyで空のGameObjectを作成します。 Hierarchyのところで、右クリ > Create Emptyで作成します。 そして、名前を付けます(例: LaserPointer)

このオブジェクトにコードを追加したいので、任意の場所で Create > C# ScriptC#のファイルを作成します。 ファイル名は自分がわかればいいでしょう!

エディタを開いて、以下のコードを貼り付けます。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class LaserPointer : MonoBehaviour {

    // 右手
    [SerializeField]
    private Transform _RightHandAnchor;

    // 左手
    [SerializeField]
    private Transform _LeftHandAnchor;

    // 目の中心
    [SerializeField]
    private Transform _CenterEyeAnchor;

    // 距離
    [SerializeField]
    private float _MaxDistance = 100.0f;

    // LineRenderer
    [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;

        // コントローラーがない or LineRendererがなければ何もしない
        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);
        }
    }
}

なるほどー。こんな関数もあるんだー。勉強になります。

シーンにあるすべてのコライダーに対して、 origin の位置から direction の方向に maxDistance の距離だけレイを投じます。 Physics.Raycast - Unity スクリプトリファレンス

保存したら、さっき作成したLaserPointerゲームオブジェクトに配置させます。 ドラッグ&ドロップでも、InspectorのAdd Componentからでも追加できます。

f:id:o21o21:20180612130816p:plain

スクリプト中の変数の値をHierarchyのオブジェクト、

  • RightHandAnchor
  • LeftHandAnchor
  • CenterEyeAnchor

をそれぞれ設定します。

こちらもドラッグ&ドロップか、変数名の値の横の丸ぽちでも設定可能です。

f:id:o21o21:20180612131259p:plain

3. レーダーを設定する

Line Rendererというものを設定します。 LaserPointerゲームオブジェクトのAdd Componentを押下。 Searchフォームで、lineと入力すると、Line Rendererが選択できるかと思います。

このLine Rendererに設定をします。 沢山の項目がありますが、今は最小限にします。

  • Cast Shadows: Off
  • Materials>Element 0: Sprites-Default (丸ぽち押下し検索フォームに"Sprites"と入力)
  • Width: 任意 (0.003 ~ くらいからがいいかな?)
  • Color: 任意

値を設定したら、変数に設定します。

f:id:o21o21:20180612132652p:plain

これで完了です。

4. 実機で確認

ここまでできたら1度実機で確認してみます。

保存して、ビルドしましょう。

f:id:o21o21:20180612134105p:plain

おう!レーダー出てますね! これでまたコードを書いて、オブジェクトに対しての操作も考えられそうです!

前々回前回の記事を観覧して頂いているかたは、 PCへUSB接続し、クロームからアプリ(Vysor)を起動。Oculusのデバイス接続が確認できたら"View"でOculus Goの画面がPCで確認できるはずです。

f:id:o21o21:20180612134216p:plain

いったん休憩

ここまでコントローラーを追加し設定しました。 あとは、コントローラーでオブジェクトに対して処理を行うコードを追加したり、 今回作成したLine Rendererでレーザーの細かい設定をしたりして、修正できます。

docs.unity3d.com

docs.unity3d.com

ここまでこちらを参考にさせて頂きました。ありがとうございます。

さらに公式でも関数についてなど記載があります。(英語)

OVRInput

次は、一人称視点で動くことをやっていきます。

Playerを設定し、動いてみる

Oculus Goに付属しているOculus Go Controllerタッチパッドで 直感的に一人称で動けるようにしてみます。

OVRCameraRigにComponentを追加

  1. HierarchyでOVRCameraRigを選択
  2. Add Componentを押下
  3. 以下を加える
  4. Capsule Collider
  5. Rigidbody
  6. C#スクリプトを追加(名前は任意)

f:id:o21o21:20180612160208p:plain

作成したスクリプトに以下を追記。 (私は少し自分流にしましたが、コードは先人の方のを使わせて頂きます。Unity初心者なので、こんな関数もあるのかと勉強になります!)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Og_Player : MonoBehaviour
{

    Rigidbody m_Rigidbody;

    // Use this for initialization
    void Start()
    {
        // 自分のRigidbodyを取ってくる
        m_Rigidbody = GetComponent<Rigidbody>();
    }

    // Update is called once per frame
    void FixedUpdate()
    {
        float x = 0.0f;
        float z = 0.0f;
        Vector2 touchPadPt = OVRInput.Get(OVRInput.Axis2D.PrimaryTouchpad);

        //右方向
        if (touchPadPt.x > 0.5 && -0.5 < touchPadPt.y && touchPadPt.y < 0.5)
        {
            // 十字キーで首を左右に回す
            transform.Rotate(new Vector3(0.0f, 0.5f, 0.0f)); 
            x += 0.5f;
        }
        //左方向
        if (touchPadPt.x < -0.5 && -0.5 < touchPadPt.y && touchPadPt.y < 0.5)
        {
            // 十字キーで首を左右に回す
            transform.Rotate(new Vector3(0.0f, -0.5f, 0.0f));
            x -= 0.5f;
        }
        //上方向
        if (touchPadPt.y > 0.5 && -0.5 < touchPadPt.x && touchPadPt.x < 0.5)
        {
            z += 5.0f;
        }
        //下方向
        if (touchPadPt.y < -0.5 && -0.5 < touchPadPt.x && touchPadPt.x < 0.5)
        {
            z -= 5.0f;
        }

        m_Rigidbody.velocity = z * transform.forward + x * transform.right;
    }

}

docs.unity3d.com

実機で確認

再度ビルドを実行して、実機で確認します。

f:id:o21o21:20180612161259p:plain

移動してEthanに会ってみました!

少し感度というか、自分が操作に慣れてないから移動に手間取りました。。 なんかタッチパッドが少し小さいかな?と個人的には思いました。

まとめ

今回はコントローラーを追加して、自分視点でフィールドで移動できるようにしました。 UnityのAsset Storeでは無料のフィールドもあるようなので、活用できそうですね!