【问题标题】:Importing animation keytracks into Maya将动画关键轨迹导入 Maya
【发布时间】:2016-04-30 07:42:09
【问题描述】:

我有一个人类双足动画文件格式,我想使用 C++ API 以编程方式将其读入 Maya。

动画文件格式与Open Asset Importer's per-node animation structure类似。

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

可以指定或更改动画的长度(时间以秒为单位)(例如,对于 30 FPS 动画,您可以将 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::unordered_map<string, std::vector<Vector3>> TranslationKeyTrack用于将一组平移向量映射到对应的骨骼。

std::unordered_map<string, std::vector<Quaternion>> RotationKeyTrack 用于将一组旋转四元数映射到相应的骨骼。

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

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

现在我想将此动画数据导入 Maya。但是,我不明白Maya's way of accepting animation data through its C++ API

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

我的问题是:如何将我拥有的数据转换为 Maya 可以理解的数据?

我通过示例更好地理解,所以一些示例代码会有所帮助。

【问题讨论】:

    标签: c++11 animation maya-api


    【解决方案1】:

    因此,经过几天的反复试验和检查互联网上的几段代码后,我设法想出了一些可行的方法。

    鉴于上述TranslationKeyTrackRotationKeyTrack

    遍历骨架。对于每个关节,

    1. 设置骨架的初始位置和方向。这是必需的,因为有些关节相对于其父关节不会移动;如果没有设置初始位置和方向,整个骨架可能会不规律地移动。
    2. 设置 AnimCurve 键。

    迭代看起来像这样:

    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);
        }
    }
    

    最后是我用于setAnimCurve 的代码。它实质上将 AnimCurve 附加到关节。 This bit of code is adapted from a mocap file importer here.万岁开源!

    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));
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-10
      相关资源
      最近更新 更多