/// <summary>
/// Internal method for locating a list of shadow casters which
/// could be affecting the frustum for a given light.
/// </summary>
/// <remarks>
/// Custom scene managers are encouraged to override this method to add optimizations,
/// and to add their own custom shadow casters (perhaps for world geometry)
/// </remarks>
/// <param name="light"></param>
/// <param name="camera"></param>
protected virtual IList FindShadowCastersForLight( Light light, Camera camera )
{
this.shadowCasterList.Clear();
if ( light.Type == LightType.Directional )
{
// Basic AABB query encompassing the frustum and the extrusion of it
AxisAlignedBox aabb = new AxisAlignedBox();
Vector3[] corners = camera.WorldSpaceCorners;
Vector3 min, max;
Vector3 extrude = light.DerivedDirection * -this.shadowDirLightExtrudeDist;
// do first corner
min = max = corners[ 0 ];
min.Floor( corners[ 0 ] + extrude );
max.Ceil( corners[ 0 ] + extrude );
for ( int c = 1; c < 8; ++c )
{
min.Floor( corners[ c ] );
max.Ceil( corners[ c ] );
min.Floor( corners[ c ] + extrude );
max.Ceil( corners[ c ] + extrude );
}
aabb.SetExtents( min, max );
if ( this.shadowCasterAABBQuery == null )
{
this.shadowCasterAABBQuery = this.CreateAABBRegionQuery( aabb );
}
else
{
this.shadowCasterAABBQuery.Box = aabb;
}
// Execute, use callback
this.shadowCasterQueryListener.Prepare( false,
light.GetFrustumClipVolumes( camera ),
light,
camera,
this.shadowCasterList,
light.ShadowFarDistanceSquared );
this.shadowCasterAABBQuery.Execute( this.shadowCasterQueryListener );
}
else
{
Sphere s = new Sphere( light.DerivedPosition, light.AttenuationRange );
// eliminate early if camera cannot see light sphere
if ( camera.IsObjectVisible( s ) )
{
// create or init a sphere region query
if ( this.shadowCasterSphereQuery == null )
{
this.shadowCasterSphereQuery = this.CreateSphereRegionQuery( s );
}
else
{
this.shadowCasterSphereQuery.Sphere = s;
}
// check if the light is within view of the camera
bool lightInFrustum = camera.IsObjectVisible( light.DerivedPosition );
PlaneBoundedVolumeList volumeList = null;
// Only worth building an external volume list if
// light is outside the frustum
if ( !lightInFrustum )
{
volumeList = light.GetFrustumClipVolumes( camera );
}
// prepare the query and execute using the callback
this.shadowCasterQueryListener.Prepare(
lightInFrustum,
volumeList,
light,
camera,
this.shadowCasterList,
light.ShadowFarDistanceSquared );
this.shadowCasterSphereQuery.Execute( this.shadowCasterQueryListener );
}
}
return this.shadowCasterList;
}