【问题标题】:Trying to load animations in OpenGL from an MD5 file using Assimp GLM尝试使用 Assimp GLM 从 MD5 文件加载 OpenGL 中的动画
【发布时间】:2023-04-04 17:17:01
【问题描述】:

我正在尝试遵循here ( at ogldev ) 提到的in this answer 的教程。

然而,我面临一些我认为与 Assimp 的行主要订单与 GLM 的列主要订单有关的问题,尽管我不太确定。

我尝试了一些变体和命令以查看其中任何一个是否有效,但无济于事。

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

    }

我当前的输出:

我尝试通过代码中使用的每个矩阵来检查是否应该转置它。我是否应该更改矩阵乘法顺序。我找不到我的问题。

如果有人能在此处指出我的错误或将我引导至其他教程以帮助我加载动画,那就太好了。

另外,我看到建议在学习的初始阶段使用基本模型。但有人告诉我 Obj 格式不支持动画,在此之前我一直在使用 Obj。我是否可以使用 Blender 以类似于本教程中所示的 MD5 的方式导出的任何其他格式?

【问题讨论】:

    标签: c++ opengl glm-math assimp


    【解决方案1】:

    几年前我使用 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
        }
    }
    

    【讨论】:

    • 感谢您的 sn-p。据我所知,您一直在使用 Assimp 的矩阵,直到您将其存储到最后为止。然后在存储它之前转置它。这太有趣了。另外,您的动画中没有缩放信息吗?我肯定会创建一个新分支并测试这种方式。理想情况下,这应该有效。
    • 据我记忆,我没有使用缩放作为动画的一部分。只是变形。祝你好运并坚持! (我休假 2 周,因此无法进一步回复)。
    • 是的。我做了你所做的(即只在最后转置),老实说,这比试图弄清楚什么要转置和什么不应该容易得多。谢谢!
    猜你喜欢
    • 2014-06-07
    • 2014-06-10
    • 2016-12-29
    • 2018-07-23
    • 2018-09-12
    • 2019-02-27
    • 1970-01-01
    • 2012-01-13
    • 1970-01-01
    相关资源
    最近更新 更多