OpenGL 3.x:使用顶点缓冲对象和glDrawElements(...)时出现访问冲突

4
我在使用顶点缓冲对象时遇到了一些几何渲染问题。我想要绘制一个点平面,也就是在我的空间中每个离散位置上都有一个顶点。然而,我无法渲染这个平面,因为每次调用glDrawElements(...)时,应用程序都会崩溃并返回访问冲突异常。我猜测初始化时出现了一些错误。以下是我目前的代码:
#define SPACE_X 512
#define SPACE_Z 512

typedef struct{
    GLfloat x, y, z; // position
    GLfloat nx, ny, nz; // normals
    GLfloat r, g, b, a; // colors
} Vertex;

typedef struct{
    GLuint i; // index
} Index;

// create vertex buffer
GLuint vertexBufferObject;
glGenBuffers(1, &vertexBufferObject);

// create index buffer
GLuint indexBufferObject;
glGenBuffers(1, &indexBufferObject);

// determine number of vertices / primitives
const int numberOfVertices = SPACE_X * SPACE_Z;
const int numberOfPrimitives = numberOfVertices; // As I'm going to render GL_POINTS, number of primitives is the same as number of vertices

// create vertex array
Vertex* vertexArray = new Vertex[numberOfVertices];

// create index array
Index* indexArray = new Index[numberOfPrimitives];

// create planes (vertex array)
// color of the vertices is red for now
int index = -1;
for(GLfloat x = -SPACE_X / 2; x < SPACE_X / 2; x++) {
    for(GLfloat z = -SPACE_Z / 2; z < SPACE_Z / 2; z++) {
        index++;
        vertexArray[index].x = x;
        vertexArray[index].y = 0.0f;
        vertexArray[index].z = z;
        vertexArray[index].nx = 0.0f;
        vertexArray[index].ny = 0.0f;
        vertexArray[index].nz = 1.0f;
        vertexArray[index].r = 1.0;
        vertexArray[index].g = 0.0;
        vertexArray[index].b = 0.0;
        vertexArray[index].a = 1.0;
    }
}

// bind vertex buffer
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject);

// buffer vertex array
glBufferData(GL_ARRAY_BUFFER, numberOfVertices * sizeof(Vertex), vertexArray, GL_DTREAM_DRAW);

// bind vertex buffer again
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject);

// enable attrib index 0 (positions)
glEnableVertexAttribArray(0);

// pass positions in
glVertexAttribPointer((GLuint)0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), vertexArray);

// enable attribute index 1 (normals)
glEnableVertexAttribArray(1);

// pass normals in
glVertexAttribPointer((GLuint)1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), &vertexArray[0].nx);

// enable attribute index 2 (colors)
glEnableVertexAttribArray(2);

// pass colors in
glVertexAttribPointer((GLuint)2, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), &vertexArray[0].r);

// create index array
for(GLunit i = 0; i < numberOfPrimitives; i++) {
    indexArray[i].i = i;
}

// bind buffer
glBindBuffer(GL_ELEMENET_ARRAY_BUFFER, indexBufferObject);

// buffer indices
glBufferData(GL_ELEMENET_ARRAY_BUFFER, numberOfPrimitives * sizeof(Index), indexArray, GL_STREAM_DRAW);

// bind buffer again
glBindBuffer(GL_ELEMENET_ARRAY_BUFFER, indexBufferObject);

// AND HERE IT CRASHES!
// draw plane of GL_POINTS
glDrawElements(GL_POINTS, numberOfPrimitives, GL_UNSIGNED_INT, indexArray);

// bind default buffers
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

// delete vertex / index buffers
glDeleteBuffers(1, &vertexBufferObject);
glDeleteBuffers(1, &indexBufferObject);

delete[] vertexArray;
vertexArray = NULL;

delete[] indexArray;
indexArray = NULL;

请始终说明您的OpenGL版本 - 3.x有些模糊。顺便说一句 - 在任何glVertexAttribPointerglEnableVertexAttribArray之前创建和绑定顶点数组对象是一个好习惯。您可能正在使用OpenGL兼容性配置文件,因此没有因此出现错误。 - Kos
好的,我猜3.x版本有点含糊。我认为即使是GL的次要版本之间也存在重大差异。所以,目前我正在使用OpenGL 3.3。 - Walter
3个回答

6

当您使用缓冲区对象时,gl*Pointer中的最后一个参数和glDrawElements中的第4个参数不再是主存储器中的地址(但您的仍然是!),而是偏移量。请确保以字节为单位计算这些偏移量!"offsetof"宏在此非常有帮助。


没错 - 如果任何VBO被绑定到GL_ELEMENT_ARRAY_BUFFER,那么最后一个参数将使用缓冲区的相对位置作为寻址基础。 值0表示“当前绑定的VBO的开头”。 操作符offsetof确实会帮助您。 - Kos
这是一个有趣的观点。所以如果我理解正确,对于颜色它应该是这样的:glVertexAttribPoint(1, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid *)(offsetof(Vertex, r))); 是这样吗? - Walter
你说得对!那就是我问题的解决方案!不仅仅是我错误地使用了glEnableClientState(...),还误解了你提到的参数。感谢你的提示。我的应用程序现在运行正常了... - Walter
它是glDrawElements的第四个参数,而不是第三个。 - user492238

0

似乎我没有看到树木。我知道那个页面,但由于某种原因,我忽略了“glEnableClientState(...)”已被弃用的事实!这有点尴尬。抱歉打扰你了。 - Walter
那是唯一的问题吗?你的代码现在正常工作了吗? - Bojan
嗯,它有点能用。我现在有一些其他的问题。 在摆脱了glEnableClientState(...)之后,我实际上第一次能够运行应用程序。然而,由于在一段时间后崩溃,因此它并不像预期的那样工作。所以,我试图找出究竟是什么导致了崩溃。 如果我省略创建顶点缓冲对象和绘制其顶点,则该应用程序可以在良好的速度下正常工作。但是,一旦添加上述代码,它可能需要15秒钟,然后应用程序崩溃。 - Walter

0

方法glEnableClientState(...)已经被弃用了!很抱歉,由于某些原因我忽略了这个事实。


1
glEnableClientState不仅已经废弃,而且在这里是不正确的-请记住,您要在VBO(即在GPU的内存中,而不是客户端的内存中)中指向顶点。如果它在VBO中,则不再是客户端状态。 :) - Kos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接