protected virtual void RenderModulativeTextureShadowedQueueGroupObjects( RenderQueueGroup group )
{
/* For each light, we need to render all the solids from each group,
then do the modulative shadows, then render the transparents from
each group.
Now, this means we are going to reorder things more, but that is required
if the shadows are to look correct. The overall order is preserved anyway,
it's just that all the transparents are at the end instead of them being
interleaved as in the normal rendering loop.
*/
// Iterate through priorities
foreach ( RenderPriorityGroup priorityGroup in group.PriorityGroups.Values )
{
// Sort the queue first
priorityGroup.Sort( this.cameraInProgress );
// Do solids
this.RenderSolidObjects( priorityGroup.solidPasses, true );
this.renderingNoShadowQueue = true;
this.RenderSolidObjects( priorityGroup.solidPassesNoShadow, true );
this.renderingNoShadowQueue = false;
}
// Iterate over lights, render received shadows
// only perform this if we're in the 'normal' render stage, to avoid
// doing it during the render to texture
if ( this.illuminationStage == IlluminationRenderStage.None )
{
this.illuminationStage = IlluminationRenderStage.RenderReceiverPass;
int sti = 0;
foreach ( Light light in this.lightsAffectingFrustum )
{
// Check limit reached
if ( sti == this.shadowTextures.Count )
break;
if ( !light.CastShadows )
{
continue;
}
Texture shadowTex = this.shadowTextures[ sti ];
Camera cam = shadowTex.GetBuffer().GetRenderTarget().GetViewport( 0 ).Camera;
// Hook up receiver texture
Pass targetPass = this.shadowTextureCustomReceiverPass != null
? this.shadowTextureCustomReceiverPass
: this.shadowReceiverPass;
TextureUnitState textureUnit = targetPass.GetTextureUnitState( 0 );
textureUnit.SetTextureName( shadowTex.Name );
// Hook up projection frustum if fixed-function, but also need to
// disable it explicitly for program pipeline.
textureUnit.SetProjectiveTexturing( !targetPass.HasVertexProgram, cam );
// clamp to border color in case this is a custom material
textureUnit.SetTextureAddressingMode( TextureAddressing.Border );
textureUnit.TextureBorderColor = ColorEx.White;
this.autoParamDataSource.TextureProjector = cam;
// if this light is a spotlight, we need to add the spot fader layer
// BUT not if using a custom projection matrix, since then it will be
// inappropriately shaped most likely
if ( light.Type == LightType.Spotlight && !cam.IsCustomProjectionMatrixEnabled )
{
// remove all TUs except 0 & 1
// (only an issue if additive shadows have been used)
while ( targetPass.TextureUnitStageCount > 2 )
{
targetPass.RemoveTextureUnitState( 2 );
}
// Add spot fader if not present already
if ( targetPass.TextureUnitStageCount == 2 &&
targetPass.GetTextureUnitState( 1 ).TextureName == "spot_shadow_fade.png" )
{
// Just set
TextureUnitState tex = targetPass.GetTextureUnitState( 1 );
tex.SetProjectiveTexturing( !targetPass.HasVertexProgram, cam );
}
else
{
// Remove any non-conforming spot layers
while ( targetPass.TextureUnitStageCount > 1 )
{
targetPass.RemoveTextureUnitState( 1 );
}
TextureUnitState tex = targetPass.CreateTextureUnitState( "spot_shadow_fade.png" );
tex.SetProjectiveTexturing( !targetPass.HasVertexProgram, cam );
tex.SetColorOperation( LayerBlendOperation.Add );
tex.SetTextureAddressingMode( TextureAddressing.Clamp );
}
}
else
{
// remove all TUs except 0 including spot
while ( targetPass.TextureUnitStageCount > 1 )
{
targetPass.RemoveTextureUnitState( 1 );
}
}
// Set lighting / blending modes
targetPass.SetSceneBlending( SceneBlendFactor.DestColor, SceneBlendFactor.Zero );
targetPass.LightingEnabled = false;
targetPass.Load();
// Fire pre-reciever event
// fireShadowTexturesPreReceiver(light, cam);
this.RenderTextureShadowReceiverQueueGroupObjects( group );
++sti;
} // for each light
this.illuminationStage = IlluminationRenderStage.None;
}
// Iterate again
foreach ( RenderPriorityGroup priorityGroup in group.PriorityGroups.Values )
{
// Do transparents
this.RenderTransparentObjects( priorityGroup.transparentPasses, true );
} // for each priority
}