Not logged in, Join Here! or Log In Below:  
News Articles Search    

 Home / 3D Theory & Graphics / HeightMap to NormalMap (D3DXComputeNormalMap) algo Account Manager
Archive Notice: This thread is old and no longer active. It is here for reference purposes. This thread was created on an older version of the flipcode forums, before the site closed in 2005. Please keep that in mind as you view this thread, as many of the topics and opinions may be outdated.

May 21, 2005, 06:41 AM


I want to implement my own version of the D3D function D3DXComputeNormalMap. I am unable to find any good resource so let me tell you what I think is right...

ComputeNormalMap(NormalMap, Height, fAmount)
for every pixel in HeightMap (x, y)
Vec3 temp
temp.z = temp.y = temp.x = (HeightMap[x][y].r * fAmount)
NormalMal[x][y].r = 128 + (128 * temp.x)
NormalMal[x][y].g = 128 + (128 * temp.y)
NormalMal[x][y].b = 128 + (128 * temp.z)

While, we are on the same topic, let me also see if my algo for Adding two normal vectors is also correct

AddNormalMaps(NormalMapAplusB, NormalMapA, NormalMapB)
for every pixel in NormalMapA(x, y)
Vec3 temp, temp2

temp.x,y,z = (NormalMapA[x][y].r,g,b - 128.0f) / 128.0f
temp2.x,y,z = (NormalMapB[x][y].r,g,b - 128.0f) / 128.0f


NormalMapAplusB[x][y].r,g,b = 128 + (128 * temp.x,y,z)

Fabian 'ryg' Giesen

May 21, 2005, 03:31 PM

Your AddNormalMap-code is okay. The ComputeNormalMap code isn't.

The absolute height isn't relevant for the normals; you can easily verify that a planar surface with e.g. constant height 240 (assuming middle is 128) should still have normals pointing right "up" (in the usual convention, this is towards the Z axis).

What you normally do is take the height *difference* along the X axis as x coordinate and the height difference along the Y axis as y coordinate. The z coordinate is typically assumed to be constant; afterwards the whole vector is normalized. This defines the "slope" at that point in the texture in x/y direction; e.g. if your heightmap is a linear gradient from 0 (top left) to 255 (bottom right), every pixel will get (approximately) the same x/y differences, and the resulting normal vector for every pixel is a vector "pointing up and leaning towards the top left of the texture" (if you understand what I mean).

How you compute the current height difference depends on the exact algorithm used. You can get arbitrarily fancy here (e.g. use some filter kernel centered on the current pixel), but the easiest (and most widely used) method is:

  2.   heightDiffX = (HeightMap[x][y+1] - HeightMap[x][y]) * amount;
  3.   heightDiffY = (HeightMap[x+1][y] - HeightMap[x][y]) * amount;

You then compute the normal from that by

  2.   normal.x = heightDiffX;
  3.   normal.y = heightDiffY;
  4.   normal.z = 1;
  5.   Normalize(normal);

This is pseudocode; you need to handle the boundary cases when there's no "next pixel" in x or y direction. For textures that tile, you can just let the coordinates wrap too, and you'll also get a tileable normal map.


May 22, 2005, 12:44 AM

Fabian 'ryg' Giesen wrote:
  2.   heightDiffX = (HeightMap[x][y+1] - HeightMap[x][y]) * amount;
  3.   heightDiffY = (HeightMap[x+1][y] - HeightMap[x][y]) * amount;

Just to check -- this should be the other way around, shouldn't it (heightDiffX = HeightMap[x+y].. etc)?


Fabian 'ryg' Giesen

May 22, 2005, 10:11 AM

Woops, yes.

I originally used [y][x] array indices and later exchanged the variables because you used the opposite convention.


May 23, 2005, 03:47 AM

Hi Fabian,

Thanks for your post. I did not quite get what you were saying at first, but then I re-worded my google search and found this... Says pretty much the same thing that you were explaining :-D. Thanks anyways.

- Sid

This thread contains 5 messages.
Hosting by Solid Eight Studios, maker of PhotoTangler Collage Maker.