Попытка загрузить анимацию в OpenGL из файла MD5 с помощью Assimp GLM - PullRequest
0 голосов
/ 10 сентября 2018

Я пытаюсь следовать руководству по здесь (по адресу ogldev) упомянул в этом ответе .

Однако я столкнулся с несколькими проблемами, в которые, как мне кажется,быть связанным с Главным Орденом Строки для Ассимпа и Главного Ордена Столба для GLM, хотя я совершенно не уверен.

Я пробовал несколько вариантов и приказов, чтобы увидеть, работает ли какой-либо из них, но чтобыбезрезультатно.

Здесь (Gist) - это класс, который я использую для загрузки полного файла MD5.И текущий результат, который у меня есть.

И это та часть, где я думаю, что она идет не так, когда я пытаюсь обновить матрицы преобразования кости.

void SkeletalModel::ReadNodeHierarchyAnimation(float _animationTime, const aiNode* _node,
        const glm::mat4& _parentTransform)
    {

        std::string node_name = _node->mName.data;

        const aiAnimation * p_animation = scene->mAnimations[0];

        glm::mat4 node_transformation(1.0f);

        convert_aimatrix_to_glm(node_transformation, _node->mTransformation);
        // Transpose it.
        node_transformation = glm::transpose(node_transformation);

        const aiNodeAnim * node_anim = FindNodeAnim(p_animation, node_name);

        if (node_anim) {

            //glm::mat4 transformation_matrix(1.0f);

            glm::mat4 translation_matrix(1.0f);
            glm::mat4 rotation_matrix(1.0f);
            glm::mat4 scaling_matrix(1.0f);

            aiVector3D translation;
            CalcInterpolatedPosition(translation, _animationTime, node_anim);

            translation_matrix = glm::translate(translation_matrix, glm::vec3(translation.x, translation.y, translation.z));

            aiQuaternion rotation;
            CalcInterpolatedRotation(rotation, _animationTime, node_anim);

            // Transpose the matrix after this.
            convert_aimatrix_to_glm(rotation_matrix, rotation.GetMatrix());
            //rotation_matrix = glm::transpose(rotation_matrix);

            aiVector3D scaling;
            CalcInterpolatedScaling(scaling, _animationTime, node_anim);
            scaling_matrix = glm::scale(scaling_matrix, glm::vec3(scaling.x, scaling.y, scaling.z));

            node_transformation = scaling_matrix * rotation_matrix * translation_matrix;
            //node_transformation = translation_matrix * rotation_matrix * scaling_matrix;

        }

        glm::mat4 global_transformation =  node_transformation * _parentTransform;

        if (boneMapping.find(node_name) != boneMapping.end()) {

            // Update the Global Transformation.
            auto bone_index = boneMapping[node_name];

            //boneInfoData[bone_index].finalTransformation = globalInverseTransform * global_transformation * boneInfoData[bone_index].boneOffset;
            boneInfoData[bone_index].finalTransformation = boneInfoData[bone_index].boneOffset * global_transformation * globalInverseTransform;
            //boneInfoData[bone_index].finalTransformation = globalInverseTransform;
        }

        for (auto i = 0; i < _node->mNumChildren; i++) {
            ReadNodeHierarchyAnimation(_animationTime, _node->mChildren[i], global_transformation);
        }

    }

Мой текущий вывод:

Current Output

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

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

Кроме того, я вижу предложения использовать базовую модель вначальные этапы изучения этого.Но мне сказали, что формат Obj не поддерживает анимацию, и до этого я использовал только Obj.Могу ли я использовать любые другие форматы, которые экспортирует Blender, аналогично MD5, как показано в этом руководстве?

1 Ответ

0 голосов
/ 10 сентября 2018

Несколько лет назад я создал анимированную сцену с использованием библиотеки Assimp, в основном следуя этим инструкциям. http://ogldev.atspace.co.uk/www/tutorial38/tutorial38.html и http://sourceforge.net/projects/assimp/forums/forum/817654/topic/3880745

Пока я использовал старый формат X (blender может работать с X, используя расширение), я могу точно подтвердить, что вам нужно транспонировать матрицы анимации assimp для использования с GML.

Что касается использования других форматов, вы можете использовать все, что вам нравится, при условии, что они поддерживаются Blender (импорт, редактирование, экспорт) и Assimp. Будьте готовы к значительным пробам и ошибкам при смене форматов!

Вместо того, чтобы пытаться понять ваш код, я опубликую соответствующие фрагменты из моей рабочей системы, в которых показан расчет костных матриц. Надеюсь, это поможет вам, так как я помню, что у меня была та же проблема, что вы описали, и я потратил некоторое время на ее устранение. Код простой 'C'.

