heightmap to normal map conversion question

865234c7c8499e881de3d4230c876ab5
0
magneeto 101 Jan 09, 2007 at 06:13

hi,

how do i convert a heightmap to a normal map? I found two different solutions but i need a correct explanation

(i)

dx=heightmap[j]-heightmap[i-1][j]
dy=heightmap[j]-heightmap[j+1]
vector3d normal=(dx,dy,1)

normal.normalize()

(ii) dz1=heightmap[j]-heightmap[i-1][j]
dz2=heightmap[j]-heightmap[j+1]

dx=(1,0,dz1)
dy=(0,1,dz2)

normal=dx.cross(dy)

the above two procedures don’t seem to be the same to me. the first one samples the heights in the X and Y directions whereas the second one defines the X and Y components as unit. which one is the correct?

3 Replies

Please log in or register to post a reply.

A8433b04cb41dd57113740b779f61acb
0
Reedbeta 168 Jan 09, 2007 at 06:51

The second one is correct, but the first one is almost correct. The cross product of (1, 0, dz1) and (0, 1, dz2) is (0*dz2 - dz1*1, dz1*0 - dz2*1, 1*1 - 0*0) = (-dz1, -dz2, 1), which is the same as the first one except for the signs being flipped in the x and y coordinates. What the second one is doing is really defining two tangent vectors dx and dy, and the normal is of course the cross product of the tangents.

6673a7d3bfd3d1db5e05c5676cc040b6
0
Goz 101 Jan 09, 2007 at 10:25

The first one is a forward difference setup. It is used in DUDV bump mapping.

46407cc1bdfbd2db4f6e8876d74f990a
0
Kenneth_Gorking 101 Jan 09, 2007 at 15:06

I always found the generated normalmaps looked too blocky using that technique, so I switched to a Sobel filter:

vector3d normal;

// Get sobel samples
float dx, dy, sobelTaps[8];
sobelTaps[0] = heightmap[i - 1][j - 1];
sobelTaps[1] = heightmap[i    ][j - 1];
sobelTaps[2] = heightmap[i + 1][j - 1];

sobelTaps[3] = heightmap[i - 1][j + 1];
sobelTaps[4] = heightmap[i    ][j + 1];
sobelTaps[5] = heightmap[i + 1][j + 1];

sobelTaps[6] = heightmap[i - 1][j    ];
sobelTaps[7] = heightmap[i + 1][j    ];

// Do y sobel filter
dy  = sobelTaps[0] * +1.0f;
dy += sobelTaps[1] * +2.0f;
dy += sobelTaps[2] * +1.0f;

dy += sobelTaps[3] * -1.0f;
dy += sobelTaps[4] * -2.0f;
dy += sobelTaps[5] * -1.0f;

// Do x sobel filter
dx  = sobelTaps[0] * -1.0f;
dx += sobelTaps[6] * -2.0f;
dx += sobelTaps[3] * -1.0f;

dx += sobelTaps[2] * +1.0f;
dx += sobelTaps[7] * +2.0f;
dx += sobelTaps[5] * +1.0f;

// Cross Product of components of gradient reduces to:
normal.x = -dx;
normal.y = -dy;
normal.z = 1;