Jump to content
  • Advertisement
Sign in to follow this  
awackate

Normal Map TO Height Map Algorithm

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

If you intended to correct an error in the post then please contact us.

Recommended Posts

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
Advertisement
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
Thanks Hodgam, but I made a mistake in the title.
I meant a Normal to Height Map (i've just edited it). But thanks anyway!!

Share this post


Link to post
Share on other sites
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
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
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
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
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!