C++ 动态环境中的OpenGL VBO安全实践(特定用例)

C++ 动态环境中的OpenGL VBO安全实践(特定用例),c++,qt,opengl,C++,Qt,Opengl,根据,在“动态VBO”部分下,如果场景经常更改,建议将VBO类型设置为“GL_dynamic_DRAW”。此外,如果必须更新整个缓冲区,则不能单独使用glBufferSubData。相反,您可以使用glBufferData,然后可以将其数据指针设置为NULL,然后调用glBufferSubData将数据加载到VBO中 我正在写一个Qt程序,它允许用户调整OpenGL可绘制区域(QGLWidget)的大小,如果给定的QGLWidget中显示了更多或更少的数据,则强制重新绘制一组线(排序的线框)。我

根据,在“动态VBO”部分下,如果场景经常更改,建议将VBO类型设置为“GL_dynamic_DRAW”。此外,如果必须更新整个缓冲区,则不能单独使用glBufferSubData。相反,您可以使用glBufferData,然后可以将其数据指针设置为NULL,然后调用glBufferSubData将数据加载到VBO中

我正在写一个Qt程序,它允许用户调整OpenGL可绘制区域(QGLWidget)的大小,如果给定的QGLWidget中显示了更多或更少的数据,则强制重新绘制一组线(排序的线框)。我有一个初始工作示例,它在第一次初始调整大小后工作。该程序看起来像:

现在,当我再次调整它的大小时,应用程序看起来像:

我已将问题缩小到重新加载与行关联的VBO。加载与线关联的顶点属性的代码为:

  bool batch_renderer::load_data(render_data_type &data, GLsizei buffer_count)
  {
    if (_vbo_id) {
      glBindBuffer(GL_ARRAY_BUFFER, _vbo_id);
      glDeleteBuffers(_byte_count, &_vbo_id);
      _vbo_id = 0;
      _vertex_count = 0;
      _byte_count = 0;
      _byte_count1 = 0;
      _byte_count2 = 0;
      _byte_count3 = 0;
      _byte_count4 = 0;
    }

    _vertex_count = data._data_1.size();
    _byte_count = data.size_of();

    glGenBuffers(buffer_count, &_vbo_id);
    if (bind()) {
      glBufferData(GL_ARRAY_BUFFER, _byte_count, NULL, GL_DYNAMIC_DRAW);
      switch (data._type_count) {
      case (4): {
        _byte_count4 = data.data4_size_of();
        size_t offset = data.t4_offset();
        glBufferSubData(GL_ARRAY_BUFFER, offset, _byte_count4,
          data._data_4.data());
      }
      case (3): {
        _byte_count3 = data.data3_size_of();
        size_t offset = data.t3_offset();
        glBufferSubData(GL_ARRAY_BUFFER, offset, _byte_count3,
          data._data_3.data());
      }
      case (2): {
        _byte_count2 = data.data2_size_of();
        size_t offset = data.t2_offset();
        glBufferSubData(GL_ARRAY_BUFFER, offset, _byte_count2,
          data._data_2.data());
      }
      case (1): {
        _byte_count1 = data.data1_size_of();
        size_t offset = data.t1_offset();
        glBufferSubData(GL_ARRAY_BUFFER, offset, _byte_count1,
          data._data_1.data());
      }
        break;
      default: {
        return false;
      }
      }
    } else {
      return false;
    }

    return true;
  }
如果我注释掉重新加载VBO的源代码,则在任何调整大小事件后,程序如下所示:


我在VBO上做错了什么,导致行出错,纹理混乱?

更新整个缓冲区时调用
glBufferData
的目的是重用现有的缓冲区对象,告诉驱动程序丢弃旧数据。这意味着你不必这么做

if (_vbo_id) {
  glBindBuffer(GL_ARRAY_BUFFER, _vbo_id);
  glDeleteBuffers(_byte_count, &_vbo_id);
  _vbo_id = 0;
  _vertex_count = 0;
  _byte_count = 0;
  _byte_count1 = 0;
  _byte_count2 = 0;
  _byte_count3 = 0;
  _byte_count4 = 0;
}
因此,在生成ID之前,只需检查它是否未设置

if(!_vbo_id)
    glGenBuffers(buffer_count, &_vbo_id);

注意,我发现使用
glBufferData
重新分配总缓冲区对象与更新整个
glBufferSubData
之间的差异是可以忽略的。但您必须分析自己的程序才能做出明智的决定。

@dantenwolf如果因为添加了更多的名称而需要向VBO添加更多的行,该怎么办。在这种情况下,我将不得不销毁VBO以向其中添加更多数据,因为VBO不支持基于push_-back或resize的操作。@MatthewHoggan:只需调用更大大小的glBufferData。glBufferData的行为类似于free,后跟malloc。如果要在现有ID上创建新的缓冲区对象以替换旧ID,则不必删除ID。