Final IK详细实现二——控制核心和头部

为了实现控制躯干和头部朝向的功能,我们需要扩展之前的方案,将MediaPipe的关键点数据映射到角色的躯干和头部骨骼上。以下是具体实现步骤:


1. 扩展MediaPipe关键点数据

MediaPipe的姿势检测模型提供了33个关键点,其中:

  • 躯干:使用髋部(索引23、24)和肩膀(索引11、12)关键点。
  • 头部:使用鼻子(索引0)、左眼(索引2)、右眼(索引5)和耳朵(索引7、8)关键点。

2. Unity中扩展角色骨骼控制

在Unity中,我们需要为躯干和头部添加额外的控制逻辑:

  • 躯干控制:通过髋部和肩膀关键点计算躯干的旋转。
  • 头部控制:通过鼻子和眼睛关键点计算头部的旋转。

3. 实现躯干和头部控制

3.1 躯干控制

躯干的旋转可以通过髋部和肩膀关键点计算。以下是实现步骤:

  1. 计算躯干方向

    • 使用髋部中点(左右髋部的平均值)和肩膀中点(左右肩膀的平均值)计算躯干的朝向。
    • 通过向量叉积计算躯干的旋转。
  2. 更新躯干骨骼
    • 将计算出的旋转应用到角色的躯干骨骼上。

3.2 头部控制

头部的旋转可以通过鼻子和眼睛关键点计算。以下是实现步骤:

  1. 计算头部方向

    • 使用鼻子关键点和眼睛中点(左右眼睛的平均值)计算头部的朝向。
    • 通过向量叉积计算头部的旋转。
  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 场景配置

  1. 角色骨骼

    • 确保角色模型有spine(躯干)和head(头部)骨骼。
    • spinehead骨骼拖拽到IKController脚本的对应字段中。
  2. Final IK配置
    • 确保四肢的LimbIK组件和对应的目标物体已正确设置。

5. 优化与注意事项

  • 坐标系对齐:确保MediaPipe的坐标与Unity的坐标对齐(如Y轴反转)。
  • 平滑处理:添加滤波(如指数平滑)减少抖动:
    Quaternion smoothedRotation = Quaternion.Slerp(currentRotation, targetRotation, smoothFactor);
  • 根骨骼移动:如果需要角色整体移动,可以使用髋部中点作为根骨骼的位置:
    Vector3 hipCenter = (leftHip + rightHip) / 2;
    transform.position = hipCenter;
  • 性能优化:确保Python和Unity的帧率匹配,避免数据堆积。

通过以上步骤,你可以实现躯干和头部朝向的控制,从而获得更完整的动作捕捉效果。根据实际需求调整关键点映射和旋转计算,可以获得更自然的效果。

此条目发表在Final IK应用分类目录。将固定链接加入收藏夹。