1. 程式人生 > >LeapMotion簡單手勢控制

LeapMotion簡單手勢控制

使用LeapMotion做手勢識別,控制物體的放大縮小/移動/旋轉/單選 需要做的效果是:

  • 伸出食指和中指,物體旋轉
  • 食指中指加拇指,物體移動
  • 五指伸出手掌垂直,物體進行放大縮小
  • 食指單指伸出,進入選擇狀態,選擇單個物體控制

準備工作

需要做的是對手指狀態的判斷,看了一些其他部落格,設定閾值判斷手指的伸直彎曲沒看明白,我用的是對手指末端指向指尖向量的判斷來處理手指的狀態. 匯入LeapMotion官方包之後,在LeapMotion檔案下選擇Core->Examples目錄下選擇Desktop 圖片上指的位置 在這個Demo上進行後續的操作; 我做的這個是單手操作的,所以手的識別處理沒做,指定左手操作. 場景列表如下,因為有食指選中的效果,所以將所有物體放在一個父節點下,子物體都要有碰撞盒.父物體可以不帶碰撞盒. 場景

程式碼編寫

新建一個指令碼Manager,新增名稱空間using Leap.Unity; 因為我的是食指單指伸出進入選中狀態,所以需要獲取指尖的座標,在Hierarchy面板中,將HandModels下的物體拖到對應的屬性中; 屬性設定 對應屬性的新增

食指單指的狀態

根據各個手指的末端指向手指的向量來判斷手指是否是伸直狀態.用一個Bool值來記錄是否進入單指狀態,預設是False; 在伸直狀態下用射線檢測碰撞的物體,當遇到的是單個物體,用來記錄單指狀態的bool值 變為true; shexian這個bool值是用來判斷射線檢測是否開啟,預設為true;當檢測到是單個物體的時候shexian=false;

 void IndexDanZhi()
    {
        Vector3 tippos = indexL.GetTipPosition();//當前手指指尖的位置座標
        Vector3 direction = indexL.GetBoneDirection(1);//末端到指尖的向量 
        Vector3 Tdirection = ThumbL.GetBoneDirection(2);//拇指
        Vector3 Mdirection = Middle.GetBoneDirection(1);//中指
        Vector3 Pdirection = Pinky.GetBoneDirection(1);//無名指
       muzhi = Tdirection;
        zhongzhi = Mdirection;
        if (direction.y > 0 && Mdirection.y < -0.1f&& Pdirection.y < 0 && Tdirection.x < 0)
        {
            Debug.Log("單指執行");
            Vector2 radion = Camera.main.WorldToScreenPoint(tippos);
            ray = Camera.main.ScreenPointToRay(radion);
            Debug.DrawRay(ray.origin, ray.direction, Color.red);
            play.GetComponent<BoxCollider>().enabled = false;
            if (Physics.Raycast(ray, out hit, int.MaxValue))
            {
                if (hit.transform.tag == "cube")
                {

                    foreach (var box in cubes)
                    {
                        if (box.name.Equals(hit.transform.name) && shexian)
                        {
                            if (box.GetComponent<MeshRenderer>().material.color == Color.white)
                            {
                                box.GetComponent<MeshRenderer>().material.color = Color.red;
                                danzhigo = box;
                                IsDanZhi = true;
                                //shexian = false;
                            }
                            else 
                            {
                                danzhigo.GetComponent<MeshRenderer>().material.color = Color.white;
                                //shexian = true;
                            }
                        }
                        else if (!box.name.Equals(hit.transform.name) && shexian)
                        {
                            {
                                IsDanZhi = false;
                                box.GetComponent<MeshRenderer>().material.color = Color.white;
                            }
                        }
                    }
                    //IsDanZhi = true;
                    //for (int j = 0; j < cubes.Length; j++)
                    //{
                    //    if (cubes[j].name.Equals(hit.transform.name) && shexian)
                    //    {
                    //        if (cubes[j].GetComponent<MeshRenderer>().material.color == Color.white)
                    //        {
                    //            cubes[j].GetComponent<MeshRenderer>().material.color = Color.red;
                    //            danzhigo = cubes[j];
                    //            shexian = false;
                    //        }
                    //        else
                    //        {
                    //            danzhigo.GetComponent<MeshRenderer>().material.color = Color.white;
                    //            shexian = true;
                    //        }
                    //    }
                        //else
                        //{
                        //    cubes[j].GetComponent<MeshRenderer>().material.color = Color.white;
                        //    IsDanZhi = false;
                        //   // shexian = false;
                        //}
                    //}
                }
                shexian = false;
                print((shexian));
            }
            else
            {
                shexian = true;
                Debug.Log("離開物體"+shexian);
            }

        }
    }

