Sign up to receive Decoded, a new monthly digest with product updates, feature release info, continuing education opportunities, and more.

Does anyone know, or can explain how to perform shading and/or refraction of a height map on a texture or image.

Say we have a 20 X 20 array which holds height values ranging from 0 to 10. How can I use this map to apply it to a 20 by 20 image ?

Say we have a 20 X 20 array which holds height values ranging from 0 to 10. How can I use this map to apply it to a 20 by 20 image ?

Lets tackle shading first.

(for simplicity lets say that the height map ranges from 0-100, just like percentage)

If height map looks like this

10 20 30

40 50 60

40 60 70

(Lets say position x,y = 50 (middle of the map))

Then DeltaX for X,Y(50) = 60-40 = 20

And DeltaY for X,Y(50) = 60-20 = 40

right ??

And if Pixel X,Y on my texture/image is a color like (R,G,B)100,155,50 (for example)

Then to get the new pixel color..??? what do I do with the Delta values..and the RGB values (100,155,50 in this example)..??

How do you want to shade your bmp? For the following I'm going to assume that pixels with a high angle of incidence (the vector points away from you, the slope is high) will be shaded and pixels with a low angle of incidence (that portion of the height map is relatively flat, "reflects" back to you) will be normally illuminated. So now we have to calculate our shading scalar. It would be nice to get a value we know is going to be between 0 and 1 this would be a posibility:

deltaX := cos(arcTan(deltaX));

deltaY := cos(arcTan(deltaY));

Note:, if everything comes out really dark you might want to try:

deltaX := cos(arcTan(deltaX/1000));

deltaY := cos(arcTan(deltaY/1000));

or some other constant. Then a simple average gets:

shadeRatio := (deltaX+deltaY)/2;

now we want that to be our total shade adjustment, and not for every r,g & b byte so:

shadeRatio := 1-(shadeRatio*sqrt(1/3));

and so:

r := r*shadeRation;

and so on.

I hope that that's clear. One thing I should make clear is that there are an infinite number of "right" ways to do this, each situation is a little different & playing with the constants, the formulas & such is highly recomended.

GL

Mike

That was X-cellent !!! Thank you !

I got the shading working pretty well !!!

Kewl.. It produces a really great effect.

You are right bout the inifite "right" ways to do it...

I had to play around with the formulas and constants a bit before I got it looking reasonable.

Can we touch on refraction ?

How do I manipulate the RGB pixels values with the delta values..?

That was X-cellent !!! Thank you !

I got the shading working pretty well !!!

Kewl.. It produces a really great effect.

You are right bout the inifite "right" ways to do it...

I had to play around with the formulas and constants a bit before I got it looking reasonable.

Can we touch on refraction ?

How do I manipulate the RGB pixels values with the delta values..?

1)Get the Normal to the plane (the height map) at the current pixel (x,y). Thats the vector perpendicular to the plane, in this case the plane tangent to the "surface" of out height field @ (x,y). We're actualy going to cheat & use (deltaX,deltaY) so we can use most of the shading code.

2)"Tune" the normal vector, if the magnitude of the vector is too high, we'll just get noise, if it's too low we won't see anything.

3)Add the normal to our current heightMap location (x,y). Check to see if our new point is outside the map, if it is, try to put it somwhere that "sorta" makes sense. If you've done a good job of "tuning", though, this shouldn't be too muich of a promblem & you can just use one of two solutions:

a)remember our height field is a linear array, so take (x,y) & get a scalar, p = x+y*heightMap.width. Remeber that x & y don't equal (x,y) any more, but (x,y)+k(deltaX,deltaY) where k is prob. some small number, like 0.001. Given this, if p < 0 then p := 0 else if p >= heightMap.width*heightMap.

b)Similar to a), once you've calculated p manipulate it like so: p := (p+heightMap.width*heightM

p := p and (16385)

which is much faster then using mod.

4)now instead of writing the rgb data from out ref. bmp to the display bmp we do something like this:

iy := p mod heightMap.width;

ix := p div heightMap.width;

destBmp[x,y] := sourceBmp[ix,iy];

Aaaaaaaaaaaaaand, that should about do it :)

GL

Mike

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.

Type

TIntegerArray = array[0..32767] of integer;

PIntegerArray = ^TIntegerArray;

that we happen to know if so wide & so tall. So we could do somthing like this:

for iy := 0 to heightMapHeight-1 do

for ix := 0 to heightMapWidth-1 do

begin

deltaX := heightMap[abs((ix-1)+(iy*h

deltaY := heightMap[abs(ix+((iy-1)*h

those rather ugly & unoptomized array ref's really just treat a 1 dim array like a 2 dim one and find the values for (a-b) & (c-d) if:

c

a,(ix,iy),b

d

It also takes care of over & under runs so you'll always refer to a real position in the array - even if you try a neg number or one past the end.

What you do with deltaX & deltaY depends on if you want shading or refraction. For shading you could adjust the rgb values of each pixel according to the the magnitude of the vector (deltaX,deltaY). For refraction you'd prob do something like this:

1)take that vector & multiply by some constant (like 0.01)

2)add the result to (ix,iy)

3)draw the pixel at (ix,iy)+i*(deltaX,deltaY) to (ix,iy)

This stuff take quite a bit of tweaking to look good - esp the refraction. if the delta vectors get too big the result just looks rather random. Another note is you'd prob. want to keep a "clean" v of your src bmp and never draw to it. So you'll need two bmp's, one for a ref, the other to prepare your shaded (or refracted, or both) bmp. That way you don't have to worry about refracting pixels that will need to be referred to later.

GL

Mike