//----------------------------------------------------------------------------- // ShadowMapBlur.cs // // Microsoft XNA Community Game Platform // Copyright (C) Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using System; using RacingGame.Graphics; using RacingGame.Helpers; namespace RacingGame.Shaders { /// /// ShadowMapBlur based on PostScreenBlur to blur the final shadow map /// output for a more smooth view on the screen. /// public class ShadowMapBlur : ShaderEffect { static readonly BlendState ZeroSourceBlend = new BlendState() { AlphaBlendFunction = BlendFunction.Add, AlphaSourceBlend = Blend.Zero, ColorSourceBlend = Blend.Zero, AlphaDestinationBlend = Blend.SourceAlpha, ColorDestinationBlend = Blend.SourceColor }; /// /// The shader effect filename for this shader. /// private const string Filename = "PostScreenShadowBlur.fx"; /// /// Effect handles for window size and scene map. /// private EffectParameter windowSize, sceneMap, blurMap; /// /// Links to the render to texture instances. /// private RenderToTexture sceneMapTexture, blurMapTexture; /// /// Scene map texture /// /// Render to texture public RenderToTexture SceneMapTexture { get { return sceneMapTexture; } } /// /// Blur map texture /// /// Render to texture public RenderToTexture BlurMapTexture { get { return blurMapTexture; } } /// /// Create shadow map screen blur shader. /// obs, using full size again: But only use 1/4 of the screen! /// public ShadowMapBlur() : base(Filename) { // Scene map texture sceneMapTexture = new RenderToTexture( //RenderToTexture.SizeType.FullScreen); //improve performance: RenderToTexture.SizeType.HalfScreen); blurMapTexture = new RenderToTexture( //RenderToTexture.SizeType.FullScreen); //improve performance: RenderToTexture.SizeType.HalfScreen); } protected override void SetParameterDefaultValues() { base.SetParameterDefaultValues(); // Weights8 is now hardcoded in the shader to avoid GLSL std140 // float-array padding mismatch on DesktopGL (each float element // would be padded to 16 bytes, causing a BlockCopy overrun). } /// /// Reload /// protected override void GetParameters() { // Can't get parameters if loading failed! if (effect == null) return; windowSize = effect.Parameters["windowSize"]; sceneMap = effect.Parameters["sceneMap"]; blurMap = effect.Parameters["blurMap"]; // We need both windowSize and sceneMap. if (windowSize == null || sceneMap == null) throw new NotSupportedException("windowSize and sceneMap must be " + "valid in PostScreenShader=" + Filename); } /// /// Render shadows /// /// Render code public void RenderShadows(BaseGame.RenderHandler renderCode) { if (renderCode == null) throw new ArgumentNullException("renderCode"); // Render into our scene map texture sceneMapTexture.SetRenderTarget(); // Clear render target sceneMapTexture.Clear(Color.White); // Render everything renderCode(); // Resolve render target sceneMapTexture.Resolve(); // Restore back buffer as render target BaseGame.ResetRenderTarget(true); } /// /// Show shadows with help of our blur map shader /// public void RenderShadows() { // Only apply post screen blur if texture is valid and effect are valid if (sceneMapTexture == null || Valid == false || // If the shadow scene map is not yet filled, there is no point // continuing here ... sceneMapTexture.XnaTexture == null) return; // Don't use or write to the z buffer BaseGame.Device.DepthStencilState = DepthStencilState.None; // Disable alpha for the first pass BaseGame.Device.BlendState = BlendState.Opaque; if (windowSize != null) windowSize.SetValue( new Vector2(sceneMapTexture.Width, sceneMapTexture.Height)); if (sceneMap != null) sceneMap.SetValue(sceneMapTexture.XnaTexture); effect.CurrentTechnique = effect.Techniques["ScreenAdvancedBlur20"]; // We must have exactly 2 passes! if (effect.CurrentTechnique.Passes.Count != 2) throw new InvalidOperationException( "This shader should have exactly 2 passes!"); // Just start pass 0 blurMapTexture.SetRenderTarget(); EffectPass effectPass = effect.CurrentTechnique.Passes[0]; effectPass.Apply(); VBScreenHelper.Render(); blurMapTexture.Resolve(); BaseGame.ResetRenderTarget(false); // Restore z buffer state BaseGame.Device.DepthStencilState = DepthStencilState.Default; // Set u/v addressing back to wrap BaseGame.Device.SamplerStates[0] = SamplerState.LinearWrap; // Restore normal alpha blending //BaseGame.Device.RenderState.BlendFunction = BlendFunction.Add; BaseGame.SetCurrentAlphaMode(BaseGame.AlphaMode.Default); } /// /// Show shadows with help of our blur map shader /// public void ShowShadows() { // Only apply post screen blur if texture is valid and effect are valid if (blurMapTexture == null || Valid == false || // If the shadow scene map is not yet filled, there is no point // continuing here ... blurMapTexture.XnaTexture == null) return; // Don't use or write to the z buffer BaseGame.Device.DepthStencilState = DepthStencilState.None; // Make sure we clamp everything to 0-1 BaseGame.Device.SamplerStates[0] = SamplerState.LinearClamp; // Restore back buffer as render target //not required: BaseGame.ResetRenderTarget(false); if (blurMap != null) blurMap.SetValue(blurMapTexture.XnaTexture); effect.CurrentTechnique = effect.Techniques["ScreenAdvancedBlur20"]; // We must have exactly 2 passes! if (effect.CurrentTechnique.Passes.Count != 2) throw new InvalidOperationException( "This shader should have exactly 2 passes!"); // Render second pass // Use ZeroSourceBlend alpha mode for the final result BaseGame.Device.BlendState = ZeroSourceBlend; /*BaseGame.Device.RenderState.AlphaBlendEnable = true; BaseGame.Device.RenderState.AlphaBlendOperation = BlendFunction.Add; BaseGame.Device.RenderState.SourceBlend = Blend.Zero; BaseGame.Device.RenderState.DestinationBlend = Blend.SourceColor;*/ EffectPass effectPass = effect.CurrentTechnique.Passes[1]; effectPass.Apply(); VBScreenHelper.Render(); // Restore z buffer state BaseGame.Device.DepthStencilState = DepthStencilState.Default; // Set u/v addressing back to wrap BaseGame.Device.SamplerStates[0] = SamplerState.LinearWrap; // Restore normal alpha blending //BaseGame.Device.RenderState.BlendFunction = BlendFunction.Add; BaseGame.SetCurrentAlphaMode(BaseGame.AlphaMode.Default); } } }