旋轉

 void IsRotation()
    {
        Vector3 tippos = indexL.GetTipPosition();//當前手指指尖的位置座標
        Vector3 direction = indexL.GetBoneDirection(1);//食指末端到指尖的向量
        Vector3 Tdirection = ThumbL.GetBoneDirection(2);//拇指
        Vector3 Mdirection = Middle.GetBoneDirection(1);//中指
        Vector3 Pdirection = Pinky.GetBoneDirection(1);//無名指
        if (direction.y > 0 && Mdirection.y > 0 && Tdirection.x < 0 && Pdirection.y < 0)
        {
            Debug.Log("旋轉執行");       
           // Vector2 radion = Camera.main.WorldToScreenPoint(tippos);
           // ray = Camera.main.ScreenPointToRay(radion);
          //  Debug.DrawRay(ray.origin, ray.direction, Color.red);
          //  if (Physics.Raycast(ray, out hit, int.MaxValue))
         //   {
                if (IsDanZhi == false)
                {
                    //foreach (var v in cubes)
                    //{
                    //    ToRotate(v.transform);
                    //}
                     ToRotate(play.transform);
                }
          //  }

            if (IsDanZhi)
            {
                ToRotate(danzhigo.transform);
            }
        }
    }
    //旋轉控制
    void ToRotate(Transform po)
    {
        if (palmtra.position.x > 0)
        {
            po.Rotate(0, -5, 0);
        }

        if (palmtra.position.x < 0)
        {
            po.Rotate(0, 5, 0);
        }

        if (palmtra.position.y < 0)
        {
            po.Rotate(-5, 0, 0);
        }

        if (palmtra.position.y > 0)
        {
            po.Rotate(5, 0, 0);
        }
    }

移動

/// <summary>
    /// 移動
    /// </summary>
    void IsMove()
    {
        Vector3 tippos = indexL.GetTipPosition();//當前手指指尖的位置座標
        Vector3 direction = indexL.GetBoneDirection(1);//食指末端到指尖的向量
        Vector3 Tdirection = ThumbL.GetBoneDirection(2);//拇指
        Vector3 Mdirection = Middle.GetBoneDirection(1);//中指
        Vector3 Pdirection = Pinky.GetBoneDirection(1);//無名指
        if (direction.y > 0 && Mdirection.y > 0 && Tdirection.x > 0.1f && Pdirection.y < 0)
        {
            Debug.Log("移動執行");
            Vector2 radion = Camera.main.WorldToScreenPoint(tippos);
           // ray = Camera.main.ScreenPointToRay(radion);
           // Debug.DrawRay(ray.origin, ray.direction, Color.red);
            
          //  if (Physics.Raycast(ray, out hit, int.MaxValue))
            //{
                if (IsDanZhi == false)
                {
                    play.transform.position = new Vector3(palmtra.position.x, palmtra.transform.position.y, disz);
                }

            //}
            if (IsDanZhi)
            {
                danzhigo.transform.position = new Vector3(palmtra.transform.position.x, palmtra.transform.position.y, danzhigo.transform.position.z);
            }

        }
    }

放大縮小

  /// <summary>
    /// 放大縮小
    /// </summary>
    void IsScace()
    {
        Vector3 tippos = indexL.GetTipPosition();//當前手指指尖的位置座標
        Vector3 direction = indexL.GetBoneDirection(1);//末端到指尖的向量 
        Vector3 Tdirection = ThumbL.GetBoneDirection(2);//拇指
        Vector3 Mdirection = Middle.GetBoneDirection(1);//中指
        Vector3 Pdirection = Pinky.GetBoneDirection(1);//無名指
        float ang = Vector3.Angle(palmtra.forward, Vector3.forward);
        e = ang;
        if (direction.y > 0 && Mdirection.y > 0 && Pdirection.y > 0 && Tdirection.x > 0 && ang > 80 && ang < 110)
        {
            Debug.Log("縮放執行");
            Vector3 v3 = new Vector3(palmtra.position.z - 0.05f, palmtra.position.z - 0.05f, palmtra.position.z - 0.05f);
            if (IsDanZhi == false)
            {
                //play.transform.localScale = v3;
                foreach (var V in cubes)
                {
                    V.transform.localScale = v3; ;
                    
                }
            }

            if (IsDanZhi)
            {
                danzhigo.transform.localScale = v3;
            }
            
                
            

        }

    }

完整指令碼

