LeapMotion簡單手勢控制
阿新 • • 發佈:2018-12-20
使用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;
}
}
}
}