navigation on terrain

Started by
40 comments, last by vpk 15 years, 8 months ago
hello can anyone tell me how do i navigate on my terrain. i am able to move forward/back/left/right by increasing the x/z values, but what i want is if there is an elevation or a hill, i should be able to go up on the hill and come down.. how do i go abt it?? is it possible to do it using camera position??
Advertisement
One method is to project forward a distance (dx), then project a ray downward and do an intersection test against the world polygons.

so the start of your test ray would be something like (x + dx, y - dy, z) projected straight down.
thanks for your response...

but i am a beginner in this so i am not able to understand clearly what you have mentioned..

can u be a little elaborate or give me some good tutorial suggestions/source code??
Hi,

a relatively easy method to figure out a point on the surface of your terrain would be to use a method called bilinear interpolation, or bilerping for short.

There are quite a few threads already on this board concerning this method but I will post some code that I use which works nicely.

float BilinearInterpolation(float iX, float iZ){	float temp[4];		//store the 4 heights next to our position	temp[0] = GetHeight((int)iX, (int)iZ);	temp[1] = GetHeight((int)(iX + 1), (int)iZ);	temp[2] = GetHeight((int)(iX + 1), (int)(iZ + 1));	temp[3] = GetHeight((int)iX, (int)(iZ + 1));		float x, z;	x = floor(iX); // get the lower x for height	z = floor(iZ); // get the lower z for height	//now for the interpolation	float tx = iX - x;	float tz = iZ - z;	float txtz = tx * tz;	//bilinear interpolation to get the current height above the surface	return ((temp[0] * (1 - tz - tx + txtz)) + (temp[1] * (tx - txtz)) + (temp[2] * txtz) + (temp[3] * (tz - txtz)));}


What happens here is you have an x, and a z coordinate (assuming you are using a right handed coordinate system) which is your player's (camera's) position along the horizontal axis.

In order to find the height (y) of the player (camera) we sample heights from the closest four vertices surrounding the camera and interpolate between them to get a y value. This is assuming that you are using a heightmap for your terrain, or something similar where you have access to height values of points at any given x,z.

The code I posed was based on some code that I found in a thread somewhere on the forum. Can't remember who/where so I give credit to this person indirectly. :)

If you seek more info just search the gamedev forum for "bilinear interpolation terrain" or something and you'll get tons of results. ;)

Enjoy...
--Jonathan Janevski
------------------------------------------------------------visit my: homepage
[EDIT] jjanevski posted at the same time and his code looks real (whereas mine is off the top of my head). I'd go with his version of it ;)

If your terrain is generated from a height-map, then you can determine the correct height by sampling the height-map.

E.g. you have a 128*128 8-bit greyscale height-map. You use this to generate a triangle-mesh with the horizontal (x/z) extents of (-500,-500) to (500,500) and a vertical (y) scale of 0 to 100.

Given an x/z coordinate, you can find the y coordinate by:

1) Converting from world-space to "height-map-space"
float pixX = (wrldX + 500)/1000.0 * 128.0;
float pixZ = (wrldZ + 500)/1000.0 * 128.0;

2) Taking a weighted average from the height-map's pixels
struct sample {  unsigned char rawByte;  float weight;}sample samples[4];int wholeX = (int)pixX;int wholeZ = (int)pixZ;float fracX = pixX - wholeX;float fracZ = pixZ - wholeZ;samples[0].rawByte = heightMap.getAt( wholeX, WholeZ );samples[0].weight = sqrt( fracX*fracX + fracY*fracY );samples[1].rawByte = heightMap.getAt( wholeX+1, WholeZ );samples[1].weight = sqrt( (1-fracX)*(1-fracX) + fracY*fracY );samples[2].rawByte = heightMap.getAt( wholeX, WholeZ+1 );samples[2].weight = sqrt( fracX*fracX + (1-fracY)*(1-fracY));samples[3].rawByte = heightMap.getAt( wholeX+1, WholeZ+1 );samples[3].weight = sqrt( 1-fracX)*(1-fracX) + (1-fracY)*(1-fracY));float rawY = 0;float weightSum = 0;for( int i=0; i<4; ++i ){  rawY += samples.rawByte * samples.weight;  weightSum += samples.weight;}rawY /= weightSum;
3) Convert the weighted height-map sample into world-space:
float y = rawY/255.0f * 100;
when we navigate on terrain, is it the camera navigating??
so if we have to move over a slope we need to move the camera over the slope, is it??

when we navigate using the keys we change the x/z values but if there is a slope how do we calculate the height over which the camera has to navigate??

hope u understood my point...
The x and z coordinates of the camera position is given, so you need to adjust the y coordinate (height) of the camera so that the camera stands on top of the terrain.
You need to define a function (look at above posts), to return the height of a point on the terrain, given the point's x,z coordinates (x and z coordinates of the camera).

As a next step you can add an offset value, so that camera doesn't sit exactly on the ground of the terrain:

CamPos.y = pTerrain->GetHeight(CamPos.x, CamPos.z) + offsetHeight;

[Edited by - Hiyar on July 31, 2008 7:14:05 AM]
Quote:Original post by Hiyar
The x and z coordinates of the camera position is given, so you need to adjust the y coordinate (height) of the camera so that the camera stands on top of the terrain.


the x and z coordinates of the camera are the x/z values which change when we navigate the keys,right??


Quote:You need to define a function (look at above posts), to return the height of a point on the terrain, given the point's x,z coordinates (x and z coordinates of the camera).


i am using a 2d array for the heightmap,so the y value will be the value at the array[x][z]..but x/z in this case is float value..so??


regards
Quote:Original post by vpk
i am using a 2d array for the heightmap,so the y value will be the value at the array[x][z]..but x/z in this case is float value..so??
So instead of reading a single value from the 2d array, you read 4 values and take a weighted average.

Instead of doing this:
float x = ..., z = ...;float y = array[int(x)][int(z)];
Do something like this:
float y1 = array[int(x)  ][int(z)  ];float y2 = array[int(x)+1][int(z)  ];float y3 = array[int(x)  ][int(z)+1];float y4 = array[int(x)+1][int(z)+1];float y = y1*w1 + y2*w2 + y3*w3 + y4*w4;


The code that jjanevski and I posted earlier shows how to perform a weighted average using bilinear filtering (i.e. it will show you how to do the above example properly).
Quote:Original post by Hodgman

The code that jjanevski and I posted earlier shows how to perform a weighted average using bilinear filtering (i.e. it will show you how to do the above example properly).


but in the code posted by you

int wholeX = (int)pixX;
int wholeZ = (int)pixZ;
float fracX = pixX - wholeX;
float fracZ = pixZ - wholeZ;

what is pixX and pixZ?? is it the x and z values at that point???

This topic is closed to new replies.

Advertisement