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.

  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
    498
    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
    498
    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
    498
    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
    I will give it a go, thanks for the help.

  8. #8
    Intern Newbie
    Join Date
    Aug 2013
    Posts
    32
    Ok, I've got glDrawElements drawing... something. It's not drawing anything like what I had with gldDrawArrays though, it's just a huge blob.

    I init like this..
    Code :
    unsigned int vboModelInd[] = {0, 1, 2};
    GLuint vboModel, ind;
     
    glGenBuffers(1, &vboModel);
    	glGenBuffers(1, &ind);
    	glBindBuffer(GL_ARRAY_BUFFER, vboModel);
    	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ind);
    	glBufferData(GL_ARRAY_BUFFER, heightMap.size()*sizeof(float), heightMap.data(), GL_STATIC_DRAW);
    	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(vboModelInd), vboModelInd, GL_STATIC_DRAW);

    I draw like this...
    Code :
    glBindBuffer(GL_ARRAY_BUFFER, vboModel);
    	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ind);
    	glEnableClientState(GL_VERTEX_ARRAY);	
    		glVertexPointer(3, GL_FLOAT, 0, NULL);
    		glDrawElements(GL_TRIANGLES, heightMap.size()*sizeof(float), GL_UNSIGNED_INT, 0);
    	glDisableClientState(GL_VERTEX_ARRAY);
    	glBindBuffer(GL_ARRAY_BUFFER, 0);
    	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

    I'm filling my data like this... I'm also tried with just adding 1 point at a time.
    Code :
    for(int z = 0; z < heights.size()-1; z++)
    	{
    		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);
     
    			vec.push_back(x+1 * tileSize);
    			vec.push_back(heights[x+1][z] * maxHeight);
    			vec.push_back(z * tileSize);
    		}
    	}

    Edit: Hm, I guess all this has to be used with indexed drawing... Oh joy another confusing bunch of days to figure this junk out.
    Last edited by Exempt; 08-15-2013 at 07:23 PM.

  9. #9
    Member Regular Contributor
    Join Date
    Jun 2013
    Posts
    498
    Quote Originally Posted by Exempt View Post
    Ok, I've got glDrawElements drawing... something. It's not drawing anything like what I had with gldDrawArrays though, it's just a huge blob.

    I init like this..
    Code :
    unsigned int vboModelInd[] = {0, 1, 2};
    The index array needs to have one element for each vertex (duplicated vertices will have duplicated indices). For an grid with M*N vertices ((M-1)*(N-1) squares) rendered using GL_TRIANGLES, you'll need 6*M*N indices (i.e. 2 triangles = 6 vertices per grid square).

    The indices can be generated like:
    Code :
    std::vector<GLuint> index;
    for (int row = 0; row < rows-1; row++) {
        for (int col = 0; col < cols-1; col++) {
            int i0 = row*cols+col;
            int i1 = i0 + cols; // = (row+1)*cols+col
     
            index.push_back(i0);
            index.push_back(i0+1);
            index.push_back(i1);
     
            index.push_back(i1);
            index.push_back(i1+1);
            index.push_back(i0+1);
        }
    }

    Essentially, glDrawArrays() is equivalent to glDrawElements() with an index array of [0,1,2,3,...]. glDrawArrays() is seldom useful when drawing triangles or quads, as you end up needing to duplicate vertices, which is more expensive than duplicating indices. It is useful with points (which have no topology) and sometimes with line strips/loops, but less useful with general wireframe meshes.

  10. #10
    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..

Posting Permissions

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