Heightmap problems

Started by
8 comments, last by Nanoha 7 years, 9 months ago

Hey everyone.

I have been following this tutorial http://www.mbsoftworks.sk/index.php?page=tutorials&series=1&tutorial=24 when trying to learn how to do a heightmap. I have managed to read in the vertex data but something is not correct.

When using the following grayscale image heightmap (in which i just display the vertex positions for now) Starts off very well but then it seems to duplicate the first part onto the end of the map (also seems like everything is a bit bunched up as the middle hole is not in the middle of the heightmap) Which results in it looking like this.

https://gyazo.com/cd642c41a92d4345bb4ca06dbc12ba1c

Atm I feel that the problem must be to do with the height of the pixel i read in but im not 100% sure. from what i have read up , the way i do it should be correct

Currently the grayscale image is a BMP 24 bitdepth 257*257. I use SDL to read in the image to calculate the vertex height

Below is the code i am currently using

getting the vertex points (like the tutorial i make sure the x and z are between -0.5 and 0.5 so it is centred)


	SDL_Surface* img = SDL_LoadBMP(imagepath);
	if (!img)
	{
	    std::cout << "could not load the image";
		return;
	}


	rows = img->h;
	cols = img->w;


	std::vector< std::vector<glm::vec3> > Tvetrices (rows,std::vector<glm::vec3>(cols));
	std::vector< std::vector<glm::vec3> > TFinalNormals = std::vector< std::vector<glm::vec3> >(rows, std::vector<glm::vec3>(cols));
	std::vector< std::vector<glm::vec2> >  TUVs (rows , std::vector<glm::vec2>(cols));

	float fTextureU = float(cols)*0.1f;
	float fTextureV = float(rows)*0.1f;

	for (int i = 0; i < rows; i++)
	{
		for (int j = 0; j < cols; j++)
		{
			float colscale = float(j) / float(cols - 1);
			float rowscale = float(i) / float(rows - 1);

			Uint32 pixle = ((Uint32*)img->pixels)[i * img->pitch/4 + j];
			Uint8 r, g, b;
			SDL_GetRGB(pixle, img->format, &r, &g, &b);
			float hight = (float)r / 255.0;


			Tvetrices[i][j] = glm::vec3((-0.5f + colscale) * 10, hight, (-0.5f + rowscale) * 10);
			TUVs[i][j] = glm::vec2(fTextureU*colscale, fTextureV*rowscale);

		}
	}

	vetrices = Tvetrices;

VBO set up (just want points for now so no intention for setup for tri's)


	for (int i = 0; i < rows; i++)
	{
		for (int j = 0; j < cols; j++)
		{
			testver.push_back(vetrices[i][j]);
		}

	}
	
	glBufferData(GL_ARRAY_BUFFER, testver.size() * sizeof(glm::vec3), &testver[0], GL_STATIC_DRAW);

draw call


	glUseProgram(_program);

	glBindVertexArray(_VAO);

	glUniformMatrix4fv(_shaderModelMatLocation, 1, GL_FALSE, glm::value_ptr(_modelMatrix));
	glUniformMatrix4fv(_shaderViewMatLocation, 1, GL_FALSE, glm::value_ptr(viewMatrix));
	glUniformMatrix4fv(_shaderProjMatLocation, 1, GL_FALSE, glm::value_ptr(projMatrix));

	glDrawArrays(GL_POINTS, 0, testver.size());

Any help will be greatly appreciated

Advertisement

It looks like you're sampling from the wrong location on the heightmap. Can you show us the original heightmap image?

original image is https://gyazo.com/9c786198b46325ccfaeaacdfb1c08e08

when using this one again the hole is off centre (like in the other image) https://gyazo.com/d7d3acb7305a8c7a93604000ab0450bb

Uint32 pixle = ((Uint32*)img->pixels)[i * img->pitch/4 + j];

What's the significance of the /4 part? According to the wiki the pitch is the number of bytes per row, not sure why you are dividing it by 4. It might be worth you accessing the Pixel Format and checking the bytes per pixel to ensure everything matches up.

Interested in Fractals? Check out my App, Fractal Scout, free on the Google Play store.

What's the significance of the /4 part? According to the wiki the pitch is the number of bytes per row, not sure why you are dividing it by 4. It might be worth you accessing the Pixel Format and checking the bytes per pixel to ensure everything matches up.

without the /4, an access violation occurs. with ever example of 24 bitdepth image that i have seen, everyone puts the /4 after

also the bits per pixel came back as 24

and the bytes per pixel came back 3

I don't know SDL, but if it's a 24bit image, each pixel might be 3 bytes instead of 4 (although sometimes 24 bit images store their data in 4 byte chunks for good memory alignment). You're treating it like if it were 4.

That is, each j that gets incremented reads from a position 4 bytes further in the buffer, since you're casting the array to a Uint32*.

Because your source image has equal values for r, g, and b, this error wouldn't be very obvious. You're basically reading an r value, then a g value, then a b value, and so on.

Instead, you may need to index it as a byte array, and increment by j * 3 (and remove the /4 from the pitch calculation).

@Phil_T

Arr yes you are correct, i am treating the image as if it was 4 bytes per pixel instead of 3 (or it was a 32 bit bitmap ofcs).

Sorry to ask as just a little confused but what do you mean by "Instead, you may need to index it as a byte array, and increment by j * 3" (the "index it as a byte array" part mainly)

Cheers

You're casting it to a Uint32* , meaning the when you index it like an array, it is indexed in 4 byte increments. You need to cast it to uint8_t* so you can index it in single byte increments (so you can obtain every third byte).

http://www.learncpp.com/cpp-tutorial/6-8a-pointer-arithmetic-and-array-indexing/

@Phil_T

Like the following?


Uint8 *pixle = ((Uint8*)img->pixels);
pixle += (i * img->pitch) + (j * sizeof(Uint8) * 3);
Uint32 temppix = *((Uint32*)pixle);

Uint8 r, g, b;
SDL_GetRGB(temppix, img->format, &r, &g, &b);
float hight = (float)r / 255.0;

i had to change it back to uint32 at the end as that is only what the SDL_GetRGB function will take.

The results are much better

https://gyazo.com/10795f58b070189ea3e23f1fd376372f

@Phil_T

Like the following?


Uint8 *pixle = ((Uint8*)img->pixels);
pixle += (i * img->pitch) + (j * sizeof(Uint8) * 3);
Uint32 temppix = *((Uint32*)pixle);

Uint8 r, g, b;
SDL_GetRGB(temppix, img->format, &r, &g, &b);
float hight = (float)r / 255.0;

i had to change it back to uint32 at the end as that is only what the SDL_GetRGB function will take.

The results are much better

https://gyazo.com/10795f58b070189ea3e23f1fd376372f

That looks a lot better. It's probably a good idea to replace that 3 with the BytesPerPixel value from the pixel format. It is probably 3 since it works but it might not always be 3.

Interested in Fractals? Check out my App, Fractal Scout, free on the Google Play store.

This topic is closed to new replies.

Advertisement