1
\$\begingroup\$

I'm new to HLSL, attempting to use MonoGame to do some simple post processing effects.

Here is my HLSL file, taken from one of rbwhitaker's xna tutorials (I would post the link, but can't post more than two with my current reputation).

//------------------------------ TEXTURE PROPERTIES ----------------------------
// This is the texture that SpriteBatch will try to set before drawing
texture ScreenTexture;

// Our sampler for the texture, which is just going to be pretty simple
sampler TextureSampler = sampler_state
{
    Texture = <ScreenTexture>;
};

//------------------------ PIXEL SHADER ----------------------------------------
// This pixel shader will simply look up the color of the texture at the
// requested point, and turns it into a shade of gray
float4 PixelShaderFunction(float2 TextureCoordinate : TEXCOORD0) : COLOR0
{
    float4 color = tex2D(TextureSampler, TextureCoordinate);

    float value = (color.r + color.g + color.b) / 3; 
    color.r = value;
    color.g = value;
    color.b = value;

    return color;
}

//-------------------------- TECHNIQUES ----------------------------------------
// This technique is pretty simple - only one pass, and only a pixel shader
technique BlackAndWhite
{
    pass Pass1
    {
        PixelShader = compile ps_4_0 PixelShaderFunction();
    }
}

The only line I've changed is the compiler version from ps_2_0 -> ps_4_0, since MonoGame needs 4.0 (I think?)

I'm using MonoGame 3.4, and I've changed nothing from the initial project template except the following:

protected override void LoadContent()
{
    // Create a new SpriteBatch, which can be used to draw textures.
    spriteBatch = new SpriteBatch(GraphicsDevice);
    // TODO: use this.Content to load your game content here
    BlackAndWhiteEffect = Content.Load<Effect>("BlackAndWhite");
    Image = Content.Load<Texture2D>("smiley");
}

private Effect BlackAndWhiteEffect
{
    get;
    set;
}

private Texture2D Image
{
    get;
    set;
}

protected override void Draw(GameTime gameTime)
{

    GraphicsDevice.Clear(Color.CornflowerBlue);

    spriteBatch.Begin(SpriteSortMode.Deferred, null, null, null, null, BlackAndWhiteEffect);
    //spriteBatch.Begin();

    spriteBatch.Draw(Image, GraphicsDevice.Viewport.Bounds, Color.White);

    spriteBatch.End();

    base.Draw(gameTime);
}

Here is the result of the code executing in monogame: MonoGame result

And here is the result from an identical project created in XNA (except for ps_2_0 in the shader, as mentioned before): enter image description here

Would appreciate any help. I can upload both solution files if needed.

\$\endgroup\$
3
\$\begingroup\$

I have solved my problem, although I am not sure why exactly this solves the problem. This post was helpful to me: http://www.software7.com/blog/monogame-hlsl-shader-example-for-a-post-processing-blur-effect/

Here is my working shader:

//------------------------------ TEXTURE PROPERTIES ----------------------------
// This is the texture that SpriteBatch will try to set before drawing
texture2D ScreenTexture;

// Our sampler for the texture, which is just going to be pretty simple
sampler TextureSampler = sampler_state
{
    Texture = <ScreenTexture>; 
};

//------------------------ PIXEL SHADER ----------------------------------------
// This pixel shader will simply look up the color of the texture at the
// requested point, and turns it into a shade of gray
float4 PixelShaderFunction(float4 pos : SV_POSITION, float4 color1 : COLOR0, float2 texCoord : TEXCOORD0) : SV_TARGET0
{
    float4 color = ScreenTexture.Sample(TextureSampler, texCoord.xy);

    float value = (color.r + color.g + color.b) / 3; 
    color.r = value;
    color.g = value;
    color.b = value;

    return color;
}

//-------------------------- TECHNIQUES ----------------------------------------
// This technique is pretty simple - only one pass, and only a pixel shader
technique BlackAndWhite
{
    pass Pass1
    {
        PixelShader = compile ps_4_0_level_9_3  PixelShaderFunction();
    }
}

Here's what I did: used Texture2D instead of Texture, changed the arguments of PixelShaderFunction (some of which I don't use, but seem to be required), used Texture.Sample instead of tex2D, and changed to ps_4_0_level_9_3

The rest of the code remained the same.

If anyone knows why this works, I'd be happy to hear the explanation.

Edit:

For anyone experiencing this problem in the future, here is the explanation. All of the parameters are needed for the PixelShaderFuction for registers to be mapped correctly. See the post here:

http://www.software7.com/blog/pitfalls-when-developing-hlsl-shader

\$\endgroup\$
0
\$\begingroup\$

You should add address mode on your texture sampler:

sampler TextureSampler = sampler_state
{
    Texture = <ScreenTexture>;

    AddressU = WRAP;
    AddressV = WRAP;
};

I'm not sure why that's necessary on monogame and not XNA but I guess it's because DX9 did things a bit different. The flipped UV coordinate puzzles me, I hope someone else can shed any light on this.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.