2

我制作了一个容器类,它基本上包含了渲染动画所需的所有信息。我正在使用 Assimp 库来加载动画。然后将来自scene->mVertices等的数据分配给我的数组缓冲区,我无法弄清楚我应该如何将其他帧的数据获取到我的缓冲区中!

我知道有一个函数叫做HasAnimations(),还有一个aiAnimation **mAnimations. 但是我在那里找不到任何与获取下一组顶点数据相关的数据。

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

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

我一直在寻找关于这个库和搅拌机导出的教程 2 天,但几乎没有发现任何有用的东西。我也确实查看了 Assimp 的文档,这让我到目前为止,但没有解释关于 aiAnimation 如何影响顶点的事情。或者我如何获得我需要的其他数据帧。

4

1 回答 1

2

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

有效地:

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

在这些步骤之后,我得到了如下所示的东西:

标题:

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

当然,它并不适用于所有事情。实际上只有翻译和整个模型。显然它没有正确读取名称值,所以我无法确定动画的用途。但这让我继续前进,也许有人会觉得这很有帮助。=)

于 2014-04-25T03:48:19.953 回答