VAO/VBO 管理 - 更改所有 VBO 数据

Posted

技术标签:

【中文标题】VAO/VBO 管理 - 更改所有 VBO 数据【英文标题】:VAO/VBO management - change all VBO data 【发布时间】:2014-06-18 10:50:01 【问题描述】:

我有一个带有 3 个 VBO 的 VAO,其中包含一个带有顶点、法线和纹理坐标的模型。

我打算经常更改这些 VBO 中的所有数据,大约从 500 毫秒到 20 毫秒的更新频率。下载到 VBO 的新模型可以比前一个模型具有更少或更多的三角形。所以缓冲区大小也会改变。

我不是 OpenGL 方面的专家,所以如果可能的话,我想要一些关于如何改进我的代码的提示。 目前,程序实现如下:

glBindVertexArray(*vao);

if (mesh->HasPositions()) 
    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()) 
    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)) 
    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

编辑:

当前的解决方案存在绘图不是应有的问题。

如果我的第一个模型很大 (50Mb),而我加载另一个小一点 (25Mb) 的模型,则仍会绘制先前模型的一部分。

如果第一个模型是小模型 (25Mb),然后我将其更改为大模型 (50Mb),则绘图没有改变(或者至少看起来没有改变)。如果我在更小的 (216kb) 之后充电,则绘图会发生变化(但仍有一部分剩余)。

所以我想我的 VBO 管理有问题?

【问题讨论】:

20 毫秒真的没那么快,除非你在做磁盘 I/O,否则那可能是不合理的。 20 毫秒是 50 赫兹(这意味着如果以 60 FPS 进行绘制,每帧可能会发生不到一次); 500 毫秒是 2 赫兹,在任何帧速率下都可以轻松管理。无论如何,此解决方案没有任何问题 - 实际上,每次更改数据时为缓冲区分配 new 存储空间以避免仍在使用的命令的管道同步是一种常见的做法旧数据;一个称为缓冲区孤立的概念。你有什么特别不喜欢这个设计的地方吗? 我或许应该退后一步,问一下:您是否曾经重用过 old 模型数据?如果是这样,与其回收旧的 VBO,不如考虑简单地创建多个 VBO,每个模型一个。 @Andon M. Coleman:在真正调用 glBufferData 以正确执行孤儿之前,他不需要使用带有 NULL 指针的 glBufferData 吗?当他只是一遍又一遍地分配它,从不释放它时,旧的缓冲区数据甚至会发生什么。 OpenGL有什么神奇的处理方式吗? 考虑到您实际上无法在 OpenGL 中释放缓冲区对象内存(使用专用命令),这不是问题。当您调用glBufferData (...) 时,它会分配新的存储空间并有效地将旧存储空间放到要释放的内存列表中(同样适用于glTexImage2D (...) 等内容)。在没有挂起的命令使用旧内存之后,OpenGL 可以开始释放它。当您孤立缓冲区时,您希望传递NULL 的原因是您要在以后调用glBufferSubData (...) 一次或多次。在这种情况下,数据是在分配的同时设置的。 20ms 是因为模型是由另一台计算机通过 tcp 带来的。但实际上使用我目前的解决方案,我有一个关于溺水的问题,我会编辑帖子来描述这个问题 【参考方案1】:

好的,我找到了问题

我正在一个线程中更新 vbo 数据。我不知道它不起作用:/

【讨论】:

你实际上可以,但取决于平台,你需要一个更多的上下文,然后使用flush。

以上是关于VAO/VBO 管理 - 更改所有 VBO 数据的主要内容,如果未能解决你的问题,请参考以下文章

VAO VBO EBO

了解 VAO、VBO 和程序

我们是不是需要序列化 ​​VAO 和 VBO

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

OpenGL:一个 VBO 的多个 VAO

如何使用不同的 VAO、VBO 绘制 2 个或更多对象?