Open19

MagicLeapToolkitに依存しない形でのハンドポインタ作成

松本隆介松本隆介

とりあえず以前作成したQiitaのアドベントカレンダーように作成したハンドポインタをベースに作るか
MagicLeapToolKitはもう一年以上更新されてないような感じだし...
MRTK使ってもいいしれんけどなんとなく自作したいよね

松本隆介松本隆介

とりあえずハンドポインター表示までは出来た、Eyeトラッキングは今回は使わないようにしよう
MainCameraの向きをある程度ポインタの向きに反映したほうがいいかも?

松本隆介松本隆介

MLHandTrackingのHandKeyPoseはこんな感じの定義

        /// <summary>
        /// Static key pose types which are available when both hands are separated.
        /// </summary>
        public enum HandKeyPose
        {
            /// <summary>
            /// Index finger.
            /// </summary>
            Finger,

            /// <summary>A
            /// A closed fist.
            /// </summary>
            Fist,

            /// <summary>
            /// A pinch.
            /// </summary>
            Pinch,

            /// <summary>
            /// A closed fist with the thumb pointed up.
            /// </summary>
            Thumb,

            /// <summary>
            /// An L shape
            /// </summary>
            L,

            /// <summary>
            /// An open hand.
            /// </summary>
            OpenHand = 5,

            /// <summary>
            /// A pinch with all fingers, except the index finger and the thumb, extended out.
            /// </summary>
            Ok,

            /// <summary>
            /// A rounded 'C' alphabet shape.
            /// </summary>
            C,

            /// <summary>
            /// No pose was recognized.
            /// </summary>
            NoPose,

            /// <summary>
            /// No hand was detected. Should be the last pose.
            /// </summary>
            NoHand
        }

松本隆介松本隆介

HandPoseのイベントの取得はこんな感じ

            MLHandTracking.KeyPoseManager.OnKeyPoseBegin += (pose, type) =>
            {
                Debug.Log($"Begin pose : {pose} | type {type}");
            };

            MLHandTracking.KeyPoseManager.OnKeyPoseEnd += (pose, type) =>
            {
                Debug.Log($"End pose : {pose} | type {type}");
            };

松本隆介松本隆介

まずは順当にMLHandTracking使うようにするか...
疎結合とかその辺は追々考えよう
できるだけ外部ライブラリを利用しないシンプルなつくりにしたい...

松本隆介松本隆介

親指と人差し指の付け根の中間にするか
親指の先と人差し指の先の中間にするか ( こっちの方がOculusQuest2のハンドトラッキングに近い )

松本隆介松本隆介

Questの形式を真似したらPinchのジェスチャでのStartPointが結構大きくぶれる -> Rayが大きくぶれるから取りやめ、人差し指と親指の根元の中間をStartPointとした

松本隆介松本隆介

選択時、選択中はPointerSelectクラス( 仮 )で他クラスから参照できるようにする?

そういえばすでにSelectedObjectなるものを作成していたな...それにデータを持たせるか

松本隆介松本隆介

とりまこんな感じ

    /// <summary>
    /// HandPointerで選択したものをカプセル化したクラス.
    /// </summary>
    public class SelectedObject
    {
        public bool IsHit => Hit.collider != null;
        public RaycastHit Hit { get; }
        public Vector3 Position => Hit.point;
        public GameObject Object => Hit.collider.gameObject;
        public HandPointer.HandPointerState State { get; }


        public SelectedObject(
            RaycastHit hit,
            HandPointer.HandPointerState state)
        {
            Hit = hit;
            State = state;
        }
    }

松本隆介松本隆介

SelectedObjectがStateを持つ必要ないな、OnSelectBegin, OnSelectContinue, OnSelectEndのイベントを作成したからそいつらが外部から見た選択状態になる

内部的には

        public enum HandPointerState
        {
            NotSelected,
            Selected,
            SelectContinue
        }

こんな感じでステートを保持しておく、今これは生のフィールドだけど値オブジェクトにしてもいいかもな

松本隆介松本隆介

多分一通り移植は完了したな
一旦今のチケットはこれで完了としてdevelopにマージしよう

松本隆介松本隆介

現時点でのシーンの最小構成
HandPointerの各種パラメータはデフォルトで扱える、カスタムしたいときは適当にいじる感じ
MainCameraはとりあえず参照つけなくてもスクリプトの中でMainCameraを探すからとりあえずは大丈夫だと思う
シーンに配置されているMain CameraオブジェクトはMagicLeapのMain Cameraプレハブを配置してる

松本隆介松本隆介

まだ選択したオブジェクトを移動するといった機能は実装していない、どうやって実装しようかは今の所まだ決めてない
OnSelectContinueのときにLock的なことをするかはまだ未定、このへんはHoloLensの動作とかを参考にしてみるか

松本隆介松本隆介

選択したときの手元の移動量ではなくて選択したときのカーソルの移動量をSelectedObjectに持たせた方がいいかもしれない

松本隆介松本隆介

HandPointer.cs一つで両手を管理する方法をやめて1コンポーネント1ハンドにした
理由としては片方の手だけ利用したいとかの場合や場合分けの分岐が増え、コード量が増加するためインスペクタで選択したLeft,Rightに合わせて使うHandPointerを生成するようにした
HandPointerを二つ利用すれば両手での操作も可能

現在のHandPointerのパラメータ、画像のInspectorでは両手を使うためにHandPointerコンポーネントを二つ利用している

あとできるだけ生のMLHandTracking周りのクラスをHandPointerで扱いたくはない気がする

松本隆介松本隆介

今のHandPointerクラスがRaycast飛ばしてhitしたオブジェクトを返す的な動作はなんか違和感HandPointerCursorがRayを飛ばしてhitしたものをイベントとかで返す形が自然な気がする

松本隆介松本隆介

Handのボーンを表示する仕組みも作っておく必要がありそう、MagicLeapToolKitには似たようなやつがあったけどあれはシーン上にオブジェクトをぶちまけてたからできればHand > 各関節 みたいにコンパクトに収めたいところ