MotionCapture/Assets/Behaviours/BoneBehaviour.cs

273 lines
10 KiB
C#

using System;
using System.Collections.Generic;
using Models;
using UnityEngine;
namespace Behaviours
{
public class BoneBehaviour : MonoBehaviour
{
private readonly UdpListener _listener = new UdpListener();
private readonly GameObject[] _nodes = new GameObject[PoseLandmarkType.MaxValue];
private readonly List<Bond> _bonds = new List<Bond>();
private Dictionary<HumanBodyBones, RotationNode> _rotationNodes;
private List<PoseLandmark> _landmarks;
private Animator _animator;
private bool _isReceived;
private const float Scale = 0.2f;
private void Start()
{
_animator = GetComponent<Animator>();
CreateRotationNodes();
CreateNodes();
CreateBonds();
_listener.AddHandler(OnReceive);
_listener.Connect(5000);
}
private void Update()
{
if (_isReceived)
{
_animator.GetBoneTransform(HumanBodyBones.Hips).rotation =
_rotationNodes[HumanBodyBones.Hips].Rotation;
/*var rotation = _rotationNodes[HumanBodyBones.Hips].CalculateRotate
* Quaternion.Inverse(_rotationNodes[HumanBodyBones.RightUpperArm].CalculateRotate);
_animator.GetBoneTransform(HumanBodyBones.RightUpperArm).Rotate(rotation.eulerAngles);*/
var mid = (_landmarks[PoseLandmarkType.LeftHip].Position +
_landmarks[PoseLandmarkType.RightHip].Position) / 2;
for (var i = 0; i < PoseLandmarkType.MaxValue; i++)
{
_nodes[i].transform.position = (_landmarks[i].Position - mid) * 5f;
}
foreach (var bond in _bonds)
{
bond.UpdateBond();
}
_animator.GetBoneTransform(HumanBodyBones.LeftUpperArm).rotation = _bonds[9].Rotation;
_animator.GetBoneTransform(HumanBodyBones.LeftUpperArm).Rotate(0, -180, 0,
Space.Self);
_animator.GetBoneTransform(HumanBodyBones.LeftLowerArm).rotation = _bonds[10].Rotation;
_animator.GetBoneTransform(HumanBodyBones.LeftLowerArm).Rotate(0, -180, 0,
Space.Self);
_animator.GetBoneTransform(HumanBodyBones.RightUpperArm).rotation = _bonds[15].Rotation;
_animator.GetBoneTransform(HumanBodyBones.RightUpperArm).Rotate(0, -180, 0,
Space.Self);
_animator.GetBoneTransform(HumanBodyBones.RightLowerArm).rotation = _bonds[16].Rotation;
_animator.GetBoneTransform(HumanBodyBones.RightLowerArm).Rotate(0, -180, 0,
Space.Self);
_animator.GetBoneTransform(HumanBodyBones.LeftUpperLeg).rotation = _bonds[22].Rotation;
_animator.GetBoneTransform(HumanBodyBones.LeftUpperLeg).Rotate(0, -180, 0,
Space.Self);
_animator.GetBoneTransform(HumanBodyBones.LeftLowerLeg).rotation = _bonds[23].Rotation;
_animator.GetBoneTransform(HumanBodyBones.LeftLowerLeg).Rotate(0, -180, 0,
Space.Self);
_animator.GetBoneTransform(HumanBodyBones.RightUpperLeg).rotation = _bonds[28].Rotation;
_animator.GetBoneTransform(HumanBodyBones.RightUpperLeg).Rotate(0, -180, 0,
Space.Self);
_animator.GetBoneTransform(HumanBodyBones.RightLowerLeg).rotation = _bonds[29].Rotation;
_animator.GetBoneTransform(HumanBodyBones.RightLowerLeg).Rotate(0, -180, 0,
Space.Self);
_isReceived = false;
}
}
private void OnDisable()
{
_listener.DisConnect();
}
private void OnReceive(List<PoseLandmark> landmarks)
{
// 计算腰部
var frontLeft = Vector3.Cross(
landmarks[PoseLandmarkType.RightHip].Position - landmarks[PoseLandmarkType.LeftHip].Position,
landmarks[PoseLandmarkType.RightShoulder].Position - landmarks[PoseLandmarkType.LeftHip].Position);
var frontRight = Vector3.Cross(
landmarks[PoseLandmarkType.LeftShoulder].Position - landmarks[PoseLandmarkType.RightHip].Position,
landmarks[PoseLandmarkType.LeftHip].Position - landmarks[PoseLandmarkType.LeftHip].Position);
var front = frontLeft + frontRight;
front.Normalize();
var oldRotation = _rotationNodes[HumanBodyBones.Hips];
_rotationNodes[HumanBodyBones.Hips] = new RotationNode(
oldRotation.UnityName,
oldRotation.Rotation,
Quaternion.LookRotation(front));
_landmarks = landmarks;
_isReceived = true;
}
private void CreateRotationNodes()
{
_rotationNodes = new Dictionary<HumanBodyBones, RotationNode>();
var bonesArray = new[]
{
HumanBodyBones.Hips,
HumanBodyBones.LeftUpperArm,
HumanBodyBones.LeftLowerArm,
HumanBodyBones.RightUpperArm,
HumanBodyBones.RightLowerArm,
HumanBodyBones.LeftUpperLeg,
HumanBodyBones.LeftLowerLeg,
HumanBodyBones.RightUpperLeg,
HumanBodyBones.RightLowerLeg
};
foreach (var bone in bonesArray)
{
var rotation = _animator.GetBoneTransform(bone).rotation;
_rotationNodes.Add(bone, new RotationNode(bone, rotation, rotation));
}
}
private void CreateNodes()
{
for (var i = 0; i < PoseLandmarkType.MaxValue; i++)
{
var ball = GameObject.CreatePrimitive(PrimitiveType.Sphere);
ball.transform.localScale = new Vector3(Scale, Scale, Scale);
if (i <= 10)
{
ball.GetComponent<Renderer>().material.color = Color.red; //给头部添加颜色
}
else if (i <= 22)
{
ball.GetComponent<Renderer>().material.color = Color.blue; //给手部添加颜色
}
else if (i <= 32)
{
ball.GetComponent<Renderer>().material.color = Color.green; //给脚部添加颜色
}
_nodes[i] = ball;
}
}
private void CreateBonds()
{
var headBonds = new[]
{
PoseLandmarkType.RightEar,
PoseLandmarkType.RightEyeOuter,
PoseLandmarkType.RightEye,
PoseLandmarkType.RightEyeInner,
PoseLandmarkType.Nose,
PoseLandmarkType.LeftEyeInner,
PoseLandmarkType.LeftEye,
PoseLandmarkType.LeftEyeOuter,
PoseLandmarkType.LeftEar
};
_bonds.AddRange(GenerateBondsList(headBonds));
var monthBonds = new[]
{
PoseLandmarkType.MouthLeft,
PoseLandmarkType.MouthRight,
};
_bonds.AddRange(GenerateBondsList(monthBonds));
var leftArmBonds = new[]
{
PoseLandmarkType.LeftShoulder,
PoseLandmarkType.LeftElbow,
PoseLandmarkType.LeftWrist,
PoseLandmarkType.LeftPinky,
PoseLandmarkType.LeftIndex,
PoseLandmarkType.LeftWrist,
PoseLandmarkType.LeftThumb
};
_bonds.AddRange(GenerateBondsList(leftArmBonds));
var rightArmBonds = new[]
{
PoseLandmarkType.RightShoulder,
PoseLandmarkType.RightElbow,
PoseLandmarkType.RightWrist,
PoseLandmarkType.RightPinky,
PoseLandmarkType.RightIndex,
PoseLandmarkType.RightWrist,
PoseLandmarkType.RightThumb
};
_bonds.AddRange(GenerateBondsList(rightArmBonds));
var leftLegBonds = new[]
{
PoseLandmarkType.LeftShoulder,
PoseLandmarkType.LeftHip,
PoseLandmarkType.LeftKnee,
PoseLandmarkType.LeftAnkle,
PoseLandmarkType.LeftHeel,
PoseLandmarkType.LeftFootIndex,
PoseLandmarkType.LeftAnkle
};
_bonds.AddRange(GenerateBondsList(leftLegBonds));
var rightLegBonds = new[]
{
PoseLandmarkType.RightShoulder,
PoseLandmarkType.RightHip,
PoseLandmarkType.RightKnee,
PoseLandmarkType.RightAnkle,
PoseLandmarkType.RightHeel,
PoseLandmarkType.RightFootIndex,
PoseLandmarkType.RightAnkle
};
_bonds.AddRange(GenerateBondsList(rightLegBonds));
// 最后手动添加身体上的两条横线
_bonds.Add(new Bond(
_nodes[PoseLandmarkType.LeftShoulder],
_nodes[PoseLandmarkType.RightShoulder],
Scale));
_bonds.Add(new Bond(
_nodes[PoseLandmarkType.LeftHip],
_nodes[PoseLandmarkType.RightHip],
Scale));
}
/// <summary>
/// 创建棍子列表
/// </summary>
/// <param name="nodes">需要连接起来的关键点 需要按顺序设置</param>
/// <returns></returns>
private List<Bond> GenerateBondsList(int[] nodes)
{
var bonds = new List<Bond>();
for (var i = 0; i < nodes.Length - 1; i++)
{
bonds.Add(new Bond(
_nodes[nodes[i]],
_nodes[nodes[i + 1]],
Scale));
}
return bonds;
}
}
}