I’ve seen code floating around that computes a normal map from a height map by estimating tangent vectors and doing a cross product. That includes a bit of unnecessary extra math, so here’s a better way to compute the same thing.
First, let’s write the height field as a function of x & y (ok, it’s a texture, so call them u and v if it makes you feel better). So a height field is basically a texture that defines
z = h(x,y)
The tangent-based code already estimated the partial derivatives of h(x,y) with respect to x and y. Let’s call those hx and hy. There are several ways to do this: forward differences
hx = h(x+1) – h(x)
hx = (h(x+1) – h(x-1)) / 2
Sobel filter (no, I’m not going to write that one out), or other derivative of a filter.
The trick comes in rewriting this thing as an implicit function of x,y,z that’s 0 on the surface, negative under the surface and positive outside the surface. That’s actually pretty easy:
f(x,y,z) = z – h(x,y)
So the neat thing is that the normal to an implicit surface like this is just the gradient of the implicit function:
N = (fx, fy, fz) = (-hx, -hy, 1)
That’s it. Much friendlier than cross( (1,0,hx), (0,1,hy) ). You could actually get exactly the same result by expanding out the cross product, but I think it’s much cooler (and more applicable in other situations) to know about the normal to an implicit function trick.