Manomotion sdk的简单使用

本篇主要说的是Manomotion sdk的简单使用,包括简单的手势交互,平滑移动等内容。

Manomotion sdk的安装见另一篇博客:

Manomotion手势识别unity sdk安装与发布_充电ing...的博客-CSDN博客

本样例测试在windows端

在打开给出的Manomotiosdkpro场景,链接摄像头发现能运行,说明已完成导入,接下来进行简单的调用。

新建一个场景File->New Scene

将Assets下的ManomotionManager,ManomotionVisualization,ManomotionCanvas,GizmoCanvas,SkeletonManager拉到场景中

将场景中的Main Camera拉入到ManomotionManager下的Mano Utils中,并将ManomotionCanvas下的statusAnimator拉到ManomotionManager下的ManoEvents中

将Main Camera拉到ManoVisualization下的ManoVisualization中,并将ManomotionCanva下的杂七杂八的东西给勾掉

同样吧GizmoCanvas下的杂项也给勾掉,只留后面会用的SmoothingSlider,同时新建几个物体拉到适当的位置

新建脚本ManoObjInteraction挂载到Main Camera下,之后开始写脚本调用sdk与场景中的物体交互,首先进行物体的选择,这里采用射线检测的方法,再新建一个脚本BoxColliderGizmo

其中,运行时,场景左下角会显示摄像头输入信息,为了方便将手势识别的结果显示在这里,在这里会看到发出的射线,BoxColliderGizmo脚本主要是射线的材质,以及选中后对物体进行方框描边,代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//namespace 
//{
    /// <summary>
    /// 描边框效果
    /// </summary>
    [RequireComponent(typeof(BoxCollider))]
    public class BoxColliderGizmo : MonoBehaviour
    {
        public bool isDraw = true;
        void OnRenderObject()
        {
            if (isDraw)
            {
                DrawOutLineGizmos();
            }
        }
        public void DrawOutLineGizmos()
        {
            var colliders = gameObject.GetComponents<BoxCollider>();
            if (colliders == null)
            {
                return;
            }
            CreateLineMaterial();
            lineMaterial.SetPass(0);
            GL.PushMatrix();
            GL.MultMatrix(transform.localToWorldMatrix);

            for (int i = 0; i < colliders.Length; i++)
            {
                var col = colliders[i];
                var c = col.center;
                var size = col.size;
                float rx = size.x / 2f;
                float ry = size.y / 2f;
                float rz = size.z / 2f;
                Vector3 p0, p1, p2, p3;
                Vector3 p4, p5, p6, p7;
                p0 = c + new Vector3(-rx, -ry, rz);
                p1 = c + new Vector3(rx, -ry, rz);
                p2 = c + new Vector3(rx, -ry, -rz);
                p3 = c + new Vector3(-rx, -ry, -rz);

                p4 = c + new Vector3(-rx, ry, rz);
                p5 = c + new Vector3(rx, ry, rz);
                p6 = c + new Vector3(rx, ry, -rz);
                p7 = c + new Vector3(-rx, ry, -rz);

                GL.Begin(GL.LINES);
                GL.Color(Color.red);
                GL.Vertex(p0);
                GL.Vertex(p1);
                GL.End();

                GL.Begin(GL.LINES);
                GL.Color(Color.red);
                GL.Vertex(p1);
                GL.Vertex(p2);
                GL.End();

                GL.Begin(GL.LINES);
                GL.Color(Color.red);
                GL.Vertex(p2);
                GL.Vertex(p3);
                GL.End();

                GL.Begin(GL.LINES);
                GL.Color(Color.red);
                GL.Vertex(p0);
                GL.Vertex(p3);
                GL.End();

                GL.Begin(GL.LINES);
                GL.Color(Color.red);
                GL.Vertex(p4);
                GL.Vertex(p5);
                GL.End();

                GL.Begin(GL.LINES);
                GL.Color(Color.red);
                GL.Vertex(p5);
                GL.Vertex(p6);
                GL.End();

                GL.Begin(GL.LINES);
                GL.Color(Color.red);
                GL.Vertex(p6);
                GL.Vertex(p7);
                GL.End();

                GL.Begin(GL.LINES);
                GL.Color(Color.red);
                GL.Vertex(p4);
                GL.Vertex(p7);
                GL.End();

                GL.Begin(GL.LINES);
                GL.Color(Color.red);
                GL.Vertex(p0);
                GL.Vertex(p4);
                GL.End();

                GL.Begin(GL.LINES);
                GL.Color(Color.red);
                GL.Vertex(p1);
                GL.Vertex(p5);
                GL.End();

                GL.Begin(GL.LINES);
                GL.Color(Color.red);
                GL.Vertex(p2);
                GL.Vertex(p6);
                GL.End();

                GL.Begin(GL.LINES);
                GL.Color(Color.red);
                GL.Vertex(p3);
                GL.Vertex(p7);
                GL.End();
            }
            GL.PopMatrix();
        }
        static Material lineMaterial;
        static void CreateLineMaterial()
        {
            if (!lineMaterial)
            {
                Shader shader = Shader.Find("Hidden/Internal-Colored");
                lineMaterial = new Material(shader);
                lineMaterial.hideFlags = HideFlags.HideAndDontSave;
                lineMaterial.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
                lineMaterial.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
                lineMaterial.SetInt("_Cull", (int)UnityEngine.Rendering.CullMode.Off);
                lineMaterial.SetInt("_ZWrite", 0);
            }
        }
    }
