为了实现控制躯干和头部朝向的功能,我们需要扩展之前的方案,将MediaPipe的关键点数据映射到角色的躯干和头部骨骼上。以下是具体实现步骤:
1. 扩展MediaPipe关键点数据
MediaPipe的姿势检测模型提供了33个关键点,其中:
- 躯干:使用髋部(索引23、24)和肩膀(索引11、12)关键点。
- 头部:使用鼻子(索引0)、左眼(索引2)、右眼(索引5)和耳朵(索引7、8)关键点。
2. Unity中扩展角色骨骼控制
在Unity中,我们需要为躯干和头部添加额外的控制逻辑:
- 躯干控制:通过髋部和肩膀关键点计算躯干的旋转。
- 头部控制:通过鼻子和眼睛关键点计算头部的旋转。
3. 实现躯干和头部控制
3.1 躯干控制
躯干的旋转可以通过髋部和肩膀关键点计算。以下是实现步骤:
-
计算躯干方向:
- 使用髋部中点(左右髋部的平均值)和肩膀中点(左右肩膀的平均值)计算躯干的朝向。
- 通过向量叉积计算躯干的旋转。
- 更新躯干骨骼:
- 将计算出的旋转应用到角色的躯干骨骼上。
3.2 头部控制
头部的旋转可以通过鼻子和眼睛关键点计算。以下是实现步骤:
-
计算头部方向:
- 使用鼻子关键点和眼睛中点(左右眼睛的平均值)计算头部的朝向。
- 通过向量叉积计算头部的旋转。
- 更新头部骨骼:
- 将计算出的旋转应用到角色的头部骨骼上。
4. 代码实现
4.1 扩展IKController.cs
在IKController.cs中添加躯干和头部控制逻辑:
using UnityEngine;
using RootMotion.FinalIK;
public class IKController : MonoBehaviour
{
public UDPReceiver udpReceiver;
// Final IK组件
public LimbIK leftArmIK;
public LimbIK rightArmIK;
public LimbIK leftLegIK;
public LimbIK rightLegIK;
// IK目标物体
public Transform leftHandTarget;
public Transform rightHandTarget;
public Transform leftFootTarget;
public Transform rightFootTarget;
// 躯干和头部骨骼
public Transform spine; // 躯干骨骼
public Transform head; // 头部骨骼
void Update()
{
if (udpReceiver.receivedLandmarks == null) return;
// 更新四肢IK目标
UpdateLimbs();
// 更新躯干和头部
UpdateTorso();
UpdateHead();
}
void UpdateLimbs()
{
// 左手腕(MediaPipe索引15)
leftHandTarget.position = udpReceiver.receivedLandmarks[15];
// 右手腕(索引16)
rightHandTarget.position = udpReceiver.receivedLandmarks[16];
// 左脚踝(索引27)
leftFootTarget.position = udpReceiver.receivedLandmarks[27];
// 右脚踝(索引28)
rightFootTarget.position = udpReceiver.receivedLandmarks[28];
// 更新IK计算
leftArmIK.solver.Update();
rightArmIK.solver.Update();
leftLegIK.solver.Update();
rightLegIK.solver.Update();
}
void UpdateTorso()
{
// 获取髋部中点(索引23和24)
Vector3 leftHip = udpReceiver.receivedLandmarks[23];
Vector3 rightHip = udpReceiver.receivedLandmarks[24];
Vector3 hipCenter = (leftHip + rightHip) / 2;
// 获取肩膀中点(索引11和12)
Vector3 leftShoulder = udpReceiver.receivedLandmarks[11];
Vector3 rightShoulder = udpReceiver.receivedLandmarks[12];
Vector3 shoulderCenter = (leftShoulder + rightShoulder) / 2;
// 计算躯干方向
Vector3 torsoDirection = (shoulderCenter - hipCenter).normalized;
Quaternion targetRotation = Quaternion.LookRotation(torsoDirection, Vector3.up);
// 应用旋转到躯干骨骼
spine.rotation = Quaternion.Slerp(spine.rotation, targetRotation, Time.deltaTime * 10);
}
void UpdateHead()
{
// 获取鼻子(索引0)和眼睛中点(索引2和5)
Vector3 nose = udpReceiver.receivedLandmarks[0];
Vector3 leftEye = udpReceiver.receivedLandmarks[2];
Vector3 rightEye = udpReceiver.receivedLandmarks[5];
Vector3 eyeCenter = (leftEye + rightEye) / 2;
// 计算头部方向
Vector3 headDirection = (nose - eyeCenter).normalized;
Quaternion targetRotation = Quaternion.LookRotation(headDirection, Vector3.up);
// 应用旋转到头部骨骼
head.rotation = Quaternion.Slerp(head.rotation, targetRotation, Time.deltaTime * 10);
}
}
4.2 场景配置
-
角色骨骼:
- 确保角色模型有
spine(躯干)和head(头部)骨骼。 - 将
spine和head骨骼拖拽到IKController脚本的对应字段中。
- 确保角色模型有
- Final IK配置:
- 确保四肢的
LimbIK组件和对应的目标物体已正确设置。
- 确保四肢的
5. 优化与注意事项
- 坐标系对齐:确保MediaPipe的坐标与Unity的坐标对齐(如Y轴反转)。
- 平滑处理:添加滤波(如指数平滑)减少抖动:
Quaternion smoothedRotation = Quaternion.Slerp(currentRotation, targetRotation, smoothFactor); - 根骨骼移动:如果需要角色整体移动,可以使用髋部中点作为根骨骼的位置:
Vector3 hipCenter = (leftHip + rightHip) / 2; transform.position = hipCenter; - 性能优化:确保Python和Unity的帧率匹配,避免数据堆积。
通过以上步骤,你可以实现躯干和头部朝向的控制,从而获得更完整的动作捕捉效果。根据实际需求调整关键点映射和旋转计算,可以获得更自然的效果。