【问题标题】:OpenGL update parts of VBO (point cloud)VBO(点云)的OpenGL更新部分
【发布时间】:2014-10-06 20:19:32
【问题描述】:

我有一个 udp 客户端,用于从服务器读取点,该服务器在 4 毫秒内生成点,每个数据包有近 3000 个点。我阅读了这些点并将它们映射到具有 100 万个坐标元素的矩阵。 (我从带有固定键的流式点创建一个哈希表。我的意思是你可以想到一个 1000 个键,每个键最多有 1000 个点,但它是不同的。完成此表后,我从服务器获得的任何新值,映射到我的键一种排序方式,我的意思是,我首先更新了较小键中的点,然后......:D

我真的很惭愧我不能这样做,我的 1990x1080 像素的 LCD 比我快! :-((

我想将它插入 VBO,然后在 30 毫秒内升级每个关键部分。

所以我想创建 1000 个用于绘图的 vbos 和 1000 个用于缓冲的 vbos,并且在每 33 ms 迭代之后,我将 50 个绘图 vbos 更改为缓冲的 vbos。每个 vbo 最多有 0f 1000 个点和颜色,一个 VBO 中的点数从 10 变为 1000;

我的问题从这里开始,我不明白 VBO 的工作原理以及实现此问题的最佳解决方案? :D

1- 我的第一个问题:我为什么要创建 VAO 以及它如何与新一代缓冲区相关联? 它看起来与下一个 glGenBuffer() 相关联,对吗?但是在我阅读的任何示例中,我都没有看到该指针的任何使用(仅用于绘制)?这是我创建从某处下载的 vbo 的代码

glGenVertexArrays(1, &vertexArrayObject);
glBindVertexArray(vertexArrayObject);

// First see if the vertex array buffer has been created...
if(uiVertexArray == 0) {    // Nope, we need to create it
    glGenBuffers(1, &uiVertexArray);
    glBindBuffer(GL_ARRAY_BUFFER, uiVertexArray);
    glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 3 * nNumVerts, NULL, GL_DYNAMIC_DRAW);
}

// Now see if it's already mapped, if not, map it
if(pVerts == NULL) {
    glBindBuffer(GL_ARRAY_BUFFER, uiVertexArray);
    pVerts = (M3DVector3f *)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
}

// Ignore if we go past the end, keeps things from blowing up
if(nVertsBuilding >= nNumVerts)
    return;

// Copy it in...
pVerts[nVertsBuilding][0] = x;
pVerts[nVertsBuilding][1] = y;
pVerts[nVertsBuilding][2] = z;
nVertsBuilding++;

对于颜色和纹理映射它的样子。哪个有更好的性能(GL_DYNAMIC_DRAW,GL_STREAM_DRAW)

2- 这是一个绘图功能?为什么使用最后一行?用于创建下一个 VBO 和 VAO?

// Set up the vertex array object
glBindVertexArray(vertexArrayObject);
glDrawArrays(primitiveType, 0, nNumVerts);
glBindVertexArray(0); 

3- 下次我想用新点更改缓冲的 VBO 内容时,我必须为不同数量的点再次执行此操作,如果我这样做,我必须删除 VBO 的最后一个缓冲区吗?

// Vertex buffer objects
if(uiVertexArray != 0)
    glDeleteBuffers(1, &uiVertexArray);

4- 我可以调整我的 VBO 的大小并且不使用重新创建缓冲区 VBO 吗?

5- 如何从缓冲区 VBO 中复制数据以绘制 VBO?

这是我在主绘制函数中绘制 VBO 的交换缓冲区,我在交换函数中从第一个开始重新创建 VBO 数据

for(int i=0; i<1000; i++)
    if(must_show_buffer(i))
    {
          bufferVBO[i].draw();
          drawedVBO[i].swap(bufferVBO[i]);
    } 
    else drawedVBO[i].draw();

更新:

我将此函数用于交换数据: 如果(批处理-> cVerts != NULL) { CopyVertexData3f(batch->cVerts); CopyColorData4f(batch->cColors); } 结束();

void GLBatch::CopyColorData4f(M3DVector4f *vColors)
{
// First time, create the buffer object, allocate the space
if(uiColorArray == 0) {
    glGenBuffers(1, &uiColorArray);
    glBindBuffer(GL_ARRAY_BUFFER, uiColorArray);
    glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4 * nNumVerts, vColors, GL_DYNAMIC_DRAW);
}
else {  // Just bind to existing object
    glBindBuffer(GL_ARRAY_BUFFER, uiColorArray);

    // Copy the data in
    glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(GLfloat) * 4 * nNumVerts, vColors);
    pColors = NULL;
    }
 }

