//-----------------------------------------------------------------------------
// 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);
}
}
}