2016-04-30 10 views
1

C++ APIを使用してプログラムでMayaを読みたい人間の二足歩行アニメーションファイル形式です。Mayaへのアニメーションキートラックのインポート

アニメーションファイルの形式は、Open Asset Importer's per-node animation structureと似ています。

各関節には、最大60個の3Dベクトルキー(関節の平行移動を説明するため)と60個の四元キー(関節の回転を表す)があります。すべてのジョイントは同じ数のキーを持つことが保証されています(または全くキーがありません)。

アニメーションの長さ(秒単位)を指定または変更することができます(たとえば、30 FPSアニメーションで60キーを2秒以上に設定することができます)。

ジョイントの平行移動と回転は、フレームごとにスケルトンツリーを伝播し、アニメーションを生成します。

ここにサンプルがあります。データ構造に関する追加の注釈は、ロギング機能によって追加されます。私は簡潔さのためにキーを切り捨てました。 C++、データ構造に

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 
    ... 

私は現在、これに対応している:

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関数のセットaddKeyFrameまたはaddKeyは、ベクトルとクォータニオンのリストを持っていますが、タイムキーに関連付けられた浮動小数点値を1つだけ受け入れます。 MFnAnimCurveは 'tangents'も受け入れます。ドキュメンテーションを読んだ後も、私が持っているデータをこれらの接線に変換する方法はまだ分かりません。

質問:私が持っているデータをMayaが理解できるように変換するにはどうしたらいいですか?

私はいくつかのサンプルコードが参考になるので、例をよく理解しています。

答えて

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