Soā¦ this kind of piqued my interest haha. Itās a neat idea and I wanted to see if I could hack something togetherā¦ so I gave it a shot! I went with a simplified version of what markus suggested, mostly because I just wanted to proof of concept it and then move on. Iāve been known to get over-involved in thingsā¦ *cough*

Anyway, my general approach was thisā¦
- Render entire scene to render target except unblurred sprite.
- Apply blur to entire render target.
- Render unblurred sprite.
I added code to be able to select a sprite or deselect it.
Hereās what it looked like unblurred:
Then with one of the balls selected:
For the shader, I just googled around the interwebs until I found some kind of blur shader and implemented it. Iām sure there are betterā¦ plus this applied to a full screen image via a render target is fairly taxing. All in all itās probably not the best solution, but it was kinda fun to play around with.
Hereās the codeā¦
blur.fx (the shader)
#if OPENGL
#define SV_POSITION POSITION
#define VS_SHADERMODEL vs_3_0
#define PS_SHADERMODEL ps_3_0
#else
#define VS_SHADERMODEL vs_4_0_level_9_1
#define PS_SHADERMODEL ps_4_0_level_9_1
#endif
Texture2D SpriteTexture;
sampler2D InputSampler = sampler_state
{
Texture = <SpriteTexture>;
};
float2 xResolution = float2(0, 0);
bool xEnabled = true;
struct VertexShaderOutput
{
float4 Position : SV_POSITION;
float4 Color : COLOR0;
float2 UV : TEXCOORD0;
};
float4 BlurShader(VertexShaderOutput input) : COLOR
{
// Adapted from:
// https://github.com/Jam3/glsl-fast-gaussian-blur
float4 c = float4(0, 0, 0, 0);
float2 uv = input.UV;
float2 uvPix = float2(1 / xResolution.x, 1 / xResolution.y);
float2 off1 = float2(1.41, 1.41);
float2 off2 = float2(3.30, 3.30);
float2 off3 = float2(5.18, 5.18);
float wBaseV = 0.196;
float4 wBase = float4(wBaseV, wBaseV, wBaseV, 1);
float w1v = 0.297 / 2;
float4 w1 = float4(w1v, w1v, w1v, 1);
float w2v = 0.0945 / 2;
float4 w2 = float4(w2v, w2v, w2v, 1);
float w3v = 0.0104 / 2;
float4 w3 = float4(w3v, w3v, w3v, 1);
c += tex2D(InputSampler, uv);
float4 cOrig = c;
if (xEnabled == true)
{
c *= wBase;
c += tex2D(InputSampler, uv + off1 * uvPix * float2(1, 0)) * w1;
c += tex2D(InputSampler, uv + off1 * uvPix * float2(-1, 0)) * w1;
c += tex2D(InputSampler, uv + off1 * uvPix * float2(0, 1)) * w1;
c += tex2D(InputSampler, uv + off1 * uvPix * float2(0, -1)) * w1;
c += tex2D(InputSampler, uv + off2 * uvPix * float2(1, 0)) * w2;
c += tex2D(InputSampler, uv + off2 * uvPix * float2(-1, 0)) * w2;
c += tex2D(InputSampler, uv + off2 * uvPix * float2(0, 1)) * w2;
c += tex2D(InputSampler, uv + off2 * uvPix * float2(0, -1)) * w2;
c += tex2D(InputSampler, uv + off3 * uvPix * float2(1, 0)) * w3;
c += tex2D(InputSampler, uv + off3 * uvPix * float2(-1, 0)) * w3;
c += tex2D(InputSampler, uv + off3 * uvPix * float2(0, 1)) * w3;
c += tex2D(InputSampler, uv + off3 * uvPix * float2(0, -1)) * w3;
}
c.a = cOrig.a;
return c;
}
technique BasicColorDrawing
{
pass P0
{
PixelShader = compile PS_SHADERMODEL BlurShader();
}
};
DOFDemoGame.cs
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System.Collections.Generic;
namespace DOFDemo
{
public class DOFDemoGame : Game
{
private GraphicsDeviceManager _graphics;
private SpriteBatch _spriteBatch;
private Entity _background;
private List<Entity> _entities = new List<Entity>();
private Effect _blurEffect;
private RenderTarget2D _target;
private Entity _selectedEntity = null;
private MouseState _oldMouseState;
public DOFDemoGame()
{
this.IsMouseVisible = true;
_graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
_graphics.PreferredBackBufferWidth = 1280;
_graphics.PreferredBackBufferHeight = 720;
_graphics.ApplyChanges();
base.Initialize();
}
protected override void LoadContent()
{
_spriteBatch = new SpriteBatch(GraphicsDevice);
_blurEffect = this.Content.Load<Effect>("blur");
_background = new Entity(this.Content.Load<Texture2D>("background"), new Rectangle(0, 0, 1280, 720)) { BlurEffect = _blurEffect };
Texture2D ball = this.Content.Load<Texture2D>("ball");
_entities.Add(new Entity(ball, new Rectangle(100, 200, ball.Width, ball.Height)));
_entities.Add(new Entity(ball, new Rectangle(600, 200, ball.Width, ball.Height)));
_target = new RenderTarget2D(_graphics.GraphicsDevice, 1280, 720);
}
protected override void Update(GameTime gameTime)
{
MouseState mouseState = Mouse.GetState();
if (mouseState.LeftButton == ButtonState.Released && _oldMouseState.LeftButton == ButtonState.Pressed)
{
Entity pickedEntity = null;
foreach (Entity e in _entities)
{
if (e.Bounds.Contains(mouseState.Position))
{
pickedEntity = e;
break;
}
}
_selectedEntity = pickedEntity;
}
_oldMouseState = mouseState;
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.Black);
_graphics.GraphicsDevice.SetRenderTarget(_target);
// Draw to target.
_spriteBatch.Begin();
_background.Draw(gameTime, _spriteBatch);
foreach (Entity e in _entities)
if (e != _selectedEntity)
e.Draw(gameTime, _spriteBatch);
_spriteBatch.End();
_graphics.GraphicsDevice.SetRenderTarget(null);
// Add blur effect to rendered stuff.
_spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, SamplerState.AnisotropicClamp, null, null, _blurEffect, null);
bool blurEnabled = (_selectedEntity == null) ? false : true;
_blurEffect.Parameters["xEnabled"].SetValue(blurEnabled);
_spriteBatch.Draw(_target, Vector2.Zero, Color.White);
_spriteBatch.End();
// Draw unblurred entity
if (_selectedEntity != null)
{
_spriteBatch.Begin();
_selectedEntity.Draw(gameTime, _spriteBatch);
_spriteBatch.End();
}
base.Draw(gameTime);
}
}
public class Entity
{
public Texture2D Texture { get; set; }
public Rectangle Bounds { get; set; }
public Color Color { get; set; } = Color.White;
public Effect BlurEffect { get; set; } = null;
public Entity(Texture2D texture, Rectangle bounds)
{
this.Texture = texture;
this.Bounds = bounds;
}
public void Draw(GameTime gameTime, SpriteBatch spriteBatch)
{
if (this.BlurEffect != null)
this.BlurEffect.Parameters["xResolution"].SetValue(new Vector2(this.Texture.Width, this.Texture.Height));
spriteBatch.Draw(this.Texture, this.Bounds, this.Color);
}
}
}