5评论

动作捕捉(MoCap)

ArtStealer 2019-01-06 2.3k浏览

说到 动作捕捉 (Motion capture)技术,很多人都会立刻联想到好莱坞的特效大片和XBox的体感游戏。


影视方面对动作捕捉技术的应用已经炉火纯青。


游戏方面尤其是一些体育类游戏在这方面的应用也很非常的广泛和接地气。在家庭娱乐方面相信很多人都接触到了体感游戏。微软的Kinect也为开发人员提供了完善的开发环境。可以很方便的进行体感游戏内容开发。


这个视频里面的小朋友以其风骚的舞步吸引了我(小伙子有很高的舞蹈天赋

好了,言归正传,本文分享的动作捕捉是在Unity中结合OpenPose的数据来开发的。

OpenPose是一个能识别图像中人体动作骨骼的开源人工智能框架。其对大量的人体图像进行训练学习,对人体是识别准确度很高。

官网地址http://openpose.org/

github: https://github.com/CMU-Perceptual-Computing-Lab/openpose


本文就是通过其3D重建部分 输出的数据导入到Unity中进行模型的动作驱动。

OpenPose输出的骨骼点原始数据:

此处不考虑头部数据,故忽略掉 14、15、16、17这4个点。

另外由8、9两个点产生一个新的节点作为动画模型的Hip骨骼节点,并将其定义为0,其他点依次顺延1。

这样Unity中HumanBodyBones枚举对的OpenPose点索引关系如下所示:

        { HumanBodyBones.Hips, 0},

        { HumanBodyBones.Head, 1},

        { HumanBodyBones.Chest, 2},

        { HumanBodyBones.RightUpperArm, 3},

        { HumanBodyBones.RightLowerArm, 4},

        { HumanBodyBones.RightHand, 5},

        { HumanBodyBones.LeftUpperArm, 6},

        { HumanBodyBones.LeftLowerArm, 7},

        { HumanBodyBones.LeftHand, 8},

        { HumanBodyBones.RightUpperLeg, 9},

        { HumanBodyBones.RightLowerLeg, 10},

        { HumanBodyBones.RightFoot, 11},

        { HumanBodyBones.LeftUpperLeg, 12},

        { HumanBodyBones.LeftLowerLeg, 13},

        { HumanBodyBones.LeftFoot, 14},


剩下的就是将OpenPose输出的节点的三维数据转换成世界坐标的旋转信息,并将其赋值到对应的骨骼上了:
void Deformation(PoseFrame frame, float t)
    {
        // update position
        Vector3 offset = GetHipPosition(frame) - initialFramePosition;
        transform.position += offset * Time.deltaTime;
        // update rotatoin
        Quaternion orientation = AvatarComputeOrientation(frame);
        transform.rotation = Quaternion.Lerp(transform.rotation, orientation, t);
        // update pose
        for (int i = 0; i < frame.positions.Count; i++)
        {
            HumanBodyBones hbb = index2MecanimMap[i];
            HumanBodyBones hbbp = mapBoneParent[hbb];
            Vector3 pos = (Vector3)frame.positions[i];
            Vector3 posParent = (Vector3)frame.positions[mecanim2IndexMap[hbbp]];
            Vector3 dir = pos - posParent;
            if (dir == Vector3.zero)
            {
                dir = Vector3.up;
            }
            Transform boneParent = null;
            Quaternion vFixRotation = Quaternion.identity;
            if (HumanBodyBones.Chest == hbb)
            {
                Transform bone = animatorComponent.GetBoneTransform(hbb);
                boneParent = animatorComponent.GetBoneTransform(HumanBodyBones.Hips);
                Vector3 dirOrig = (bone.position - boneParent.position);
                vFixRotation = Quaternion.FromToRotation(dirOrig, dir);
            }
            else
            {
                if (mapBoneValid[hbbp])
                {
                    Transform bone = animatorComponent.GetBoneTransform(hbb);
                    boneParent = bone.transform.parent;
                    Vector3 dirOrig = (bone.position - bone.transform.parent.position);
                    vFixRotation = Quaternion.FromToRotation(dirOrig, dir);
                }
            }
            if (boneParent)
            {
                Quaternion aimrot = vFixRotation * boneParent.rotation;
                Quaternion rotation = Quaternion.Lerp(boneParent.rotation, aimrot, t);
                boneParent.rotation = rotation;
            }
        }
    }

好了,看看实际效果:


初始状态:

目标状态:

过程动图:


好了,本文到处结束。欢迎关注公众号(ArtStealer)进行技术探讨。