【问题标题】:Using VBO to draw line string使用VBO画线串
【发布时间】:2015-08-19 09:40:39
【问题描述】:

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

    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);

和绘图调用。我注意到第一行的最后一个点正在连接到该行的第一个点。

    glDrawArrays(GL_LINE_STRIP, 0,pt_count);

【问题讨论】:

    标签: opengl vector shader vbo polyline


    【解决方案1】:

    glBufferData

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

    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:

    指定连续通用顶点属性之间的字节偏移量。如果 stride 为 0,则通用顶点属性被理解为紧密封装在数组中。初始值为 0。 reference

    【讨论】:

    • size_t pt_count = 0; for(int i=0;i
    • 是的,代码相同,只是没有基于范围的 for 循环。有效吗?
    • 我可以从我的数据中查看我期望的几行 3k 行
    • 你能检查一下 pt_count 是否适合你的总点数吗?以及子数据循环之后是否 start == pt_count * sizeof(Point) ?你在绘图命令中使用 pt_count 作为顶点数吗?
    • :-) 非常感谢,我错过了 pt_count 部分并在验证子数据循环后开始 == pt_count * sizeof(Point)。
    【解决方案2】:

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

    //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);  
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-09
      • 1970-01-01
      • 2013-09-19
      • 1970-01-01
      • 1970-01-01
      • 2018-04-15
      相关资源
      最近更新 更多