Beispiel #1
0
		/// <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
		}
Beispiel #2
0
        public SceneManager( string name )
			: base()
		{
			this.cameraList = new CameraCollection();
			this.sceneNodeList = new SceneNodeCollection();
			this.animationList = new AnimationCollection();
			this.animationStateList = new AnimationStateSet();
			this.regionList = new List<StaticGeometry.Region>();

			this.shadowCasterQueryListener = new ShadowCasterSceneQueryListener( this );

			// create the root scene node
			this.rootSceneNode = new SceneNode( this, "Root" );
			this.rootSceneNode.SetAsRootNode();
			this.defaultRootNode = this.rootSceneNode;

			this.name = name;

			// default to no fog
			this.fogMode = FogMode.None;

			// no shadows by default
			this.shadowTechnique = ShadowTechnique.None;

			// setup default shadow camera setup
			this._defaultShadowCameraSetup = new DefaultShadowCameraSetup();

			this.illuminationStage = IlluminationRenderStage.None;
			this.renderingNoShadowQueue = false;
			this.renderingMainGroup = false;
			this.shadowColor.a = this.shadowColor.r = this.shadowColor.g = this.shadowColor.b = 0.25f;
			this.shadowDirLightExtrudeDist = 10000;
			this.shadowIndexBufferSize = 51200;
			this.shadowTextureOffset = 0.6f;
			this.shadowTextureFadeStart = 0.7f;
			this.shadowTextureFadeEnd = 0.9f;
			this.shadowTextureSize = 512;
			this.shadowTextureCount = 1;
			this.findVisibleObjects = true;
			this.suppressRenderStateChanges = false;
			this.suppressShadows = false;
			this.shadowUseInfiniteFarPlane = true;
		}
Beispiel #3
0
		/// <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
		}
Beispiel #4
0
		/// <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
		}
Beispiel #5
0
		private void _preFindVisibleObjects( SceneManager source, IlluminationRenderStage irs, Viewport v )
		{
			//Early-out
			if ( !IsLoaded )
			{
				return;
			}

			// check deferred updates
			var currMillis = Root.Instance.Timer.Milliseconds;
			var elapsedMillis = currMillis - this.mLastMillis;
			if ( this.mCompositeMapUpdateCountdown > 0 && elapsedMillis > 0 )
			{
				if ( elapsedMillis > this.mCompositeMapUpdateCountdown )
				{
					this.mCompositeMapUpdateCountdown = 0;
				}
				else
				{
					this.mCompositeMapUpdateCountdown -= elapsedMillis;
				}

				if ( this.mCompositeMapUpdateCountdown == 0 )
				{
					UpdateCompositeMap();
				}
			}
			this.mLastMillis = currMillis;
			// only calculate LOD once per LOD camera, per frame, per viewport height
			var lodCamera = v.Camera.LodCamera;
			var frameNum = (ulong)Root.Instance.NextFrameNumber;
			var vpHeight = v.ActualHeight;
			if ( this.mLastLODCamera != lodCamera || frameNum != this.mLastLODFrame || this.mLastViewportHeight != vpHeight )
			{
				this.mLastLODCamera = lodCamera;
				this.mLastLODFrame = frameNum;
				this.mLastViewportHeight = vpHeight;
				CalculateCurrentLod( v );
			}
		}
