/// <summary> /// Called by the <see cref="DeferredRenderSystem"/> when this <see cref="SimulatedPostProcess"/> component needs render itself. /// Override this method with component-specific drawing code. /// </summary> /// <param name="gameTime">Time passed since the last call to Draw.</param> /// <param name="renderSystem"><see cref="DeferredRenderSystem"/> to render with.</param> protected override void Render(GameTime gameTime, DeferredRenderSystem renderSystem) { RenderTarget2D shadowMap = renderSystem.RenderTargets.GetTemporaryRenderTarget(SurfaceFormat.Color); // The core shadow map this.GenerateShadowMap(renderSystem, shadowMap); renderSystem.SetRenderTargets(RenderTargetTypes.LightMap, 1); // Request light map as output this.PostProcessEffect.ConfigureShader(renderSystem); // Configure the shader // Set parameters this.PostProcessEffect.GetParameter("viewProjection").SetValue(renderSystem.GameCamera.GetViewProjectionMatrix(renderSystem)); this.PostProcessEffect.GetParameter("cameraPosition").SetValue(renderSystem.GameCamera.PixelPosition); this.PostProcessEffect.GetParameter("lightPosition").SetValue(this.PixelPosition); this.PostProcessEffect.GetParameter("lightPower").SetValue(this.Power); this.PostProcessEffect.GetParameter("lightRange").SetValue(this.World.GetPixelFromWorld(this.Range)); this.PostProcessEffect.GetParameter("lightDecay").SetValue(this.Decay); this.PostProcessEffect.GetParameter("lightColor").SetValue(this.Color.ToVector4()); this.PostProcessEffect.GetParameter("specularStrength").SetValue(this.SpecularStrength); this.PostProcessEffect.GetParameter("normalMap").SetValue(renderSystem.RenderTargets.NormalMap); this.PostProcessEffect.GetParameter("optionsMap").SetValue(renderSystem.RenderTargets.OptionsMap); this.PostProcessEffect.GetParameter("shadowMap").SetValue(shadowMap); // Render this.PostProcessEffect.ApplyPass(0); renderSystem.DirectScreenPaint(this.GetWorldDrawBounds()); renderSystem.SetRenderTargets(RenderTargetTypes.None, 0); // Resolve the render target renderSystem.RenderTargets.ReleaseTemporaryRenderTarget(shadowMap); }
/// <summary> /// Called by the <see cref="DeferredRenderSystem" /> when this <see cref="StaticPostProcess" /> component needs render itself. /// Override this method with component-specific drawing code. /// </summary> /// <param name="gameTime">Time passed since the last call to Draw.</param> /// <param name="renderSystem"><see cref="DeferredRenderSystem" /> to render with.</param> public override void Draw(GameTime gameTime, DeferredRenderSystem renderSystem) { RenderTarget2D intermediateColorMap = renderSystem.RenderTargets.GetTemporaryRenderTarget(SurfaceFormat.Color); // Intermediate map used for selective sampling renderSystem.GraphicsDevice.SetRenderTarget(intermediateColorMap); this.PostProcessEffect.ConfigureShader(renderSystem); this.PostProcessEffect.GetParameter("spriteTexture").SetValue(renderSystem.RenderTargets.ColorMap); this.PostProcessEffect.ApplyPass(0); renderSystem.DirectScreenPaint(); renderSystem.SetRenderTargets(RenderTargetTypes.ColorMap, 1); this.PostProcessEffect.ConfigureShader(renderSystem); this.PostProcessEffect.GetParameter("spriteTexture").SetValue(intermediateColorMap); this.PostProcessEffect.ApplyPass(0); renderSystem.DirectScreenPaint(); renderSystem.RenderTargets.ReleaseTemporaryRenderTarget(intermediateColorMap); }
/// <summary> /// Generates the shadow map to be used when rendering this light. /// </summary> /// <remarks>If this instance is not to cast shadows the shadow map is cleared.</remarks> /// <param name="renderSystem">The render system to render with.</param> /// <param name="shadowMap">The shadow map to render on</param> protected virtual void GenerateShadowMap(DeferredRenderSystem renderSystem, RenderTarget2D shadowMap) { RenderTarget2D intermediateShadowMap = renderSystem.RenderTargets.GetTemporaryRenderTarget(SurfaceFormat.Color); // Intermediate map used for selective sampling RectangleF lightDrawBounds = this.GetWorldDrawBounds(); renderSystem.GraphicsDevice.SetRenderTarget(shadowMap); renderSystem.ClearCurrentRenderTarget(Color.White); // Clear the core shadow map // Only render the shadows if we are to cast them if (this.CastsShadows) { // Render the shadow caused by each object within the lights range List <SpriteBase> objectList = this.World.GetSpriteObjectsInArea(lightDrawBounds).Where(currObj => (currObj.RenderOptions & SpriteRenderOptions.CastsShadows) != 0).OrderBy(s => s.LayerDepth).ToList(); if (objectList.Count > 0) { int lastLayerDepth = 0; int lastLayerDepthIndex = 0; bool renderedShadow = false; // This is used so that we don't bother occluding objects if we didn't even render anything lastLayerDepth = (int)objectList[0].LayerDepth; for (int objectIndex = 0; objectIndex < objectList.Count; objectIndex++) { SpriteBase currObj = objectList[objectIndex]; RectangleF spriteWorldBounds = currObj.SpriteWorldBounds; // If the object we found doesn't cast shadows (or we're inside it), skip it if (spriteWorldBounds.Contains(base.Position)) { continue; } this.shadowMapShader.ConfigureShader(renderSystem); // Configure the shader this.shadowMapShader.GetParameter("viewProjection").SetValue(renderSystem.GameCamera.GetViewProjectionMatrix(renderSystem)); this.shadowMapShader.GetParameter("cameraPosition").SetValue(renderSystem.GameCamera.PixelPosition); // If we switched light planes remove occlusion from all previous objects if (lastLayerDepth != (int)currObj.LayerDepth) { // Only occlude if we actually rendered something if (renderedShadow) { // Loop through all the objects between the last layer index and the current index for (int clearObjIndex = lastLayerDepthIndex; clearObjIndex < objectIndex; clearObjIndex++) { this.ProcessSpriteDepthTransition(renderSystem, objectList[clearObjIndex]); } } // Save the last values lastLayerDepth = (int)currObj.LayerDepth; lastLayerDepthIndex = objectIndex; renderedShadow = false; // Reset this } // Create the shadow map caused by the current sprite this.shadowMapShader.ApplyPass(0); // Construct the vertex primitive to mask with Vector2[] extrema; if (currObj.SpriteWorldShape != null) { extrema = currObj.SpriteWorldShape.GetRelativeExtrema(base.Position); // Get the extrema that cause the shadow } else { extrema = spriteWorldBounds.GetRelativeExtrema(base.Position); // Get the extrema that cause the shadow } Vector2 widthVector = Vector2.Normalize(extrema[0] - base.Position); // Get the vector to the first extrema Vector2 heightVector = Vector2.Normalize(extrema[1] - base.Position); // Get the vector to the second extrema VertexPrimitive shadowArea = new VertexPrimitive(PrimitiveType.TriangleStrip, 4); shadowArea.Add(extrema[0]); shadowArea.Add(extrema[1]); // Let's extend the shadow vector until it hits the edge of the draw bounds shadowArea.Add(lightDrawBounds.CastInternalRay(extrema[0], widthVector)); shadowArea.Add(lightDrawBounds.CastInternalRay(extrema[1], heightVector)); // Let's get the remaining verts that might exist to finish up the rect List <Vector2> interiorVerts = lightDrawBounds.GetInteriorVertices(base.Position, widthVector, heightVector); shadowArea.Add(interiorVerts); // Add the interior verts (if any exist) renderSystem.DirectScreenPaint(shadowArea); // Render the shadow renderedShadow = true; // We just rendered a shadow; keep track of that } // Loop through all the objects between the last layer index and the current index if (renderedShadow) { // Remove the shadows over the LAST shadow plane for (int clearObjIndex = lastLayerDepthIndex; clearObjIndex < objectList.Count; clearObjIndex++) { this.ProcessSpriteDepthTransition(renderSystem, objectList[clearObjIndex]); } // Blur the shadow map if enabled if (!float.IsPositiveInfinity(this.minShadowBlurDistance)) { renderSystem.GraphicsDevice.SetRenderTarget(intermediateShadowMap); // We need to render to a temp target // Configure the shader this.shadowMapShader.ConfigureShader(renderSystem, 1); // Set parameters this.shadowMapShader.GetParameter("viewProjection").SetValue(renderSystem.GameCamera.GetViewProjectionMatrix(renderSystem)); this.shadowMapShader.GetParameter("cameraPosition").SetValue(renderSystem.GameCamera.PixelPosition); this.shadowMapShader.GetParameter("lightPosition").SetValue(base.PixelPosition); this.shadowMapShader.GetParameter("maxBlurDistance").SetValue(this.World.GetPixelFromWorld(this.maxShadowBlurDistance)); this.shadowMapShader.GetParameter("minBlurDistance").SetValue(this.World.GetPixelFromWorld(this.maxShadowBlurDistance)); this.shadowMapShader.GetParameter("shadowMap").SetValue(shadowMap); this.shadowMapShader.ApplyPass(0); renderSystem.DirectScreenPaint(lightDrawBounds); // Render the shadow renderSystem.GraphicsDevice.SetRenderTarget(shadowMap); // Set the shadow map for final render // Update shadow map this.shadowMapShader.GetParameter("shadowMap").SetValue(intermediateShadowMap); this.shadowMapShader.ApplyPass(0); renderSystem.DirectScreenPaint(lightDrawBounds); // Render } } } } renderSystem.SetRenderTargets(RenderTargetTypes.None, 0); // Resolve the render target renderSystem.RenderTargets.ReleaseTemporaryRenderTarget(intermediateShadowMap); }