PDA

View Full Version : Terrain Engine Math Problem

Starnut coder
12-30-2001, 06:16 PM
I created a Terrain Engine which consists
of Traingles in the following fashion:

h2__dist___h3
| /|
| / |
dist| / |dist
| / |
|/________|
h1 dist h4

These Squares with the length 'dist' are
put next to eachother. The amount of
squares in x-Direction is 'xlength'.
The amount in z-Direction is 'zlength'.
Now the Terrain works perfectly so I
will not go into the creation code.
Here comes the Problem:
I made an Algorithm that calculates the
Height of the Terrain in any Point (x;z)
but it doesn't seem to work perfectly.
Heres the code maybe you can give me a
better solution or correct mine:

float GetHeightXZ(float x, float z)
{
int xx, zz;
float halfx = (dist*xlength)/2;
float halfz = (dist*zlength)/2;
xx = (int)(xlength/2)+(x/dist);
zz = (int)(zlength/2)+(z/dist);
float xxw = x-((xx*dist)-halfx);
float zzw = z-((zz*dist)-halfz);
float h11, h33;
if(zzw > xxw)
{
h11 = h1-h2;
h33 = h3-h2;
float prozent1 = h11/10000;
float prozent2 = h33/10000;
float prozent3 = dist/10000;
x = h2+((((dist-zzw)/prozent3) *prozent1)+((xxw/prozent3)*prozent2));

}
else
{
h11 = h1-h4;
h33 = h3-h4;
float prozent1 = h11/10000;
float prozent2 = h33/10000;
float prozent3 = dist/10000;
x = h4+(((zzw/prozent3)*prozent1)+(((dist-xxw)/prozent3)*prozent2));

}
return x;
}

Many thanks in advance.
-Starnut

[This message has been edited by Starnut coder (edited 12-30-2001).]

[This message has been edited by Starnut coder (edited 12-30-2001).]

[This message has been edited by Starnut coder (edited 12-30-2001).]

Dodger
12-30-2001, 09:19 PM
Try this (i'll describe it only for the X axis and assume you're using a heightmap, rewriting it for getting the height from a mesh should be easy as long as you're on a regular grid).

First, find out which square you're on (in other words, in between which vertices of your mesh or pixels of your heightmap you are). For example, if you have a 512 pixel wide heightmap that stretch from 0 to say 100 in world coordinates (playerX is your player's x position on that grid):

xP = playerX*(512.0/100.0);

then xp is your position on the map in pixels (i'll go with the heightmap 'cause it's easier to explain).

now, you can find the heightmap pixel left and right of your player position with:

left = (int)xP;
right = left+1;

then get the 2 heights from the heightmap

hLeft = *(heightmap+left)
hRight = *(heightmap+right)

and then interpolate between these 2 positions depending on the position in between:

i = (xP-left);
playerHeightX = (1.0-i)*hLeft + i*hRight;

of course you also have to consider the y axis of your heightmap but that's fairly easy to figure out http://www.opengl.org/discussion_boards/ubb/wink.gif

Hope that helped

BlackJack
12-30-2001, 10:35 PM
StarNut, you make the problem too complex for nothing. We've an even much more complex built landscape built of diamonds which can be made of 8, 4 or 2 tris depending on LOD, but we absolutely don't care about that on any heighttests and this works now since more than 2 years very fine, because the user anyway won't see any difference in general, if you check the exact triangles or not, so I think you make yourself much more work than needed. So simply use something like this:

float height(float fx,float fz)
{
float x2=x-floor(fx),z2=z-floor(fz);
int x=(int) fx;
int z=(int) fz;
return (height[x,z]*(1-x2)+height[x+1,z]*x2)*(1-z2)+(height[x,z+1]*(1-x2)+height[x+1,z+1]*x2)*z2;
};

I think that should work. If you really want to test your triangles...hm...lemme see...something like (pseudocode)

float height(float fx,float fz)
{
float x2=x-floor(fx),z2=z-floor(fz);
int x=(int) fx;
int z=(int) fz;
cvector v1=vec(0,0,height[x,z]); //lower left
cvector v2=vec(0,1,height[x,z+1]); //upper left
cvector v3=vec(1,1,height[x+1,z+1]); //upper right
cvector v4=vec(1,0,height[x+1,z]); //lower right
cvector v5;
if((x2+z2)<1) //lower left tri?
{
v5=StretchVec(VSumm(v1,v2),0.5); //middlepoint between upper right and lower left fieldcorner
v4=VSumm(v2,StretchVec(VDiff(v5,v2),2)); //v4 now contains the 4th edge, if we had a flat quad using points v1,v2,v3 as first three points
return (v1*(1-x2)+v4*x2)*(1-z2)+(v2*(1-x2)+v3*x2)*z2;
}
else
{
...
};

VSumm = V+V2 //simple addition of all components
VDiff = V2-V //vector from V2 -> V
StretchVec = V*f //multiplication of all components with 2nd parameter

I think this would work (in the case that a field had a width and depth of 1).

Michael

[This message has been edited by BlackJack (edited 12-31-2001).]

Starnut coder
01-03-2002, 05:17 AM
Thanks for your Answers Guys.
Really appreciate it.

LaBasX2
01-03-2002, 06:33 AM
Hi!

I was using this code in an old terrain engine. It was working perfectly.

It is delphi code but should be easily readable.

function TTerrain.GetHeight(x, z: single): single;
var
gx, gy: integer;
dx, dy: single;
h1, h2, h3: single;
xslope, yslope: single;
begin
Result := 0;

gx := Trunc(x / 400); gy := Trunc(z / 400);

if (gx < 0) or (gx > 1024) or (gy < 0) or (gy > 1024) then exit;

dx := x - gx * 400; dy := z - gy * 400;

h1 := HeightMap[gx, gy];
h2 := HeightMap[gx + 1, gy + 1];

if dx < dy then
begin
// left triangle
h3 := HeightMap[gx, gy + 1];
xslope := (h2 - h3) / 400;
yslope := (h3 - h1) / 400;

Result := h1 + (dx * xslope + dy * yslope);
end
else
begin
// right triangle
h3 := HeightMap[gx + 1, gy];
xslope := (h3 - h1) / 400;
yslope := (h2 - h3) / 400;

Result := h1 + (dx * xslope + dy * yslope);
end;
end;