I'm trying to apply a shader postprocessing effect to my rendered game.
Here is the game code:
namespace ShaderTestDesktop
{
public class Game1 : Game
{
private GraphicsDeviceManager graphics;
private SpriteBatch _spriteBatch;
private Texture2D _alien;
private RenderTarget2D _renderTexture;
private Effect _shader;
private float _angle;
private Vector2 _position;
private bool _isShaderApplied;
private KeyboardState _keyboardState;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
base.Initialize();
_keyboardState = Keyboard.GetState();
}
protected override void LoadContent()
{
_spriteBatch = new SpriteBatch(GraphicsDevice);
_shader = Content.Load<Effect>("nop");
_alien = Content.Load<Texture2D>("alien");
_renderTexture = new RenderTarget2D(
GraphicsDevice,
graphics.PreferredBackBufferWidth,
graphics.PreferredBackBufferHeight
);
_position = new Vector2(
GraphicsDevice.Viewport.Width / 2,
GraphicsDevice.Viewport.Height / 2
);
}
protected override void Update(GameTime gameTime)
{
_angle += 2f * (float)gameTime.ElapsedGameTime.TotalSeconds;
var newState = Keyboard.GetState();
if (!_keyboardState.IsKeyDown(Keys.Space) && newState.IsKeyDown(Keys.Space))
_isShaderApplied = !_isShaderApplied;
_keyboardState = newState;
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
// render the sprite to the intermediate texture
GraphicsDevice.SetRenderTarget(_renderTexture);
GraphicsDevice.Clear(Color.Transparent);
_spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend);
_spriteBatch.Draw(_alien, _position, null, Color.White, _angle, new Vector2(128, 128), 1, SpriteEffects.None, 0);
_spriteBatch.End();
// post-process
GraphicsDevice.SetRenderTarget(null);
GraphicsDevice.Clear(Color.CornflowerBlue);
_spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, null, null, null, _isShaderApplied ? _shader : null);
_spriteBatch.Draw(_renderTexture, Vector2.Zero, Color.White);
_spriteBatch.End();
base.Draw(gameTime);
}
}
}
The shader currently does nothing and is defined simply as:
sampler2D s0;
float4 MainPS(float2 coords: TEXCOORD0) : COLOR
{
return tex2D(s0, coords);
}
technique BasicColorDrawing
{
pass P0
{
PixelShader = compile ps_4_0_level_9_1 MainPS();
}
};
Rendering without the shader looks like this (rotates clockwise):
When the shader is applied, the object is apparently moved, scaled and mirrored (rotates counter-clockwise):
The behaviour is consistent across platforms (at least Desktop and WP8). What am I doing wrong?
UPDATE:
As suggested in the comments, I modified the shader code to add a vertex shader too. Some articles suggested also creating a matrix to match the default transformation matrix from SpriteBatch.
Here's the new shader code:
matrix WorldViewProjection;
struct VertexShaderInput
{
float4 Position : SV_POSITION;
float4 Color : COLOR0;
};
struct VertexShaderOutput
{
float4 Position : SV_POSITION;
float4 Color : COLOR0;
};
VertexShaderOutput MainVS(in VertexShaderInput input)
{
VertexShaderOutput output = (VertexShaderOutput)0;
output.Position = mul(input.Position, WorldViewProjection);
output.Color = input.Color;
return output;
}
float4 MainPS(VertexShaderOutput input) : COLOR
{
return input.Color;
}
technique BasicColorDrawing
{
pass P0
{
VertexShader = compile vs_4_0_level_9_1 MainVS();
PixelShader = compile ps_4_0_level_9_1 MainPS();
}
};
New shader initialization code:
var halfPixel = Matrix.CreateTranslation(-0.5f, -0.5f, 0);
var offCenter = Matrix.CreateOrthographicOffCenter(0, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height, 0, 0, 1);
_shader = Content.Load<Effect>("nop");
_shader.Parameters["WorldViewProjection"].SetValue(halfPixel * offCenter);
New result (notice the 1px CornflowerBlue border at the right):



TEXCOORD0through actually worked. Thanks! If you submit this as an answer, I will mark it as solution. \$\endgroup\$