多网格模型的 vao 管理

Posted

技术标签:

【中文标题】多网格模型的 vao 管理【英文标题】:vao management for model with multiple mesh 【发布时间】:2014-07-07 08:05:53 【问题描述】:

我有一个带有多个网格的 .obj 模型。我想为每个网格创建一个 vao。然后渲染所有的东西。

为此,我想创建一个 vao 指针,根据模型中的网格数量更改其大小。

我使用 assimp 为模型充电。

编译没有问题,但执行时程序崩溃。

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

知道我的程序出了什么问题? (我对 openGL 有点陌生)

我的代码:

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

    

【问题讨论】:

【参考方案1】:

您正在将 newed 数组分配给局部变量。函数返回后,这块内存就丢失了。

应该是这样的:

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

(注意**在两个参数中,_作为示例)

然后,:

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

第二个参数也一样。

num_mesh 是一个指针,但您正在为它分配整数(它是本地的,所以值再次丢失)。应该是*num_mesh = scene-&gt;mNumMeshes;

另一件事是您在循环中使用glGenVertexArrays - 它应该只使用一次;在每次迭代中,您都会丢失以前的数据。

目前还不清楚一旦不再需要顶点数组,将如何删除它们,因为调用方不知道这些值是什么。

【讨论】:

以上是关于多网格模型的 vao 管理的主要内容,如果未能解决你的问题,请参考以下文章

使用 VAO/VBO 进行 OpenGL 模型/纹理渲染

一个 VBO 可以绑定多个 VAO 吗?

VAO VBO EBO

配置 VAO 以处理具有多个网格的 VBO

多个网格、多个 VBO、多个 VAO、OpenGL 4.1

WebGL 多模型场景