//}

 在ManoObjInteraction脚本中调用手势识别的结果并进行射线检测,为了直观,先画出整个手势识别的结果(文章最后会给出整个脚本的代码),这部分代码为

//OnEnable
for (int i = 0; i < 21; i++)
        {
            point[i] = GameObject.CreatePrimitive(PrimitiveType.Sphere);
            point[i].SetActive(true);
            point[i].transform.localScale = new Vector3(0.005f, 0.005f, 0.005f);
            Renderer render = point[i].GetComponent<Renderer>();
            render.material.SetColor("_Color", Color.red);
        }

//Update
//初始化坐标
for (int i = 0; i < 21; i++)
        {
            point[i].transform.position = ManomotionManager.Instance.Hand_infos[0].hand_info.tracking_info.skeleton.joints[i];
        }
//根据该坐标划线
for (int i = 1; i < 21; i++)
        {
            if (i != 4 && i != 8 && i != 12 && i != 16 && i != 20)
                Debug.DrawLine(point[i].transform.position, point[i + 1].transform.position, Color.green);
        }
        Debug.DrawLine(point[0].transform.position, point[1].transform.position, Color.black);
        Debug.DrawLine(point[0].transform.position, point[5].transform.position, Color.black);
        Debug.DrawLine(point[0].transform.position, point[9].transform.position, Color.black);
        Debug.DrawLine(point[0].transform.position, point[13].transform.position, Color.black);
        Debug.DrawLine(point[0].transform.position, point[17].transform.position, Color.black);

射线检测代码为

public GameObject GetRayHitObject()
    {
        //起始点
        ray.origin = ManomotionManager.Instance.Hand_infos[0].hand_info.tracking_info.skeleton.joints[8];
        
        Debug.Log("起始位置" + ray.origin);
        //方向
        ray.direction = ManomotionManager.Instance.Hand_infos[0].hand_info.tracking_info.skeleton.joints[6] - ManomotionManager.Instance.Hand_infos[0].hand_info.tracking_info.skeleton.joints[5];
        
        Debug.Log("8号位方向" + ray.direction);
        Debug.DrawLine(ray.origin, ray.origin + ray.direction *1000, Color.red);
        
        //是否碰撞
        bool isCollider = Physics.Raycast(ray, out RaycastHit hit, 1000);
        if (isCollider)
        {
            SetRayObject(hit.collider.gameObject);
        }
        else
        {
            ResetRayObject();
        }
        //返回检测到的物体
        return hit.collider.gameObject;
        
    }
public void SetRayObject(GameObject newGameObject)
    {
        SelectGameObject = newGameObject;
        if (SelectGameObject != null)
        {
            if (SelectGameObject.GetComponent<BoxColliderGizmo>() == null)
            {
                SelectGameObject.AddComponent<BoxColliderGizmo>().isDraw = true;
            }
            else
            {
                SelectGameObject.GetComponent<BoxColliderGizmo>().isDraw = true;
            }
        }
    }
    public void ResetRayObject()
    {
        if (SelectGameObject != null)
        {
            if (SelectGameObject.GetComponent<BoxColliderGizmo>() == null)
            {
                SelectGameObject.AddComponent<BoxColliderGizmo>().isDraw = false;
            }
            else
            {
                SelectGameObject.GetComponent<BoxColliderGizmo>().isDraw = false;
            }
            SelectGameObject = null;
        }
    }

//Update
//当手姿为指向姿势时,获取指向的物体
if (ManomotionManager.Instance.Hand_infos[0].hand_info.gesture_info.mano_gesture_continuous == ManoGestureContinuous.POINTER_GESTURE)
        {
            mControObj = GetRayHitObject();
        }

选中后对物体进行操作,拇指与食指点击姿势进行物体的显示与隐藏

void OnClick()
    {
        if (mControObj.activeInHierarchy)
        {
            mControObj.SetActive(false);
        }
        else
        {
            mControObj.SetActive(true);
        }
        
    }