Вы можете увидеть, где происходит транспонирование в конце кода.

// calculateAnimPose() calculates the bone transformations for a mesh at a particular time in an animation (in scene)
// Each bone transformation is relative to the rest pose.
void calculateAnimPose(aiMesh* mesh, const aiScene* scene, int animNum, float poseTime, mat4 *boneTransforms) {

    if(mesh->mNumBones == 0 || animNum < 0) {    // animNum = -1 for no animation
        boneTransforms[0] = mat4(1.0);           // so, just return a single identity matrix
        return;
    }
    if(scene->mNumAnimations <= (unsigned int)animNum)    
        failInt("No animation with number:", animNum);

    aiAnimation *anim = scene->mAnimations[animNum];  // animNum = 0 for the first animation

    // Set transforms from bone channels 
    for(unsigned int chanID=0; chanID < anim->mNumChannels; chanID++) {
        aiNodeAnim *channel = anim->mChannels[chanID];        
        aiVector3D curPosition;
        aiQuaternion curRotation;   // interpolation of scaling purposefully left out for simplicity.

        // find the node which the channel affects
        aiNode* targetNode = scene->mRootNode->FindNode( channel->mNodeName );

        // find current positionKey
        size_t posIndex = 0;
        for(posIndex=0; posIndex+1 < channel->mNumPositionKeys; posIndex++)
            if( channel->mPositionKeys[posIndex + 1].mTime > poseTime )
                break;   // the next key lies in the future - so use the current key

        // This assumes that there is at least one key
        if(posIndex+1 == channel-> mNumPositionKeys)
             curPosition = channel->mPositionKeys[posIndex].mValue;  
        else {
            float t0 = channel->mPositionKeys[posIndex].mTime;   // Interpolate position/translation
            float t1 = channel->mPositionKeys[posIndex+1].mTime;
            float weight1 = (poseTime-t0)/(t1-t0);  

            curPosition = channel->mPositionKeys[posIndex].mValue * (1.0f - weight1) + 
                          channel->mPositionKeys[posIndex+1].mValue * weight1;
        }

        // find current rotationKey
        size_t rotIndex = 0;
        for(rotIndex=0; rotIndex+1 < channel->mNumRotationKeys; rotIndex++)
            if( channel->mRotationKeys[rotIndex + 1].mTime > poseTime )
                break;   // the next key lies in the future - so use the current key

        if(rotIndex+1 == channel-> mNumRotationKeys)
            curRotation = channel->mRotationKeys[rotIndex].mValue;
        else {
            float t0 = channel->mRotationKeys[rotIndex].mTime;   // Interpolate using quaternions
            float t1 = channel->mRotationKeys[rotIndex+1].mTime;
            float weight1 = (poseTime-t0)/(t1-t0); 

            aiQuaternion::Interpolate(curRotation, channel->mRotationKeys[rotIndex].mValue, 
                                      channel->mRotationKeys[rotIndex+1].mValue, weight1);
            curRotation = curRotation.Normalize();
        }

        aiMatrix4x4 trafo = aiMatrix4x4(curRotation.GetMatrix());             // now build a rotation matrix
        trafo.a4 = curPosition.x; trafo.b4 = curPosition.y; trafo.c4 = curPosition.z; // add the translation
        targetNode->mTransformation = trafo;  // assign this transformation to the node
    }

    // Calculate the total transformation for each bone relative to the rest pose
    for(unsigned int a=0; a<mesh->mNumBones; a++) { 
        const aiBone* bone = mesh->mBones[a];
        aiMatrix4x4 bTrans = bone->mOffsetMatrix;  // start with mesh-to-bone matrix to subtract rest pose

        // Find the bone, then loop through the nodes/bones on the path up to the root. 
        for(aiNode* node = scene->mRootNode->FindNode(bone->mName); node!=NULL; node=node->mParent)
            bTrans = node->mTransformation * bTrans;   // add each bone's current relative transformation

        boneTransforms[a] =  mat4(vec4(bTrans.a1, bTrans.a2, bTrans.a3, bTrans.a4),
                                  vec4(bTrans.b1, bTrans.b2, bTrans.b3, bTrans.b4),
                                  vec4(bTrans.c1, bTrans.c2, bTrans.c3, bTrans.c4), 
                                  vec4(bTrans.d1, bTrans.d2, bTrans.d3, bTrans.d4));   // Convert to mat4
    }
}
...