glDrawElements crash (OpenGL 3.2 / Windows 7)

做~自己de王妃 提交于 2019-12-18 17:26:27

问题


I'm trying to draw a simple quad in OpenGL 3.2 however the application crashes with "Access violation reading location 0x00000000" when I call "glDrawElements".

I assume the issue is that the Vertex Buffer data is wrong, but I am unsure how to fix the issue / debug it (an OpenGL trace would be fantastic but I do not know how to enable this either...)

Initialization code:

std::vector<CUShort> Indices;
const CUShort IndicesArray[] = { 0, 1, 2, 2, 0, 3 };

for(size_t j = 0; j < 1; j++) {
    for(size_t i = 0; i < sizeof(IndicesArray) / sizeof(*IndicesArray); i++) {
        Indices.push_back(4 * j + IndicesArray[i]);
    }
}

glGenBuffers(1, &m_Elements);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_Elements);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, Indices.size() * sizeof(CUShort), &Indices[0], GL_STATIC_DRAW);

glGenVertexArrays(1, &m_Array);
glBindVertexArray(m_Array);

glGenBuffers(1, &m_Buffer);
glBindBuffer(GL_ARRAY_BUFFER, m_Buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(TexColorVertex), NULL, GL_DYNAMIC_DRAW);

glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_TRUE, sizeof(TexColorVertex), (const GLvoid*)offsetof(TexColorVertex, Color));

glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(TexColorVertex), (const GLvoid*)offsetof(TexColorVertex, Position));

glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(TexColorVertex), (const GLvoid*)offsetof(TexColorVertex, Texcoord));

glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

Drawing code:

glBindBuffer(GL_ARRAY_BUFFER, m_Buffer);

TexColorVertex Vertices[4];

glm::vec4 SpritePos = glm::vec4(0, 0, 1024.0f, 384.0f);
Vertices[0].Position = glm::vec2(SpritePos.x, SpritePos.y);
Vertices[1].Position = glm::vec2(SpritePos.x, SpritePos.w);
Vertices[2].Position = glm::vec2(SpritePos.z, SpritePos.w);
Vertices[3].Position = glm::vec2(SpritePos.z, SpritePos.y);

Color Kittens = Color::HotPink();
Vertices[0].Color = glm::vec4(Kittens.R(), Kittens.G(), Kittens.B(), 1.0f);
Vertices[1].Color = glm::vec4(Kittens.R(), Kittens.G(), Kittens.B(), 1.0f);
Vertices[2].Color = glm::vec4(Kittens.R(), Kittens.G(), Kittens.B(), 1.0f);
Vertices[3].Color = glm::vec4(Kittens.R(), Kittens.G(), Kittens.B(), 1.0f);

Vertices[0].Texcoord = glm::vec2(0.0f, 0.0f);
Vertices[1].Texcoord = glm::vec2(0.0f, 1.0f);
Vertices[2].Texcoord = glm::vec2(1.0f, 1.0f);
Vertices[3].Texcoord = glm::vec2(1.0f, 0.0f);

glBufferSubData(GL_ARRAY_BUFFER, sizeof(Vertices), sizeof(Vertices), Vertices);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_Elements);
glBindVertexArray(m_Array);

glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, (const GLvoid*)0);

The vertex struct is declared as such:

struct TexColorVertex
{
    TexColorVertex(void) { }
    TexColorVertex(glm::vec2 const& Position, glm::vec2 const& Texcoord) :
        Position(Position), Texcoord(Texcoord)
    { }
    glm::vec2 Position;
    glm::vec2 Texcoord;
    glm::vec4 Color;
};

Does anyone have any suggestions on how to fix this and draw a simple quad that takes up half the screen?


回答1:


While user3256930 does bring up a valid point about the allocated size of your buffer, that is actually not the cause of your crash.

The problem is not with glBufferSubData (...), but rather with the call to glDrawElements (...). This call is attempting to dereference a NULL pointer, which is a red flag that nothing is bound to GL_ELEMENT_ARRAY_BUFFER.

When nothing is bound to GL_ELEMENT_ARRAY_BUFFER, then the pointer you pass to glDrawElements (...) is an actual pointer to client memory rather than an offset into Buffer Object (server) memory.


To understand why this occurs, recall what Vertex Array Objects store:

  1. Vertex Attribute State [Pointers, Enable/Disable]
  2. Element Array Buffer Binding (GL_ELEMENT_ARRAY_BUFFER)

Now, consider the order of these two calls:

glBindBuffer      (GL_ELEMENT_ARRAY_BUFFER, m_Elements);
glBindVertexArray (m_Array);

First you bind something to GL_ELEMENT_ARRAY_BUFFER (m_Elements) and immediately afterwards you bind a Vertex Array Object (m_Array), which replaces the element array buffer you just bound with the binding it keeps track of internally.

You should consider either (1) using your VAO to persistently reference a single element array buffer or (2) reversing the order of these two calls.


If your Vertex Array Object (m_Array) will always be used with the same element array buffer, then I would suggest you use the first approach. This can be implemented simply by moving the following code in your initialization:

glGenVertexArrays (1, &m_Array);
glBindVertexArray (m_Array);

To come before:

glGenBuffers (1, &m_Elements);
glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, m_Elements);
glBufferData (GL_ELEMENT_ARRAY_BUFFER, Indices.size() * sizeof(CUShort), &Indices[0], GL_STATIC_DRAW);

With this approach, nothing needs to be explicitly bound to GL_ELEMENT_ARRAY_BUFFER in your drawing code.




回答2:


You are not allocating enough space for your vertices in your call to glBufferData. You pass sizeof(TexColorVertex) which allocates space for 1 vertex. If you want to draw a quad then you need to allocate space for 4 vertices so you should change your call to glBuffer Data as follows:

glBufferData(GL_ARRAY_BUFFER, 4*sizeof(TexColorVertex), NULL, GL_DYNAMIC_DRAW);

That way when you make your subsequent calls to glBufferSubData you will not be attempting to access GPU memory that is out of range.



来源:https://stackoverflow.com/questions/23026612/gldrawelements-crash-opengl-3-2-windows-7

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!