Beispiel #6
0
		/// <summary>
		/// Internal method for preparing shadow textures ready for use in a regular render
		/// </summary>
		/// <param name="camera"></param>
		/// <param name="viewPort"></param>
		protected internal virtual void PrepareShadowTextures( Camera camera, Viewport viewPort )
		{
			// Set the illumination stage, prevents recursive calls
			IlluminationRenderStage savedStage = this.illuminationStage;
			this.illuminationStage = IlluminationRenderStage.RenderToTexture;

			// Determine far shadow distance
			float shadowDist = this.shadowFarDistance;
			if ( shadowDist == 0.0f )
			{
				// need a shadow distance, make one up
				shadowDist = camera.Near * 300;
			}
			// set fogging to hide the shadow edge
			float shadowOffset = shadowDist * this.shadowTextureOffset;
			// Precalculate fading info
			float shadowEnd = shadowDist + shadowOffset;
			float fadeStart = shadowEnd * this.shadowTextureFadeStart;
			float fadeEnd = shadowEnd * this.shadowTextureFadeEnd;
			// Additive lighting should not use fogging, since it will overbrighten; use border clamp
			if ( !this.IsShadowTechniqueAdditive )
			{
				this.shadowReceiverPass.SetFog( true,
												FogMode.Linear,
												ColorEx.White,
												0,
												fadeStart,
												fadeEnd );
				// if we have a custom receiver material, then give it the fog params too
				if ( this.shadowTextureCustomReceiverPass != null )
				{
					this.shadowTextureCustomReceiverPass.SetFog( true,
																 FogMode.Linear,
																 ColorEx.White,
																 0,
																 fadeStart,
																 fadeEnd );
				}
			}
			else
			{
				// disable fogging explicitly
				this.shadowReceiverPass.SetFog( true, FogMode.None );
				// if we have a custom receiver material, then give it the fog params too
				if ( this.shadowTextureCustomReceiverPass != null )
				{
					this.shadowTextureCustomReceiverPass.SetFog( true, FogMode.None );
				}
			}

			// Iterate over the lights we've found, max out at the limit of light textures
			int sti = 0;
			foreach ( Light light in this.lightsAffectingFrustum )
			{
				// Check limit reached
				if ( sti == this.shadowTextures.Count )
					break;

				// Skip non-shadowing lights
				if ( !light.CastShadows )
				{
					continue;
				}

				Texture shadowTex = this.shadowTextures[ sti ];
				RenderTarget shadowRTT = shadowTex.GetBuffer().GetRenderTarget();
				Viewport shadowView = shadowRTT.GetViewport( 0 );
				Camera texCam = this.shadowTextureCameras[ sti ];

				// rebind camera, incase another SM in use which has switched to its cam
				shadowView.Camera = texCam;

				// Associate main view camera as LOD camera
				texCam.LodCamera = camera;

				//Vector3 dir;

				// set base
				if ( light.Type == LightType.Point )
					texCam.Direction = light.DerivedDirection;
				if ( light.Type == LightType.Directional )
					texCam.Position = light.DerivedPosition;

				// Use the material scheme of the main viewport
				// This is required to pick up the correct shadow_caster_material and similar properties.
				shadowView.MaterialScheme = viewPort.MaterialScheme;

				if ( light.CustomShadowCameraSetup == null )
				{
					_defaultShadowCameraSetup.GetShadowCamera( this, camera, viewPort, light, texCam, sti );
				}
				else
				{
					light.CustomShadowCameraSetup.GetShadowCamera( this, camera, viewPort, light, texCam, sti );
				}

				shadowView.BackgroundColor = ColorEx.White;

				// Fire shadow caster update, callee can alter camera settings
				// fireShadowTexturesPreCaster(light, texCam);

				// Update target
				shadowRTT.Update();

				++sti;
			}
			// Set the illumination stage, prevents recursive calls
			this.illuminationStage = savedStage;

			//fireShadowTexturesUpdated( std::min(mLightsAffectingFrustum.size(), mShadowTextures.size()));
		}
        public SceneManager(string smName)
        {
            this.smName = smName;
            cameraList = new Dictionary<string, Camera>();
            //lightList = new LightList();
            //entityList = new EntityList();
            movableObjectCollectionMap = new Dictionary<string, Dictionary<string, MovableObject>>();
            sceneNodeList = new Dictionary<string, SceneNode>();
            //billboardSetList = new Dictionary<string, BillboardSet>();
            animationList = new Dictionary<string, Animation>();
            animationStateList = new AnimationStateSet();
            regionList = new List<Region>();

            // create the root scene node
            rootSceneNode = new SceneNode(this, "Root");
            defaultRootNode = rootSceneNode;

            // default to no fog
            fogMode = FogMode.None;

            // no shadows by default
            shadowTechnique = ShadowTechnique.None;

            illuminationStage = IlluminationRenderStage.None;
            renderingNoShadowQueue = false;
            renderingMainGroup = false;
            shadowColor = new ColorEx(0.25f, 0.25f, 0.25f);
            shadowDirLightExtrudeDist = 10000;
            shadowIndexBufferSize = 51200;
            shadowTextureOffset = 0.6f;
            shadowTextureFadeStart = 0.7f;
            shadowTextureFadeEnd = 0.9f;
            shadowTextureSize = 512;
            shadowTextureConfigDirty = true;
            ShadowTextureCount = 1;
            findVisibleObjects = true;
            suppressRenderStateChanges = false;
            suppressShadows = false;
            shadowUseInfiniteFarPlane = true;
            shadowCasterRenderBackFaces = true;
            defaultShadowCameraSetup = new DefaultShadowCameraSetup();
        }
        /// <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 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 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>
        /// Internal method for preparing shadow textures ready for use in a regular render
        /// </summary>
        /// <param name="camera"></param>
        /// <param name="viewPort"></param>
        protected internal virtual void PrepareShadowTextures(Camera camera, Viewport viewPort)
        {
            prepareShadowTexturesMeter.Enter();

            // create shadow textures if needed
            EnsureShadowTexturesCreated();

            // Set the illumination stage, prevents recursive calls
            IlluminationRenderStage savedStage = illuminationStage;
            illuminationStage = IlluminationRenderStage.RenderToTexture;

            // Determine far shadow distance
            float shadowDist = shadowFarDistance;
            if (shadowDist == 0.0f) {
                // need a shadow distance, make one up
                shadowDist = camera.Near * 300;
            }
            // set fogging to hide the shadow edge
            float shadowOffset = shadowDist * shadowTextureOffset;
            // Precalculate fading info
            float shadowEnd = shadowDist + shadowOffset;
            float fadeStart = shadowEnd * shadowTextureFadeStart;
            float fadeEnd = shadowEnd * shadowTextureFadeEnd;

            // set auto param for the start and end of the shadow fade region
            autoParamDataSource.ShadowFadeParams = new Vector4(fadeStart, fadeEnd, 0, 0);

            // Additive lighting should not use fogging, since it will overbrighten; use border clamp
            if (!IsShadowTechniqueAdditive) {
                shadowReceiverPass.SetFog(true, FogMode.Linear, ColorEx.White,
                                          0, fadeStart, fadeEnd);
                // if we have a custom receiver material, then give it the fog params too
                if (shadowTextureCustomReceiverPass != null)
                    shadowTextureCustomReceiverPass.SetFog(true, FogMode.Linear, ColorEx.White,
                                                           0, fadeStart, fadeEnd);
            } else {
                // disable fogging explicitly
                shadowReceiverPass.SetFog(true, FogMode.None);
                // if we have a custom receiver material, then give it the fog params too
                if (shadowTextureCustomReceiverPass != null)
                    shadowTextureCustomReceiverPass.SetFog(true, FogMode.None);
            }

            // Iterate over the lights we've found, max out at the limit of light textures
            for (int i = 0, sti = 0;
                i < lightsAffectingFrustum.Count && sti < shadowTextures.Count; i++) {
                Light light = lightsAffectingFrustum[i];
                // Skip non-shadowing lights
                if (!light.CastShadows)
                    continue;

                Texture shadowTex = shadowTextures[sti];
                RenderTarget shadowRTT = shadowTex.GetBuffer().GetRenderTarget();
                Viewport shadowView = shadowRTT.GetViewport(0);
                Camera texCam = shadowTextureCameras[sti];
                // rebind camera, incase another SM in use which has switched to its cam
                // This seems pretty silly - - is there any reason to do it?
                shadowView.Camera = texCam;

                // update shadow cam - light mapping
                shadowCamLightMapping[texCam] = light;

                if (light.CustomShadowCameraSetup == null)
                    defaultShadowCameraSetup.GetShadowCamera(this, camera, shadowView, light, texCam);
                else
                    light.CustomShadowCameraSetup.GetShadowCamera(this, camera, shadowView, light, texCam);

                // Setup background colour
                shadowView.BackgroundColor = ColorEx.White;

                // Fire shadow caster update, callee can alter camera settings
                // fireShadowTexturesPreCaster(light, texCam);

                // Update target
                shadowRTT.Update();

                sti++;

            }
            illuminationStage = savedStage;

            //fireShadowTexturesUpdated(Math.Min(lightsAffectingFrustum.Count, shadowTextures.Count));

            ShadowTextureManager.Instance.ClearUnused();

            prepareShadowTexturesMeter.Exit();
        }