Can't get intersection when starting position is over the map and it crashes when it's out.
/*
Given a point that is on a ray, move it until it is within a given heightmap's borders.
*/
void MoveIntoMap(Vec3f& point, Vec3f ray, Heightmap* hmap)
{
// Already within map?
if(point.x >= 1
&& point.x < hmap->m_widthx * TILE_SIZE - 1
&& point.z >= 1
&& point.z < hmap->m_widthz * TILE_SIZE - 1)
return;
// Get x distance off the map.
float xdif = 0;
if(point.x < 0) // If start x is behind the map
xdif = point.x - 5; // Add padding to make sure we're within the map
else if(point.x > hmap->m_widthx * TILE_SIZE) // If start x is in front of the map
xdif = hmap->m_widthx * TILE_SIZE - point.x + 5; // Add padding to make sure we're within the map
// Ray is of unit length, so this gives us how much we travel along the ray to get x to within the map border.
float x0moveratio = -xdif / ray.x;
point = point + ray * x0moveratio;
// Get z distance off the map.
float zdif = 0;
if(point.z < 0) // If start z is behind the map
zdif = point.z - 5; // Add padding to make sure we're within the map
else if(point.z > hmap->m_widthz * TILE_SIZE) // If start z is in front of the map
zdif = hmap->m_widthz * TILE_SIZE - point.z + 5; // Add padding to make sure we're within the map
// Ray is of unit length, so this gives us how much we travel along the ray to get z to within the map border.
float z0moveratio = -zdif / ray.z;
point = point + ray * z0moveratio;
}
bool TileIntersect(Heightmap* hmap, Vec3f* line, int x, int z, Vec3f* intersection)
{
Vec3f tri[3];
const int wx = hmap->m_widthx;
const int wz = hmap->m_widthz;
Vec3f* v = hmap->m_vertices;
tri[0] = v[ (z * wx + x) * 3 * 2 + 0 ];
tri[1] = v[ (z * wx + x) * 3 * 2 + 1 ];
tri[2] = v[ (z * wx + x) * 3 * 2 + 2 ];
if(IntersectedPolygon(tri, line, 3, intersection))
return true;
tri[0] = v[ (z * wx + x) * 3 * 2 + 3 ];
tri[1] = v[ (z * wx + x) * 3 * 2 + 4 ];
tri[2] = v[ (z * wx + x) * 3 * 2 + 5 ];
if(IntersectedPolygon(tri, line, 3, intersection))
return true;
return false;
}
bool FastMapIntersect(Heightmap* hmap, Vec3f line[2], Vec3f* intersection)
{
// If both start and end are on one side of the map, we can't get an intersection, so return false.
if(line[0].x < 0 && line[1].x < 0)
return false;
if(line[0].x >= hmap->m_widthx * TILE_SIZE && line[1].x >= hmap->m_widthx * TILE_SIZE)
return false;
if(line[0].z < 0 && line[1].z < 0)
return false;
if(line[0].z >= hmap->m_widthz * TILE_SIZE && line[1].z >= hmap->m_widthz * TILE_SIZE)
return false;
Vec3f ray = Normalize( line[1] - line[0] );
float lengthsqrd = Magnitude2( line[1] - line[0] );
MoveIntoMap(line[0], ray, hmap); // Move the start to within the map if it isn't already.
MoveIntoMap(line[1], ray, hmap); // Move the end to within the map if it isn't already.
float lengthdone = 0;
Vec3f currpoint = line[0];
int currtilex = currpoint.x / TILE_SIZE;
int currtilez = currpoint.z / TILE_SIZE;
int nexttilex = currtilex;
int nexttilez = currtilez;
// The directions in which we will move to the next tile on the x and z axis
int tiledx = 0;
int tiledz = 0;
if(ray.x > 0)
tiledx = 1;
else if(ray.x < 0)
tiledx = -1;
if(ray.z > 0)
tiledz = 1;
else if(ray.z < 0)
tiledz = -1;
// Move from tile to tile along the line until,
// testing each tile's triangles for intersection.
while(lengthdone*lengthdone < lengthsqrd)
{
float xdif = fabs( currtilex * TILE_SIZE - currpoint.x );
float zdif = fabs( currtilez * TILE_SIZE - currpoint.z );
float xmoveratio = xdif / ray.x + 1; // Add padding to make sure we get into the next tile
float zmoveratio = zdif / ray.z + 1; // Add padding to make sure we get into the next tile
float moveratio = 0;
// Move the smallest distance to the next tile
if(xmoveratio < zmoveratio)
{
moveratio = xmoveratio;
}
else
{
moveratio = zmoveratio;
}
currpoint = currpoint + ray * moveratio;
if(TileIntersect(hmap, line, currtilex, currtilez, intersection))
return true;
lengthdone += moveratio;
// Move the smallest distance to the next tile
if(xmoveratio < zmoveratio)
{
currtilex = nexttilex;
nexttilex += tiledx;
}
else
{
currtilez = nexttilez;
nexttilez += tiledz;
}
}
return false;
}
When I test each tile for intersection it works, but that's too slow, so I'm trying to get this to work.