Solved

Render a height map on a texture ?

Posted on 2001-07-19
9
413 Views
Last Modified: 2010-04-06
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 ?
0
Comment
Question by:CyberKnight
  • 4
  • 4
9 Comments
 
LVL 6

Accepted Solution

by:
edey earned 60 total points
Comment Utility
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)
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
0
 
LVL 21

Expert Comment

by:gemarti
Comment Utility
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 Comment

by:CyberKnight
Comment Utility
Ok Mike, I kind of follow.

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

Expert Comment

by:edey
Comment Utility
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:

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
0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 

Author Comment

by:CyberKnight
Comment Utility
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 Comment

by:CyberKnight
Comment Utility
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
 
LVL 6

Expert Comment

by:edey
Comment Utility
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 Comment

by:CyberKnight
Comment Utility
Ok, Excellent ! Finally got the refraction working well.

Thanx Mike !!!!!!
0
 
LVL 6

Expert Comment

by:edey
Comment Utility
Excelelnt, glad to be of service :)

GL
Mike
0

Featured Post

Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

Join & Write a Comment

This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
Objective: - This article will help user in how to convert their numeric value become words. How to use 1. You can copy this code in your Unit as function 2. than you can perform your function by type this code The Code   (CODE) The Im…
It is a freely distributed piece of software for such tasks as photo retouching, image composition and image authoring. It works on many operating systems, in many languages.
This demo shows you how to set up the containerized NetScaler CPX with NetScaler Management and Analytics System in a non-routable Mesos/Marathon environment for use with Micro-Services applications.

728 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

9 Experts available now in Live!

Get 1:1 Help Now