Sign in to follow this  

Normal from 2D heightmap

This topic is 3662 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

I've created a height map with some perlin noise, where the pixel values correspond to the Y coordinate of my vertices. Now, I want to calculate normals based on this height map. I guess I can use GLSLs dFdx & dFdy to get the height variation (in X & Z directions) but how do I create the normal from that? I tried vec3 N = normalize(vec3(dFdx(sampel.y), 1.0, dFdy(sampel.y))); but then all normal.y's got very close to 1.0, and that's not correct.

Share this post


Link to post
Share on other sites
I have no direct experience with GLSL, but presumably those gradient operators don't scale the return-values. So I suspect you'd have to multiply the x- and z-coordinates by the respective texture dimensions prior to normalisation.

Share this post


Link to post
Share on other sites
Mathematically the normal is defined like this:

Let S(x,y):R^2 -> R^3 be your surface, and f(x,y):R^2 - > R be your heightmap.

S(x,y) = <x, y, f(x,y)>

dSdx(x,y) = <1, 0, dfdx(x,y)>
dSdy(x,y) = <0, 1, dfdy(x,y)>

The normal of S at (x,y) is defined by dSdx(x,y) cross dSdy(x,y). The cross product can be computed by taking the rows of a 3x3 matrix to be [<i,j,k>, dSdx, dSdy], and then taking the determinant. This yields:

N(x,y) = normalize < dfdx(x,y), -dfdy(x,y), 1>

So, your result just switches around the axis

Share this post


Link to post
Share on other sites
Quote:
Original post by yahastu
This yields:

N(x,y) = normalize < dfdx(x,y), -dfdy(x,y), 1>

I'm sure it's just a typo, but you've lost a sign. Though you're quite right about the normals being upside-down. In akerlund's case, the correct formula for the upward normal is

vec3 N = normalize(vec3(-dFdx(sample.y), 1.0, -dFdy(sample.y)));

Share this post


Link to post
Share on other sites
Yep, the final equation I wrote was supposed to be:

N(x,y) = normalize < -dfdx(x,y), -dfdy(x,y), 1>

(the first term because it is 0*ddy - 1*ddx = -ddx)

Share this post


Link to post
Share on other sites
Well, my map is S(x,y) = <x, f(x,y), y >, so the normal should then be

N = normalize < -dfdx(x,y), 1, -dfdy(x,y)>

right?

This still gives way too high Y values. Scaling the df's with the texture size (512) helps but it's not 100% correct. Scaling with 256 gives a better result. But how can that be?

Share this post


Link to post
Share on other sites
You need to make sure that you scale both XY (image plane) and Z (image depth) appropriately. For example, if f(x,y) ranges from 0-255, and your image is 512x512 so X/Y range from 0-512, and you want to map this into world space such that it is inside a 20x20x20 cube, then you would have to scale f(x,y)/255*20, X/512*20, Y/512*20 ...you get the idea

Share this post


Link to post
Share on other sites

This topic is 3662 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.

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