Search code examples
c++pointersopenglvbovao

vao management for model with multiple mesh


I have a .obj model with multiple mesh. I want to create a vao for each mesh. And then render the all thing.

For this i want to create a vao pointer change its sized depending to the number of mesh in the model.

I charge the model using assimp.

No compile problem but the program crash when executing this.

      glBindVertexArray(modele_multvao[z]);
      glDrawArrays(GL_TRIANGLES, 0, modele_multcount[z]);

An idea of what is wrong in my program? (i'm kinda new on openGL)

My code:

GLuint *modele_vao;
int *point_count;
int number_of_mesh;

bool load_mesh(const char* file_name, GLuint* vao, int* point_count,int* num_mesh) {
/* load file with assimp and print some stats */
const aiScene* scene = aiImportFile(file_name, aiProcess_Triangulate);
if (!scene) {
    std::wcout <<"ERROR: reading mesh: "<< file_name << std::endl;
    std::wcout << aiGetErrorString() << std::endl;
    return false;
}
std::wcout << "mesh import succeeded" << std::endl;
std::wcout << scene->mNumAnimations << " animations" << std::endl;
std::wcout << scene->mNumCameras << " cameras" << std::endl;
std::wcout << scene->mNumLights << " lights" << std::endl;
std::wcout << scene->mNumMaterials << " materials" << std::endl;
std::wcout << scene->mNumMeshes << " meshes" << std::endl;
std::wcout << scene->mNumTextures << " textures" << std::endl;

num_mesh=scene->mNumMeshes;
vao = new GLuint[scene->mNumMeshes];
point_count=new int[scene->mNumMeshes];

int i=0;
for(i=1;i<=(scene->mNumMeshes);i++)
{
    /* get mesh n°i in file  */
    const aiMesh* mesh = scene->mMeshes[i-1];
    std::wcout << "vertices in mesh :" << mesh->mNumVertices<< std::endl;

    /* pass back number of vertex points in mesh */
    *point_count = mesh->mNumVertices;

    /* generate a VAO, using the pass-by-reference parameter that we give to the
    function */

    glGenVertexArrays(scene->mNumMeshes, vao);
    glBindVertexArray(vao[i-1]);

    /* we really need to copy out all the data from AssImp's funny little data
    structures into pure contiguous arrays before we copy it into data buffers
    because assimp's texture coordinates are not really contiguous in memory.
    i allocate some dynamic memory to do this. */
    GLfloat* points = NULL; // array of vertex points
    GLfloat* normals = NULL; // array of vertex normals
    GLfloat* texcoords = NULL; // array of texture coordinates
    if (mesh->HasPositions()) {
        points = (GLfloat*)malloc(*point_count * 3 * sizeof (GLfloat));
        for (int i = 0; i < *point_count; i++) {
            const aiVector3D* vp = &(mesh->mVertices[i]);
            points[i * 3] = (GLfloat)vp->x;
            points[i * 3 + 1] = (GLfloat)vp->y;
            points[i * 3 + 2] = (GLfloat)vp->z;
        }
    }
    if (mesh->HasNormals()) {
        normals = (GLfloat*)malloc(*point_count * 3 * sizeof (GLfloat));
        for (int i = 0; i < *point_count; i++) {
            const aiVector3D* vn = &(mesh->mNormals[i]);
            normals[i * 3] = (GLfloat)vn->x;
            normals[i * 3 + 1] = (GLfloat)vn->y;
            normals[i * 3 + 2] = (GLfloat)vn->z;
        }
    }
    if (mesh->HasTextureCoords(0)) {
        texcoords = (GLfloat*)malloc(*point_count * 2 * sizeof (GLfloat));
        for (int i = 0; i < *point_count; i++) {
            const aiVector3D* vt = &(mesh->mTextureCoords[0][i]);
            texcoords[i * 2] = (GLfloat)vt->x;
            texcoords[i * 2 + 1] = (GLfloat)vt->y;
        }
    }

    /* copy mesh data into VBOs */
    if (mesh->HasPositions()) {
        GLuint vbo_pos;
        glGenBuffers(1, &vbo_pos);
        glBindBuffer(GL_ARRAY_BUFFER, vbo_pos);
        glBufferData(
            GL_ARRAY_BUFFER,
            3 * *point_count * sizeof (GLfloat),
            points,
            GL_DYNAMIC_DRAW
            );
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
        glEnableVertexAttribArray(0);
        free(points); // free our temporary memory
    }
    if (mesh->HasNormals()) {
        GLuint vbo_norm;
        glGenBuffers(1, &vbo_norm);
        glBindBuffer(GL_ARRAY_BUFFER, vbo_norm);
        glBufferData(
            GL_ARRAY_BUFFER,
            3 * *point_count * sizeof (GLfloat),
            normals,
            GL_DYNAMIC_DRAW
            );
        glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, NULL);
        glEnableVertexAttribArray(2);
        free(normals); // free our temporary memory
    }
    if (mesh->HasTextureCoords(0)) {
        GLuint vbo_tex;
        glGenBuffers(1, &vbo_tex);
        glBindBuffer(GL_ARRAY_BUFFER, vbo_tex);
        glBufferData(
            GL_ARRAY_BUFFER,
            2 * *point_count * sizeof (GLfloat),
            texcoords,
            GL_DYNAMIC_DRAW
            );
        glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, NULL);
        glEnableVertexAttribArray(1);
        free(texcoords); // free our temporary memory
    }
    if (mesh->HasTangentsAndBitangents()) {
        // NB: could store/print tangents here
    }
}

/* free assimp's copy of memory */
aiReleaseImport(scene);
std::wcout << "mesh loaded" << std::endl;

return true;
}



int main()
{
    load_mesh("somewhere", modele_vao, point_count, &num_of_mesh)

    [...]

    while(1){

        [...]

        for(z=0;z<num_of_mesh;z++){
            glBindVertexArray(modele_vao[z]);
            glDrawArrays(GL_TRIANGLES, 0, modele_count[z]);
        }

    }
}

Solution

  • You're assigning newed arrays to local variables. After function returns, this memory is lost.

    It should be something like:

    bool load_mesh(const char* file_name, GLuint** _vao, int** _point_count,int* num_mesh)
    

    (note ** in two parameters, and _ for the sake of example)

    And then,:

    GLuint *vao = new GLuint[scene->mNumMeshes];
    *_vao = vao;
    

    And the same for second param.

    num_mesh is a pointer, but you're assigning integer to it (and it is local, so value lost once again). It should be *num_mesh = scene->mNumMeshes;.

    Another thing is that you're using glGenVertexArrays in loop - it should be used only once; on each iteration, you're loosing previous data.

    It is unclear how you're going to remove your vertex arrays once you no longer need them, since calling side have no ideas what this values are.