//Update
//当触发点击手势时,触发点击事件
        ManoGestureTrigger curState = ManomotionManager.Instance.Hand_infos[0].hand_info.gesture_info.mano_gesture_trigger;
        if (curState != lastState)
        {
            if (curState == ManoGestureTrigger.CLICK)
            {
                OnClick();
            }
            lastState = curState;
        }

保持食指与拇指闭合并移动,对物体进行旋转

public void OnDraging()
    {
        Vector3 vPos = ManomotionManager.Instance.Hand_infos[0].hand_info.tracking_info.poi;
        Vector3 sPos = Camera.main.ViewportToScreenPoint(vPos);
        if (lastHandPos == Vector3.zero)
        {
            lastHandPos = sPos;
            return;
        }
        float offsetX = sPos.x - lastHandPos.x;
        mControObj.transform.Rotate(-Vector3.up * offsetX * 0.5f, Space.Self);//绕Y轴进行旋转
        lastHandPos = sPos;
    }

//Update
//当前手势为捏住状态时,持续触发拖拽事件,否则结束拖拽
        if (ManomotionManager.Instance.Hand_infos[0].hand_info.gesture_info.mano_gesture_continuous == ManoGestureContinuous.HOLD_GESTURE)
        {
            OnDraging();
        }

握拳姿势并移动,对物体进行移动

public void OnMoving()
    {
       
        TrackingInfo tracking = ManomotionManager.Instance.Hand_infos[0].hand_info.tracking_info;

        Vector3 vPos = tracking.poi;
        Vector3 sPos = Camera.main.ViewportToScreenPoint(new Vector3(vPos.x, vPos.y, tracking.depth_estimation * 1000));

        if (lastHandPos == Vector3.zero)
        {
            lastHandPos = sPos;
            return;
        }


        float offsetX = sPos.x - lastHandPos.x;
        float offsetY = sPos.y - lastHandPos.y;
        float offsetZ = sPos.z - lastHandPos.z;
        mControObj.transform.position += new Vector3(offsetX, offsetY, offsetZ);
        lastHandPos = sPos;
    }

//Update
if (ManomotionManager.Instance.Hand_infos[0].hand_info.gesture_info.mano_gesture_continuous == ManoGestureContinuous.CLOSED_HAND_GESTURE)
        {
            OnMoving();
        }

完整代码如下

