Чтение и отображение анимации из файла *.FBX

Я хочу прочитать 3d модель из fbx файл и отобразить его в openGL es 2.0 двигатель на iPhone (не используется Unity), а также я хочу отображать анимацию для чтения 3D-объекта.

Как я могу получить анимацию от fbx файл?

В настоящее время я могу получить список названий поз с, как я понял, идущим с матрицей преобразования, полным списком поз в слое, стеках, слоях и множестве кривых.

Как эта вся информация может быть объединена для отображения правильной анимации?

Я также пытаюсь разобрать некоторую информацию в TakeInfo, но результат немного странный, как для меня, например:

    FbxTakeInfo *ltakeInfo  =  pScene->GetTakeInfo(lAnimStack->GetName());
    FbxTime start = ltakeInfo->mLocalTimeSpan.GetStart();
    FbxTime end = ltakeInfo->mLocalTimeSpan.GetStop();

    self.startTime = start.GetSecondDouble();
    self.endTime = end.GetSecondDouble();

здесь я получил start = 0 а также end = 0.014 для каждого из проанализированных слоев, так что я думаю, это неправильно (fbx файл, который я хочу отобразить, содержит 1 меш с простой анимацией продолжительностью 5 секунд).


Обновить

После нескольких часов расследования я получил следующие вещи:

Для справки это структура объекта теста, который я хочу отобразить:

Здесь вы можете увидеть множество костей (более конкретно - 19). Мне удалось получить (как отмечено выше) 19 анимированных объектов в списке (например, имена костей / объектов) и 19 групп кривых в пределах 151 кадра каждая (с частотой кадров). 30 ровно 5 сек анимации - 30*5=150 + 1 последняя единичная матрица).

Если я пытаюсь использовать каждую группу кривых для своей сетки по одной (я могу анализировать только 1 сетку), я вижу анимацию различной части сетки, примененной ко всей сетке (например, вертикальное вращение или горизонтальное перемещение), поэтому я думаю, что это Кривые в каждой группе должны применяться точно к конкретной кости, и в результате я получу анимацию для моей сетки. Проблема в том, что я не знаю, как анимировать только выбранную часть костной вершины.

Теперь проблема заключается в том, как применить все анимации, разделенные на отдельные группы, относящиеся к кости, ко всему объекту (потому что у меня только одна сетка)?

Как я могу получить 1 глобальный список кривой для каждого кадра из списка со всеми группами кривой?


Update2

Благодаря совету @codetiger, я следую инструкциям в предоставленной ссылке в комментарии, и с помощью этой техники я могу получить список матов, специфичных для костей, с начальным и конечным временем и необходимыми преобразованиями, но это почти то же самое, что я получал раньше с кривыми - единственное отличие в том, что с помощью кривых я должен создать мат из 9 кривых (перевести / масштабировать / повернуть для x y z) вместо использования полной матрицы, но проблема все еще остается - как я могу объединить их в 1 глобальную матрицу?

Код, который я использую (нашел несколько ссылок на него):

FbxNode* modelNode = _fbxScene->GetRootNode();
FbxAMatrix geometryTransform = GetGeometryTransformation(modelNode);
for (unsigned int deformerIndex = 0; deformerIndex < numOfDeformers; ++deformerIndex) {
    FbxSkin* currSkin = reinterpret_cast<FbxSkin*>(mesh->GetDeformer(deformerIndex, FbxDeformer::eSkin));
    if (!currSkin) {
        continue;
    }
    unsigned int numOfClusters = currSkin->GetClusterCount();
    for (unsigned int clusterIndex = 0; clusterIndex < numOfClusters; ++clusterIndex) {
        FbxCluster* currCluster = currSkin->GetCluster(clusterIndex);
        std::string currJointName = currCluster->GetLink()->GetName();

        FbxAMatrix transformMatrix;
        FbxAMatrix transformLinkMatrix;
        FbxAMatrix globalBindposeInverseMatrix;

        currCluster->GetTransformMatrix(transformMatrix);   
        currCluster->GetTransformLinkMatrix(transformLinkMatrix);   
        globalBindposeInverseMatrix = transformLinkMatrix.Inverse() * transformMatrix * geometryTransform;

        FbxAnimStack* currAnimStack = _fbxScene->GetSrcObject<FbxAnimStack>(0);
        FbxString animStackName = currAnimStack->GetName();
        char *mAnimationName = animStackName.Buffer();
        FbxTakeInfo* takeInfo = _fbxScene->GetTakeInfo(animStackName);
        FbxTime start = takeInfo->mLocalTimeSpan.GetStart();
        FbxTime end = takeInfo->mLocalTimeSpan.GetStop();
        FbxLongLong mAnimationLength = end.GetFrameCount(FbxTime::eFrames24) - start.GetFrameCount(FbxTime::eFrames24) + 1;

        for (FbxLongLong i = start.GetFrameCount(FbxTime::eFrames24); i <= end.GetFrameCount(FbxTime::eFrames24); ++i) {
            FbxTime currTime;
            currTime.SetFrame(i, FbxTime::eFrames24);

            FbxAMatrix currentTransformOffset = modelNode->EvaluateGlobalTransform(currTime) * geometryTransform;
            FbxAMatrix mat = currentTransformOffset.Inverse() * currCluster->GetLink()->EvaluateGlobalTransform(currTime);

        }
    }
}