using System.Collections;
using System.Collections.Generic;
using Leap;
using Leap.Unity;
using Leap.Unity.Infix;
using UnityEngine;
using UnityEngine.UI;

public class Manager : MonoBehaviour
{
    public Transform[] bonesL;//左手所有手指指尖
    public HandModelBase leftHand;//左手
    public Transform palmtra;//左手掌心
    public RigidFinger indexL;//左手食指
    public RigidFinger ThumbL;//左手拇指
    public RigidFinger Middle;//左手中指
    public RigidFinger Pinky;//左手無名指
    public GameObject play;//物體的整體
    public GameObject[] cubes;//場景中的物體
    public Vector3 shouzhang, muzhi, zhongzhi;//測試用
    public bool IsDanZhi = false;
    public float e;//手掌和Z正方向的夾角,測試用
    private static  GameObject danzhigo;//選中的物體
    List<HandModelBase> handModelList = new List<HandModelBase>();
    private float disz;
    void Start()
    {
        disz = play.transform.position.z;
    }
 
    // Update is called once per frame
    void Update()
    {
        // 如果兩個手都沒有識別 清空 list 表
        if (!leftHand.IsTracked)
        {
            if (handModelList.Contains(leftHand))
            {
                handModelList.Remove(leftHand);
            }
        }
        // 滑鼠移動 根據 list[0] 去操作,判斷識別手的先後關係
        if (leftHand != null && leftHand.IsTracked)
        {
            if (!handModelList.Contains(leftHand))
            {
                handModelList.Add(leftHand);
            }
        }

        shouzhang = palmtra.position;

        IndexDanZhi();
        IsRotation();
        IsMove();
        IsScace();
      //  QueDan();
    }

    void LateUpdate()
    {

    }
    Ray ray;
    RaycastHit hit;

    /// <summary>
    /// 食指單指伸出
    /// </summary>
    void IndexDanZhi()
    {
        Vector3 tippos = indexL.GetTipPosition();//當前手指指尖的位置座標
        Vector3 direction = indexL.GetBoneDirection(1);//末端到指尖的向量 
        Vector3 Tdirection = ThumbL.GetBoneDirection(2);//拇指
        Vector3 Mdirection = Middle.GetBoneDirection(1);//中指
        Vector3 Pdirection = Pinky.GetBoneDirection(1);//無名指

        muzhi = Tdirection;
        zhongzhi = Mdirection;
        if (direction.y > 0 && Mdirection.y < -0.1f&& Pdirection.y < 0 && Tdirection.x < 0)
        {
            Debug.Log("單指執行");
            Vector2 radion = Camera.main.WorldToScreenPoint(tippos);
            ray = Camera.main.ScreenPointToRay(radion);
            Debug.DrawRay(ray.origin, ray.direction, Color.red);
            play.GetComponent<BoxCollider>().enabled = false;
            if (Physics.Raycast(ray, out hit, int.MaxValue))
            {
                if (hit.transform.tag == "cube")
                {

                    foreach (var box in cubes)
                    {
                        if (box.name.Equals(hit.transform.name) && shexian)
                        {
                            if (box.GetComponent<MeshRenderer>().material.color == Color.white)
                            {
                                box.GetComponent<MeshRenderer>().material.color = Color.red;
                                danzhigo = box;
                                IsDanZhi = true;
                                //shexian = false;
                            }
                            else 
                            {
                                danzhigo.GetComponent<MeshRenderer>().material.color = Color.white;
                                //shexian = true;
                            }
                        }
                        else if (!box.name.Equals(hit.transform.name) && shexian)
                        {
                            {
                                IsDanZhi = false;
                                box.GetComponent<MeshRenderer>().material.color = Color.white;
                            }
                        }
                    }
                    //IsDanZhi = true;
                    //for (int j = 0; j < cubes.Length; j++)
                    //{
                    //    if (cubes[j].name.Equals(hit.transform.name) && shexian)
                    //    {
                    //        if (cubes[j].GetComponent<MeshRenderer>().material.color == Color.white)
                    //        {
                    //            cubes[j].GetComponent<MeshRenderer>().material.color = Color.red;
                    //            danzhigo = cubes[j];
                    //            shexian = false;
                    //        }
                    //        else
                    //        {
                    //            danzhigo.GetComponent<MeshRenderer>().material.color = Color.white;
                    //            shexian = true;
                    //        }
                    //    }
                        //else
                        //{
                        //    cubes[j].GetComponent<MeshRenderer>().material.color = Color.white;
                        //    IsDanZhi = false;
                        //   // shexian = false;
                        //}
                    //}
                }
                shexian = false;
                print((shexian));
            }
            else
            {
                shexian = true;
                Debug.Log("離開物體"+shexian);
            }

        }
    }

