leapmotion手势的unity使用相关

https://blog.csdn.net/sky1466181491/article/details/86628384

准备

官方文档

根据官方介绍,使用leapmotion需要两个东西:

  1. Ultraleap Hand Tracking Camera(就是你的手势追踪设备)
  2. Hand Tracking Software(官方提供的软件)

开发文档
官方DEMO
官方unity插件 走包管理下载也行自己看官方介绍

步骤

Unity Plugin 5.5.0 + 2019.4.30
1.下载并安装官方Hand Tracking Software
2.连上手势追踪设备并启动软件
3.unity工程导入官方插件
官方给的插件包

  1. 案例
  2. 先行版预览案例(不保证支持)
  3. 先行版预览功能(不保证支持)
  4. 核心包This includes Core, Interaction Engine, and the Hands Module.

4.Service Provider(类型)预制体拖入-(程序可以连接并获取到追踪数据了)
5.HandModels预制体拖入 (可以运行看到手模型的运动了)

交互

交互三件套:

  • InteractionManager :交互功能计算实现管理
  • InteractionController :两个实体类:InteractionHand 和 InteractionXRController(XR用) 手的控制器
  • InteractionBehaviour:可交互物体挂载,使物体可以参与交互 需要刚体和碰撞

Interaction Engine找到Interaction Manager预制体拖入场景,给需要交互的物体添加InteractionBehaviour即可。

注意:它会改变unity物理的重力大小-4.905来达到好的交互效果,可以自己改回去
更多交互例子

手部模型

模型拖入场景,建立个父物体,挂上HandBinder,可以自动挂载数据点和对应模型节点,也能手动更改

手势解析

  • LeapProvider类里包含了每帧获取到的追踪数据(世界坐标)
    LeapProvider.CurrentFrame 当前帧数据
  • Frame类里包含了手部和手指的每帧数据(位置,朝向,姿势等)
    .Hand:获取手状态集合

官方现在好像没有手势解析的直接API调用,只能自己根据手指位置等数据提取自己想要的手势

手势提取代码

自己写的一个手势提取工具。使用时保证获取到leapprovider后,给左右手注册事件即可,也能够在外部访问一些数据(双手,手掌方向等)

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

public class LeapGestureTool : MonoBehaviour
{
  
    //当前帧手数量
    public enum HandState
    {
        none,
        leftHand,
        rightHand,
        bothHands
    }

    public HandState _HandState = HandState.none;
    
    LeapProvider _lp;

    void Start()
    {
        _lp = GetComponent<LeapProvider>();
    }


    void Update()
    {
        //获取追踪帧数据
        if(_lp!=null)
            AnalyseLeapFrameData(_lp.CurrentFrame);
    }


    public GestureHelper l_helper = new GestureHelper();
    public GestureHelper r_helper = new GestureHelper();
    /// <summary>
    /// 解析leapmotion的帧数据
    /// </summary>
    /// <param name="frame_data"></param>
    private void AnalyseLeapFrameData(Frame frame_data)
    {
        //左右手判断 并更新手
        _HandState = GetHandState(frame_data.Hands);

        //手势信息更新
        l_helper.UpdateInf();
        r_helper.UpdateInf();

        //双手距离获取
        BothHandScale(frame_data);
    }



    #region 基础
    /// <summary>
    /// 当前使用手判断 并添加helper
    /// </summary>
    /// <param name="lpHands"></param>
    /// <returns></returns>
    private HandState GetHandState(List<Hand> lpHands)
    {
        if(lpHands.Count == 1)//单手
        {
            if (lpHands[0].IsLeft)
            {
                l_helper.ChangeHandData(lpHands[0]);
                return HandState.leftHand;
            }
              
            if (lpHands[0].IsRight)
            {
                r_helper.ChangeHandData(lpHands[0]);
                return HandState.rightHand;
            }
            l_helper.ChangeHandData(null);
            r_helper.ChangeHandData(null);
            return HandState.none;
        }else if(lpHands.Count == 2)//双手
        {
            foreach(var x in lpHands)
            {
                if (x.IsLeft)
                {
                    l_helper.ChangeHandData(x);
                }

                if (x.IsRight)
                {
                    r_helper.ChangeHandData(x);
                }
            }
            return HandState.bothHands;
        }
        //无效数据
        l_helper.ChangeHandData(null);
        r_helper.ChangeHandData(null);
        return HandState.none;
    }