Здесь я получаю 121 матрицу вместо 151 - но длительность некоторых матричных преобразований занимает больше, чем длительность рисования 1 кадра, поэтому q-ty здесь я думаю также правильным

float duration = end.GetSecondDouble() - start.GetSecondDouble(); //return 5 as and expected

Я думаю, что это Autodesk SDK есть способ получить 1 глобальное преобразование за каждый розыгрыш

Какие-либо предложения? Это возможно?


Добавьте награду для всех, кто может описать, как отображать анимацию на iPhone в openGLES 2.0 с помощью Autodesk SDK... (извините за опечатку вместо Facebook)


Вот что я могу получить

Оригинальный объект в blender

Если я рисую кость отдельно (тот же VBO с разным преобразованием и только индексы для каждой кости соответственно)

1 ответ

Вот как визуализировать анимированную сетку в OpenGL ES. Это даст вам информацию о плате за проезд и о том, какие данные вам нужно прочитать из файла.

Метод 1: (Скинг на GPU)

Этот метод работает только на ограниченном количестве костей в зависимости от возможностей оборудования. Обычно это зависит от количества матриц, которые вы можете отправить в шейдер.

Привязать информацию о сетке к графическому процессору, используя BindAttributes, один раз и отправить матрицы шейдеру в униформе.

Шаг 1: Считайте всю матрицу костей, создайте массив матриц и отправьте эти данные в шейдер в униформе.

Шаг 2: В вершинном шейдере вычислите gl_position, как показано ниже

attribute vec3 vertPosition;
attribute vec3 vertNormal;
attribute vec2 texCoord1;
attribute vec3 vertTangent;
attribute vec3 vertBitangent;
attribute vec4 optionalData1;
attribute vec4 optionalData2;

uniform mat4 mvp, jointTransforms[jointsSize];

void main()
{
    mat4 finalMatrix;

    int jointId = int(optionalData1.x);
    if(jointId > 0)
        finalMatrix = jointTransforms[jointId - 1] * optionalData2.x;

    jointId = int(optionalData1.y);
    if(jointId > 0)
        finalMatrix = finalMatrix + (jointTransforms[jointId - 1] * optionalData2.y);

    jointId = int( optionalData1.z);
    if(jointId > 0)
        finalMatrix = finalMatrix + (jointTransforms[jointId - 1] * optionalData2.z);

    jointId = int( optionalData1.w);
    if(jointId > 0)
        finalMatrix = finalMatrix + (jointTransforms[jointId - 1] * optionalData2.w);

    gl_Position = mvp * finalMatrix * vec4(vertPosition, 1.0);
}

В этом шейдере я отправляю информацию о массе краски в атрибутах AdditionalData1 и OptionData2. Данные упакованы следующим образом: (BoneId1, BoneId2, BoneId3, BoneId4) и (Weight4Bone1, Weight4Bone2, Weight4Bone3, Weight4Bone4). Так что в этом случае вы ограничены максимум четырьмя костями, влияющими на каждый атрибут. Часть фрагмента шейдера обычная.

Способ 2: (Скинг процессора)

Если вы не можете жить с ограничением скинов графического процессора, то единственный способ - это выполнить вычисления на стороне процессора.

Шаг 1: Рассчитайте положение вершины в текущем кадре, умножив матрицы, которые принадлежат костям, которые влияют на вершину.

Шаг 2: Соберите новые позиции для текущего кадра и отправьте информацию в GPU в Атрибутах Вершины.

Шаг 3: пересчитать новые позиции вершин в каждом кадре и обновить буфер атрибутов.

Этот метод переносит нагрузку на вычисления в CPU.

Другие вопросы по тегам