我一直在使用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;
在初始化函数中,我用一个简单的绿色三角形填充这些 vector :
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);
然后我绑定(bind)缓冲区:
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);
然后在设置着色器程序并绑定(bind)属性名称后,我使用 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 正在尝试读取从未正确设置的 float 。
最佳答案
在这种情况下,您应该为每个顶点属性指针使用单个 VBO。您正在提供具有交错数据的单个数据存储。您需要做的就是更改设置顶点属性指针的调用,以便它们具有正确的步长和基偏移地址。因此,这个“颜色缓冲区”VBO(这是一个糟糕的名称选择,因为 OpenGL 已经有一种称为颜色缓冲区的东西)很可能是问题的根源。。 p>
另一个问题,正如其他地方提到的,是你的元素索引从 1 开始。在这个例子中你有 3 个顶点,元素缓冲区应该填充 0,1,2 的某种组合。元素缓冲区中有 3 个元素将导致绘制时出现未定义的行为。很多时候,如果您使用无效索引,驱动程序不会崩溃,而且遗憾的是 GL 没有索引越界的错误状态。通常,在这种情况下您只知道出了问题,因为屏幕上出现了垃圾。
我担心如果不从 GL 状态机查询该信息,您甚至不知道 IBO 中有多少个元素。抱歉,这是糟糕的应用程序设计。您应该事先知道要绘制多少个元素。无论如何,VBO 应该包装在数据结构或类中(至少包括分配的元素数量),您不想简单地在缓冲区对象句柄上乱七八糟,而不知道它们代表什么。
此外,使用浮点值作为顶点颜色可能会很浪费,您几乎从不需要它们(GLubyte
和 0-255 通常效果很好)。 1 个 GLfloat 占用的内存相当于 4 个 GLubytes,而您正在使用 4 个 GLfloat...使用 4 个 GLubytes如果您选择使用 xyz 而不是 xyzw 作为顶点位置,还可以帮助对齐。
在较旧的硬件上,4x GLubyte 颜色是硬件 T&L 的“快速路径”。它们在较新的硬件上占用的内存仍然较少,因此几乎在所有情况下它们都是胜利:)
关于c++ - 在 OpenGL 中使用索引缓冲区对象的结构会导致段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18394247/