Sign in to follow this  
remdul

per triangle terain height

Recommended Posts

Hi, Until now I was doing my height lookup through a bilinear interpolation. I'm now trying to do it per triangle for accuracy, so it matches the visual terrain. But I sort of got stuck. When the two triangles normals are not parallel, the code below gives bad result (point at center is either above or below the surface in that case). I know why, but I can't really figure a way how to do it right. I think the last lerp is wrong.
float CTerrain::GetHeight(float x, float z) const
{
 float p1;
 float p2;
 float p3;
 float p4;
 float dx;                // [0-1] x coordinate
 float dz;                // [0-1] z coordinate
 float h_top;             // p1 to p2
 float h_btm;             // p3 to p4
 int fx = floor(x);
 int fz = floor(z);
 p1 = GetHeight(fx,     fz);
 p2 = GetHeight(fx + 1, fz);
 p3 = GetHeight(fx,     fz + 1);
 p4 = GetHeight(fx + 1, fz + 1);
 dx = x - fx;
 dz = z - fz;
 if (dx + dz < 1) {
  // triangle A
  h_top = Lerp(p1, p2, dx);
  h_btm = p3;
 } else {
  // triangle B
  h_top = p2;
  h_btm = Lerp(p3, p4, dx);
 }
 return Lerp(h_top, h_btm, dz);
}


Triangle A is top left (x-,z-), triangle B is bottom right (x+,z+). Source/pseudo code is highly appreciated, for I completely suck at math theory.

Share this post


Link to post
Share on other sites
I didn't look at your code too carefully, but the easiest way is probably to:

1. Identify the triangle corresponding to the point (I think you're already doing this?)

2. Use the plane equation of the triangle to solve for the height given the 2D point coordinates

You can test the first part by drawing the target triangle in a different color, just to make sure that you're getting the right one. The calculation in step 2 is pretty easy, but post back if you have any problems with it.

Share this post


Link to post
Share on other sites

extern float getheight(float x,float z){
float r=0;//only r
int ix=(int) x, iz=(int) z;

if( ix<0 || iz<0 || ix+1>=heightmapx || iz+1>=heightmapz);
else{

x-=(float)ix;
z-=(float)iz;

float oneminusx=1-x;
float oneminusz=1-z;

r+=oneminusx*(heightmap[(ix+(iz*heightmapx))]);
r+=oneminusz*(heightmap[(ix+(iz*heightmapx))]);

r+=oneminusx*(heightmap[(ix+((iz+1)*heightmapx))]);
r+=z*(heightmap[(ix+((iz+1)*heightmapx))]);

r+=x*(heightmap[((ix+1)+((iz+1)*heightmapx))]);
r+=z*(heightmap[((ix+1)+((iz+1)*heightmapx))]);

r+=x*(heightmap[((ix+1)+(iz*heightmapx))]);
r+=oneminusz*(heightmap[((ix+1)+(iz*heightmapx))]);

r/=4;

return(r);
}
return(0);
}


Though I later optimised it this results in per tri height.

Share this post


Link to post
Share on other sites
Allright, I figured it out.

Here's the code:
float CTerrain::GetHeight(float x, float z) const
{
float p1;
float p2;
float p3;
float p4;
float dx;
float dz;
int fx = floor(x);
int fz = floor(z);
p1 = GetHeight(fx, fz);
p2 = GetHeight(fx + 1, fz);
p3 = GetHeight(fx, fz + 1);
p4 = GetHeight(fx + 1, fz + 1);
dx = x - fx;
dz = z - fz;
if (dx + dz < 1) {
return p1 + ((p2 - p1) * dx) + ((p3 - p1) * dz);
} else {
return p4 + ((p3 - p4) * (1 - dx)) + ((p2 - p4) * (1 - dz));
}
}





The idea is that (in case of triangle A) you calculate two vectors from p1 to p2 and p3, and use those two to 'transform' the point at (x,z). E.g.:

vx = p2 - p1
vz = p3 - p1
height = p1 + (vx * dx) + (vz * dz)

@Th0ughtCr1me: Doesn't your code do just a bilerp or something?

Share this post


Link to post
Share on other sites
No it's per triangle, and based on classic rasterization techniques. as is it results in a:

glBegin(GL_TRIANGLE_STRIP);
glVertex3f(1,0,0);
glVertex3f(0,0,0);
glVertex3f(1,0,1);
glVertex3f(0,0,1);
glEnd();

order, and is faster than a straight triangle check.

I'm Glad you got yours working though :)

Share this post


Link to post
Share on other sites

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