使用VBO绘制线串

Using VBO to draw line string

我可以使用 OpenGL 中的 VBO 和着色器渲染以下点 4.x。

    typedef struct Point
    {
        double x,y,z,w;
    }Point;

    std::vector<Point>vPoints;

    glBufferData(GL_ARRAY_BUFFER,  vPoints.size()* sizeof(Point),  &vPoints[0], GL_STATIC_DRAW);
    glVertexAttribPointer(0, 4, GL_DOUBLE, GL_FALSE, vPoints.size()*sizeof(GLdouble), (GLvoid*)0)

我们如何指定 VBO 使用以下变量绘制线串

    typedef struct LineString
    {
     vector<Point> vPointList;

    }LineString;
    vector<LineString> vLines;
    glBufferData(GL_ARRAY_BUFFER,  ????,  ????, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 4, GL_DOUBLE, GL_FALSE, ????, (GLvoid*)0)

我尝试了以下设置,但它似乎不起作用

   glBufferData(GL_ARRAY_BUFFER,  vLines.size()* sizeof(LineString)*sizeof(Point),  &vLines[0].vPointList[0], GL_STATIC_DRAW);
   glVertexAttribPointer(0, 4, GL_DOUBLE, GL_FALSE, vLines.size()*sizeof(GLdouble), (GLvoid*)0);   

我以为我几乎可以通过以下代码创建 VBO

         for(int i=0;i< vLines.size();i++)
           pt_count += vLines[i].vPointList.size();

  fprintf( stdout, "Total point Count: %d\n", pt_count);    
  glBufferData(GL_ARRAY_BUFFER, pt_count * sizeof(Point), nullptr, GL_STATIC_DRAW);

size_t start = 0;
for(int i=0;i< vLines.size();i++)
{
    size_t v_size =vLines[i].vPointList.size() * sizeof(Point);
    glBufferSubData(GL_ARRAY_BUFFER, start, v_size, &vLines[i].vPointList[0]);
    start += v_size;
}

if(start == pt_count * sizeof(Point) )
{
    fprintf( stdout, "INFO: %s\n", "Same count");   

}

glVertexAttribPointer(0, 4, GL_DOUBLE, GL_FALSE, 4 * sizeof(GLdouble), (GLvoid*)0);

和绘图 call.I 注意到第一条线的最后一个点连接到线的第一个点。

    glDrawArrays(GL_LINE_STRIP, 0,pt_count);

glBufferData

对于 glBufferData,需要以字节为单位的数据总大小。此外,需要一个连续的内存段,vector<vector<T>> 不提供。从技术上讲,每个内部向量都有自己的存储数据的内存段,这使得无法一次上传数据。我想到的唯一方法是首先像这样计算总大小:

size_t pt_count = 0;
for (auto& v : vLines)
    pt_count += v.vPointList.size();

分配GPU内存,但不上传任何数据

glBufferData(GL_ARRAY_BUFFER, pt_count * sizeof(Point), nullptr, GL_STATIC_DRAW);

最后一步是逐步上传所有点:

size_t start = 0;
for (auto& v : vLines)
{
    size_t v_size = v.vPointList.size() * sizeof(Point);
    glBufferSubData(GL_ARRAY_BUFFER, start, v_size, &v.vPointList[0]);
    start += v_size;
}

但是如果你可以在 C++ 代码中改变数据布局,我强烈建议你首先将所有的点存储在一个连续的内存段中。

glVertexAttribPointer

glVertexAttribPointer 的第五个参数告诉OpenGL 缓冲区中连续顶点之间的偏移量。所以想像这样的缓冲区:

        | x | y | z | w | x | y | z | w |
stride  |-------------->|-------------->|

这是必需的,因为这是可能的,在两个顶点条目之间存储额外的数据。在您的情况下,偏移量必须为 4 * sizeof(GLdouble),或者由于数据紧凑,因此 0:

Specifies the byte offset between consecutive generic vertex attributes. If stride is 0, the generic vertex attributes are understood to be tightly packed in the array. The initial value is 0. reference

可以通过使用 glMultiDrawArrays() 来解决这个问题。通过正确指定索引找到解决方案 positions.The 代码在修复后如下所示。

//globals
size_t pt_count = 0;
GLint  *startIndices;
GLint *endIndices;
GLint nLineCount;


//create the VBO
for(int i=0;i< vLines.size();i++)
    pt_count += vLines[i].vPointList.size();


  startIndices= new GLint[vLines.size()];
  endIndices= new GLint[vLines.size()];


  fprintf( stdout, "Total point Count: %d\n", pt_count);    
  glBufferData(GL_ARRAY_BUFFER, pt_count * sizeof(POINT), nullptr, GL_STATIC_DRAW);

    size_t start = 0;
    size_t firsts=0;
    for(int i=0;i< vLines.size();i++)
    {


        size_t v_size =vLines[i].vPointList.size() * sizeof(POINT);

        glBufferSubData(GL_ARRAY_BUFFER, start, v_size, &vLines[i].vPointList[0]);
        start += v_size;

        startIndices[i]=firsts;
        endIndices[i]=vLines[i].vPointList.size();
        firsts+=endIndices[i];
        fprintf( stdout, "start: %d\n",startIndices[i]);
        fprintf( stdout, "size: %d\n", endIndices[i] );

    } 


    if(start == pt_count * sizeof(POINT) )
    {
        fprintf( stdout, "INFO: %s\n", "Same count");   

    }

  glVertexAttribPointer(0, 4, GL_DOUBLE, GL_FALSE,  4 * sizeof(GLdouble), (GLvoid*)0);

  nLineCount=vLines.size();
  vLines.clear();
 //Draw the lines
 glMultiDrawArrays(GL_LINE_STRIP, startIndices,endIndices,nLineCount);