(この記事の使用環境: Unity5.5.0f3 Personal、Windows10、SteamVR Plugin 1.2.0、VRTK3.0.1)


VR用アセット「VRTK」の Example 032_Controller_CustomControllerModel の解説です。
コントローラーの代わりに手のモデルを使うデモです。
SnapCrab_NoName_2017-2-9_16-52-17_No-00

■公式サイトの解説

VRTK公式サイトでこのExampleの解説文及び解説動画を見ることができます。ただし、動画に関してはVRTK旧バージョンのときに作られたものであり、VRTK3.0(以降)では設定等が異なっている場合があることに留意してください。動きを中心に見てもらえれば良いかと思います。

このExampleの解説動画
(このExampleの公式解説動画はまだアップされていません)


■VRTKのセットアップ方法および使用されているスクリプトの解説

適宜、以下の記事を参照願います。

■Exampleの解説

VRTK/Examples 内にある当該番号のシーンを呼び出すことで、デモを動かしてみることができます。

このシーンはデフォルトのHTC Viveコントローラーモデルの代わりに、コントローラーにカスタムモデルを使用する方法を示しています。デフォルトのコントローラの位置にシンプルな手のモデルを配置し、グラブボタンまたはトリガーボタンを押すことでシンプルな状態変化をします。
SnapCrab_NoName_2017-2-9_16-39-25_No-00


以下、シーンに配置されているオブジェクトについての概要説明です。
  • ExampleObjects: スナップ設定の異なる複数の Gun と、LightSaber。デフォルトのHTC Viveコントローラーモデルを使用したときと同様に、カスタムモデルを使用したときにも設定に応じてさまざまにスナップ可能。スナップ設定の詳細は Example014の解説 を参照。
    SnapCrab_NoName_2017-2-9_17-7-33_No-00

  • Left Controller、RightController: [VRTK] ゲームオブジェクトの下に配置されている、左右のコントローラー用のVRTKスクリプトをアタッチするゲームオブジェクト。
    VRTK_ControllerEvents 、VRTK_InteractGrab 、 VRTK_InteractUse などのスクリプトがアタッチされており、また、子オブジェクトとして Hand プレハブがぶら下げられている(下図参照)。
    SnapCrab_NoName_2017-2-9_17-10-28_No-00

  • Hand: 左右のコントローラーの位置に付けられる手のプレハブ。モデルは手首、手のひら、親指、人差し指(PointerFinger)、中指・薬指・小指(GripFingers)などから成り、コライダーとCustomGrabAttachPoint(物を掴むときの位置)が設定されている。トップのオブジェクトには手の動きを記述した Controller_Hand スクリプトがアタッチされており、インスペクタで左右どちらの手のモデルを使うか設定できるようになっている。
    SnapCrab_NoName_2017-2-9_17-18-59_No-00

    Controller_Hand スクリプトの中身。
    namespace VRTK.Examples
    {
        using UnityEngine;
    
        // --- コントローラーの手 -------------------------------------------
        public class Controller_Hand : MonoBehaviour
        {
            public enum Hands
            {
                Right,      // 右手
                Left        // 左手
            }
    
            public Hands hand = Hands.Right;    // どちらの手か
    
            private Transform pointerFinger;    // 人差し指
            private Transform gripFingers;      // 中指・薬指・小指(1つのオブジェクトになっている)
            private float maxRotation = 90f;    // (指を曲げたときの)最大角度
            private float originalPointerRotation;  // 人差し指の元の角度
            private float originalGripRotation;     // 中指・薬指・小指の元の角度
            private float targetPointerRotation;
            private float targetGripRotation;
    
            // --- 初期化 ------------------------------------
            private void Start()
            {
                // --- 個別に定義した処理をコントローラーの操作に紐づける --------------------
                GetComponentInParent<VRTK_ControllerEvents>().AliasGrabOn += new ControllerInteractionEventHandler(DoGrabOn);
                GetComponentInParent<VRTK_ControllerEvents>().AliasGrabOff += new ControllerInteractionEventHandler(DoGrabOff);
                GetComponentInParent<VRTK_ControllerEvents>().AliasUseOn += new ControllerInteractionEventHandler(DoUseOn);
                GetComponentInParent<VRTK_ControllerEvents>().AliasUseOff += new ControllerInteractionEventHandler(DoUseOff);
    
                var handContainer = "ModelPieces";
                pointerFinger = transform.Find(handContainer + "/PointerFingerContainer");
                gripFingers = transform.Find(handContainer + "/GripFingerContainer");
    
                // --- もし左手なら、各パーツの位置・回転を反転させる -----------
                if (hand == Hands.Left)     
                {
                    InversePosition(pointerFinger);
                    InversePosition(gripFingers);
                    InversePosition(transform.Find(handContainer + "/Palm"));
                    InversePosition(transform.Find(handContainer + "/Thumb"));
                }
    
                originalPointerRotation = pointerFinger.localEulerAngles.y;
                originalGripRotation = gripFingers.localEulerAngles.y;
    
                targetPointerRotation = originalPointerRotation;
                targetGripRotation = originalGripRotation;
            }
    
            // --- (左手用)位置・回転を反転させる -------------------------------------
            private void InversePosition(Transform givenTransform)
            {
                givenTransform.localPosition = new Vector3(givenTransform.localPosition.x * -1, givenTransform.localPosition.y, givenTransform.localPosition.z);
                givenTransform.localEulerAngles = new Vector3(givenTransform.localEulerAngles.x, givenTransform.localEulerAngles.y * -1, givenTransform.localEulerAngles.z);
            }
    
            // --- Grabボタンを押したときの処理(中指・薬指・小指を曲げる) ------------------------
            private void DoGrabOn(object sender, ControllerInteractionEventArgs e)
            {
                targetGripRotation = maxRotation;
            }
    
            // --- Grabボタンを離したときの処理(曲げていた中指・薬指・小指をもとに戻す) ----------
            private void DoGrabOff(object sender, ControllerInteractionEventArgs e)
            {
                targetGripRotation = originalGripRotation;
            }
    
            // --- Useボタンを押したときの処理(人差し指を曲げる) ------------------------
            private void DoUseOn(object sender, ControllerInteractionEventArgs e)
            {
                targetPointerRotation = maxRotation;
            }
    
            // --- Useボタンを離したときの処理(曲げていた人差し指をもとに戻す) ----------
            private void DoUseOff(object sender, ControllerInteractionEventArgs e)
            {
                targetPointerRotation = originalPointerRotation;
            }
    
            // --- 更新処理 ------------------------------------
            private void Update()
            {
                pointerFinger.localEulerAngles = new Vector3(targetPointerRotation, 0f, 0f);
                gripFingers.localEulerAngles = new Vector3(targetGripRotation, 0f, 0f);
            }
        }
    }
    

今回は以上です。