    #endregion




    #region  功能
    /// <summary>
    /// 双手离远或拉近趋势
    /// </summary>
    public float HandsZoom = 0;
    /// <summary>
    /// 双手距离
    /// </summary>
    public float lrHandDistance = 0;
    /// <summary>
    /// 【双手】获取双手之间的距离
    /// </summary>
    /// <param name="lpframe"></param>
    private void BothHandScale(Frame lpframe)
    {
        if (_HandState == HandState.bothHands)
        {
            //双手不动时不计算
            if(l_helper.isStayPos && r_helper.isStayPos)
            {
                lrHandDistance = 0;
                HandsZoom = 0;
            }


            if (lrHandDistance == 0)
                lrHandDistance = Vector3.Distance(l_helper.handPos, r_helper.handPos);

            float tempdis = Vector3.Distance(l_helper.handPos, r_helper.handPos);
            HandsZoom = tempdis - lrHandDistance;
            lrHandDistance = tempdis;
        }
        else
        {
            lrHandDistance = 0;
            HandsZoom = 0;
        }
    }
    #endregion
}


public class GestureHelper
{
    /// <summary>
    /// 获取当前手掌位置
    /// </summary>
    public Vector3 handPos
    {
        get
        {
            if (m_hand != null)
                return m_hand.PalmPosition.ToVector3();
            return Vector3.zero;
        }
    }

    //手掌朝向
    public Vector3 palmNormal
    {
        get
        {
            if (m_hand != null)
                return m_hand.PalmNormal.ToVector3();
            return Vector3.zero;
        }
    }

    private Hand m_hand;//手部数据
    public GestureHelper() { }

    public GestureHelper(Hand hand)
    {
        m_hand = hand;
    }

    public void ChangeHandData(Hand hand)
    {
        m_hand = hand;
    }


    /// <summary>
    /// 更新手部 数据  提取  手势
    /// </summary>
    public void UpdateInf()
    {
        if (m_hand == null)
        {
            //丢失数据重置信息
            NullReset();
            return;
        }
        GetHandGesture();
    }

    //手势触发事件执行
    public delegate void GestureEventHandle();
    public delegate void GestureEventHandle<T>(T value);//带返回数据的
    public GestureEventHandle GestureEvent_Grab;//握拳
    public GestureEventHandle GestureEvent_Open;//张开
    public GestureEventHandle GestureEvent_Pinch;//捏
    public GestureEventHandle GestureEvent_Stay;//原地不动

    public GestureEventHandle GestureEvent_OnlyIndexFinger;//仅食指伸出
    public GestureEventHandle<Hand> GestureEvent_OnlyIndexFinger_BackHand;

    public GestureEventHandle GestureEvent_JianDao;

    public GestureEventHandle<float> GestureEvent_Bending;//手掌弯曲(程度)
    public GestureEventHandle<float> GestureEvent_MoveX;//x轴移动(左右)
    public GestureEventHandle<float> GestureEvent_MoveY;//y轴移动(上下)
    public GestureEventHandle<float> GestureEvent_MoveZ;//z轴移动(前后)


    public bool isGrabing = false;
    public bool isStayPos = false;
    public string JSB = string.Empty;

