normal map from height map.

Started by
4 comments, last by Wilhelm van Huyssteen 11 years, 2 months ago
Hi.
Im trying to create normal maps from height maps myself. I have one height map for wich i created a normal map in a third party tool (a nvidia plugin for photoshop). That normal map looks like this.
a1.png
when i use this normal map for rendering the result is this.
a2.png
all good.
now I try to generate the normal map myself. The best i get is this
b1.png
and the rendering result is this...
b2.png
I try to generate the normal map by calculating and avaraging the 6 surrounding triangles normals for every vertex. like this.
diagram.png
[source]
private void testCalcNormals() {
StaticTile[][] tiles = world.staticTerrain.tiles;
StaticTile tile = tiles[10][5];//one StaticTile contains a 1024x1024 heightmap and normal map among other things.

for (int x = 0; x < 1024; x++)
{
for (int y = 0; y < 1024; y++)
{

float a1 = tile.getHeight(x-1, y-1);
float a2 = tile.getHeight(x, y-1);
float a3 = tile.getHeight(x+1, y-1);
float b1 = tile.getHeight(x-1, y);
float b2 = tile.getHeight(x, y);
float b3 = tile.getHeight(x+1, y);
float c1 = tile.getHeight(x-1, y+1);
float c2 = tile.getHeight(x, y+1);
float c3 = tile.getHeight(x+1, y+1);

float w = 100f;

Vector3 A1 = v(-w,a1,-w);
Vector3 A2 = v(0,a2,-w);
Vector3 A3 = v(w,a3,-w);
Vector3 B1 = v(-w,b1,0);
Vector3 B2 = v(0,b2,0);
Vector3 B3 = v(w,b3,0);
Vector3 C1 = v(-w,c1,w);
Vector3 C2 = v(0,c2,w);
Vector3 C3 = v(w,c3,w);


Vector3 t1 = surfaceNormal(B2, A2, B3);
Vector3 t2 = surfaceNormal(B2, B3, C3);
Vector3 t3 = surfaceNormal(B2, C3, C2);
Vector3 t4 = surfaceNormal(B2, C2, B1);
Vector3 t5 = surfaceNormal(B2, B1, A1);
Vector3 t6 = surfaceNormal(B2, A1, A2);




Vector3 normal = t1.add(t2).add(t3).add(t4).add(t5).add(t6).divide(6);
normal.normalize();
tile.setNormal(x, y, normal);



}
}
}

private static Vector3 surfaceNormal(Vector3 c1, Vector3 c2, Vector3 c3)
{
Vector3 edge1 = new Vector3(c2.x - c1.x, c2.y - c1.y, c2.z - c1.z);
Vector3 edge2 = new Vector3(c3.x - c1.x, c3.y - c1.y, c3.z - c1.z);

Vector3 normal = edge1.cross(edge2);
normal.normalize();

return normal;
}[/source]
What am I doing wrong here?
Thnx in Advance!
Advertisement

Not spent much time examining your code, because there's a simpler way to calculate normals from a height map without even having to worry about the triangulation. You pretty much just pass a 3x3 sobel filter kernel over your height map data. There's some code in this link (Kenneth Gorking's post): http://devmaster.net/forums/topic/6611-heightmap-to-normal-map-conversion-question/

If you're doing a simple average of your normals, that means that some of them are going to have negative values for X and Y. These need to be converted so that they fall in the (0,1) range, with 0.5 meaning 0. That is, multiply your X and Y components by 0.5 then add 0.5 after your normalize step. Otherwise, you end up with negative values for red or green color components, which is not what you want. A "neutral" (non-perturbed) vector in a normal map encoded like this (ie, the color representing a (0,0,1) vector relative to the normal of the face) is represented by the color (128,128,255) which is why normal maps in tangent space have that cool bluish hue.

Thnx. getting the normals into the 0,1 range solved the problem.

Your "failed" normal maps looks awesome :D

"I AM ZE EMPRAH OPENGL 3.3 THE CORE, I DEMAND FROM THEE ZE SHADERZ AND MATRIXEZ"

My journals: dustArtemis ECS framework and Making a Terrain Generator

^^

This topic is closed to new replies.

Advertisement