public Terrain RaySelectNeighbour( Ray ray, Real distanceLimit )
{
var modifiedRay = new Ray( ray.Origin, ray.Direction );
// Move back half a square - if we're on the edge of the AABB we might
// miss the intersection otherwise; it's ok for everywhere else since
// we want the far intersection anyway
modifiedRay.Origin = modifiedRay.GetPoint( -this.mWorldSize/this.mSize*0.5f );
// transform into terrain space
var tPos = Vector3.Zero;
var tDir = Vector3.Zero;
ConvertPosition( Space.WorldSpace, modifiedRay.Origin, Space.TerrainSpace, ref tPos );
ConvertDirection( Space.WorldSpace, modifiedRay.Direction, Space.TerrainSpace, ref tDir );
// Discard rays with no lateral component
if ( Utility.RealEqual( tDir.x, 0.0f, 1e-4 ) && Utility.RealEqual( tDir.y, 0.0f, 1e-4 ) )
{
return null;
}
var terrainRay = new Ray( tPos, tDir );
// Intersect with boundary planes
// Only collide with the positive (exit) side of the plane, because we may be
// querying from a point outside ourselves if we've cascaded more than once
var dist = Real.MaxValue;
IntersectResult intersectResult;
if ( tDir.x < 0.0f )
{
intersectResult = Utility.Intersects( terrainRay, new Plane( Vector3.UnitX, Vector3.Zero ) );
if ( intersectResult.Hit && intersectResult.Distance < dist )
{
dist = intersectResult.Distance;
}
}
else if ( tDir.x > 0.0f )
{
intersectResult = Utility.Intersects( terrainRay, new Plane( Vector3.NegativeUnitX, Vector3.UnitX ) );
if ( intersectResult.Hit && intersectResult.Distance < dist )
{
dist = intersectResult.Distance;
}
}
if ( tDir.y < 0.0f )
{
intersectResult = Utility.Intersects( terrainRay, new Plane( Vector3.UnitY, Vector3.Zero ) );
if ( intersectResult.Hit && intersectResult.Distance < dist )
{
dist = intersectResult.Distance;
}
}
else if ( tDir.y > 0.0f )
{
intersectResult = Utility.Intersects( terrainRay, new Plane( Vector3.NegativeUnitY, Vector3.UnitY ) );
if ( intersectResult.Hit && intersectResult.Distance < dist )
{
dist = intersectResult.Distance;
}
}
// discard out of range
if ( dist*this.mWorldSize > distanceLimit )
{
return null;
}
var terrainIntersectPos = terrainRay.GetPoint( dist );
var x = terrainIntersectPos.x;
var y = terrainIntersectPos.y;
var dx = tDir.x;
var dy = tDir.y;
// Never return diagonal directions, we will navigate those recursively anyway
if ( Utility.RealEqual( x, 1.0f, 1e-4f ) && dx > 0 )
{
return GetNeighbour( NeighbourIndex.East );
}
else if ( Utility.RealEqual( x, 0.0f, 1e-4f ) && dx < 0 )
{
return GetNeighbour( NeighbourIndex.West );
}
else if ( Utility.RealEqual( y, 1.0f, 1e-4f ) && dy > 0 )
{
return GetNeighbour( NeighbourIndex.North );
}
else if ( Utility.RealEqual( y, 0.0f, 1e-4f ) && dy < 0 )
{
return GetNeighbour( NeighbourIndex.South );
}
return null;
}