Confusion about shader system

I’m a little bit confused about how the shader system in Monogame works, and where you can learn more about it.

The documentation is a little confusing so please let me know if I’m totally incorrect but I think it says they’ve written their own shader system, MGFX, and in order to make my own custom effects I either have to write it in HLSL and run it through MGFXC, or I can just create a .fx file with the Monogame Content Pipeline and then…continue to write it in HLSL?

But it also seems like shaders from XNA don’t convert directly over to Monogame and there seems to be very little documentation, articles, guides, anything as to how to actually just get a shader up and running and what language to use.

Can anyone give me a bit of guidance?

Hey Rilesly,

To avoid confusion let me first make a clear distinction. The programming language you write your shaders in in MonoGame is HLSL. But on top of that MonoGame emulates DirectX’s FX framework. With DirectX FX’s framework you can define your sampler states, shaders and techniques all inside the shader. Instead of having to define these in code. Note that you can also set sampler states in code in MonoGame through the GraphicsDevice states.

This is similar to how you did this in XNA. However since MonoGame also transcodes HLSL shaders to OpenGL there a few minor details that you have to look at.

This probably one of the simplest shaders you can write in MonoGame. It outputs a solid color for the entire 3D model. Note the defines at the start

// Standard defines
#if OPENGL
	#define SV_POSITION POSITION
	#define VS_SHADERMODEL vs_5_0
	#define PS_SHADERMODEL ps_5_0
#else
	#define VS_SHADERMODEL vs_5_0
	#define PS_SHADERMODEL ps_5_0
#endif

// Properties you can use from C# code
float4x4 World;
float4x4 View;
float4x4 Projection;
float4 Color;

// Required attributes of the input vertices
struct VertexShaderInput
{
    float3 Position : POSITION0;
};

// Semantics for output of vertex shader / input of pixel shader
struct VertexShaderOutput
{
    float4 Position : POSITION0;
};

// Actual shaders
VertexShaderOutput MainVS(in VertexShaderInput input)
{
    VertexShaderOutput output = (VertexShaderOutput)0;
    float4 worldPosition = mul(float4(input.Position.xyz, 1), World);
    float4 viewPosition = mul(worldPosition, View);

    output.Position = mul(viewPosition, Projection);

    return output;
}

float4 MainPS(VertexShaderOutput input) : COLOR0
{    
    return Color;
}

// Technique and passes within the technique
technique ColorEffect
{
    pass Pass0
    {
        VertexShader = compile VS_SHADERMODEL MainVS();
        PixelShader = compile PS_SHADERMODEL MainPS();
    }
}

After you then compile this effect using the MonoGame content pipeline tool. You can load it using the content manager

Effect effect = ContentManager.Load<Effect>("MyEffect");

And you can then apply the technique like this, make sure to set the properties before applying the technique!

effect.Parameters["World"].SetValue(Matrix.Identity);
// etc //
effect.CurrentTechnique = this.effect.Techniques["ColorEffect"];
effect.CurrentTechnique.Passes[0].Apply(); // Since we only have one pass

If you then draw something it will be done using the applied effect

graphicsDevice.DrawUserIndexedPrimitives(PrimitiveType.TriangleList, vertices, 0, vertices.Length,
            indices, 0, 12);

Models usually their own shaders baked in when its build. You can overwrite the standard shaders used by setting a different processor for that mode in the MonoGame content pipeline tool. However this is quite an advanced technique and you can overwrite a model’s effect using code at runtime. So if you need that I suggest you start with that.

(For an example content pipeline extension that adds a different shader see: https://github.com/roy-t/MiniRTS/tree/master/Engine/ModelExtension)