【问题标题】:OpenGL optimize Mesh Drawing (VAO? without indices?)OpenGL优化网格绘图(VAO?没有索引?)
【发布时间】:2015-03-20 03:32:33
【问题描述】:

好的,经过一段时间的超时,我正在继续我关于 OpenGL3.2+ 的研究,现在我对如何优化这样的东西感到困惑:

// Verts
glBindBuffer(GL_ARRAY_BUFFER, VertBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * size, verts, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(VERTEX_COORD_ATTRIB);
glVertexAttribPointer(VERTEX_COORD_ATTRIB,3,GL_FLOAT, GL_FALSE, sizeof(float) * floatsPerVertex, 0);

// Textures
glBindBuffer(GL_ARRAY_BUFFER, TexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * texsize, tex, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(TEXTURE_COORD_ATTRIB);
glVertexAttribPointer(TEXTURE_COORD_ATTRIB, 2, GL_FLOAT, GL_FALSE, sizeof(float) * TexCoords2D, 0);

//add light color info
glBindBuffer(GL_ARRAY_BUFFER, ColorBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * colorsize, lightcolor, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(COLOR_ATTRIB);
glVertexAttribPointer(COLOR_ATTRIB, 4, GL_FLOAT, GL_FALSE, sizeof(float) * ColorInfo, 0);

// Draw
glDrawArrays(GL_TRIANGLES, 0, size);

// Clean up
glDisableVertexAttribArray(VERTEX_COORD_ATTRIB);
glDisableVertexAttribArray(TEXTURE_COORD_ATTRIB);
glDisableVertexAttribArray(COLOR_ATTRIB);

假设这是为几个网格完成的,目前每个网格总是像这样被推送、绑定、缓冲和绘制。不用说,这肯定不是有效的方法。

现在在阅读(许多)教程时,我经常看到的一件事是建议使用 VAO 来改进它,现在我难以理解的是 - 每个单独的教程似乎也与索引绘图相关。虽然在使用像 2 个四边形这样极其简单的示例时,这种方法似乎非常好,但我现在想知道应该如何为真正的复杂网格创建索引?还是只是假设这是可用的(由于 .obj 文件或其他原因)。 此外,我对 VAO 是否总是需要索引或是否可以不使用索引感到困惑?如果是这样,那么它是否有意义,因为我读到优化利用知道索引? 你看这里有很多混乱,我意识到这可能又是一个愚蠢的问题:)

但是,我最终想要实现的是,不是像这样推送每个网格,而是在显卡的内存中缓冲每个网格一次,然后从缓冲区中重绘它。 我还不知道 VAO 是否是正确的方法,但我阅读的每个教程似乎都将 VAO 作为下一步。

【问题讨论】:

    标签: c++ opengl


    【解决方案1】:

    首先,您应该将使用 glBufferData() 写入的 GRAM 与使用 glDrawArrays() 的绘图调用分开。这会显着降低您的性能,因为您基本上是在每次绘图调用时将数据从 RAM 复制到 GRAM。

    为此,您可以使用 VAO:

    // 设置缓冲区

    glBindVertexArray(VertexArrayIndex);
    
    glBindBuffer(GL_ARRAY_BUFFER, VertBuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(float) * size, verts, GL_DYNAMIC_DRAW);
    glEnableVertexAttribArray(VERTEX_COORD_ATTRIB);
    glVertexAttribPointer(VERTEX_COORD_ATTRIB,3,GL_FLOAT, GL_FALSE, sizeof(float) * floatsPerVertex, 0);
    
    // Textures
    glBindBuffer(GL_ARRAY_BUFFER, TexBuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(float) * texsize, tex, GL_DYNAMIC_DRAW);
    glEnableVertexAttribArray(TEXTURE_COORD_ATTRIB);
    glVertexAttribPointer(TEXTURE_COORD_ATTRIB, 2, GL_FLOAT, GL_FALSE, sizeof(float) * TexCoords2D, 0);
    
    //add light color info
    glBindBuffer(GL_ARRAY_BUFFER, ColorBuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(float) * colorsize, lightcolor, GL_DYNAMIC_DRAW);
    glEnableVertexAttribArray(COLOR_ATTRIB);
    glVertexAttribPointer(COLOR_ATTRIB, 4, GL_FLOAT, GL_FALSE, sizeof(float) * ColorInfo, 0);
    
    glBindVertexArray(0);
    

    // 你的绘图调用

    glBindVertexArray(VertexArrayIndex);
     glDrawArrays(GL_TRIANGLES, 0, size);
    glBindVertexArray(0);
    

    如果您想绘制非常大的网格(它们的大小大于显卡上可用的 GRAM),您应该对将数据分成小块感兴趣。将所有数据放在一个大数组中可能会导致一些令人讨厌的内存分配和渲染问题(相信我 - 我曾经去过那里;))。

    【讨论】:

    • 您确切地说了我的示例中最大的问题是什么以及我想摆脱的部分。我真的很惊讶它确实如此简单,并且它也在某种程度上回答了我的 VAO 问题 - 也感谢记忆提示,我相信我迟早会达到这一点:) 会尝试并报告
    • 真的很酷。我应该早点在这里问,我想我认为这比现在更复杂。想知道为什么实际上每个教程都必须将其绑定到索引绘图而不提及如此简单的设置。谢谢!!
    【解决方案2】:

    我建议您的下一步应该是将顶点属性转换为结构而不是单独的数组。这样一来,您只使用一个数组对象,而 GPU 更喜欢这种内存布局。

    除此之外:

    您是否编入索引在很大程度上取决于您的数据;这不是快速性能的要求,但它可以提供帮助;另一种选择是使用三角形带,这也减少了顶点数据量。如果您在单个数组对象中有多个网格,您可以简单地将顶点属性指针更改为从数组对象中的不同位置开始,以便绘制不同的网格。这样你就不会在数组对象之间切换太多了。

    这些决定中的大多数应该由您的约束和性能测量驱动!

    【讨论】:

    • 谢谢,这已经为我提供了非常有价值的信息,而且我之前确实使用过三角条 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-07-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多