Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Page 1 of 2 12 LastLast
Results 1 to 10 of 15

Thread: Trying to render a heightmap as a VBO, no error just not showing up.

Hybrid View

  1. #1
    Intern Newbie
    Join Date
    Aug 2013
    Posts
    32

    Trying to render a heightmap as a VBO, no error just not showing up.

    Edit: I'm trying to use opengl 2.1 to avoid shaders for now.

    I can render a simple triangle without issue as a vbo but when I made this function and try to render a height map it doesn't display anything. I'm guess it's something to do with trying to fill the data with a vector<float> but not to sure.

    It's probably something simple but I'm pretty new to opengl and 3d programming in general -.-, thanks for any help.

    I load a bmp image (gray scale) and just fill a vector<float> like so..
    Code :
    std::vector<float> loadHeightMap(const char* fileName, float tileSize, float maxHeight)
    {
    	std::vector<float> vec;
    	SDL_Surface* img = SDL_LoadBMP(fileName);
    	if(!img)
    	{
    		std::cout<<"Failed to load " << fileName << "." << std::endl;
    		return vec;
    	}
     
    	for(int i = 0; i < img->h; i++)
    	{
    		for(int j = 0; j < img->w; j++)
    		{
    			Uint32 pixel = ((Uint32*)img->pixels)[i * img->pitch/4 + j];
    			Uint8 r, g, b;
    			SDL_GetRGB(pixel, img->format, &r, &g, &b);
     
    			vec.push_back((float)i * tileSize);
    			vec.push_back((float)(r / 255) * maxHeight);
    			vec.push_back((float)j * tileSize);
    		}
    	}
    	SDL_FreeSurface(img);
     
    	return vec;
    };

    Init the vbo...
    Code :
    glGenBuffers(1, &vboModel);
    	glBindBuffer(GL_ARRAY_BUFFER, vboModel);
    	glBufferData(GL_ARRAY_BUFFER, heightMap.size(), heightMap.data(), GL_STATIC_DRAW);
    	glBindBuffer(GL_ARRAY_BUFFER, 0);

    and finally I try to draw the vbo
    Code :
    glBindBuffer(GL_ARRAY_BUFFER, vboModel);
    	glEnableClientState(GL_VERTEX_ARRAY);	
    		glVertexPointer(3, GL_FLOAT, 0, NULL);
    		glDrawArrays(GL_TRIANGLES, 0, 3);
    	glDisableClientState(GL_VERTEX_ARRAY);
    	glBindBuffer(GL_ARRAY_BUFFER, 0);

    Edit: Well I see why it doesn't display anything cause i'm not actually making tryings filling the vector like I currently am... Guess i'll have to think more lol.

    I edited the height map function to actually make vertice but I see only 1 triangle.

    Code :
    std::vector<float> loadHeightMap(const char* fileName, float tileSize, float maxHeight)
    {
    	std::vector<float> vec;
    	SDL_Surface* img = SDL_LoadBMP(fileName);
    	if(!img)
    	{
    		std::cout<<"Failed to load " << fileName << "." << std::endl;
    		return vec;
    	}
     
    	for(int i = 0; i < img->h; i++)
    	{
    		for(int j = 0; j < img->w; j++)
    		{
    			Uint32 pixel = ((Uint32*)img->pixels)[i * img->pitch/4 + j];
    			Uint8 r, g, b;
    			SDL_GetRGB(pixel, img->format, &r, &g, &b);
     
    			vec.push_back((float)i * tileSize);
    			vec.push_back((float)(r / 255) * maxHeight);
    			vec.push_back((float)j * tileSize);
     
    			vec.push_back((float)i+1 * tileSize);
    			vec.push_back((float)(r / 255) * maxHeight);
    			vec.push_back((float)j * tileSize);
     
    			vec.push_back((float)i * tileSize);
    			vec.push_back((float)(r / 255) * maxHeight);
    			vec.push_back((float)j+1 * tileSize);
    		}
    	}
    	SDL_FreeSurface(img);
     
    	return vec;
    };

    edit: I changed
    Code :
    glDrawArrays(GL_TRIANGLES, 0, (heightMap.size()));
    and now I have a huge square but the height doesn't seem to be right... hmm

    Edit: I changes the load height map function to load a 4th vertex and use triangle strips to render it... seems to work better but I still have no Z or height value...

    Seems that r is also equal to 0... odd. r should be a range from 0-255.. the image I use has colors from black to near white all over it...

    Edit: The issue is Uint32 pixel = ((Uint32*)img->pixels)[i * img->pitch / 4 + j]; ... seems that it doesn't return the correct pixel so I guess i'll have to find a new way to find the currect pixel.


    Edit..again: Well I have it loading mountains and stuff now but... all the vertex are flat so it's got gaps lol... I see why it's happening but not sure of a solution just yet -.-
    Last edited by Exempt; 08-14-2013 at 07:22 PM.

  2. #2
    Member Regular Contributor
    Join Date
    Jun 2013
    Posts
    490
    Quote Originally Posted by Exempt View Post
    I can render a simple triangle without issue as a vbo but when I made this function and try to render a height map it doesn't display anything. I'm guess it's something to do with trying to fill the data with a vector<float> but not to sure.

    Code :
    	glBufferData(GL_ARRAY_BUFFER, heightMap.size(), heightMap.data(), GL_STATIC_DRAW);
    heightMap.size() is the number of floats in the vector, but the second argument to glBufferData() is the number of bytes, so you're only uploading a quarter of the data.

    Quote Originally Posted by Exempt View Post
    I changes the load height map function to load a 4th vertex and use triangle strips to render it... seems to work better but I still have no Z or height value...
    Quote Originally Posted by Exempt View Post
    Code :
    			Uint8 r, g, b;
    			...
    			vec.push_back((float)(r / 255) * maxHeight);
    As r and 255 are both integers, the division will yield an integer, so the value of r/255 will be either zero (if r<255) or one (if r==255). You need to convert at least one of the operands to the division to a float, e.g.
    Code :
    			vec.push_back((r / 255.0f) * maxHeight);
    Converting the result of the division to a float won't work; you're just converting 0 to 0.0f every time.

  3. #3
    Intern Newbie
    Join Date
    Aug 2013
    Posts
    32
    Edit: I changed this hole post because of some new changes it was pointless to leave it as it was with no replies to it.

    I've got the terrain loading correctly side from it loading a flat plane over the map... I have no idea why as it shouldn't be there at all...

    I init the vbo like so...
    Code :
    glGenBuffers(1, &vboModel);
    	glBindBuffer(GL_ARRAY_BUFFER, vboModel);
    	glBufferData(GL_ARRAY_BUFFER, heightMap.size()*sizeof(float), heightMap.data(), GL_STATIC_DRAW);
    	glBindBuffer(GL_ARRAY_BUFFER, 0);

    I draw like so..
    Code :
    glBindBuffer(GL_ARRAY_BUFFER, vboModel);
    	glEnableClientState(GL_VERTEX_ARRAY);	
    		glVertexPointer(3, GL_FLOAT, 0, NULL);
    		glDrawArrays(GL_TRIANGLE_STRIP, 0, heightMap.size()*sizeof(float));
    	glDisableClientState(GL_VERTEX_ARRAY);
    	glBindBuffer(GL_ARRAY_BUFFER, 0);

    my new loadHeightMap..
    Code :
    std::vector<float> loadHeightMap(const char* fileName, float tileSize, float maxHeight)
    {
    	std::vector<float> vec;
    	std::vector<std::vector<float>> heights;
    	SDL_Surface* img = SDL_LoadBMP(fileName);
    	if(!img)
    	{
    		std::cout<<"Failed to load " << fileName << "." << std::endl;
    		return vec;
    	}
     
     
     
    	std::vector<float> tmp;
    	for(int i = 0; i < img->h; i++) //I load the heights into a vector<vector<float>> now for easy access.
    	{
    		tmp.clear();
    		for(int j = 0; j < img->w; j++)
    		{
    			Uint32 pixel = ((Uint32*)img->pixels)[i * img->pitch / 4 + j];
    			Uint8 r, g, b;
    			SDL_GetRGB(pixel, img->format, &r, &g, &b);
     
    			tmp.push_back((float)r/255.0);
    		}
    		heights.push_back(tmp);
    	}
     
    	for(int z = 0; z < heights.size()-1; z++) //I just use 2 vertice now for the triangle strip.
    	{
    		for(int x = 0; x < heights[0].size()-1; x++)
    		{
    			vec.push_back(x * tileSize);
    			vec.push_back(heights[x][z] * maxHeight);
    			vec.push_back(z * tileSize);
     
    			vec.push_back(x * tileSize);
    			vec.push_back(heights[x][z+1] * maxHeight);
    			vec.push_back(z+1 * tileSize);
    		}
    	}
    	SDL_FreeSurface(img);
     
    	return vec;
    };

    Edit: Could this be caused because I use triangle strips? I might need to make a new triangle strip for each row of vertex?
    Last edited by Exempt; 08-15-2013 at 01:24 PM.

  4. #4
    Member Regular Contributor
    Join Date
    Jun 2013
    Posts
    490
    Quote Originally Posted by Exempt View Post
    Could this be caused because I use triangle strips?
    Yes.
    Quote Originally Posted by Exempt View Post
    I might need to make a new triangle strip for each row of vertex?
    Yes. Or use glDrawElements(GL_TRIANGLES) to draw it all in one go.

  5. #5
    Intern Newbie
    Join Date
    Aug 2013
    Posts
    32
    GL_TRIANGLES would require me to change my loader to add complete triangles though right?
    Last edited by Exempt; 08-15-2013 at 02:19 PM.

  6. #6
    Member Regular Contributor
    Join Date
    Jun 2013
    Posts
    490
    Quote Originally Posted by Exempt View Post
    GL_TRIANGLES would require me to change my loader to add complete triangles though right?
    With glDrawElements(), you'd just store each vertex as it's loaded, with no duplicates. The index array specifies which vertices form each triangle.

  7. #7
    Intern Newbie
    Join Date
    Aug 2013
    Posts
    32
    If I wanted to create a real index like 0, 1, 2, 3, 2, 1 to reuse vertice correctly I'd also have to remove the duplicated vertex from my data right?

    I think I may go ahead and bump up to opengl 3.3 soon so I can use the primitive restart method but that's for triangle strips and I'm not sure why I need a index for triangle strips since really I just need the first 2 point and then just one point to continue the strip after that... I've read its faster with way but primative restart requires a index which seems pointless to me for triangle strips...

    I'd try to test this but I've got no access to my pc atm so I'm just thinking out loud here..

  8. #8
    Member Regular Contributor
    Join Date
    Jun 2013
    Posts
    490
    Quote Originally Posted by Exempt View Post
    If I wanted to create a real index like 0, 1, 2, 3, 2, 1 to reuse vertice correctly I'd also have to remove the duplicated vertex from my data right?
    There would be no point in duplicating the vertices, but if they were present you could construct an index array which either ignored them or used them. The example code I posted assumes that the vertices are "packed", i.e. the vertex comprising elements 3*n,3*n+1,3*n+2 is for row (n/cols) and column (n%cols).

    Quote Originally Posted by Exempt View Post
    I think I may go ahead and bump up to opengl 3.3 soon so I can use the primitive restart method but that's for triangle strips and I'm not sure why I need a index for triangle strips since really I just need the first 2 point and then just one point to continue the strip after that...
    If you try to render a grid using strips, you'll find that the end of each row doesn't work out; one of the last two vertices will be on the "far" side of the strip. Triangle strips/fans used to have a performance benefit on older hardware, but nowadays there isn't really any advantage beyond reducing the size of the index arrays.

    The main problem with using glDrawArrays() for typical meshes is that you have to duplicate most of the interior vertices, which wastes memory and complicates matters if you need to modify vertices dynamically. It's more useful for points and line strips/loops.

    Note that, for strips, you can get by without primitive restart by just repeating the first vertex of a new section, effectively linking the sections with degenerate triangles (their area will be zero, so nothing will be drawn). That won't work with fans, though (or with glPolygonMode(GL_LINE) if the sections are disjoint).

  9. #9
    Intern Newbie
    Join Date
    Aug 2013
    Posts
    32
    I see, so I just fill my data with complete triangles then i can just pass 0,1,2,3,4... As my index and it will work with glDrawElements.

    Just to make sure I'm right, the index is just a single point right?

    Edit: to optimize this more I could use indexing like i said before to reuse points for the triangles...

  10. #10
    Member Regular Contributor
    Join Date
    Jun 2013
    Posts
    490
    Quote Originally Posted by Exempt View Post
    I see, so I just fill my data with complete triangles then i can just pass 0,1,2,3,4... As my index and it will work with glDrawElements.

    Just to make sure I'm right, the index is just a single point right?
    The vertex data passed to glVertexPointer() is just the vertices, e.g. for a rectangular grid:

    GLfloat vertices[rows*cols][3];

    The ordering can be whatever is convenient, but it would make sense to use the same order in which you read the heights from the image file.

    The index array is one GLubyte/GLushort/GLuint (depending upon how many bits you need) per vertex. You need as many indices for glDrawElements() as you would need complete vertices for glDrawArrays(). Rather than using vertex[first+0], vertex[first+1], etc, it uses vertex[indices[0]], vertex[indices[1]], etc. So instead of than duplicating or re-ordering vertices, you just duplicate or re-order the indices.

    For a height map generated from an M*N image and rendered with GL_TRIANGLES, you'd have M*N vertices (M*N*3 floats) and 6*(M-1)*(N-1) indices. For GL_QUADS, the number of indices would be 4*(M-1)*(N-1). Using triangle strips could reduce the number of indices further, but there probably isn't a need unless M*N is huge (in which case, storing the heights as a texture and generating the vertex data in a vertex shader would provide much bigger savings).

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •