在OpenGL中使用struct作为索引缓冲区对象会导致segfault

时间:2013-08-23 03:29:20

标签: c++ c opengl struct valgrind

我一直在使用std::vector<glm::vec3>来存储顶点属性,一切正常,渲染各种不同的网格物体。但是在重构之后我的顶点属性存储在结构中我无法获得最简单的渲染。这是结构(简化):

struct Vertex{
  GLfloat x, y, z;        //Vertex
  GLfloat r, g, b, a;     //Color
};

我有两个std::vector,一个用于存储顶点属性,另一个用于索引:

std::vector<GLushort> indices;
std::vector<struct Vertex> vertices;

在初始化函数中,我用一个简单的绿色三角形填充这些向量:

struct Vertex vertex1;
vertex1.x=1.0;
vertex1.y=0.0;
vertex1.z=0.0;
vertex1.r=0.0;
vertex1.g=1.0;
vertex1.b=0.0;
vertex1.a=1.0;
vertices.push_back(vertex1);
struct Vertex vertex2;
vertex2.x=0.0;
vertex2.y=1.0;
vertex2.z=0.0;
vertex2.r=0.0;
vertex2.g=1.0;
vertex2.b=0.0;
vertex2.a=1.0;
vertices.push_back(vertex2);
struct Vertex vertex3;
vertex3.x=1.0;
vertex3.y=1.0;
vertex3.z=0.0;
vertex3.r=0.0;
vertex3.g=1.0;
vertex3.b=0.0;
vertex3.a=1.0;
vertices.push_back(vertex3);

indices.push_back(1);
indices.push_back(2);
indices.push_back(3);

然后我绑定缓冲区:

glGenBuffers(1, &ibo_elements);
glBindBuffer(GL_ARRAY_BUFFER, ibo_elements);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(struct Vertex), &vertices[0], GL_STATIC_DRAW);

glGenBuffers(1, &elementbuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementbuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(GLushort), &indices[0], GL_STATIC_DRAW);

然后在设置着色器程序和绑定属性名称后,我使用glutDisplayFunc来运行此回调:

#define BUFFER_OFFSET(i) ((char *)NULL + (i))

void onDisplay()
{
  glClearColor(0.0, 0.0, 0.0, 1.0);
  glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

  glUseProgram(program);

  glBindBuffer(GL_ARRAY_BUFFER, ibo_elements);
  glVertexAttribPointer(
                        attribute_v_coord,
                        3,
                        GL_FLOAT,
                        GL_FALSE,
                        sizeof(struct Vertex),
                        BUFFER_OFFSET(0)
                        );
  glEnableVertexAttribArray(attribute_v_coord);

  glBindBuffer(GL_ARRAY_BUFFER, colorbuffer);
  glVertexAttribPointer(
                        attribute_v_color,
                        4,
                        GL_FLOAT,
                        GL_FALSE,
                        sizeof(struct Vertex),
                        BUFFER_OFFSET(sizeof(GLfloat)*3)
                        );
  glEnableVertexAttribArray(attribute_v_color);

  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementbuffer);
  int size; glGetBufferParameteriv(GL_ELEMENT_ARRAY_BUFFER, GL_BUFFER_SIZE, &size);
  glDrawElements(GL_TRIANGLES, size/sizeof(GLushort), GL_UNSIGNED_SHORT, 0);

  glDisableVertexAttribArray(attribute_v_coord);
  glDisableVertexAttribArray(attribute_v_color);
  glutSwapBuffers();
}

一切都与我以前的工作非常相似。所以我猜它与数据结构的变化有关。 Valgrind显示了这个错误:

==5382== Invalid read of size 4
==5382==    at 0x404EF6A: ??? (in /tmp/glR69wrn (deleted))
==5382==    by 0x870E8A9: ??? (in /usr/lib/libnvidia-glcore.so.325.15)
==5382==    by 0x200000003: ???
==5382==    by 0x404EEBF: ??? (in /tmp/glR69wrn (deleted))
==5382==    by 0x2: ???
==5382==    by 0xAFFC09F: ???
==5382==    by 0x41314D3: ???
==5382==    by 0x40E6FFF: ??? (in /dev/nvidia0)
==5382==    by 0xFFFFFFFE: ???
==5382==  Address 0x28 is not stack'd, malloc'd or (recently) free'd

我没有正确定义顶点属性指针吗?看起来OpenGL正试图读取一个从未正确设置的浮点数。

2 个答案:

答案 0 :(得分:4)

在这种情况下,您应该为每个顶点attrib指针使用单个VBO。您正在提供具有交错数据的单个数据存储。您需要做的就是更改设置顶点attrib指针的调用,以便它们具有正确的步幅和基址偏移地址。所以这个“colorbuffer”VBO(这是一个糟糕的名字选择,因为OpenGL已经有一个叫做colorbuffer 的东西)很可能是你问题的来源

另一个问题,如其他地方所提到的,你的元素索引从1开始。在这个例子中你有3个顶点,元素缓冲区应该填充0,1,2的某种组合。在元素缓冲区中有3个将在绘制时导致未定义的行为。很多时候,如果使用无效索引,驱动程序不会崩溃,而且遗憾的是GL没有索引超出范围的错误状态。通常你只知道在这种情况下出现问题,因为垃圾出现在你的屏幕上。

我担心如果不从GL状态机查询该信息,您甚至不知道IBO中有多少元素。那是糟糕的应用程序设计,遗憾的是。你一定要知道你想要绘制多少元素。 VBO应该包含在数据结构或类中(至少包括分配的元素数量),你不想简单地抛弃缓冲区对象句柄而不知道它们代表什么。


使用顶点颜色的浮点值也很浪费,几乎不需要它们(GLubyte和0-255通常运行良好)。 1 GLfloat占用的内存与4 GLubytes一样多,而您正在使用4 GLfloats ...如果您选择使用xyz,则使用4 GLubytes也可以帮助对齐of xyzw for vertex position。

在较旧的硬件上,4x GLubyte颜色是硬件T&amp; L的“快速路径”。他们仍然在较新的硬件上占用较少的内存,因此几乎在所有情况下它们都是胜利:)

答案 1 :(得分:1)

indices.push_back(0);
indices.push_back(1);
indices.push_back(2);

另外,打印尺寸时会得到什么?

我也习惯在不需要时解除缓冲区的绑定:

glBindBuffer(GL_ARRAY_BUFFER, 0); //etc

最后......

glBindBuffer(GL_ARRAY_BUFFER, colorbuffer); //what's colorbuffer?

(因为你是从同一个ibo_elements缓冲区进行交错,所以这一行应该在这里吗?)