Calculating normals from 2D heightmap

This topic is 4449 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

Recommended Posts

Hi I have a simple question. I can't figure out how to calculate the normals for a 2D heightmap. normal.x = 128 - 64 //Height value row2 col 0 and 2 normal.z = 96 - 128 //Height value row 1 col 1 row 3 col 1 Now how do I calculate the x normal and z normal from this input? I am asuming height of map 0-255, angles between -90 and + 90 degrees. Thanks

Share on other sites
Here's an easy way to do it, lets say at row i, column j. I am assuming columns increase along x (increasing j = increasing x), rows increase along y (increasing i = increasing y), and the height is z.

First, create a representative 3D vector between columns, a vector at row i. At row i, the vector should be computed using points at columns (j+1) and (j-1):

T1 = <X(i,j+1),Y(i,j+1),Z(i,j+1)> - <X(i,j-1),Y(i,j-1),Z(i,j-1)>

Next, do the same t hing between rows, e.g., a vector at column j. It uses rows (i+1) and (i-1):

T2 = <X(i+1,j),Y(i+1,j),Z(i+1,j)> - <X(i-1,j),Y(i-1,j),Z(i-1,j)>

Normalize T1 and T2. These are your tangent vectors! You can easily compute the normal from those:

N = CrossProduct(T1,T2)

Now, there are more sophisticated methods. This is basically a bilinear interpolation type approach. You could fit a more complex surface, such as a bicubic surface, which would give a polynomial function in two variables that you can take derivatives of to get the two tangent vectors. But, this is an easy approach for you to try.

Hope that helps!

Share on other sites
Actually, the tangent vectors T1 and T2 don't have to be normalized to use them in a cross product to get the surface normal. Without normalizing T1 and T2, the cross product result will also not be normalized. Since you'll likely want a normalized surface normal, you can merely normalize this result, instead of T1 and T2.

Share on other sites
I do it like that:
normal.x=(h[x-1,y]-h[x+1,y]);
normal.y=(h[x,y-1]-h[x,y+1]);
normal.z=vertical_scaling_factor*2;
normal.Normalize();
where h is heightfield, vertical scaling factor is the unit height in the units of height grid.

How it works: For heightfield h( the vector v = [-dh/dx , -dh/dx, 1] is normal to the surface. Which can be proved as follows:
The vector 1,0,dh/dx is tangent to the surface. It's dot product with v is -dh/dx*1 -dh/dx*0 + dh/dx*1 = 0 . The vector 0,1,dh/dy is different, non-parallel tangent, it also has dot product with v equal to zero. Therefore the v is orthogonal to both tangents, and is orthogonal to the surface.

Share on other sites
Great method, Dmytry. Just a typo correction:

vector v = [-dh/dx , -dh/dy, 1]

I worked out your method just to prove your solution to myself, and I noticed the slope is computed in the same method that grhodes_at_work mentioned (which I also use).

I am not sure if this is well known (since I did the simple math myself, and didn't research this), but I thought I should point out to the original poster (and perhaps others) that computing the slope as: slope = h2 - h0 / 2, given three equally spaced height values h0, h1, and h2, is actually the solution of the derivative (slope), at the middle value, of the quadratic interpolation of these three heights. So, it's not just a quick 'hack'; it's quite meaningful.

1. 1
2. 2
3. 3
4. 4
Rutin
15
5. 5

• 13
• 26
• 10
• 11
• 9
• Forum Statistics

• Total Topics
633724
• Total Posts
3013554
×