Terrain Following Bug

Started by
3 comments, last by Infinite_Daremo 15 years, 8 months ago
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:
Any ideas how to sort this? [Edited by - Infinite_Daremo on July 28, 2008 2:41:56 PM]
Advertisement
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.
RIP GameDev.net: launched 2 unusably-broken forum engines in as many years, and now has ceased operating as a forum at all, happy to remain naught but an advertising platform with an attached social media presense, headed by a staff who by their own admission have no idea what their userbase wants or expects.Here's to the good times; shame they exist in the past.
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]
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.
RIP GameDev.net: launched 2 unusably-broken forum engines in as many years, and now has ceased operating as a forum at all, happy to remain naught but an advertising platform with an attached social media presense, headed by a staff who by their own admission have no idea what their userbase wants or expects.Here's to the good times; shame they exist in the past.
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:

- 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 :(

This topic is closed to new replies.

Advertisement