    public bool shexian = true;
   
    /// <summary>
    /// 食指和中指,控制旋轉
    /// </summary>
    void IsRotation()
    {
        Vector3 tippos = indexL.GetTipPosition();//當前手指指尖的位置座標
        Vector3 direction = indexL.GetBoneDirection(1);//食指末端到指尖的向量
        Vector3 Tdirection = ThumbL.GetBoneDirection(2);//拇指
        Vector3 Mdirection = Middle.GetBoneDirection(1);//中指
        Vector3 Pdirection = Pinky.GetBoneDirection(1);//無名指
        if (direction.y > 0 && Mdirection.y > 0 && Tdirection.x < 0 && Pdirection.y < 0)
        {
            Debug.Log("旋轉執行");       
           // Vector2 radion = Camera.main.WorldToScreenPoint(tippos);
           // ray = Camera.main.ScreenPointToRay(radion);
          //  Debug.DrawRay(ray.origin, ray.direction, Color.red);
          //  if (Physics.Raycast(ray, out hit, int.MaxValue))
         //   {
                if (IsDanZhi == false)
                {
                    //foreach (var v in cubes)
                    //{
                    //    ToRotate(v.transform);
                    //}
                     ToRotate(play.transform);
                }
          //  }

            if (IsDanZhi)
            {
                ToRotate(danzhigo.transform);
            }
        }
    }
    //旋轉控制
    void ToRotate(Transform po)
    {
        if (palmtra.position.x > 0)
        {
            po.Rotate(0, -5, 0);
        }

        if (palmtra.position.x < 0)
        {
            po.Rotate(0, 5, 0);
        }

        if (palmtra.position.y < 0)
        {
            po.Rotate(-5, 0, 0);
        }

        if (palmtra.position.y > 0)
        {
            po.Rotate(5, 0, 0);
        }
    }

    /// <summary>
    /// 移動
    /// </summary>
    void IsMove()
    {
        Vector3 tippos = indexL.GetTipPosition();//當前手指指尖的位置座標
        Vector3 direction = indexL.GetBoneDirection(1);//食指末端到指尖的向量
        Vector3 Tdirection = ThumbL.GetBoneDirection(2);//拇指
        Vector3 Mdirection = Middle.GetBoneDirection(1);//中指
        Vector3 Pdirection = Pinky.GetBoneDirection(1);//無名指
        if (direction.y > 0 && Mdirection.y > 0 && Tdirection.x > 0.1f && Pdirection.y < 0)
        {
            Debug.Log("移動執行");
            Vector2 radion = Camera.main.WorldToScreenPoint(tippos);
           // ray = Camera.main.ScreenPointToRay(radion);
           // Debug.DrawRay(ray.origin, ray.direction, Color.red);
            
          //  if (Physics.Raycast(ray, out hit, int.MaxValue))
            //{
                if (IsDanZhi == false)
                {
                    play.transform.position = new Vector3(palmtra.position.x, palmtra.transform.position.y, disz);
                }

            //}
            if (IsDanZhi)
            {
                danzhigo.transform.position = new Vector3(palmtra.transform.position.x, palmtra.transform.position.y, danzhigo.transform.position.z);
            }

        }
    }
    /// <summary>
    /// 放大縮小
    /// </summary>
    void IsScace()
    {
        Vector3 tippos = indexL.GetTipPosition();//當前手指指尖的位置座標
        Vector3 direction = indexL.GetBoneDirection(1);//末端到指尖的向量 
        Vector3 Tdirection = ThumbL.GetBoneDirection(2);//拇指
        Vector3 Mdirection = Middle.GetBoneDirection(1);//中指
        Vector3 Pdirection = Pinky.GetBoneDirection(1);//無名指
        float ang = Vector3.Angle(palmtra.forward, Vector3.forward);
        e = ang;
        if (direction.y > 0 && Mdirection.y > 0 && Pdirection.y > 0 && Tdirection.x > 0 && ang > 80 && ang < 110)
        {
            Debug.Log("縮放執行");
            Vector3 v3 = new Vector3(palmtra.position.z - 0.05f, palmtra.position.z - 0.05f, palmtra.position.z - 0.05f);
            if (IsDanZhi == false)
            {
                //play.transform.localScale = v3;
                foreach (var V in cubes)
                {
                    V.transform.localScale = v3; ;
                    
                }
            }

            if (IsDanZhi)
            {
                danzhigo.transform.localScale = v3;
            }
            
                
            

        }

    }

}