Sign in to follow this  
awackate

Normal Map TO Height Map Algorithm

Recommended Posts

awackate    100
Hello everyone, I need to program a Normal Map to Height Map convertor for a programming class. But I couldn’t find a simple algorithm anywere. I tryied doing “inverse ingenieering” with some of the most common “Height to Normal” apps, but had no success. I need a simple algorithm, and doesn’t have to be 100% precise... just something that works for simple inorganic 3d Objetcts’s maps. If anyone knows about any simple (or at least not so complicated) way of doing this, I would be really greatful. Sorry about my English, i’m from South America. Thanks

Share this post


Link to post
Share on other sites
Hodgman    51336
You can use trigonometry to create a basic algorithm.

For each pixel in the height map, look at it's neighbouring pixels. Using the heights of two pixels, you can form a triangle.
  |\ 
a | \c
|__\
b
a is the height difference between the two pixels, b is the distance between the two pixels, and the line that is tangential to c can be summed into your normal.

Share this post


Link to post
Share on other sites
szecs    2990
I can think of a pretty straightforward way.


But I can't think about any precise methods.
Because I would simply start to sum up the values calculated from the normalmap.
height_increment_x_dir = normal_x/normal_z * size_of_one_square_in_heightmap or
height_increment_y_dir = normal_y/normal_z * size_of_one_square_in_heightmap depending on the direction (x or y)

image.

I think you got the idea, but I'm not sure (at all) about precision, and you have to state an arbitrary initial height.


You have to go through the map like this:

image

So every values will depend on every other values (at least the values calculated before it)

You can go on any routes, but notice, that every point can be reached from two neighboring points which should give the same results, so you can use it to improve prevision (but I don't know much about self-precision-improver methods (or whatever they're called)).

[Edited by - szecs on February 7, 2010 2:00:38 AM]

Share this post


Link to post
Share on other sites
Lutz    462
If your normal map has been created by an artist in Photoshop or even if the vectors have been normalized before storing the normal map (this is what you usually do), there might not be a heightmap that exactly represents the normal map (only an approximation). Ad-hoc approaches like the suggested approach are likely to have visual artifacts because of this. Mathematically, it is an integration problem and if there is error in the derivative (that you integrate), the error sums up. A standard approach to solve the problem is by noting that an (unnormalized) normal map is technically the derivative of a height map:
n_x = -dh/dx and
n_y = -dh/dy or simply
n = -grad h
Applying the divergence to both sides yields
div n = - div grad h = - laplace h,
so you have to solve the Laplace equation. Try searching for "shape from shading" or "height from gradient" for details.

If your normal maps are tiling and hence the height maps are supposed to be tiling as well, you won't be able to achieve good results at all with the suggested ad-hoc summation method because of the error that sums up and you'll get discontinuities at the image boundaries. The height map won't be tiling. In this case, I recommend using the Fourier transform as it guarantees that the results are always tiling. The idea is that the Fourier transform F(f') of a derivative of a function f equals the Fourier transform of the function multiplied by i*omega, i.e. F(f') = i*omega*F(f), so that
F(n_x) = -F(dh/dx) = -i*omega_x*F(h) and
F(n_y) = -F(dh/dy) = -i*omega_y*F(h).
Multiplying the terms with i*omega_x resp. i*omega_y yields
i*omega_x*F(n_x) = omega_x^2*F(h) and
i*omega_y*F(n_y) = omega_y^2*F(h)
since i*i=-1. Adding both terms together yields
F(h) = i*(omega_x*F(n_x) + omega_y * F(n_y)) / (omega_x^2 * omega_y^2)
For the zero-frequency (where both omega_x and omega_y are zero) you'll get a division by zero. To solve this, just set F(h) to 0 at that frequency. This problem corresponds to the fact that the height map is only determined up to an additive constant since the constant is lost when you take the derivative of h. The zero frequency corresponds to a constant term. So to get h, you compute the Fourier transforms of n_x and n_y, compute the above equation for F(h) and then take the inverse Fourier transform.

- Lutz

Share this post


Link to post
Share on other sites
awackate    100
Thanks you all very much!

I think it is more complicated than I thought. I get the general idea of both proceses but I will probably change my final work for something easier. The idea was to prove I can program, but doing this kind of algorithm seems too much.

Thanks Everyone.

Share this post


Link to post
Share on other sites
szecs    2990
Thanks for that Lutz!
I know that my solution is very imprecise.
But I like to draw diagrams with paint [grin]

OP: if it's just a programming assignment, why not doing the opposite? (height to normal map?)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this