使用Assimp了解动画加载

时间:2014-04-25 00:28:30

标签: animation blender assimp

我创建了一个容器类,它基本上包含了渲染动画所需的所有信息。我正在使用Assimp库来加载动画。然后将scene->mVertices等数据分配给我的数组缓冲区,我找不到的是我应该如何将其他帧的数据存入我的缓冲区!

我知道有一个名为HasAnimations()的函数,还有一个aiAnimation **mAnimations。但是,我无法找到与获取下一组顶点数据相关的任何数据。

我已经设法加载了一系列obj文件并绘制它们以确认我的类正常工作。但显然,当我想扩展到真正的交易时,我更愿意或者通常需要使用别的东西。因为单独装载250帧需要几分钟。 (加载一个简单的动画应该在大约5秒内完成,对吗?)

我愿意使用任何类型的文件格式。但我需要知道如何在Blender中设置它以便动画将被导出。因为我现在似乎也失败了,因为我对Blender几乎没有经验。

我一直在寻找关于这个库和搅拌机出口2天的教程,发现几乎没什么用处。我确实查看了Assimp的文档,这对我来说是迄今为止,但没有解释aiAnimation如何影响顶点。或者我如何获得我需要的其他数据帧。

1 个答案:

答案 0 :(得分:0)

好吧,我确实设法让它在无数个小时后工作!排序...我创建了一个在循环x+5, y+5, x-5, y-5中转换的模型... 我最终做了什么,这是我唯一能想到的事情。正在读取场景中的数据 - > mAnimations [],这基本上只包含关键帧数组。所以我不得不自己插入所有顶点(这总是一个有趣的任务!)。

