2016-04-30 8 views
1

Ich habe ein zweibeiniges Animationsdateiformat, das ich programmatisch in Maya mit der C++ API einlesen möchte.Importieren von Animations-Keytracks in Maya

Das Animationsdateiformat ist ähnlich dem von Open Asset Importer's per-node animation structure.

Für jedes Gelenk gibt es eine Reihe von bis zu 60 3D-Vektorschlüsseln (um die Translation des Gelenks zu beschreiben) und 60 Quaternion-Tasten (um die Rotation des Gelenks zu beschreiben). Jedes Gelenk hat garantiert die gleiche Anzahl an Schlüsseln (oder gar keine Schlüssel).

Die Länge (Zeit in Sekunden) der Animation kann angegeben oder geändert werden (so dass Sie beispielsweise festlegen können, dass die 60 Tasten bei einer Animation mit 30 FPS über 2 Sekunden hinweg ausgeführt werden).

Die Translationen und Drehungen der Gelenke laufen in jedem Frame den Skelettbaum hinunter und erzeugen die Animation.

Hier ist ein Beispiel. Zusätzliche Bemerkungen über die Datenstruktur werden von der Protokollierungseinrichtung hinzugefügt. Ich habe die Tasten abgeschnitten, um sie kurz zu halten.

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

In C++, die Datenstruktur I entspricht diese Zeit haben:

std::unordered_map<string, std::vector<Vector3>> TranslationKeyTrack verwendet wird, eine Reihe von Translationsvektoren zu dem entsprechenden Knochen zu kartieren.

std::unordered_map<string, std::vector<Quaternion>> RotationKeyTrack wird verwendet, um einen Satz Rotationsquaternionen dem entsprechenden Knochen zuzuordnen.

Zusätzliche Anmerkungen: Es gibt einige Knochen, die sich nicht relativ zum Mutterknochen bewegen; Diese Knochen haben überhaupt keine Schlüssel (aber einen Eintrag mit 0 Schlüsseln). Es gibt auch einige Knochen, die nur Rotation oder nur Positionsschlüssel haben. Die Skelettdaten werden in einer separaten Datei gespeichert, die ich bereits mit MFnIkJoint in Maya einlesen kann.

Die in der Animationsdatei angegebenen Bones sind 1: 1 zu den Bones in diesen Skeleton-Daten.

Jetzt möchte ich diese Animationsdaten in Maya importieren. Allerdings verstehe ich nicht Maya's way of accepting animation data through its C++ API.

Insbesondere die MFnAnimCurve-Funktion gesetzt addKeyFrame oder addKey akzeptiert nur einen einzigen Fließkommawert gebunden an einen Zeitschlüssel, während ich eine Liste von Vektoren und Quaternionen habe. MFnAnimCurve akzeptiert auch "Tangenten"; Nach dem Lesen der Dokumentation bin ich immer noch unsicher, wie ich die Daten, die ich habe, in diese Tangenten umwandeln kann.

Meine Frage ist: Wie konvertiere ich die Daten in etwas, das Maya versteht?

Ich verstehe besser mit Beispielen, so dass einige Beispielcode hilfreich sein wird.

Antwort

1

Also nach ein paar Tagen des Versuch-und-Irrtums und der Untersuchung der wenigen Fragmente von Code im Internet, habe ich es geschafft, etwas zu finden, das funktioniert.

die oben angegebene TranslationKeyTrack und RotationKeyTrack Anbetracht

Iterate durch das Skelett.Für jede Verbindung

  1. Legen Sie die Anfangspositionen und -orientierungen des Skeletts fest. Dies ist erforderlich, da einige Gelenke sich nicht relativ zum übergeordneten Element bewegen. Wenn die Anfangspositionen und Orientierungen nicht festgelegt sind, kann sich das gesamte Skelett unregelmäßig bewegen.
  2. Legen Sie die AnimCurve-Schlüssel fest.

Die Iteration sieht wie folgt aus:

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

Der Kürze halber werde ich auslassen setPositionAnimKeys zeigt, und zeigen nur setRotationAnimKeys nur. Die Ideen für beide sind jedoch gleich. Beachten Sie, dass ich kAnimCurveTL für Übersetzungsspuren verwendet habe.

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

Schließlich ist die Spitze des Codes verwendete ich für setAnimCurve. Es fügt die AnimCurve im Wesentlichen an das Gelenk an. This bit of code is adapted from a mocap file importer here. Hurra Open Source!

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