如题:Unity + ReadSense D435 + Nuitrack 人体识别,
现在的功能有:
- 识别左右半转身
- 识别行走
- 日后更新。。。。
脚本:GestureManager.cs 用于检测动作的脚本。
using Intel.RealSense;
using System.Collections;
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.Configuration;
using UnityEngine.Events;
public enum GestureMode
{
Face = 0,
Back = 1,
}
public delegate void Motion();
[Serializable]
public class TextureEvent : UnityEvent<Texture> { }
public class GestureManager : MonoBehaviour
{
/// <summary>
/// 检测模式
/// </summary>
public GestureMode gestureMode = GestureMode.Face;
/// <summary>
/// 单例
/// </summary>
static GestureManager instance;
public static GestureManager Instance
{
get
{
if (instance == null)
{
instance = FindObjectOfType<GestureManager>();
if (instance == null)
{
GameObject container = new GameObject();
container.name = "GestureManager";
instance = container.AddComponent<GestureManager>();
}
DontDestroyOnLoad(instance);
}
return instance;
}
}
/// <summary>
/// 左转
/// </summary>
public event Motion onTurnLeft;
/// <summary>
/// 右转
/// </summary>
public event Motion onTurnRight;
/// <summary>
/// 立正
/// </summary>
public event Motion onTurnStraight;
/// <summary>
/// 移动
/// </summary>
public event Motion onMovement;
/// <summary>
/// 显示图片的 事件
/// </summary>
public TextureEvent rawImage;
/// <summary>
/// 移动延迟时间
/// </summary>
private float movementCacheTime = 0.5f;
public float MovementCacheTime { get => movementCacheTime; set => movementCacheTime = value; }
/// <summary>
/// 计时器
/// </summary>
private float counter = 0;
/// <summary>
/// 单例
/// </summary>
private nuitrack.Skeleton skeleton;
private void Start()
{
if (rawImage != null)
{
NuitrackManager.onColorUpdate += (frame) =>
{
rawImage.Invoke(frame.ToTexture2D());
};
}
}
void Update()
{
if (CurrentUserTracker.CurrentUser == 0)
{
return;
}
skeleton = CurrentUserTracker.CurrentSkeleton;
Movement(skeleton);
}
[HideInInspector]
public float waistHight = 0;
/// <summary>
/// 移动判断
/// </summary>
/// <param name="skeleton"></param>
private void Movement(nuitrack.Skeleton skeleton)
{
#region 旋转
Quaternion di = skeleton.GetJoint(nuitrack.JointType.Neck).ToQuaternion();
float dot = UnityEngine.Quaternion.Dot(UnityEngine.Quaternion.LookRotation(Vector3.right), di);
switch (gestureMode)
{
case GestureMode.Face:
if (dot > 0.85f)
{
onTurnRight?.Invoke();
}
else if (dot < 0.35f)
{
onTurnLeft?.Invoke();
}
else
{
onTurnStraight?.Invoke();
}
break;
case GestureMode.Back:
if (dot > 0.85f)
{
onTurnLeft?.Invoke();
}
else if (dot < 0.35f)
{
onTurnRight?.Invoke();
}
else
{
onTurnStraight?.Invoke();
}
break;
}
#endregion
#region 移动
float L_Hand = skeleton.GetJoint(nuitrack.JointType.LeftHand).ToVector3().y;
float R_Hand = skeleton.GetJoint(nuitrack.JointType.RightHand).ToVector3().y;
//手>0 膝盖>-500 摄像机安装方式高度:保持双手双臂放松下垂时,手腕上方5cm高度
//抬左手右脚 和 抬右手左脚
if ((L_Hand > waistHight && R_Hand > waistHight))
{
counter = movementCacheTime;
}
if (counter >= 0)
{
counter -= Time.deltaTime;
onMovement?.Invoke();
}
#endregion
}
/// <summary>
/// 校准
/// </summary>
public void Calibration()
{
if (skeleton == null) return;
waistHight = skeleton.GetJoint(nuitrack.JointType.Waist).ToVector3().y;
}
}
面板设置:
脚本:PlayerMovement.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using tracker;
public class PlayerMovement : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
rig = GetComponent<Rigidbody>();
if (rig == null)
{
rig = gameObject.AddComponent<Rigidbody>();
}
GestureManager.Instance.onTurnRight += Instance_onTurnRight;
GestureManager.Instance.onTurnLeft += Instance_onTurnLeft;
GestureManager.Instance.onMovement += Instance_onMovement;
GestureManager.Instance.onTurnStraight += Instance_onTurnStraight;
}
public float moveSpeed = 10;
public float rotaSpeed = 10;
public bool turning = false;
public bool moveing = false;
private Rigidbody rig;
private void Instance_onTurnStraight()
{
if (turning || moveing)
{
}
else
{
//做一些只有在立正时才做的事情 比如 添加手势控制功能 操作UI等
}
}
/// <summary>
/// 移动
/// </summary>
private void Instance_onMovement()
{
Moveing(1, moveSpeed);
}
/// <summary>
/// 旋转——Right
/// </summary>
private void Instance_onTurnRight()
{
Turning(1, rotaSpeed);
}
/// <summary>
/// 旋转——Left
/// </summary>
private void Instance_onTurnLeft()
{
Turning(-1, rotaSpeed);
}
/// <summary>
/// 旋转
/// </summary>
private void Turning(int dir, float speed)
{
float angel = transform.localRotation.eulerAngles.y;
transform.localRotation = Quaternion.Lerp(transform.localRotation, Quaternion.Euler(0, angel += (speed * dir), 0), Time.deltaTime * speed);
}
/// <summary>
/// 移动
/// </summary>
/// <param name="dir">方向</param>
/// <param name="speed">速度</param>
private void Moveing(int dir, float speed)
{
rig.MovePosition(transform.localPosition += transform.forward * speed * Time.deltaTime);
}
}
代码比较简单,就不写注释了。注意刚体设置。
脚本:BoxControl.cs 摄像机跟随脚本,可以实现碰撞缩进。
using UnityEngine;
/// <summary>
/// 脚本附着在 CameraBox上
/// </summary>
public class BoxControl : MonoBehaviour
{
public Transform target;
private Transform mainCam;
private float disT2B;
// Use this for initialization
void Start()
{
mainCam = GameObject.FindWithTag("MainCamera").transform;
disT2B = Vector3.Distance(target.position, transform.position);//记录target和CameraBox之间的初始距离
}
// Update is called once per frame
void LateUpdate()
{
Modulation();
//相机个cameraBox做插值
mainCam.position = Vector3.Lerp(mainCam.position, transform.position, 0.1f);
//相机始终看向角色正前方
mainCam.LookAt(target.position);
}
RaycastHit hit;//声明一个检测碰撞的对象
float disT2H;
void Modulation()
{
Vector3 rayDir = -target.forward.normalized;//获取 target 指向 相机盒子 方向的单位向量
//检测射线碰撞并填充 hit
if (Physics.Raycast(target.position, rayDir, out hit, disT2B))
{
disT2H = hit.distance;
}
else
{
disT2H = disT2B;
}
transform.position = disT2H * rayDir + target.position;
}
}
其中 CameraBox 是Player 的子物体。具体设置方法见网址:http://www.narkii.com/club/thread-412883-1.html
也是我写的,有时间誊到csdn上。
实现的效果:
Unity + ReadSense D435 + Nuitrack 人体动作识别