【问题标题】:glBufferData does not delete existing data storeglBufferData 不会删除现有的数据存储
【发布时间】:2017-02-17 17:34:56
【问题描述】:

documentation 状态

glBufferData 为当前的缓冲区对象创建一个新的数据存储 绑定到目标。任何预先存在的数据存储都将被删除。新数据 以指定的字节大小和使用情况创建存储。

所以我编码

    // allocate storage in GPU and copy data
    glBufferData(
      GL_ARRAY_BUFFER,
      myData.VertexCount()*sizeof(GL_FLOAT),
      myData.Vertex(),
      GL_STREAM_DRAW);
    ...
    glDrawArrays(
      GL_TRIANGLES,
      0,
      myData.VertexCount() );

每次我需要刷新场景时都会执行。

顶点的数量有时会发生很大变化。当顶点数减少时,旧数据似乎仍然存在,并出现旧数据的乱码渲染。

我可以通过在每次刷新开始时创建缓冲区索引,然后将其删除来解决此问题

    // construct buffer index
    GLuint vertexbuffer;
    glGenBuffers(1, &vertexbuffer);

   ...

   glDeleteBuffers(1,&vertexbuffer);

目前这很好,但我想稍后进行优化,包括重用缓冲区中的一些顶点,而无需在每次刷新时制作新副本。

问题并未出现在我的所有机器上。显卡好一点的机器好像没有问题

作为参考,这里是整个渲染代码:

    void Render()
    {
        // Background color
        glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
        glEnable(GL_DEPTH_TEST);
        glDepthFunc(GL_LESS);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );

        glUseProgram( myShaderID );

        // Send our transformation to the currently bound shader,
        // in the "MVP" uniform
        glUniformMatrix4fv(myMatrixID, 1, GL_FALSE, &MVP[0][0]);

        // enable vertices attribute buffer
        glEnableVertexAttribArray(0);

        // make current
        glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);

        // allocate storage in GPU and copy data
        glBufferData(GL_ARRAY_BUFFER, myData.VertexCount()*sizeof(GL_FLOAT),
                     myData.Vertex(), GL_STREAM_DRAW);

        // let shaders access buffer
        glVertexAttribPointer(
            0,                  // attribute. No particular reason for 0, but must match the layout in the shader.
            3,                  // size
            GL_FLOAT,           // type
            GL_FALSE,           // normalized?
            0,                  // stride
            (void*)0            // array buffer offset
        );

        // 2nd attribute buffer : colors
        glEnableVertexAttribArray(1);
        glBindBuffer(GL_ARRAY_BUFFER, colorbuffer);
        glBufferData(GL_ARRAY_BUFFER, myData.VertexCount()*sizeof(GL_FLOAT),
                     myData.Color(), GL_STREAM_DRAW);
        glVertexAttribPointer(
            1,                                // attribute. No particular reason for 1, but must match the layout in the shader.
            3,                                // size
            GL_FLOAT,                         // type
            GL_FALSE,                         // normalized?
            0,                                // stride
            (void*)0                          // array buffer offset
        );

        glDrawArrays(GL_TRIANGLES, 0, myData.VertexCount() );

        glDisableVertexAttribArray(0);
        glDisableVertexAttribArray(1);

        glFlush();
        myCanvas->SwapBuffers();
}

这是最终的、固定的生产代码。 VertexCount() 现在返回实际的顶点数,而不仅仅是顶点向量中的浮点数。

