/// <summary> /// Default constructor. /// </summary> internal RenderPriorityGroup(RenderQueueGroup parent, bool splitPassesByLightingType, bool splitNoShadowPasses, bool shadowCastersCannotBeReceivers) { this._parent = parent; // sorted list, using Pass as a key (sorted based on hashcode), and IRenderable as the value this.solidPasses = new SortedList(new SolidSort(), 50); this.solidPassesDiffuseSpecular = new SortedList(new SolidSort(), 50); this.solidPassesDecal = new SortedList(new SolidSort(), 50); this.solidPassesNoShadow = new SortedList(new SolidSort(), 50); this.splitPassesByLightingType = splitPassesByLightingType; this.splitNoShadowPasses = splitNoShadowPasses; this.shadowCastersCannotBeReceivers = shadowCastersCannotBeReceivers; }
/// <summary> /// Adds a renderable item to the queue. /// </summary> /// <param name="item">IRenderable object to add to the queue.</param> /// <param name="groupID">Group to add the item to.</param> /// <param name="priority"></param> public void AddRenderable(IRenderable renderable, ushort priority, RenderQueueGroupID groupID) { RenderQueueGroup group = GetQueueGroup(groupID); // let the material know it has been used, which also forces a recompile if required if (renderable.Material != null) { renderable.Material.Touch(); } // add the renderable to the appropriate group group.AddRenderable(renderable, priority); }
/// <summary> /// Get a render queue group. /// </summary> /// <remarks> /// New queue groups are registered as they are requested, /// therefore this method will always return a valid group. /// </remarks> /// <param name="queueID">ID of the queue group to retreive.</param> /// <returns></returns> public RenderQueueGroup GetQueueGroup(RenderQueueGroupID queueID) { var group = this.renderGroups[queueID] as RenderQueueGroup; // see if there is a current queue group for this group id if (group == null) { // create a new queue group for this group id group = new RenderQueueGroup(this, this.splitPassesByLightingType, this.splitNoShadowPasses, this.shadowCastersCannotBeReceivers); // add the new group to cached render group this.renderGroups.Add(queueID, group); } return(group); }
/// <summary> /// Render a group with the added complexity of modulative texture shadows. /// </summary> /// <param name="group">Render queue group.</param> 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 }
/// <summary> /// Render a group rendering only shadow casters. /// </summary> /// <param name="group">Render queue group.</param> protected virtual void RenderTextureShadowCasterQueueGroupObjects( RenderQueueGroup group ) { // This is like the basic group render, except we skip all transparents // and we also render any non-shadowed objects // Note that non-shadow casters will have already been eliminated during // FindVisibleObjects // Override auto param ambient to force vertex programs and fixed function to // use shadow colour if ( this.IsShadowTechniqueAdditive ) { this.autoParamDataSource.AmbientLight = ColorEx.Black; this.targetRenderSystem.AmbientLight = ColorEx.Black; } else { this.autoParamDataSource.AmbientLight = this.shadowColor; this.targetRenderSystem.AmbientLight = this.shadowColor; } // Iterate through priorities foreach ( RenderPriorityGroup priorityGroup in group.PriorityGroups.Values ) { // Sort the queue first priorityGroup.Sort( this.cameraInProgress ); // Do solids, override light list in case any vertex programs use them this.RenderSolidObjects( priorityGroup.solidPasses, false, this.nullLightList ); this.renderingNoShadowQueue = true; this.RenderSolidObjects( priorityGroup.solidPassesNoShadow, false, this.nullLightList ); this.renderingNoShadowQueue = false; // Do transparents that cast shadows this.RenderTransparentShadowCasterObjects( priorityGroup.transparentPasses, false, this.nullLightList ); } // for each priority // reset ambient light this.autoParamDataSource.AmbientLight = this.ambientColor; this.targetRenderSystem.AmbientLight = this.ambientColor; }
/// <summary> /// Render a group with the added complexity of modulative stencil shadows. /// </summary> /// <param name="group">Render queue group.</param> protected virtual void RenderModulativeStencilShadowedQueueGroupObjects( 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 it 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. */ foreach ( RenderPriorityGroup priorityGroup in group.PriorityGroups.Values ) { // sort the group first priorityGroup.Sort( this.cameraInProgress ); // do solids this.RenderSolidObjects( priorityGroup.solidPasses, true ); } // iterate over lights, rendering all volumes to the stencil buffer foreach ( Light light in this.lightsAffectingFrustum ) { if ( light.CastShadows ) { // clear the stencil buffer this.targetRenderSystem.ClearFrameBuffer( FrameBufferType.Stencil ); this.RenderShadowVolumesToStencil( light, this.cameraInProgress ); // render full-screen shadow modulator for all lights this.SetPass( this.shadowModulativePass ); // turn the stencil check on this.targetRenderSystem.StencilCheckEnabled = true; // we render where the stencil is not equal to zero to render shadows, not lit areas this.targetRenderSystem.SetStencilBufferParams( CompareFunction.NotEqual, 0 ); this.RenderSingleObject( this.fullScreenQuad, this.shadowModulativePass, false ); // reset stencil buffer params this.targetRenderSystem.SetStencilBufferParams(); this.targetRenderSystem.StencilCheckEnabled = false; this.targetRenderSystem.SetDepthBufferParams(); } } // for each light foreach ( RenderPriorityGroup priorityGroup in group.PriorityGroups.Values ) { // Do non-shadowable solids this.renderingNoShadowQueue = true; this.RenderSolidObjects( priorityGroup.solidPassesNoShadow, true ); this.renderingNoShadowQueue = false; } // for each priority foreach ( RenderPriorityGroup priorityGroup in group.PriorityGroups.Values ) { // Do transparents this.RenderTransparentObjects( priorityGroup.transparentPasses, true ); } // for each priority }
/// <summary> /// Render a group with the added complexity of additive stencil shadows. /// </summary> /// <param name="group">Render queue group.</param> protected virtual void RenderAdditiveStencilShadowedQueueGroupObjects( RenderQueueGroup group ) { LightList tempLightList = new LightList(); foreach ( RenderPriorityGroup priorityGroup in group.PriorityGroups.Values ) { // sort the group first priorityGroup.Sort( this.cameraInProgress ); // Clear light list tempLightList.Clear(); // Render all the ambient passes first, no light iteration, no lights this.illuminationStage = IlluminationRenderStage.Ambient; this.RenderSolidObjects( priorityGroup.solidPasses, false, tempLightList ); // Also render any objects which have receive shadows disabled this.renderingNoShadowQueue = true; this.RenderSolidObjects( priorityGroup.solidPassesNoShadow, true ); this.renderingNoShadowQueue = false; // Now iterate per light this.illuminationStage = IlluminationRenderStage.PerLight; foreach ( Light light in lightsAffectingFrustum ) { // Set light state if ( light.CastShadows ) { // Clear stencil this.targetRenderSystem.ClearFrameBuffer( FrameBufferType.Stencil ); this.RenderShadowVolumesToStencil( light, this.cameraInProgress ); // turn stencil check on this.targetRenderSystem.StencilCheckEnabled = true; // NB we render where the stencil is equal to zero to render lit areas this.targetRenderSystem.SetStencilBufferParams( CompareFunction.Equal, 0 ); } // render lighting passes for this light tempLightList.Clear(); tempLightList.Add( light ); this.RenderSolidObjects( priorityGroup.solidPassesDiffuseSpecular, false, tempLightList ); // Reset stencil params this.targetRenderSystem.SetStencilBufferParams(); this.targetRenderSystem.StencilCheckEnabled = false; this.targetRenderSystem.SetDepthBufferParams(); } // for each light // Now render decal passes, no need to set lights as lighting will be disabled this.illuminationStage = IlluminationRenderStage.Decal; this.RenderSolidObjects( priorityGroup.solidPassesDecal, false ); } // for each priority // reset lighting stage this.illuminationStage = IlluminationRenderStage.None; // Iterate again foreach ( RenderPriorityGroup priorityGroup in group.PriorityGroups.Values ) { // Do transparents this.RenderTransparentObjects( priorityGroup.transparentPasses, true ); } // for each priority }
private void UpdateRenderQueueGroupSplitOptions( RenderQueueGroup group, bool suppressShadows, bool suppressRenderState ) { if ( this.IsShadowTechniqueStencilBased ) { // Casters can always be receivers group.ShadowCastersCannotBeReceivers = false; } else if ( this.IsShadowTechniqueTextureBased ) { group.ShadowCastersCannotBeReceivers = !this.shadowTextureSelfShadow; } if ( !suppressShadows && this.currentViewport.ShowShadows && this.IsShadowTechniqueAdditive ) { // Additive lighting, we need to split everything by illumination stage group.SplitPassesByLightingType = true; } else { group.SplitPassesByLightingType = false; } if ( !suppressShadows && this.currentViewport.ShowShadows && this.IsShadowTechniqueInUse ) { // Tell render queue to split off non-shadowable materials group.SplitNoShadowPasses = true; } else { group.SplitNoShadowPasses = false; } }
/// <summary> /// Get a render queue group. /// </summary> /// <remarks> /// New queue groups are registered as they are requested, /// therefore this method will always return a valid group. /// </remarks> /// <param name="queueID">ID of the queue group to retreive.</param> /// <returns></returns> public RenderQueueGroup GetQueueGroup( RenderQueueGroupID queueID ) { var group = this.renderGroups[ queueID ] as RenderQueueGroup; // see if there is a current queue group for this group id if ( group == null ) { // create a new queue group for this group id group = new RenderQueueGroup( this, this.splitPassesByLightingType, this.splitNoShadowPasses, this.shadowCastersCannotBeReceivers ); // add the new group to cached render group this.renderGroups.Add( queueID, group ); } return group; }
/// <summary> /// Render the objects in a given queue group. /// </summary> /// <param name="group">Group containing the objects to render.</param> protected virtual void RenderQueueGroupObjects( RenderQueueGroup group ) { // Redirect to alternate versions if stencil shadows in use bool doShadows = group.ShadowsEnabled && this.currentViewport.ShowShadows && !this.suppressShadows && !this.suppressRenderStateChanges; if ( doShadows && this.shadowTechnique == ShadowTechnique.StencilAdditive ) { this.RenderAdditiveStencilShadowedQueueGroupObjects( group ); } else if ( doShadows && this.shadowTechnique == ShadowTechnique.StencilModulative ) { this.RenderModulativeStencilShadowedQueueGroupObjects( group ); } else if ( this.IsShadowTechniqueTextureBased ) { // Modulative texture shadows in use if ( this.illuminationStage == IlluminationRenderStage.RenderToTexture ) { // Shadow caster pass if ( this.currentViewport.ShowShadows && !this.suppressShadows && !this.suppressRenderStateChanges ) { this.RenderTextureShadowCasterQueueGroupObjects( group ); } } else { // Ordinary + receiver pass if ( doShadows ) { if ( this.IsShadowTechniqueAdditive ) { this.RenderAdditiveTextureShadowedQueueGroupObjects( group ); } else { this.RenderModulativeTextureShadowedQueueGroupObjects( group ); } } else { this.RenderBasicQueueGroupObjects( group ); } } } else { // No shadows, ordinary pass this.RenderBasicQueueGroupObjects( group ); } }
/// <summary> /// Render a group with the added complexity of additive texture shadows. /// </summary> /// <param name="group">Render queue group.</param> void RenderAdditiveTextureShadowedQueueGroupObjects(RenderQueueGroup group) { List<Light> tempLightList = new List<Light>(); for(int i = 0; i < group.NumPriorityGroups; i++) { RenderPriorityGroup priorityGroup = group.GetPriorityGroup(i); // Sort the queue first priorityGroup.Sort(cameraInProgress); // Clear light list tempLightList.Clear(); // Render all the ambient passes first, no light iteration, no lights RenderSolidObjects(priorityGroup.solidPasses, false, tempLightList); // Also render any objects which have receive shadows disabled renderingNoShadowQueue = true; RenderSolidObjects(priorityGroup.solidPassesNoShadow, true); renderingNoShadowQueue = false; // only perform this next part if we're in the 'normal' render stage, to avoid // doing it during the render to texture if (illuminationStage == IlluminationRenderStage.None) { ICollection<MovableObject> lightList = GetMovableObjectCollection("Light"); List<Light> lightList2 = new List<Light>(); foreach (Light l in lightList) lightList2.Add(l); lightList2.Sort(); // Iterate over lights, render masked for (int li = 0, sti = 0; li < lightsAffectingFrustum.Count; li++) { Light light = lightsAffectingFrustum[li]; // Set light state if (light.CastShadows && sti < shadowTextures.Count) { Texture shadowTex = shadowTextures[sti]; // Get camera for current shadow texture Camera camera = shadowTex.GetBuffer().GetRenderTarget().GetViewport(0).Camera; // Hook up receiver texture Pass targetPass = shadowTextureCustomReceiverPass != null ? shadowTextureCustomReceiverPass : shadowReceiverPass; targetPass.GetTextureUnitState(0).SetTextureName(shadowTex.Name); // Hook up projection frustum targetPass.GetTextureUnitState(0).SetProjectiveTexturing(true, camera); autoParamDataSource.TextureProjector = camera; // Remove any spot fader layer if (targetPass.NumTextureUnitStages > 1 && targetPass.GetTextureUnitState(1).TextureName == "spot_shadow_fade.png") { // remove spot fader layer (should only be there if // we previously used modulative shadows) targetPass.RemoveTextureUnitState(1); } // Set lighting / blending modes targetPass.SetSceneBlending(SceneBlendFactor.One, SceneBlendFactor.One); targetPass.LightingEnabled = true; targetPass.Load(); // increment shadow texture since used ++sti; illuminationStage = IlluminationRenderStage.RenderModulativePass; } else { illuminationStage = IlluminationRenderStage.None; } // render lighting passes for this light if (tempLightList.Count == 0) tempLightList.Add(light); else tempLightList[0] = light; RenderSolidObjects(priorityGroup.solidPassesDiffuseSpecular, false, lightList2); }// for each light illuminationStage = IlluminationRenderStage.None; // Now render decal passes, no need to set lights as lighting will be disabled RenderSolidObjects(priorityGroup.solidPassesDecal, false); } }// for each priority for(int i = 0; i < group.NumPriorityGroups; i++) { RenderPriorityGroup priorityGroup = group.GetPriorityGroup(i); // Do transparents RenderTransparentObjects(priorityGroup.transparentPasses, true); }// for each priority }
/// <summary> /// Render a group with the added complexity of additive texture shadows. /// </summary> /// <param name="group">Render queue group.</param> private void RenderAdditiveTextureShadowedQueueGroupObjects( RenderQueueGroup group ) { LightList tempLightList = new LightList(); foreach ( RenderPriorityGroup priorityGroup in group.PriorityGroups.Values ) { // Sort the queue first priorityGroup.Sort( this.cameraInProgress ); // Clear light list tempLightList.Clear(); // Render all the ambient passes first, no light iteration, no lights this.RenderSolidObjects( priorityGroup.solidPasses, false, tempLightList ); // Also render any objects which have receive shadows disabled this.renderingNoShadowQueue = true; this.RenderSolidObjects( priorityGroup.solidPassesNoShadow, true ); this.renderingNoShadowQueue = false; // only perform this next part if we're in the 'normal' render stage, to avoid // doing it during the render to texture if ( this.illuminationStage == IlluminationRenderStage.None ) { // Iterate over lights, render masked int sti = 0; foreach ( Light light in this.lightsAffectingFrustum ) { // Set light state if ( light.CastShadows && sti < this.shadowTextures.Count ) { Texture shadowTex = this.shadowTextures[ sti ]; // Get camera for current shadow texture Camera camera = shadowTex.GetBuffer().GetRenderTarget().GetViewport( 0 ).Camera; // Hook up receiver texture Pass targetPass = this.shadowTextureCustomReceiverPass != null ? this.shadowTextureCustomReceiverPass : this.shadowReceiverPass; targetPass.GetTextureUnitState( 0 ).SetTextureName( shadowTex.Name ); // Hook up projection frustum targetPass.GetTextureUnitState( 0 ).SetProjectiveTexturing( true, camera ); this.autoParamDataSource.TextureProjector = camera; // Remove any spot fader layer if ( targetPass.TextureUnitStageCount > 1 && targetPass.GetTextureUnitState( 1 ).TextureName == "spot_shadow_fade.png" ) { // remove spot fader layer (should only be there if // we previously used modulative shadows) targetPass.RemoveTextureUnitState( 1 ); } // Set lighting / blending modes targetPass.SetSceneBlending( SceneBlendFactor.One, SceneBlendFactor.One ); targetPass.LightingEnabled = true; targetPass.Load(); // increment shadow texture since used ++sti; this.illuminationStage = IlluminationRenderStage.RenderReceiverPass; } else { this.illuminationStage = IlluminationRenderStage.None; } // render lighting passes for this light tempLightList.Clear(); tempLightList.Add( light ); this.RenderSolidObjects( priorityGroup.solidPassesDiffuseSpecular, false, tempLightList ); } // for each light this.illuminationStage = IlluminationRenderStage.None; // Now render decal passes, no need to set lights as lighting will be disabled this.RenderSolidObjects( priorityGroup.solidPassesDecal, false ); } } // for each priority foreach ( RenderPriorityGroup priorityGroup in group.PriorityGroups.Values ) { // Do transparents this.RenderTransparentObjects( priorityGroup.transparentPasses, true ); } // for each priority }
/// <summary> /// Render the objects in a given queue group. /// </summary> /// <param name="group">Group containing the objects to render.</param> protected virtual void RenderQueueGroupObjects(RenderQueueGroup group) { // Redirect to alternate versions if stencil shadows in use bool doShadows = group.ShadowsEnabled && currentViewport.ShadowsEnabled && !suppressShadows && !suppressRenderStateChanges; renderQueueGroupMeter.Enter(); if(doShadows && shadowTechnique == ShadowTechnique.StencilAdditive) { renderAdditiveGroupMeter.Enter(); RenderAdditiveStencilShadowedQueueGroupObjects(group); renderAdditiveGroupMeter.Exit(); } else if(doShadows && shadowTechnique == ShadowTechnique.StencilModulative) { renderModulativeGroupMeter.Enter(); RenderModulativeStencilShadowedQueueGroupObjects(group); renderModulativeGroupMeter.Exit(); } else if (IsShadowTechniqueTextureBased) { // Modulative texture shadows in use if (illuminationStage == IlluminationRenderStage.RenderToTexture) { // Shadow caster pass if (currentViewport.ShadowsEnabled && !suppressShadows && !suppressRenderStateChanges) { renderTextureCasterGroupMeter.Enter(); RenderTextureShadowCasterQueueGroupObjects(group); renderTextureCasterGroupMeter.Exit(); } } else { // Ordinary + receiver pass if (doShadows) { renderTextureShadowedGroupMeter.Enter(); if (IsShadowTechniqueAdditive) RenderAdditiveTextureShadowedQueueGroupObjects(group); else RenderModulativeTextureShadowedQueueGroupObjects(group); renderTextureShadowedGroupMeter.Exit(); } else RenderBasicQueueGroupObjects(group); } } else // No shadows, ordinary pass RenderBasicQueueGroupObjects(group); renderQueueGroupMeter.Exit(); }
/// <summary> /// Render a group with the added complexity of modulative texture shadows. /// </summary> /// <param name="group">Render queue group.</param> 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 renderModulativeGroupsMeter.Enter(); for(int i = 0; i < group.NumPriorityGroups; i++) { RenderPriorityGroup priorityGroup = group.GetPriorityGroup(i); // Sort the queue first priorityGroup.Sort(cameraInProgress); // Do solids RenderSolidObjects(priorityGroup.solidPasses, true); renderingNoShadowQueue = true; RenderSolidObjects(priorityGroup.solidPassesNoShadow, true); renderingNoShadowQueue = false; } renderModulativeGroupsMeter.Exit(); renderModulativeLightsMeter.Enter(); // 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 (illuminationStage == IlluminationRenderStage.None) { illuminationStage = IlluminationRenderStage.RenderModulativePass; for (int i = 0, sti = 0; i < lightsAffectingFrustum.Count && sti < shadowTextures.Count; i++) { Light light = lightsAffectingFrustum[i]; if (!light.CastShadows) continue; Texture shadowTex = shadowTextures[sti]; Camera cam = shadowTex.GetBuffer().GetRenderTarget().GetViewport(0).Camera; // Hook up receiver texture Pass targetPass = shadowTextureCustomReceiverPass != null ? shadowTextureCustomReceiverPass : shadowReceiverPass; targetPass.GetTextureUnitState(0).SetTextureName(shadowTex.Name); // Hook up projection frustum targetPass.GetTextureUnitState(0).SetProjectiveTexturing(true, cam); autoParamDataSource.TextureProjector = cam; // if this light is a spotlight, we need to add the spot fader layer if (light.Type == LightType.Spotlight) { // remove all TUs except 0 & 1 // (only an issue if additive shadows have been used) while (targetPass.NumTextureUnitStages > 2) targetPass.RemoveTextureUnitState(2); // Add spot fader if not present already if (targetPass.NumTextureUnitStages == 2 && targetPass.GetTextureUnitState(1).TextureName == "spot_shadow_fade.png") { // Just set TextureUnitState tex = targetPass.GetTextureUnitState(1); tex.SetProjectiveTexturing(true, cam); } else { // Remove any non-conforming spot layers while (targetPass.NumTextureUnitStages > 1) targetPass.RemoveTextureUnitState(1); TextureUnitState tex = targetPass.CreateTextureUnitState("spot_shadow_fade.png"); tex.SetProjectiveTexturing(true, cam); tex.SetColorOperation(LayerBlendOperation.Add); tex.TextureAddressing = TextureAddressing.Clamp; } } else { // remove all TUs except 0 including spot while (targetPass.NumTextureUnitStages > 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); RenderTextureShadowReceiverQueueGroupObjects(group); ++sti; } // for each light illuminationStage = IlluminationRenderStage.None; } renderModulativeLightsMeter.Exit(); // Iterate again for (int i = 0; i < group.NumPriorityGroups; i++) { RenderPriorityGroup priorityGroup = group.GetPriorityGroup(i); // Do transparents RenderTransparentObjects(priorityGroup.transparentPasses, true); } // for each priority }
/// <summary> /// Render a group in the ordinary way /// </summary> /// <param name="group">Group containing the objects to render.</param> protected virtual void RenderBasicQueueGroupObjects(RenderQueueGroup group) { // Basic render loop // Iterate through priorities for(int i = 0; i < group.NumPriorityGroups; i++) { RenderPriorityGroup priorityGroup = group.GetPriorityGroup(i); // Sort the queue first priorityGroup.Sort(cameraInProgress); // Do solids RenderSolidObjects(priorityGroup.solidPasses, true); // Do transparents RenderTransparentObjects(priorityGroup.transparentPasses, true); }// for each priority }
/// <summary> /// Render a group with the added complexity of additive stencil shadows. /// </summary> /// <param name="group">Render queue group.</param> protected virtual void RenderAdditiveStencilShadowedQueueGroupObjects(RenderQueueGroup group) { List<Light> tempLightList = new List<Light>(); for(int i = 0; i < group.NumPriorityGroups; i++) { RenderPriorityGroup priorityGroup = group.GetPriorityGroup(i); // sort the group first priorityGroup.Sort(cameraInProgress); // Clear light list tempLightList.Clear(); // Render all the ambient passes first, no light iteration, no lights illuminationStage = IlluminationRenderStage.Ambient; RenderSolidObjects(priorityGroup.solidPasses, false, tempLightList); // Also render any objects which have receive shadows disabled renderingNoShadowQueue = true; RenderSolidObjects(priorityGroup.solidPassesNoShadow, true); renderingNoShadowQueue = false; // Now iterate per light illuminationStage = IlluminationRenderStage.PerLight; for (int li = 0; li < lightsAffectingFrustum.Count; li++) { Light light = lightsAffectingFrustum[li]; // Set light state if (light.CastShadows) { // Clear stencil targetRenderSystem.ClearFrameBuffer(FrameBuffer.Stencil); RenderShadowVolumesToStencil(light, cameraInProgress); // turn stencil check on targetRenderSystem.StencilCheckEnabled = true; // NB we render where the stencil is equal to zero to render lit areas targetRenderSystem.SetStencilBufferParams(CompareFunction.Equal, 0); } // render lighting passes for this light if (tempLightList.Count == 0) { tempLightList.Add(light); } else { tempLightList[0] = light; } RenderSolidObjects(priorityGroup.solidPassesDiffuseSpecular, false, tempLightList); // Reset stencil params targetRenderSystem.SetStencilBufferParams(); targetRenderSystem.StencilCheckEnabled = false; targetRenderSystem.SetDepthBufferParams(); }// for each light // Now render decal passes, no need to set lights as lighting will be disabled illuminationStage = IlluminationRenderStage.Decal; RenderSolidObjects(priorityGroup.solidPassesDecal, false); }// for each priority // reset lighting stage illuminationStage = IlluminationRenderStage.None; // Iterate again for(int i = 0; i < group.NumPriorityGroups; i++) { RenderPriorityGroup priorityGroup = group.GetPriorityGroup(i); // Do transparents RenderTransparentObjects(priorityGroup.transparentPasses, true); }// for each priority }
/// <summary> /// Render a group rendering only shadow receivers. /// We have our own version here to add some optimizations /// </summary> /// <param name="group">Render queue group.</param> protected override void RenderTextureShadowReceiverQueueGroupObjects(RenderQueueGroup group) { // Override auto param ambient to force vertex programs to go full-bright autoParamDataSource.AmbientLight = ColorEx.White; targetRenderSystem.AmbientLight = ColorEx.White; // Iterate through priorities for (int i = 0; i < group.NumPriorityGroups; i++) { RenderPriorityGroup priorityGroup = group.GetPriorityGroup(i); // Do solids, override light list in case any vertex programs use them RenderShadowReceiverObjects(priorityGroup.SolidPasses, false, nullLightList); // Don't render transparents or passes which have shadow receipt disabled }// for each priority // reset ambient autoParamDataSource.AmbientLight = ambientColor; targetRenderSystem.AmbientLight = ambientColor; }
/// <summary> /// Render a group rendering only shadow receivers. /// </summary> /// <param name="group">Render queue group.</param> protected virtual void RenderTextureShadowReceiverQueueGroupObjects( RenderQueueGroup group ) { // Override auto param ambient to force vertex programs to go full-bright this.autoParamDataSource.AmbientLight = ColorEx.White; this.targetRenderSystem.AmbientLight = ColorEx.White; // Iterate through priorities foreach ( RenderPriorityGroup priorityGroup in group.PriorityGroups.Values ) { // Do solids, override light list in case any vertex programs use them this.RenderSolidObjects( priorityGroup.solidPasses, false, this.nullLightList ); // Don't render transparents or passes which have shadow receipt disabled } // for each priority // reset ambient this.autoParamDataSource.AmbientLight = this.ambientColor; this.targetRenderSystem.AmbientLight = this.ambientColor; }
internal void Invoke( RenderQueueGroup queueGroup, SceneManager sceneManager ) { throw new NotImplementedException(); }
/// <summary> /// Render a group in the ordinary way /// </summary> /// <param name="group">Group containing the objects to render.</param> protected virtual void RenderBasicQueueGroupObjects( RenderQueueGroup group ) { // Basic render 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 ); // Do transparents this.RenderTransparentObjects( priorityGroup.transparentPasses, true ); } // for each priority }
/// <summary> /// Get a render queue group. /// </summary> /// <remarks> /// New queue groups are registered as they are requested, /// therefore this method will always return a valid group. /// </remarks> /// <param name="queueID">ID of the queue group to retreive.</param> /// <returns></returns> public RenderQueueGroup GetQueueGroup(RenderQueueGroupID queueID) { RenderQueueGroup group = null; // see if there is a current queue group for this group id if(renderGroups[queueID] == null) { // create a new queue group for this group id group = new RenderQueueGroup(this, splitPassesByLightingType, splitNoShadowPasses, shadowCastersCannotBeReceivers); // add the new group to cached render group renderGroups.Add(queueID, group); } else { // retreive the existing queue group group = (RenderQueueGroup)renderGroups[queueID]; } return group; }