Sign in to follow this  
Infinite_Daremo

Terrain Following Bug

Recommended Posts

Ive got a strange bug with my terrain following, it follows roughly but certain cells dont seem to be calculating right. This is being done in OpenGL. An entity checks its x and z position against a certain piece of terrain like so:
m_position.y = terrain->getHeight(m_position.x, m_position.z) + (m_pModel->getRadius() * 2);

Get radius is definetly right, heres the terrain checking code. Im un-necessarily calculating triangle normals here because i could figure out an algorithm to see which triangles are in a specific cell, i do have all surface normals pre calculated so if you guys know that it'd be great:
float CTerrain::getHeight(float x, float z)
{	
	int cellX = (x - m_pos.x) / MAP_SCALE; // Find cellX which entity point lies within
	int cellZ = -(z - m_pos.z) / MAP_SCALE; // Find cellZ which entity point lies within, negative because the way terrain verts are created

	int currentCell = (( cellZ * MAP_X ) + cellX ); // Find exact cell point lies within


	CVector bottomLeftVert = m_vTerrain[ currentCell ] + m_pos; // Vertices around current cell
	CVector bottomRightVert = m_vTerrain[ currentCell + 1 ] + m_pos;
	CVector topLeftVert = m_vTerrain[ (currentCell + MAP_X) ] + m_pos;
	CVector topRightVert = m_vTerrain[ (currentCell + MAP_X) + 1 ] + m_pos;

	float dx = x - bottomLeftVert.x; // x distance is cell
	float dz = -(z - bottomLeftVert.z); // z distance in cell

	if( dx > dz )
	{
		CVector normal = (topLeftVert - bottomLeftVert).CrossProduct( bottomRightVert - bottomLeftVert ); // Get normal of triangle

		// height = bottomLeftVert + ((dx * triNorm.x) + (dz * triNorm.z)) / -triNorm.y
		float height = bottomLeftVert.y + ( normal.x * dx + normal.z * dz ) / -normal.y;
	}

	else // dz > dx
	{
		CVector normal = (topLeftVert - topRightVert).CrossProduct( bottomRightVert - topRightVert );
     	        float height = topRightVert.y + ( normal.z * dz + normal.x * dx ) / -normal.y;

		return height;
	}





} m_pos = Vector of position in space, refers to first point. MAP_SCALE = Distance between vertices MAP_X = num verts in grid I used toymaker as reference for this, heres the exact guide i used: http://www.toymaker.info/Games/html/terrain_follow.html The specific bit is halfway down. Heres the vid: http://www.youtube.com/watch?v=xkGsPRqXgOY Any ideas how to sort this? [Edited by - Infinite_Daremo on July 28, 2008 2:41:56 PM]

Share this post


Link to post
Share on other sites
Your problem seems to be that you're calculating one normal in the opposite direction from the other. Try changing "/ -normal.y" to just "/ normal.y" in the dz > dx case, and see what happens.

Use the right-hand rule. For "A cross B equals C", point your index down A and your middle finger down B. Put your thumb at a right angle to your index finger, and your thumb is pointing in the direction of C.

If you do this for your math, you'll see that your thumb should point up in one case and down in the other case.

Share this post


Link to post
Share on other sites
Thanks for the reply, i re did some of the code and found how to get which triangles are in a specific cell. Its just currentCell * 2 for the bottom triangle and currentCell * 2 + 1 for the top, but its even weirder now so im guessing either the normals are wrong or its the way im doing it. Now i precalculate all my surface normals at creation like this:

void CTerrain::calculateSurfaceNormals()
{
int currentVertex = 0;
// Tri Normal calculations
for( int z = 0; z < MAP_Z-1; z++ )
{
for( int x = 0; x < MAP_X-1; x++ )
{
currentVertex = z * MAP_X + x;
m_vTriNormals[currentVertex * 2] = UTILITY.calculateNormal( &m_vTerrain[currentVertex], &m_vTerrain[currentVertex + 1], &m_vTerrain[currentVertex + MAP_Z]);
m_vTriNormals[(currentVertex * 2) +1] = UTILITY.calculateNormal( &m_vTerrain[currentVertex + MAP_Z + 1], &m_vTerrain[currentVertex + MAP_Z], &m_vTerrain[currentVertex + 1]);
}
}
}




And that code is here:


CVector CUtility::calculateNormal(CVector *p1, CVector *p2, CVector *p3)
{
CVector a, b, result;
float length;

a.x = (p1->x - p2->x);
a.y = (p1->y - p2->y);
a.z = (p1->z - p2->z);

b.x= ( p1->x - p3->x );
b.y= ( p1->y - p3->y );
b.z= ( p1->z - p3->z );

result.x = ( a.y * b.z ) - ( b.y * a.z );
result.y = ( b.x * a.z ) - ( a.x * b.z );
result.z = ( a.x * b.y ) - ( b.x * a.y );

length = (float)sqrt(result.x * result.x + result.y * result.y + result.z * result.z);

result.x /= length;
result.y /= length;
result.z /= length;

return result;
}




Then all that has changed in the terrain following bit is this:


int currentCell = (( cellZ * MAP_X ) + cellX ); // Find exact cell point lies within
int xTriangle = (currentCell * 2);
int zTriangle = (currentCell * 2) + 1;

if( dx > dz )
{
// height = bottomLeftVert + ((dx * triNorm.x) + (dz * triNorm.z)) / -triNorm.y
float height = bottomLeftVert.y + ( (m_vTriNormals[ xTriangle ].x * dx) + (m_vTriNormals[ xTriangle ].z * dz) ) / -m_vTriNormals[ xTriangle ].y;
return height;
}

else // dz > dx
{
float height = bottomLeftVert.y + ( (m_vTriNormals[ zTriangle ].x * dx) + (m_vTriNormals[ zTriangle ].z * dz) ) / m_vTriNormals[ zTriangle ].y;
return height;
}




I tried your suggestion about the normal being in the opposite direction, it just made the model go under the map. One thing to note though is that if i force dz to be always less than dx it looks believable-ish except when the two triangles dont correlate at all so im assuming the calculating for the z triangle is messed up.

[Edited by - Infinite_Daremo on July 29, 2008 9:24:23 AM]

Share this post


Link to post
Share on other sites
If your model is consistently under the map after that change, then it was the wrong case I changed; probably your up axis was the opposite direction to what I assumed. So, apply my suggestion to the dx>dz case instead of the dz>dx one.

Share this post


Link to post
Share on other sites
Thanks for the help so far, i did your suggestion but did it for both values and it works on some test terrain that mimics stairs, heres the result:

http://www.youtube.com/watch?v=ciwnvboMD_A - Seems to work

But with irregular terrain the result is like in the other video. The heigh calculation code seems to be fine. No i dont know if im calculating the normals incorrectly or im using the wrong cell to figure out the height.

My head hurts :(

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