尝试使用Assimp GLM从MD5文件加载OpenGL中的动画

问题描述 投票:1回答:1

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

然而,我面临一些问题,我认为这些问题与Assimp的Row Major Order和GLM的Column主要订单有关,尽管我不太确定。

我尝试了一些变化和命令,看看是否有任何工作,但无济于事。

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

    }

我目前的输出:

Current Output

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

如果有人可以在这里指出我的错误或者指导我帮助我加载动画的其他教程,那就太棒了。

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

c++ opengl glm-math assimp
1个回答
1
投票

几年前我使用Assimp库构建了一个动画场景,基本上遵循这些教程。 http://ogldev.atspace.co.uk/www/tutorial38/tutorial38.htmlhttp://sourceforge.net/projects/assimp/forums/forum/817654/topic/3880745

当我使用旧的X格式(搅拌器可以使用X,使用扩展名)时,我肯定可以确认你需要转换用于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
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.