# Render a height map on a texture ?

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 ?
###### Who is Participating?

Commented:
For both shading & refraction you'd want to calculate a list of delta values for each heightmap "pixel". I'm assuming that the height map is stored in a 1 dim array, say a PIntegerArray:

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*heightMapWidth))mod(heightMapWidth*heightMap.Height)]-heightMap[abs((ix+1)+(iy*heightMapWidth))mod(heightMapWidth*heightMap.Height)];
deltaY := heightMap[abs(ix+((iy-1)*heightMapWidth))mod(heightMapWidth*heightMap.Height)]-heightMap[abs(ix+((iy+1)*heightMapWidth))mod(heightMapWidth*heightMap.Height)];

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)
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
0

Commented:
You can try using the openGL library. It's very powerful. if you have opengl32.dll and glu32.dll on your PC your almost there; you just have to write to code. Delphi also includes openGl.pas/dcu etc.

0

Author Commented:
Ok Mike, I kind of follow.

(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)..??
0

Commented:
The general idea is to get some scalar value from (deltaX,deltaY) with which to modify (somehow) (r,g,b). Let's tackle the former first.

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:

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

and so:

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
0

Author Commented:
Hey 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..?
0

Author Commented:
Hey 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..?
0

Commented:
Refraction, In my opinion, is actually simpler and more straight forward.  A couple general steps:

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.height then p := heightMap.width*heightMap.height-1

b)Similar to a), once you've calculated p manipulate it like so: p := (p+heightMap.width*heightMap.height)mod (heightMap.width*heightMap.height).  This will ensure that it's a legal value, but not nec. one of the two values allowed by a).  Note, if you're clever you'll choose the dim's of you're height map carefully.  For example, if the dim's are both [0..127] then the above can be replaced with:

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
0

Author Commented:
Ok, Excellent ! Finally got the refraction working well.

Thanx Mike !!!!!!
0

Commented:
Excelelnt, glad to be of service :)

GL
Mike
0
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.