/// <summary>
/// Internal method for rendering all the objects for a given light into the stencil buffer.
/// </summary>
/// <param name="light">The light source.</param>
/// <param name="camera">The camera being viewed from.</param>
protected virtual void RenderShadowVolumesToStencil( Light light, Camera camera )
{
// get the shadow caster list
IList casters = this.FindShadowCastersForLight( light, camera );
if ( casters.Count == 0 )
{
// No casters, just do nothing
return;
}
// Set up scissor test (point & spot lights only)
bool scissored = false;
if ( light.Type != LightType.Directional &&
this.targetRenderSystem.Capabilities.HasCapability( Capabilities.ScissorTest ) )
{
// Project the sphere onto the camera
float left, right, top, bottom;
Sphere sphere = new Sphere( light.DerivedPosition, light.AttenuationRange );
if ( camera.ProjectSphere( sphere, out left, out top, out right, out bottom ) )
{
scissored = true;
// Turn normalised device coordinates into pixels
int iLeft, iTop, iWidth, iHeight;
this.currentViewport.GetActualDimensions( out iLeft, out iTop, out iWidth, out iHeight );
int szLeft, szRight, szTop, szBottom;
szLeft = (int)( iLeft + ( ( left + 1 ) * 0.5f * iWidth ) );
szRight = (int)( iLeft + ( ( right + 1 ) * 0.5f * iWidth ) );
szTop = (int)( iTop + ( ( -top + 1 ) * 0.5f * iHeight ) );
szBottom = (int)( iTop + ( ( -bottom + 1 ) * 0.5f * iHeight ) );
this.targetRenderSystem.SetScissorTest( true, szLeft, szTop, szRight, szBottom );
}
}
this.targetRenderSystem.UnbindGpuProgram( GpuProgramType.Fragment );
// Can we do a 2-sided stencil?
bool stencil2sided = false;
if ( this.targetRenderSystem.Capabilities.HasCapability( Capabilities.TwoSidedStencil ) &&
this.targetRenderSystem.Capabilities.HasCapability( Capabilities.StencilWrap ) )
{
// enable
stencil2sided = true;
}
// Do we have access to vertex programs?
bool extrudeInSoftware = true;
bool finiteExtrude = !this.shadowUseInfiniteFarPlane ||
!this.targetRenderSystem.Capabilities.HasCapability(
Capabilities.InfiniteFarPlane );
if ( this.targetRenderSystem.Capabilities.HasCapability( Capabilities.VertexPrograms ) )
{
extrudeInSoftware = false;
this.EnableHardwareShadowExtrusion( light, finiteExtrude );
}
else
{
this.targetRenderSystem.UnbindGpuProgram( GpuProgramType.Vertex );
}
// Add light to internal list for use in render call
tmpLightList.Clear();
tmpLightList.Add( light );
// Turn off color writing and depth writing
this.targetRenderSystem.SetColorBufferWriteEnabled( false, false, false, false );
this.targetRenderSystem.DepthBufferWriteEnabled = false;
this.targetRenderSystem.StencilCheckEnabled = true;
this.targetRenderSystem.DepthBufferFunction = CompareFunction.Less;
// Calculate extrusion distance
float extrudeDistance = 0;
if ( light.Type == LightType.Directional )
{
extrudeDistance = this.shadowDirLightExtrudeDist;
}
// get the near clip volume
PlaneBoundedVolume nearClipVol = light.GetNearClipVolume( camera );
// Determine whether zfail is required
// We need to use zfail for ALL objects if we find a single object which
// requires it
bool zfailAlgo = false;
this.CheckShadowCasters( casters,
nearClipVol,
light,
extrudeInSoftware,
finiteExtrude,
zfailAlgo,
camera,
extrudeDistance,
stencil2sided,
tmpLightList );
// revert colour write state
this.targetRenderSystem.SetColorBufferWriteEnabled( true, true, true, true );
// revert depth state
this.targetRenderSystem.SetDepthBufferParams();
this.targetRenderSystem.StencilCheckEnabled = false;
this.targetRenderSystem.UnbindGpuProgram( GpuProgramType.Vertex );
if ( scissored )
{
// disable scissor test
this.targetRenderSystem.SetScissorTest( false );
}
}