Original post that was rewritten for current MonoGame framework - https://gmjosack.github.io/posts/my-first-2d-pixel-shaders-part-1/
It has been about 7-8 years after the original post I linked above
and its pretty outdated, So I thought I might make a fresh one that works (What worked for me after I tried many things) so lets get into it.
SETTING UP:
The first thing we’ll want to do add our texture to our project. Go ahead and add the texture you chose to the Content Pipeline (Double click on the Content.mgcb)
Texture2D texture;
Then in yout LoadContent method add the following line at the end substituting your assets name:
texture = Content.Load<Texture2D>("surge") // or whatever sprite you're using
Now lets go ahead and Draw it just to make sure everything is working as expected. Add the following to
your Draw method right above base.Draw();
spriteBatch.Begin();
spriteBatch.Draw(texture, new Vector2(0, 0), Color.White);
spriteBatch.End();
Now hit F5 and make sure everything compiles and looks okay. If you’re following along it should look something like this:
SETTING UP THE SHADER:
Open your Content Pipeline (like we previously did to add our sprite)
Follow the screenshot and create a “New Item…”
choose whatever name you’d like and be sure you’re selecting the Sprite Effect (.fx) option and then click OK.
Now lets go back to our Game1.cs (or whatever name you gave to your project/game)
Add a member variable of:
Effect effect;
And in your LoadContent method add the following line:
effect = Content.Load<Effect>("Effect1");
The rest of our changes will be in the Draw method. First we’re going to have to update our spriteBatch.Begin() call to use a new sort mode.
spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);
You can look up the details of these options in the MSDN Reference. SpriteSortMode.Immediate is required to apply the effect.
BlendState.AlphaBlend is the default. After your Begin call we’re going to add the following line which will Apply the pixel shader to the sprite.
effect.CurrentTechnique.Passes[0].Apply();
Now open up your freshly created shader and you’ll see somthing like this:
#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 SpriteTextureSampler = sampler_state
{
Texture = <SpriteTexture>;
};
struct VertexShaderOutput
{
float4 Position : SV_POSITION;
float4 Color : COLOR0;
float2 TextureCoordinates : TEXCOORD0;
};
float4 MainPS(VertexShaderOutput input) : COLOR
{
return tex2D(SpriteTextureSampler,input.TextureCoordinates) * input.Color;
}
technique SpriteDrawing
{
pass P0
{
PixelShader = compile PS_SHADERMODEL MainPS();
}
};
on the original tutorial it says to tear everything apart well DON’T DO IT EVER because you’ll
have lots and lots of errors and believe me you dont want them.
Our main function the we’re going to work with rightnow is:
float4 MainPS(VertexShaderOutput input) : COLOR
{
return tex2D(SpriteTextureSampler,input.TextureCoordinates) * input.Color;
}
It takes in as a parameter a struct VertexShaderOutput where we have our variables
struct VertexShaderOutput
{
float4 Position : SV_POSITION;
float4 Color : COLOR0;
float2 TextureCoordinates : TEXCOORD0;
};
Lets add a sampler2d you’ll be using these pretty often
right after your
Texture2D SpriteTexture;
add
sampler s0;
now lets change our float4 MainPS function to our needs
your new function should look as follows:
float4 MainPS(VertexShaderOutput input) : COLOR
{
float4 color = tex2D(s0, input.TextureCoordinates);
return color;
}
if you’ll compile it right now you’ll see no changes but lets add another line above the return color;
color.gb = color.r;
So your function in the end will look like:
float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
float4 color = tex2D(s0, input.TextureCoordinates);
color.gb = color.r;
return color;
}
Hit F5 and see it in action
Hope I helped you starting with your first shader because I had hard time trying to setup something to work.
//If you saw some mistakes I made, please do let me now so I can fix it and make this tutorial as helpful as I can.