C++11 将动画关键点轨迹导入Maya 我有一个人类双足动画文件格式,我想用C++ API编程到玛雅中。

C++11 将动画关键点轨迹导入Maya 我有一个人类双足动画文件格式,我想用C++ API编程到玛雅中。,c++11,animation,maya-api,C++11,Animation,Maya Api,动画文件格式与的类似 对于每个关节,都有一系列多达60个三维矢量关键点(用于描述关节的平移)和60个四元数关键点(用于描述关节的旋转)。每个关节都保证有相同数量的键(或根本没有键) 可以指定或更改动画的长度(以秒为单位的时间)(例如,对于每秒30帧的动画,可以将60个关键点设置为在2秒内发生) 关节的平移和旋转在每一帧沿骨架树向下传播,生成动画 这是一个样品。有关数据结构的附加说明由日志记录工具添加。为了简洁起见,我把键截断了 Bone Bip01 Parent null 60

动画文件格式与的类似

对于每个关节,都有一系列多达60个三维矢量关键点(用于描述关节的平移)和60个四元数关键点(用于描述关节的旋转)。每个关节都保证有相同数量的键(或根本没有键)

可以指定或更改动画的长度(以秒为单位的时间)(例如,对于每秒30帧的动画,可以将60个关键点设置为在2秒内发生)

关节的平移和旋转在每一帧沿骨架树向下传播,生成动画

这是一个样品。有关数据结构的附加说明由日志记录工具添加。为了简洁起见,我把键截断了

Bone Bip01
    Parent null
    60 Position Keys
    0 0.000000 4.903561 99.240829 -0.000000
    1 0.033333 4.541568 99.346550 -2.809127
    2 0.066667 4.182590 99.490318 -5.616183
    ... (truncated)
    57 1.366667 5.049816 99.042770 -116.122604
    58 1.400000 4.902135 99.241692 -118.754120
    59 1.400000 4.902135 99.241692 -118.754120

    60 Rotation Keys
    0 0.000000 -0.045869 0.777062 0.063631 0.624470
    1 0.033333 -0.043855 0.775018 0.061495 0.627400
    2 0.066667 -0.038545 0.769311 0.055818 0.635212
    ... (truncated)
    57 1.366667 -0.048372 0.777612 0.065493 0.623402
    58 1.400000 -0.045869 0.777062 0.063631 0.624470
    59 1.400000 -0.045869 0.777062 0.063631 0.624470

Bone Bip01_Spine
    Parent Bip01
    60 Position Keys
    ...
    60 Rotation Keys
    ...
在C++中,我现在的数据结构对应于:

std::无序映射平移KeyTrack
用于将一组平移向量映射到相应的骨骼

std::无序映射旋转KeyTrack
用于将一组旋转四元数映射到相应的骨骼

附加说明:有些骨骼不相对于其父骨骼移动;这些骨骼根本没有关键点(但有一个包含0个关键点的条目)。 还有一些骨骼只有旋转或位置关键点。 骨架数据存储在一个单独的文件中,我已经可以使用MFnIkJoint将其读入Maya

动画文件中指定的骨骼与该骨骼数据中的骨骼比例为1:1

现在,我想将此动画数据导入Maya。不过,我不明白

特别是,MFnAnimCurve函数集
addKeyFrame
addKey
只接受绑定到时间键的单个浮点值,而我有一个向量和四元数列表。MFnAnimCurve也接受“切线”;阅读文档后,我仍然不确定如何将我拥有的数据转换为这些切线

我的问题是:如何将我拥有的数据转换为Maya能够理解的内容


我更了解示例,因此一些示例代码将很有帮助。

因此,经过几天的反复试验,并检查了互联网上的一些代码片段,我终于想出了一些可行的方法

鉴于上述
TranslationKeyTrack
RotationKeyTrack

遍历骨架。对于每个接头

  • 设置骨架的初始位置和方向。这是必需的,因为有些关节不相对于其父关节移动;如果未设置初始位置和方向,则整个骨架可能会不稳定地移动
  • 设置动画曲线关键点
  • 迭代如下所示:

    MStatus status;
    MItDag dagIter(MItDag::kDepthFirst, MFn::kJoint, &status);
        for (; !dagIter.isDone(); dagIter.next()) {
            MDagPath dagPath;
            status = dagIter.getPath(dagPath);
            MFnIkJoint joint(dagPath);
            string name_key = joint.name().asChar();
    
            // Set initial position, and the translation AnimCurve keys.
            if (TranslationKeyTrack.find(name_key) != TranslationKeyTrack.end()) {
                auto pos = TranslationKeyTrack[name_key][0];
                joint.setTranslation(MVector(pos.x, pos.y, pos.z), MSpace::kTransform);
                setPositionAnimKeys(dagPath.node(), positionTracks[name_key]);
            }
    
            // Set initial orientation, and the rotation AnimCurve keys.
            if (RotationKeyTrack.find(name_key) != RotationKeyTrack.end()) {
                auto rot = rotationTracks[name_key][0];
                joint.setOrientation(rot.x, rot.y, rot.z, rot.w);
                setRotationAnimKeys(dagPath.node(), RotationKeyTrack[name_key]);
            }
    }
    
    为简洁起见,我将省略显示
    setPositionAnimKeys
    ,而仅显示
    setRotationAnimKeys
    。然而,两者的想法是相同的。请注意,我使用了
    kAnimCurveTL
    进行翻译跟踪

    void MayaImporter::setRotationAnimKeys(MObject joint, const vector<Quaternion>& rotationTrack) {
        if (rotationTrack.size() < 2) return; // Check for empty tracks.
    
        MFnAnimCurve rotX, rotY, rotZ;
        setAnimCurve(joint, "rotateX", rotX, MFnAnimCurve::kAnimCurveTA);
        setAnimCurve(joint, "rotateY", rotY, MFnAnimCurve::kAnimCurveTA);
        setAnimCurve(joint, "rotateZ", rotZ, MFnAnimCurve::kAnimCurveTA);
    
        MFnIkJoint j(joint);
        string name = j.name().asChar();
    
        for (int i = 0; i < rotationTrack.size(); i++) {
            auto rot = rotationTrack[i];
            MQuaternion rotation(rot.x, rot.y, rot.z, rot.w);
    
            // Depending on your input, you may have to do additional processing
            // to get the correct Euler rotation here.
            auto euler = rotation.asEulerRotation();
            MTime time(FPS*i, MTime::kSeconds); // FPS is a number defined elsewhere.
    
            rotX.addKeyframe(time, euler.x);
            rotY.addKeyframe(time, euler.y);
            rotZ.addKeyframe(time, euler.z);
        }
    }
    
    void MayaImporter::setAnimCurve(const MObject& joint, const MString attr, MFnAnimCurve& curve, MFnAnimCurve::AnimCurveType type) {
        MStatus status;
        MPlug plug = MFnDependencyNode(joint).findPlug(attr, false, &status);
    
        if (!plug.isKeyable())
            plug.setKeyable(true);
    
        if (plug.isLocked())
            plug.setLocked(false);
    
        if (!plug.isConnected()) {
            curve.create(joint, plug, type, nullptr, &status);
            if (status != MStatus::kSuccess)
                cout << "Creating anim curve at joint failed!" << endl;
        } else {
            MFnAnimCurve animCurve(plug, &status);
            if (status == MStatus::kNotImplemented)
                cout << "Joint " << animCurve.name() << " has more than one anim curve." << endl;
            else if (status != MStatus::kSuccess)
                cout << "No anim curves found at joint " << animCurve.name() << endl;
            curve.setObject(animCurve.object(&status));
        }
    }