glDrawElements崩溃(OpenGL 3.2 / Windows 7)

时间:2014-04-12 05:43:39

标签: c++ opengl opengl-3 glm-math

我试图在OpenGL 3.2中绘制一个简单的四边形但是应用程序崩溃了"访问冲突读取位置0x00000000"当我打电话给" glDrawElements"。

我认为问题在于顶点缓冲区数据是错误的,但我不确定如何解决问题/调试它(OpenGL跟踪会很棒,但我不知道如何启用它...)< / p>

初始化代码:

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

绘图代码:

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

顶点结构声明如下:

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

有没有人对如何解决此问题有任何建议,并绘制一个占据屏幕一半的简单四边形?

2 个答案:

答案 0 :(得分:13)

虽然user3256930确实提出了有关缓冲区分配大小的有效点,但实际上并不是导致崩溃的原因。

glBufferSubData (...)问题,而是调用glDrawElements (...)。此调用尝试取消引用 NULL 指针,这是一个红色标记,表示没有绑定到GL_ELEMENT_ARRAY_BUFFER

如果没有绑定到GL_ELEMENT_ARRAY_BUFFER,则传递给glDrawElements (...)的指针是指向客户端内存的实际指针,而不是缓冲区对象的偏移量(服务器)内存。


要了解这种情况发生的原因,请回想一下顶点数组对象存储:

  1. 顶点属性状态[指针,启用/禁用]
  2. 元素数组缓冲区绑定 GL_ELEMENT_ARRAY_BUFFER
  3. 现在,考虑这两个调用的顺序:

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

    首先将某些内容绑定到GL_ELEMENT_ARRAY_BUFFER m_Elements ),然后立即绑定一个顶点数组对象( m_Array ),它将替换元素数组缓冲区只是绑定它在内部跟踪的绑定。

    您应该考虑(1)使用您的VAO持久引用单个元素数组缓冲区或(2)反转这两个调用的顺序。


    如果您的顶点数组对象( m_Array )将始终与相同的元素数组缓冲区一起使用,那么我建议您使用第一种方法。这可以通过在初始化中移动以下代码来实现:

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

    之前

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

    使用这种方法,不需要在绘图代码中将任何内容明确绑定到GL_ELEMENT_ARRAY_BUFFER

答案 1 :(得分:4)

在调用glBufferData时,没有为顶点分配足够的空间。您传递sizeof(TexColorVertex),它为1个顶点分配空间。如果你想绘制一个四边形,那么你需要为4个顶点分配空间,所以你应该将你的调用更改为glBuffer Data,如下所示:

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

这样,当您对glBufferSubData进行后续调用时,您将不会尝试访问超出范围的GPU内存。