用途不同:

  1. 您可以获得关键帧应该完全插补的时间。
  2. 然后减去当前对象的位置,以确定需要移动多少。
  3. 现在你需要弄清楚每一步的移动量,所以我采取了最简单的解决方案,将它除以运动应分割的帧数。
  4. 现在只需更新我的所有顶点,然后再将它们发送到VBO。 (此步骤可能会因您的数据设置而有所不同)
  5. 在这些步骤之后,我得到了这样的东西:

    部首:

    class AssimpMesh {
    private:
        struct ShaderProgram {
            //Shader data
            GLuint program;
            string programName;
            vector <GLuint> shaders, uniforms;
        };
    
        struct MeshData {
            //Mesh data
            GLuint meshArray;
            vector <GLuint> buffers;
            vector <string> bufferNames;
    
            //Shader data
            ShaderProgram *shader;
    
            vector <aiVector3D> transedVertices;
            int totalIndices;
        };
    
        struct Frame {
            vector <MeshData*> meshes;
        };
    
        struct Animation {
            string name;
            vector <Frame*> frames;
        };
    
        //Global shader data
        ShaderProgram *globalShader;
    
        //Model data
        Assimp::Importer importer;
        const aiScene *scene;
    
        //Mesh data
        bool initialized, perMeshShading;
        vector <Animation*> animations;
        int currentFrame, currentAnimation;
        Uint32 lastFrameTicks;
        Transform *transform;
        glm::mat4 projectionView;
        aiVector3D lightPosition;
    
        void loadScene(string filePath);
        void loadAnimation(Animation *animation, int numFrames);
        void initMesh(aiMesh *mesh, MeshData *data);
        ...
    
    public:
        AssimpMesh(string filePath);
        ~AssimpMesh();
    
        void draw();
        ...
    };
    

    来源:

    void AssimpMesh::loadScene(string filePath) {
        //Load animation file
        scene = importer.ReadFile(filePath.c_str(), aiProcessPreset_TargetRealtime_MaxQuality);
    
        if (scene) {
            if (scene->HasAnimations()) {
                for (int i = 0; i < scene->mNumAnimations; i++) {
                    aiAnimation *anime = scene->mAnimations[i];
                    int framesInAnimation = ceil(anime->mDuration * ANIMATION_IMPORT_FPS);
    
                    Animation *animation = new Animation();
                    animation->name = anime->mName.C_Str();
                    loadAnimation(animation, framesInAnimation);
                    animations.push_back(animation);
                }
            }
            else {
                Animation *animation = new Animation();
                animation->name = "Default";
                loadAnimation(animation, 1);
                animations.push_back(animation);
            }
            printf("Done loading '%s'\n", filePath.c_str());
        }
        else {
            //Report error
            printf("Assimp error: %s\n", importer.GetErrorString());
        }
    }
    
    void AssimpMesh::loadAnimation(Animation *animation, int numFrames) {
        int nextKeyframe = -1;
        int nextKeyframeId = -1;
        int transedFrames = 0;
        aiVector3D transPos = aiVector3D();
        aiVector3D transVec = aiVector3D();
    
        for (int f = 0; f < numFrames; f++) {
            Frame *frame = new Frame();
    
            if (f > nextKeyframe && nextKeyframe < numFrames) {
                //Get the new keyframe
                aiAnimation *anime = scene->mAnimations[animations.size()];
                aiNodeAnim *aniNode = anime->mChannels[0];
                aiVectorKey key = aniNode->mPositionKeys[++nextKeyframeId];
                nextKeyframe = ceil(key.mTime * ANIMATION_IMPORT_FPS);
    
                if (!nextKeyframeId) {
                    transVec = key.mValue;
                    transPos = key.mValue;
                }
                else {
                    int transFrames = nextKeyframe - (f - 1);
                    aiVector3D transDir = key.mValue - transPos;
                    transPos = key.mValue;
                    transVec = transDir;
                    transVec /= transFrames;
                    transedFrames = 0;
                }
            }
    
            if (scene->HasLights()) {
                aiLight *light = scene->mLights[0];
                //lightPosition = light->mPosition;
            }
    
            //Put data into vertex arrays
            transedFrames++;
            aiMesh *mesh;
            MeshData *data;
            for (int i = 0; i < scene->mNumMeshes; i++) {
                mesh = scene->mMeshes[i];
                data = new MeshData();
    
                if (!i) {
                    for (int j = 0; j < mesh->mNumVertices; j++) {
                        if (!f) {
                            data->transedVertices.push_back(mesh->mVertices[j] + transVec);
                        }
                        else {
                            data->transedVertices.push_back(animation->frames[f-1]->meshes[i]->transedVertices[j] + transVec);
                        }
                    }
                }
    
                //Assign VBO
                initMesh(mesh, data);
    
                //Assign shader
                if (perMeshShading) {
                    initShader(mesh, data);
                    setUniforms(mesh, data);
                }
    
                frame->meshes.push_back(data);
            }
    
            animation->frames.push_back(frame);
        }
    }
    
    void AssimpMesh::initMesh(aiMesh *mesh, MeshData *data) {
        //Buffer for temporary storage of new ids
        GLuint id;
    
        //Make vertex array
        if (!initialized) {
            glGenVertexArrays(1, &id);
        }
        data->meshArray = id;
    
        //Tell OpenGL to use this array
        glBindVertexArray(id);
    
        //Assign vertices
        if (mesh->HasPositions()) {
            //Make buffer
            if (!initialized) {
                glGenBuffers(1, &id);
            }
            data->buffers.push_back(id);
            data->bufferNames.push_back("Positions");
    
            //Set buffer data
            glBindBuffer(GL_ARRAY_BUFFER, id);
            if (data->transedVertices.size()) {
                glBufferData(GL_ARRAY_BUFFER, sizeof(aiVector3D) * data->transedVertices.size(), &data->transedVertices[0], GL_STATIC_DRAW);
            }
            else {
                glBufferData(GL_ARRAY_BUFFER, sizeof(aiVector3D) * mesh->mNumVertices, &mesh->mVertices[0], GL_STATIC_DRAW);
            }
            //Set shader attribute data
            glEnableVertexAttribArray(VBO_VERTEX);
            glVertexAttribPointer(VBO_VERTEX, 3, GL_FLOAT, GL_FALSE, NULL, NULL);
        }
    
        unsigned int matId = mesh->mMaterialIndex;
        aiMaterial *material = scene->mMaterials[matId];
        vector <aiColor3D> colors;
        aiColor3D diffuse(0, 0, 0);
        material->Get(AI_MATKEY_COLOR_DIFFUSE, diffuse);
    
        for (int i = 0; i < mesh->mNumVertices; i++) {
            colors.push_back(diffuse);
        }
    
        //Make buffer
        if (!initialized) {
            glGenBuffers(1, &id);
        }
        data->buffers.push_back(id);
        data->bufferNames.push_back("Colors");
    
        //Set buffer data
        glBindBuffer(GL_ARRAY_BUFFER, id);
        glBufferData(GL_ARRAY_BUFFER, sizeof(aiColor3D) * mesh->mNumVertices, &colors.front(), GL_STATIC_DRAW);
    
        //Set shader attribute data
        glEnableVertexAttribArray(VBO_COLOR);
        glVertexAttribPointer(VBO_COLOR, 3, GL_FLOAT, GL_FALSE, NULL, NULL);
    
        //Assign texture coords
        if (mesh->HasTextureCoords(0)) {
            //Make buffer
            if (!initialized) {
                glGenBuffers(1, &id);
            }
            data->buffers.push_back(id);
            data->bufferNames.push_back("TextureCoords");
    
            //Set buffer data
            glBindBuffer(GL_ARRAY_BUFFER, id);
            glBufferData(GL_ARRAY_BUFFER, sizeof(aiVector3D) * mesh->mNumVertices, &mesh->mTextureCoords[0], GL_STATIC_DRAW);
    
            //Set shader attribute data
            glEnableVertexAttribArray(VBO_TEXCORD);
            glVertexAttribPointer(VBO_TEXCORD, 3, GL_FLOAT, GL_FALSE, NULL, NULL);
        }
    
        //Assign colors
        if (mesh->HasNormals()) {
            //Make buffer
            if (!initialized) {
                glGenBuffers(1, &id);
            }
            data->buffers.push_back(id);
            data->bufferNames.push_back("Normals");
    
            //Set buffer data
            glBindBuffer(GL_ARRAY_BUFFER, id);
            glBufferData(GL_ARRAY_BUFFER, sizeof(aiVector3D) * mesh->mNumVertices, &mesh->mNormals[0], GL_STATIC_DRAW);
    
            //Set shader attribute data
            glEnableVertexAttribArray(VBO_NORMAL);
            glVertexAttribPointer(VBO_NORMAL, 3, GL_FLOAT, GL_FALSE, NULL, NULL);
        }
    
        if (mesh->HasFaces()) {
            vector <unsigned int> indices;
            aiFace face;
            for (int i = 0; i < mesh->mNumFaces; i++) {
                face = mesh->mFaces[i];
                for (int j = 0; j < face.mNumIndices; j++) {
                    indices.push_back(face.mIndices[j]);
                }
            }
            data->totalIndices = indices.size();
    
            //Make buffer
            if (!initialized) {
                glGenBuffers(1, &id);
            }
            data->buffers.push_back(id);
            data->bufferNames.push_back("Faces");
    
            //Set buffer data
            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, id);
            glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * indices.size(), &indices.front(), GL_STATIC_DRAW);
        }
    }
    

    当然,它对一切都不起作用。实际上只翻译和整个模型。显然它没有正确读取名称值,所以我不能用于动画的网格。但它让我走了,也许有人会觉得这很有帮助。 =)