这种方法是正确的,但是 glBufferSubData 增加内存使用的速度如此之快,我得到一个内存溢出异常

还有这种方法

    if(batch->uiVertexArray != NULL)
    {
    // First time, create the buffer object, allocate the space
    if(uiVertexArray == 0) {
        glGenBuffers(1, &uiVertexArray);
        glBindBuffer(GL_ARRAY_BUFFER, uiVertexArray);
        glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 3 * nNumVerts, NULL, GL_DYNAMIC_DRAW);
    }

    // Fast copy data
    glBindBuffer(GL_COPY_READ_BUFFER, batch->uiVertexArray);
    glBindBuffer(GL_COPY_WRITE_BUFFER, uiVertexArray);
    glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, nNumVerts);
    glBindBuffer(GL_COPY_READ_BUFFER, 0);
    glBindBuffer(GL_COPY_WRITE_BUFFER, 0);

    //copy color data
    if(uiColorArray == 0) {
        glGenBuffers(1, &uiColorArray);
        glBindBuffer(GL_ARRAY_BUFFER, uiColorArray);
        glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4 * nNumVerts, NULL, GL_DYNAMIC_DRAW);
    }

    glBindBuffer(GL_COPY_READ_BUFFER, batch->uiColorArray);
    glBindBuffer(GL_COPY_WRITE_BUFFER, uiColorArray);
    glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, nNumVerts);
    glBindBuffer(GL_COPY_READ_BUFFER, 0);
    glBindBuffer(GL_COPY_WRITE_BUFFER, 0);
}

没有内存分配问题但不清除之前的点

我在每个实现中错过了什么?

【问题讨论】:

  • 一篇帖子中有很多问题恕我直言。
  • 为什么不使用 wiki 和手册页? (opengl.org/sdk/docs/manopengl.org/wiki) 您的问题很基础,很容易在这些网站上找到答案。
  • 可能适合您,但我不明白复制和调整大小部分?我想知道它的实施好还是最差

标签: c++ opengl vbo


【解决方案1】:
  1. 在 glVertexAttribPointer 期间 VBO 与当前绑定的 VAO 相关联

  2. 取消绑定缓冲区是一种很好的做法,请记住绑定状态是全局的,您所依赖的全局状态越少越好

  3. 无需删除 VBO,您可以跳过glGenBuffers(1, &amp;uiVertexArray); 调用

  4. 是的,使用新的 nNumVerts 对 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 3 * nNumVerts, NULL, GL_DYNAMIC_DRAW); 的新调用将调整缓冲区大小(并破坏任何现有数据)

  5. 您可以执行以下操作:

    glBindBuffer(GL_COPY_READ_BUFFER, bufferVBO);
    glBindBuffer(GL_COPY_WRITE_BUFFER, drawVBO);
    glCopyBufferSubData(GL_COPY_READ_BUFFER​, GL_COPY_WRITE_BUFFER​, 0​, 0, size​);
    glBindBuffer(GL_COPY_READ_BUFFER, 0);
    glBindBuffer(GL_COPY_WRITE_BUFFER, 0);
    

我已经在屏幕上写了 700k 点/秒,只需将它们全部上传到单个 VBO 并绘制它即可。

【讨论】:

  • 感谢您在 2 中的回答,您的意思是调整 VBO 的大小,我必须调用这两个命令并且不要删除主缓冲区:glBindBuffer(GL_ARRAY_BUFFER, uiVertexArray); glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 3 * nNumVerts, NULL, GL_DYNAMIC_DRAW);
  • 什么时候必须使用 GL_STREAM_DRAW?
  • 这个答案对我有很大帮助,但我无法解决 vbos 的问题,所以我使用数组向量:D
猜你喜欢
  • 2021-03-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多