OpenGL glBufferSubData 偏移问题

Posted

技术标签:

【中文标题】OpenGL glBufferSubData 偏移问题【英文标题】:OpenGL glBufferSubData Offset issue 【发布时间】:2020-06-13 04:46:38 【问题描述】:

我在使用 glBufferSubData() 将所有数据复制/上传到缓冲区时遇到问题。我想逐块复制到缓冲区。所以我使用了这种方法。当我尝试渲染时,我看到一个空白屏幕。请在下面找到我的代码。您在计算缓冲区偏移量时看到任何问题吗?或者这不是将数据复制到缓冲区的方法吗?

下面是数据结构

struct DisplayIndexID 
        int idx;
        DrawStateT drawState;
        //Every display Index ID has its own draw models.
        std::vector<std::unique_ptr<vertexModel>> readytoDrawModels;
    ;


void initVboData(std::vector<DisplayIndexID> & v)


    glBindBuffer(GL_ARRAY_BUFFER, geomVBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(QVector3D) * 4096, NULL, GL_DYNAMIC_DRAW);

    std::vector<QVector3D> vecToDraw;
    GLintptr offset = 0;

    for (int i = 0; i < v.size(); i++) 
        for (auto& vModel : v[i].readytoDrawModels)
        
            if (vModel) 
                vecToDraw = vModel->getVertices();
                glBufferSubData(GL_ARRAY_BUFFER, offset, sizeof(QVector3D) * vecToDraw.size(), &vecToDraw[0]);
                offset += sizeof(QVector3D) * vecToDraw.size(); // is this offset calculation fine?
            
        

 

 //Below is my draw function

 void drawDisplayLists(std::vector<DisplayIndexID> & v) 

    initVboData(v);
    for (int i = 0; i < v.size(); i++)
    
        //Make context current      
        makeCurrent();
        bool isTextureUsed = false;

        //Apply Projection Matrix.
        GLint mvp_mat = 0;
        GLint mvp_matText = 0;

        ///***********PRINT AREA***********************/
        for (auto& vModel : v[i].readytoDrawModels)
        
         // Code related to Shaders
            ......


          glEnableVertexAttribArray(0);
          glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(QVector3D), nullptr);  how to get the offset and add offset here. 

switch (vModel->getDrawMode())
    
                case 0: //GL_POINTS
                    glDrawArrays(GL_POINTS, 0, vModel->getVertices().size());
                    break;

                case 1: //GL_LINES
                    glDrawArrays(GL_LINES, 0, vModel->getVertices().size());
                    break;

                case 2: //GL_LINE_LOOP
                    glDrawArrays(GL_LINE_LOOP, 0, vModel->getVertices().size());
                    break;
                
        
    

【问题讨论】:

您的 drawDisplayLists()initVboData() 不匹配 - 您突然在方法中使用了 vModel 变量 undefined。如果drawDisplayLists() 以与初始化相同的方式迭代v,则应在循环中使用偏移量调用glVertexAttribPointer()。请在报价中添加缺失的代码。 非常感谢。我已经在编辑部分更新了我的代码。是的,甚至 drawDisplayLists() 以与初始化相同的方式迭代 v。请让我知道如何为 glVertexAttribPointer() 调用添加偏移量。谢谢,非常感谢。 @gkv311 “那么 glVertexAttribPointer() 应该在循环中使用偏移量调用” - 抱歉,这是错误的。只有顶点坐标,所以不需要偏移。如果要绘制网格的特定区域,则必须在 glDrawArrays 处指定偏移量和不同的大小 谢谢大家。如果我将 glBufferSubData() 移动到 for 循环下的 drawDisplayList() 内,它就可以工作。但我不想每帧都复制块。这可能会影响性能。所以我想到了之前复制它并在框架开始之前准备好它。有什么办法可以做到这一点吗?因为我的顶点不会改变。一切都存储在向量中。我还尝试使用 glBufferData() 复制整个缓冲区。这没有用。如何解决这个问题?非常感谢。 @Rabbid76 glVertexAttribPointer()glDrawArrays() 都可用于指定偏移量 - 执行此操作的位置取决于条件。如果可能,将偏移量传递给glDrawArrays() 可能会减少一点开销。 【参考方案1】:

考虑到您已经像这样初始化了持久 VBO:

  GLintptr offset = 0;
  for (int i = 0; i < v.size(); i++) 
    for (auto& vModel : v[i].readytoDrawModels) 
      if (vModel) 
        vecToDraw = vModel->getVertices();
        glBufferSubData(GL_ARRAY_BUFFER, offset, sizeof(QVector3D) * vecToDraw.size(), &vecToDraw[0]);
        offset += sizeof(QVector3D) * vecToDraw.size();
      
    
  

那么您应该在绘图循环中复制相同的偏移量。 这可以通过将字节偏移量传递给glVertexAttribPointer() 来完成,其计算方式与 VBO 初始化期间完全相同:

  GLintptr offset = 0;
  for (int i = 0; i < v.size(); i++) 
    for (auto& vModel : v[i].readytoDrawModels) 
      if (vModel) 
        vecToDraw = vModel->getVertices();
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(QVector3D), offset);
        glDrawArrays(GL_LINES, 0, vecToDraw.size());
        offset += sizeof(QVector3D) * vecToDraw.size();
      
    
  

或通过将顶点数量的偏移量传递给glDrawArrays(),以防所有模型具有与您的代码 sn-p (in vec3 Position) 中相同的顶点定义:

  GLintptr aFirstIndex = 0;
  glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(QVector3D), nullptr);
  for (int i = 0; i < v.size(); i++) 
    for (auto& vModel : v[i].readytoDrawModels) 
      if (vModel) 
        vecToDraw = vModel->getVertices();
        glDrawArrays(GL_LINES, aFirstIndex, vecToDraw.size());
        aFirstIndex += vecToDraw.size();
      
    
  

确保分配的 VBO 具有适当的大小,并将 4096 替换为实际大小:

    glBufferData(GL_ARRAY_BUFFER, sizeof(QVector3D) * 4096, NULL, GL_DYNAMIC_DRAW);

顺便说一句,按GL_POINTS/GL_LINES 数组类型和相同的表示属性(颜色/材质/等)对模型进行分组将允许使用单个glDrawArrays() 调用来渲染每个组,而不是大量的glDrawArrays()对于每个模型,从性能的角度来看,这将是更优化的。

【讨论】:

非常感谢@gkv311。有效。惊人的 !性能也有所提升。

以上是关于OpenGL glBufferSubData 偏移问题的主要内容,如果未能解决你的问题,请参考以下文章

结构的 glBufferSubData 偏移量

在 OpenGL ES Android 中使用 glBufferSubData 和 glMultiDrawArrays

OpenGL glBufferSubData - 无法让它工作

为啥 glBufferSubData 需要等到 glDrawElements 不使用 VBO?

OpenGL +无法使用buffersubdata更新缓冲区数据

OpenGL 属性偏移未按预期工作