using UnityEngine.UI;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ManoObjInteraction : MonoBehaviour
{
    public string des;
    public GameObject mControObj;

    GameObject[] point = new GameObject[21];

    private Ray ray;
    private LineRenderer line;
    private GameObject SelectGameObject = null;
   
    Vector3 lastHandPos = Vector3.zero;
   
    ManoGestureTrigger lastState;

    private void Update()
    {

        ManomotionManager.Instance.ShouldCalculateSkeleton3D(true);
        GizmoManager.Instance.ShouldDisplaySmoothingSlider(true);
        
        for (int i = 0; i < 21; i++)
        {
            point[i].transform.position = ManomotionManager.Instance.Hand_infos[0].hand_info.tracking_info.skeleton.joints[i];
        }
        for (int i = 1; i < 21; i++)
        {
            if (i != 4 && i != 8 && i != 12 && i != 16 && i != 20)
                Debug.DrawLine(point[i].transform.position, point[i + 1].transform.position, Color.green);
        }
        Debug.DrawLine(point[0].transform.position, point[1].transform.position, Color.black);
        Debug.DrawLine(point[0].transform.position, point[5].transform.position, Color.black);
        Debug.DrawLine(point[0].transform.position, point[9].transform.position, Color.black);
        Debug.DrawLine(point[0].transform.position, point[13].transform.position, Color.black);
        Debug.DrawLine(point[0].transform.position, point[17].transform.position, Color.black);

        if (ManomotionManager.Instance.Hand_infos[0].hand_info.gesture_info.mano_gesture_continuous == ManoGestureContinuous.POINTER_GESTURE)
        {
            mControObj = GetRayHitObject();
        }

        //当触发点击手势时,触发点击事件
        ManoGestureTrigger curState = ManomotionManager.Instance.Hand_infos[0].hand_info.gesture_info.mano_gesture_trigger;
        if (curState != lastState)
        {
            if (curState == ManoGestureTrigger.CLICK)
            {
                OnClick();
            }
            lastState = curState;
        }
        //当前手势为捏住状态时,持续触发拖拽事件,否则结束拖拽
        if (ManomotionManager.Instance.Hand_infos[0].hand_info.gesture_info.mano_gesture_continuous == ManoGestureContinuous.HOLD_GESTURE)
        {
            OnDraging();
        }

        if (ManomotionManager.Instance.Hand_infos[0].hand_info.gesture_info.mano_gesture_continuous == ManoGestureContinuous.CLOSED_HAND_GESTURE)
        {
            OnMoving();
        }        
    }
    private void OnEnable()
    {
        for (int i = 0; i < 21; i++)
        {
            point[i] = GameObject.CreatePrimitive(PrimitiveType.Sphere);
            point[i].SetActive(true);
            point[i].transform.localScale = new Vector3(0.005f, 0.005f, 0.005f);
            Renderer render = point[i].GetComponent<Renderer>();
            render.material.SetColor("_Color", Color.red);
        }
    }
    private void OnDisable()
    {
        lastHandPos = Vector3.zero;
    }

    #region CallBack
    void OnClick()
    {
        if (mControObj.activeInHierarchy)
        {
            mControObj.SetActive(false);
        }
        else
        {
            mControObj.SetActive(true);
        }
        
    }
    public void OnDraging()
    {
        Vector3 vPos = ManomotionManager.Instance.Hand_infos[0].hand_info.tracking_info.poi;
        Vector3 sPos = Camera.main.ViewportToScreenPoint(vPos);
        if (lastHandPos == Vector3.zero)
        {
            lastHandPos = sPos;
            return;
        }
        float offsetX = sPos.x - lastHandPos.x;
        mControObj.transform.Rotate(-Vector3.up * offsetX * 0.5f, Space.Self);//绕Y轴进行旋转
        lastHandPos = sPos;
    }
    
    public void OnMoving()
    {
       
        TrackingInfo tracking = ManomotionManager.Instance.Hand_infos[0].hand_info.tracking_info;

        Vector3 vPos = tracking.poi;
        Vector3 sPos = Camera.main.ViewportToScreenPoint(new Vector3(vPos.x, vPos.y, tracking.depth_estimation * 1000));

        if (lastHandPos == Vector3.zero)
        {
            lastHandPos = sPos;
            return;
        }


        float offsetX = sPos.x - lastHandPos.x;
        float offsetY = sPos.y - lastHandPos.y;
        float offsetZ = sPos.z - lastHandPos.z;
        mControObj.transform.position += new Vector3(offsetX, offsetY, offsetZ);
        lastHandPos = sPos;
    }

    public void SetRayObject(GameObject newGameObject)
    {
        SelectGameObject = newGameObject;
        if (SelectGameObject != null)
        {
            if (SelectGameObject.GetComponent<BoxColliderGizmo>() == null)
            {
                SelectGameObject.AddComponent<BoxColliderGizmo>().isDraw = true;
            }
            else
            {
                SelectGameObject.GetComponent<BoxColliderGizmo>().isDraw = true;
            }
        }
    }
    public void ResetRayObject()
    {
        if (SelectGameObject != null)
        {
            if (SelectGameObject.GetComponent<BoxColliderGizmo>() == null)
            {
                SelectGameObject.AddComponent<BoxColliderGizmo>().isDraw = false;
            }
            else
            {
                SelectGameObject.GetComponent<BoxColliderGizmo>().isDraw = false;
            }
            SelectGameObject = null;
        }
    }

    public GameObject GetRayHitObject()
    {
        ray.origin = ManomotionManager.Instance.Hand_infos[0].hand_info.tracking_info.skeleton.joints[8];
        
        Debug.Log("起始位置" + ray.origin);
        
        ray.direction = ManomotionManager.Instance.Hand_infos[0].hand_info.tracking_info.skeleton.joints[6] - ManomotionManager.Instance.Hand_infos[0].hand_info.tracking_info.skeleton.joints[5];
        
        Debug.Log("8号位方向" + ray.direction);
        Debug.DrawLine(ray.origin, ray.origin + ray.direction *1000, Color.red);
        bool isCollider = Physics.Raycast(ray, out RaycastHit hit, 1000);
        if (isCollider)
        {
            SetRayObject(hit.collider.gameObject);
        }
        else
        {
            ResetRayObject();
        }

        return hit.collider.gameObject;
        
    }

    #endregion

}

 

之后就可以运行测试了,而运行时会发现,game面板总是摄像头输入的信息,可以在ManoVisualization中将Show BackgroundLayer给勾掉就可以显示场景内容了

此时我们还会发现,抖动严重,这是因为每帧更新一次位置,而manomotion还内置了平滑移动,这就是之前拉到场景中的GizmCanvas中的内容了,就是显示的那个滑动条,拉动滑动条就可以控制缓慢的速度,让结果缓缓飘过去,就不会有抖动了。而代码也在前面给出的ManoObjInteration脚本中了,就是下面这行。

GizmoManager.Instance.ShouldDisplaySmoothingSlider(true);

在下载manomotion sdk时除了两个unity package外还有一个说明文档,里面还有更多内容,有兴趣的读者还请自行探索。
       

 

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值