2016-04-30 2 views
1

У меня есть формат файла бипал-анимации человека, который я бы хотел программно прочитать в Maya с использованием C++ API.Импорт анимационных анимационных клипов в Maya

Формат файла анимации аналогичен формату Open Asset Importer's per-node animation structure.

Для каждого сустава существует серия до 60 трехмерных векторных клавиш (для описания перевода сустава) и 60 кватернионных клавиш (для описания вращения сустава). Гарантируется, что каждое соединение имеет одинаковое количество ключей (или вообще никаких ключей).

Длина (время в секундах) анимации может быть указана или изменена (чтобы вы могли установить 60 ключей, которые будут выполняться в течение 2 секунд для анимации 30 FPS, например).

Переводы и вращения суставов распространяются по дереву скелета в каждом кадре, создавая анимацию.

Вот образец. Дополнительные замечания о структуре данных добавляются средством ведения журнала. Я сократил ключи для краткости.

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 ключами). Есть также некоторые кости, которые имеют только поворот или только клавиши положения. Данные скелета хранятся в отдельном файле, который я уже могу прочитать в Maya с использованием MFnIkJoint.

Кости, указанные в файле анимации, равны 1: 1 костям в данных скелета.

Теперь я хотел бы импортировать эти данные анимации в Maya. Однако я не понимаю Maya's way of accepting animation data through its C++ API.

В частности, функция MFnAnimCurve, установленная addKeyFrame или addKey, принимает только одно значение с плавающей запятой, привязанное к ключевому слову, тогда как у меня есть список векторов и кватернионов. MFnAnimCurve также принимает «касательные»; после прочтения документации, я все еще не уверен, как преобразовать данные, которые у меня есть, в эти касательные.

Мой вопрос: Как мне преобразовать данные, которые у меня есть во что-то, что понимает Майя?

Я лучше понимаю примеры, поэтому некоторые примеры кода будут полезны.

ответ

1

Итак, после нескольких дней проб и ошибок и изучения нескольких фрагментов кода в Интернете мне удалось придумать что-то, что работает.

Учитывая вышеупомянутую TranslationKeyTrack и RotationKeyTrack,

перебирать скелета.Для каждого соединения

  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. Hooray с открытым исходным кодом!

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)); 
    } 
} 
Смежные вопросы