    /// <summary>
    /// 姿势提取
    /// </summary>
    private void GetHandGesture()
    {
        //grab测试的是  除大拇指外的四个手指的 平均 值   (依据指向方向来)
        //position是相对于LeapProvider物体的位置(单位缩小10)
        if (m_hand.GrabStrength == 1)
        {
            isGrabing = true;
            if (GestureEvent_Grab != null)
                GestureEvent_Grab();
            // Debug.Log("握拳");
            JSB = "石头";
        }
        else if (m_hand.GrabStrength == 0)//只要不是紧握
        {
            isGrabing = false;
            if (GestureEvent_Open != null)
                GestureEvent_Open();
            // Debug.Log("张开");
            JSB = "布";
        }
        else// 0-1之间,手指在不断弯曲
        {
            isGrabing = false;
            if (GestureEvent_Bending != null)
                GestureEvent_Bending(m_hand.GrabStrength);
            //Debug.Log("正在握紧"+ lpHand.GrabStrength);
        }

        //捏 和 握拳 会有交叉   必须用到大拇指
        if (m_hand.PinchStrength == 1)
        {
            if (GestureEvent_Pinch != null)
                GestureEvent_Pinch();
            //Debug.Log("捏");
        }

        //剪刀手的判断 
        //1.先判断打开的手指数
        //2.判断是否是 中指 食指
        //
        //判断中指
        //Debug.Log(m_hand.GetMiddle().IsExtended);

        int tt = 0;
        foreach(var t in m_hand.Fingers)
        {
            if (t.IsExtended)
                tt++;
        }
        if (tt == 2)
        {
            if(m_hand.GetMiddle().IsExtended && m_hand.GetIndex().IsExtended)
            {
                if (GestureEvent_JianDao != null)
                    GestureEvent_JianDao();
                JSB = "剪刀";
            }
        }

        if(tt == 1)
        {
            if (m_hand.GetIndex().IsExtended)
            {
                //箭头 手势
                if (GestureEvent_OnlyIndexFinger != null)
                    GestureEvent_OnlyIndexFinger();

                //返回手部数据
                if (GestureEvent_OnlyIndexFinger_BackHand != null)
                    GestureEvent_OnlyIndexFinger_BackHand(m_hand);  
            }
        }
        //手掌方向


        //手的【原地不动】【移动方向】
        GetMoveDir();
    }



    Vector3 oldMovePosition;
    //原地不动判断条件:手的三方向上的速度和阈值
    static float smallestVelocity = 0.3f;
    float move_X;
    float move_Y;
    float move_Z;

    //手部移动方向获取
    private void GetMoveDir()
    {
        //原地不动
        if(m_hand.PalmVelocity.Magnitude < smallestVelocity)
        {
            if (GestureEvent_Stay != null)
                GestureEvent_Stay();

            isStayPos = true;
            //位置重置
            oldMovePosition = Vector3.zero;
            move_X = move_Y = move_Z = 0;
        }
        else//
        {
            isStayPos = false;

            if (oldMovePosition == Vector3.zero)
                oldMovePosition = m_hand.PalmPosition.ToVector3();

            //效果不好的话加阈值
            move_X += m_hand.PalmPosition.ToVector3().x - oldMovePosition.x;
            move_Y += m_hand.PalmPosition.ToVector3().y - oldMovePosition.y;
            move_Z += m_hand.PalmPosition.ToVector3().z - oldMovePosition.z;
            if (move_X > 0)//右移
            {
                if (GestureEvent_MoveX != null)
                    GestureEvent_MoveX(move_X);
               //   Debug.LogError("→");
                //move_X = 0;
            }

            if(move_X < 0)//左移
            {
                if (GestureEvent_MoveX != null)
                    GestureEvent_MoveX(move_X);
                 // Debug.LogError("←");
                //move_X = 0;
            }

            if (move_Y > 0)//上
            {
                if (GestureEvent_MoveY != null)
                    GestureEvent_MoveY(move_Y);
                //  Debug.LogError("↑");
            }

            if (move_Y < 0)//下
            {
                if (GestureEvent_MoveY != null)
                    GestureEvent_MoveY(move_Y);
                // Debug.LogError("↓");
            }

            if (move_Z > 0)//前
            {
                if (GestureEvent_MoveZ != null)
                    GestureEvent_MoveZ(move_Z);
                //  Debug.LogError("前");
            }

            if (move_Z < 0)//后
            {
                if (GestureEvent_MoveZ != null)
                    GestureEvent_MoveZ(move_Z);
                //  Debug.LogError("后");
            }
            //替换当前位置
            oldMovePosition = m_hand.PalmPosition.ToVector3();
        }
    }

    private void NullReset()
    {
        //抓握
        isGrabing = false;
        //上一帧位置
        oldMovePosition = Vector3.zero;
        //移动趋势
        move_X = move_Y = move_Z = 0;
    }



}

扩展

unity插件里的核心:

  • Core. 获取追踪到的数据,模型和数据绑定等接口提供
  • The Interaction Engine.交互功能,类似物理引擎
  • Hands. 手部模型渲染相关

核心组件:

  • LeapServiceProvider:功能入口,连接并获取追踪数据(XR项目用XR版的)
  • Attachment Hands:协助自动绑定追踪数据到手部模型
  • InteractionManager:通过FixedUpdate 和 交互逻辑来实现交互功能 控制交互数据(交互功能必须存在此组件)
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值