7
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【UnityでOculus Quest向けのアプリを作る】ハンドトラッキングで物を掴む

Last updated at Posted at 2020-02-18

#◆ はじめに
前回、ハンドトラッキングの実装しました。
なので、今回は物を掴む方法について書きます。

手の動き、指の取得は

OculusQuest ハンドトラッキングSDKから、指Boneの情報を取得し分析する

こちらの記事を参考にしてください。

必要あれば前の記事を参考してください。
Oculus Quest向けのAPPをビルドして、動作確認する
物を掴む為には(物体の制作)
ハンドトラッキングの実装

今回の記事ですが、
完全に自己流の方法でやっているので、無理矢理感がある為、要注意です。

#◆ 開発環境
macOS Mojave バージョン 10.14.6
Unity 2018.4.12f1
Android SDK
ハンドトラッキング機能を使用する為、
Oculusのバージョンは(Ver12)以上、にアップデートする必要があります。
#◆ 手順

  • 準備した物の説明
  • 掴む実装方法説明
  • 指動作の判断
  • 論理およびコード説明]
  • 動作確認

準備した物の説明

スクリーンショット 2020-02-17 18.43.04.png まず、必要なObjectを準備しました。 ハンドトラッキングを実装して、物体(Cube)とテーブルを用意します。 Cubeのサイズは自由に設置しても構いません。

プログラムがちゃんと動いてるかどうか、
結果を見やすくする為に、Canvasを作りました。必須ではないですが、あった方が便利です。
また、テーブルも必須ではないです。
##掴む実装方法説明
以前の物を掴む為にはでは、
無事に手を表示後普通に物体を掴む事ができますが、ハンドトラッキングではできないらしいです。
02.png
なので、
今回やるべき事は手が物体を当たった状態で、掴むという動作をした時、物体を手の階層に入れる。
要するに、物体を手の子要素にするという事です。

勿論、
子要素にするのではなく、掴む判定の時、物体のポジションを手と同じにするというのも方法の一つです。
##指動作の判断

ovrHand.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ovrHand : MonoBehaviour
{
    private OVRHand _ovrHand;
    // 掴む状態
    public bool _catching;

    // Start is called before the first frame update
    void Start()
    {
        _catching = false;
        _ovrHand = this.gameObject.GetComponent<OVRHand>();
    }
    // Update is called once per frame
    void Update()
    {
        if (_ovrHand.GetFingerIsPinching(OVRHand.HandFinger.Index))
        {
            _catching = true;
        }
        else
        {
            _catching = false;
        }
    }
}

上記のコードは「OVRHandPrefab」に追加します。
手を取得し、変数「_ catching」を作ります。「_ catching」の説明は後で

GetFingerIsPinchingは、指先と指先が触れているかどうかを取得する事ができます。
OVRHand.HandFingerは、親指とどの指が触れているかを判定できます。今回は人差し指にします。

今回は、指先と指先が触れてたら「_catching」は真にします。
状態はCanvas上に表示します。
(Canvas作ってないなら書く必要はないです、この後にCanvas関する説明も全部省略します)

##論理およびコード説明

cubeTouch.cs
    private ovrHand _ovrHand;
    private bool _touchIN;      //当たり
    private bool _catch;        //掴む
    private bool _hold;         //取れる

    // Start is called before the first frame update
    void Start()
    {
        _ovrHand = FindObjectOfType<ovrHand>();
    }
void Update()
    {
        // 手は選択状態なのかを常に取得する
        _catch = _ovrHand._catching;
        touchCube();
        CatchCube();
    }
void touchCube()
    {
        if (_touchIN == true && _catch == false)
        {
            _hold = true;
        }
    }

    void CatchCube()
    {
        if (_hold == true && _catch == true)
        {
            _touchIN = false;
        }
        else if (_touchIN = false && _touchIN == false)
        {
            _hold = false;
        }
    }

まず、掴むという動作について考えます。

手は握った状態で物体に当たったら、物体をつかめる。
物体に当たった後、手を握ると、物体をつかめる。

このことを、上記のコードで表しています。

cubeTouch.cs
void OnCollisionStay(Collision other)
    {
        // 物体をタッチした時 タッチ変数は 真になる
        if (other.gameObject.name == "Hand_Index3_CapsuleRigidBody" ||
            other.gameObject.name == "Hand_Index2_CapsuleRigidBody" ||
            other.gameObject.name == "Hand_Thumb3_CapsuleRigidBody" ||
            other.gameObject.name == "Hand_Thumb2_CapsuleRigidBody" 
            )
        {
            _touchIN = true;
            // 位置固定し物理削除する
            gameObject.GetComponent<Rigidbody>().constraints = RigidbodyConstraints.FreezeAll;
            gameObject.GetComponent<Rigidbody>().isKinematic = true;
        }
    }

上の説明に合わせ、
まず、物体をタッチしないと始まらないので、当たり判定書きます。

それぞれの指の名前は一番上の参考リンクを参照してください。
タッチしたら、「 _touchIN」は真になります。

cubeTouch.cs
void CatchCube()
    {
        if (_hold == true && _catch == true)
        {
            Debug.Log("_catch = " + _catch + " 物を掴みました!");
            // 右手の子供になる
            gameObject.transform.SetParent(_rightHandAnchor.gameObject.transform);
            // 重力抜き 当たり判定しない
            gameObject.GetComponent<Rigidbody>().useGravity = false;
            gameObject.GetComponent<BoxCollider>().isTrigger = true;
            _touchIN = false;
        }
        else if (_touchIN = false && _touchIN == false)
        {
            // 親関係解除
            gameObject.transform.parent = null;
            // 重力 当たり判定 復帰
            gameObject.GetComponent<Rigidbody>().useGravity = true;
            gameObject.GetComponent<BoxCollider>().isTrigger = false;
            // 位置移動可 物理復帰
            gameObject.GetComponent<Rigidbody>().constraints = RigidbodyConstraints.None;
            gameObject.GetComponent<Rigidbody>().isKinematic = false;
            _hold = false;
        }
    }

今回のCubeは物理演算を入れているので、掴む時は物理演算を抜く必要があります。
「CatchCube()」の中に必要な処理を追加します。
コードの意味は 、コメントアウトで書いているので参考にしてください。

最後に、「cubeTouch.cs」をCubeの中に入れば完成です。
##動作確認
com.oculus.vrshell-20200218-204038_1_1.gif

ビルドして、動作確認するとこうなります。

7
4
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?