/** Update GL display */
void Render()
{
    // Background color
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );

    glUseProgram( myShaderID );

    // Send our transformation to the currently bound shader,
    // in the "MVP" uniform
    glUniformMatrix4fv(
        myMatrixID,
        1,
        GL_FALSE,
        myCamera.ModelViewProjection() );

    // enable vertices attribute buffer
    glEnableVertexAttribArray(0);

    // make current
    glBindBuffer(GL_ARRAY_BUFFER, myVertexBufferID);

    // allocate storage in GPU and copy data
    glBufferData(
        GL_ARRAY_BUFFER,
        3 * myData.VertexCount()*sizeof(GL_FLOAT),
        myData.Vertex(),
        GL_STREAM_DRAW);

    // let shaders access buffer
    glVertexAttribPointer(
        0,                  // attribute. No particular reason for 0, but must match the layout in the shader.
        3,                  // size
        GL_FLOAT,           // type
        GL_FALSE,           // normalized?
        0,                  // stride
        (void*)0            // array buffer offset
    );

    // 2nd attribute buffer : colors
    glEnableVertexAttribArray(1);
    glBindBuffer(GL_ARRAY_BUFFER, myColorBufferID);
    glBufferData(
        GL_ARRAY_BUFFER,
        3 * myData.VertexCount()*sizeof(GL_FLOAT),
        myData.Color(),
        GL_STREAM_DRAW);
    glVertexAttribPointer(
        1,                                // attribute. No particular reason for 1, but must match the layout in the shader.
        3,                                // size
        GL_FLOAT,                         // type
        GL_FALSE,                         // normalized?
        0,                                // stride
        (void*)0                          // array buffer offset
    );

    glDrawArrays(GL_TRIANGLES, 0, myData.VertexCount() );

    glDisableVertexAttribArray(0);
    glDisableVertexAttribArray(1);

    glFlush();
    myCanvas->SwapBuffers();

}

【问题讨论】:

  • “预先存在的数据存储已被删除”而不是“数据存储d”您如何渲染旧数据?刷新的时候不更新吗?您是否在 glDrawXXX 上使用了不同的 count 与在 glBufferData 中使用的不匹配?您希望如何重用您之前声明为已删除的数据?请多解释一下。
  • 考虑像 C++ 指针一样的 bufferID(即“数据存储”)。您可以删除指针而不清除指向的数据。仅将内存再次标记为空闲。
  • glBufferData 是缓冲区副本,而不是缓冲区映射 - 存储应该被认为是新的并且未初始化。如果您在渲染时看到旧数据,则说明您正在上传旧数据,或者以某种方式触发了未定义的行为(例如,渲染了太多顶点)。

标签: opengl


【解决方案1】:

您的代码不正确。您将顶点属性指针设置为每个顶点读取 3 个GLfloats,并使用myData.VertexCount() 作为绘图调用中的顶点数,但您仅将myData.VertexCount()*sizeof(GL_FLOAT) 字节上传到VBO。结果,您将读取超出缓冲区末尾的方式,结果只是未定义的行为。

.

【讨论】:

  • 我想我明白了。我需要写
    glDrawArrays(GL_TRIANGLES, 0, myData.VertexCount() / 3 );
  • 你可以这样做,但我建议你打电话给VertexCount 别的东西,因为这不是名字所暗示的。
  • 这是测试我对您答案的理解的快速解决方案。在生产代码中,我保持 glDrawArrays 调用不变,并将传递给 glBufferData 的字节数写入并增加了三倍
【解决方案2】:

发生的情况是,当您调用glBufferData 时,GL 驱动程序会在其内存中为您提供一个位置,该位置可能与之前的位置相同。你认为你可以用glBufferData 更新整个的一部分,但事实并非如此。其余的可能与旧数据一致,也可能不一致。

我认为您最好使用glBufferSubData 而不是glBufferData 来更新新数据(或其中的一部分),而无需删除和重新创建数据存储。

newSize > oldSize 时需要删除并重新创建。

【讨论】:

  • 这个解释是有道理的。它没有解释为什么要绘制旧数据。我用正确的、减少的顶点数调用 glDrawArrays,但它会继续渲染顶点数。
  • 您在glBufferData之前是否再次致电glBindBuffer
  • 不确定您所说的“再次”是什么意思。我确实在 glBufferData 之前调用了 glBindBuffer
猜你喜欢
  • 2020-12-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多