OpenGL crash on glDrawElements while trying to render Height Map

290 views Asked by At

I'm writing a class to render a height map from a 32-bit bmp using modern OpenGL techniques. I had it working with immediate mode but wanted to try converting it to a modern OpenGL context. I'm using an element array buffer with the index data for the map and a vbo which has the vertex data where the y component is taken from the height (pixel color) of the bitmap.

Right now, I'm getting an unhandled exception/access violation at the draw call. Here's my code:

void HeightMap::initHeightMap(const char* filePath, float size, float height){
SDL_Surface* image = SDL_LoadBMP(filePath);
if (!image)
{
    smodgine::fatalError("Image could not be loaded!");
}

std::vector<float> tmp;
for (int y = 0; y< image->h; y++)
{
    tmp.clear();
    for (int x = 0; x < image->w; x++)
    {
        Uint32 pixel = ((Uint32*)image->pixels)[y * image->pitch/4 + x];
        Uint8 r, g, b;
        SDL_GetRGB(pixel, image->format, &r, &g, &b);

        tmp.push_back((float)r / 255.0f);
    }
    heights.push_back(tmp);
}

for (int z = 0; z < heights.size(); z++)
{
    for (int x = 0; x < heights[0].size(); x++)
    {
        vertices.push_back(x * size);
        vertices.push_back(heights[z][x] * height);
        vertices.push_back(z * size);
    }
}

if (_vbo == 0) {
    glGenBuffers(1, &_vbo);
}

glBindBuffer(GL_ARRAY_BUFFER, _vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);

_numRows = heights.size() - 1;
_numColumns = heights[0].size() - 1;

SDL_FreeSurface(image);

createElementBuffer();
}

void HeightMap::renderHeightMap()
{
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _eleBuffer);

glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_SHORT, 0);
}

void HeightMap::createElementBuffer()
{
for (int z = 0; z < _numRows; z++)
{
    for (int x = 0; x < _numColumns; x++)
    {
        //top left
        indices.push_back(z * _numRows + x);
        //bottom left
        indices.push_back((z + 1) * _numRows + x);
        //top right
        indices.push_back(z * _numRows + (x + 1));

        //top right
        indices.push_back(z * _numRows + (x + 1));
        //bottom left
        indices.push_back((z + 1) * _numRows + x);
        //bottom right
        indices.push_back((z + 1) * _numRows + (x + 1));
    }
}

if (_eleBuffer == 0){
    glGenBuffers(1, &_eleBuffer);
}

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _eleBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}

I've only been using modern OpenGL for about a week or so, any help is appreciated :D

2

There are 2 answers

0
smodman On

I figured it out, other than the bug that Reto Koradi helped me with, in another part of my code (during the main function) i had accidentally been calling glEnableVertexAttribArray(1)

1
Reto Koradi On

You're using the sizeof operator for instances of std::vector, expecting that it will give you the size of the data in the vector:

glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices.data(), GL_STATIC_DRAW);
...
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices.data(), GL_STATIC_DRAW);

That will not produce the expected result. sizeof gives you the size in memory of the vector object, not of the data stored in the vector. That data is dynamically allocated, and not stored in the vector instance itself.

To get the correct size, you can use:

glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(vertices[0]), vertices.data(), GL_STATIC_DRAW);
...
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(indices[0]), indices.data(), GL_STATIC_DRAW);