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;
            }
            
                
            

        }

    }

}

  • 4
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值