OpenGL: Terrain not drawing (heightmap)
c++, heightmap, opengl
Solution
I'm pretty sure that when you say :
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
you actually want to say :
glBufferData(GL_ARRAY_BUFFER, sizeof (Vector4f) * w * l, vertices, GL_STATIC_DRAW);
(same to color buffer, etc)
Problem
EDIT: I'm thinking the problem might be when I'm loading the vertices and indices. Maybe focus on that section :) I'm trying to load a heightmap from a bmp file and displaying it in OpenGL. As with most things I try, everything compiles and runs without errors but nothing is drawn on the screen. I can't seem to isolate the issue that much, since all the code works on its own, but when combined to draw terrain, nothing works. Terrain class I have a terrain class. It has 2 VBOs, 1 IBO and 1 VAO. It also stores the vertices, indices, colours of the vertices and the heights. It is loaded from a bmp file. Loading terrain: ``` Terrain* Terrain::loadTerrain(const std::string& filename, float height) { BitMap* bmp = BitMap::load(filename); Terrain* t = new Terrain(bmp->width, bmp->length); for(unsigned y = 0; y < bmp->length; y++) { for(unsigned x = 0; x < bmp->width; x++) { unsigned char color = (unsigned char)bmp->pixels[3 * (y * bmp->width + x)]; float h = height * ((color / 255.0f) - 0.5f); t->setHeight(x, y, h); } } delete bmp; t->initGL(); return t; } ``` Initializing the buffers: ``` void Terrain::initGL() { // load vertices from heights data vertices = new Vector4f[w * l]; int vertIndex = 0; for(unsigned y = 0; y < l; y++) { for(unsigned x = 0; x < w; x++) { vertices[vertIndex++] = Vector4f((float)x, (float)y, heights[y][x], 1.0f); } } // generate indices for indexed drawing indices = new GLshort[(w - 1) * (l - 1) * 6]; // patch count * 6 (2 triangles per terrain patch) int indicesIndex = 0; for(unsigned y = 0; y < (l - 1); ++y) { for(unsigned x = 0; x < (w - 1); ++x) { int start = y * w + x; indices[indicesIndex++] = (GLshort)start; indices[indicesIndex++] = (GLshort)(start + 1); indices[indicesIndex++] = (GLshort)(start + w); indices[indicesIndex++] = (GLshort)(start + 1); indices[indicesIndex++] = (GLshort)(start + 1 + w); indices[indicesIndex++] = (GLshort)(start + w); } } // generate colours for the vertices colours = new Vector4f[w * l]; for(unsigned i = 0; i < w * l; i++) { colours[i] = Vector4f(0.0f, 1.0f, 0.0f, 1.0f); // let's make the entire terrain green } // THIS CODE WORKS FOR CUBES (BEGIN) // vertex buffer object glGenBuffers(1, &vbo); glBindBuffer(GL_ARRAY_BUFFER, vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); // index buffer object glGenBuffers(1, &ibo); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); // colours vertex buffer object glGenBuffers(1, &colour_vbo); glBindBuffer(GL_ARRAY_BUFFER, colour_vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(colours), colours, GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); // create vertex array object glGenVertexArrays(1, &vao); glBindVertexArray(vao); glBindBuffer(GL_ARRAY_BUFFER, vbo); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0); glBindBuffer(GL_ARRAY_BUFFER, colour_vbo); glEnableVertexAttribArray(1); glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); glBindVertexArray(0); // THIS CODE WORKS FOR CUBES (END) } ``` The part where I create the VBOs, IBO and VAO works fine for cubes, they are drawn nicely. Rendering terrain: ``` void Terrain::render() { glUseProgram(shaderProgram); glBindVertexArray(vao); int indices_length = (w - 1) * (l - 1) * 6; glDrawElements(GL_TRIANGLES, indices_length, GL_UNSIGNED_SHORT, 0); } ``` Shaders These are the vertex and fragment shaders. Vertex: ``` #version 330 layout (location = 0) in vec4 position; layout (location = 1) in vec4 vertexColour; out vec4 fragmentColour; uniform vec3 offset; uniform mat4 perspectiveMatrix; void main() { vec4 cameraPos = position + vec4(offset.x, offset.y, offset.z, 0.0); gl_Position = perspectiveMatrix * cameraPos; fragmentColour = vertexColour; } ``` Fragment: ``` #version 330 in vec4 fragmentColour; out vec4 outputColour; void main() { outputColour = fragmentColour; } ``` Perspective matrix Here are the settings for the "camera": ``` struct CameraSettings { static const float FRUSTUM_SCALE = 1.0f; static const float Z_NEAR = 0.5f; static const float Z_FAR = 3.0f; static float perspective_matrix[16]; }; float CameraSettings::perspective_matrix[16] = { FRUSTUM_SCALE, 0, 0, 0, 0, FRUSTUM_SCALE, 0, 0, 0, 0, (Z_FAR + Z_NEAR) / (Z_NEAR - Z_FAR), -1.0f, 0, 0, (2 * Z_FAR * Z_NEAR) / (Z_NEAR - Z_FAR), 0 }; ``` The uniforms get filled in after `initGL()` is called: ``` // get offset uniform offsetUniform = ShaderManager::getUniformLocation(shaderProgram, "offset"); perspectiveMatrixUniform = ShaderManager::getUniformLocation(shaderProgram, "perspectiveMatrix"); // set standard uniform data glUseProgram(shaderProgram); glUniform3f(offsetUniform, xOffset, yOffset, zOffset); glUniformMatrix4fv(perspectiveMatrixUniform, 1, GL_FALSE, CameraSettings::perspective_matrix); glUseProgram(0); ``` Could someone check out my code and give suggestions?