Apply PixelShader on Texture2D

For some reasons applying pixel shader does not work as excepted.

Shader.fx (Grayscale effect)

sampler TextureSampler : register(s0);

float4 PixelShaderFunction(float2 texCoord : TEXCOORD0) : COLOR0
{
	float4 c = 0;
	c = tex2D(TextureSampler, texCoord);
	c.a = clamp(c.a - 0.05, 0, 1);
	c.r = c.r * c.a;
	c.g = c.g * c.a;
	c.b = c.b * c.a;
	return c;
}

technique Technique1
{
    pass Pass1
    {
		PixelShader = compile ps_4_0_level_9_1 PixelShaderFunction();
    }
}

Draw call

spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);
Shader.CurrentTechnique.Passes[0].Apply();
spriteBatch.Draw(...);
spriteBatch.End();

This shader with this draw call, will result in no output. (Transparent or not visible) However, many other .fx also did result in a disappearing texture. Even following code returns nothing:

	float4 c = 0;
	c = tex2D(TextureSampler, texCoord);
	return c;

Am I missing something? Also, using spriteBatch.Begin(SpriteSortMode.Immediate…); kinda grinds my gear. If I interpret the doc correct, after every .draw(); the GPU will receive the texture and instantly draw it. Isn’t that very unperformant? Can I use pixel/vertex shader and still draw in batches?

Thanks in advance

Edit:

return float4(1, 0, 0, 0);

works like a charm. (Each pixel same color)

Make sure you take the full input that the SpriteEffect vertex shader outputs:

struct VertexShaderOutput
{  
    float4 Position : SV_POSITION;  
    float4 Color : COLOR0;  
    float2 TextureCoordinates : TEXCOORD0;
};

You can pass your effect to SpriteBatch.Begin instead of explicitly applying it. Then you can use Deferred or whatever other SpriteSortMode.

Thanks Jjagg!

Do you have any links to tutorials or something? I am totally new to shaders and I want to read myself into.
I did copy and paste your code, but I guess I have to apply it somewhere. (Or at least call it?)

While searching for Shader tuts online, I only discovered obsolete ones.
A kick start would be great.

(E.g: My First 2D Pixel Shader(s) - Part 1 - gmjosack is what I copy+c+v. Maybe did work in XNA times)

Thanks

Therefore, the effect would apply to all textures? I will play around with the setup.

Oh, sorry I confused your avatar with @jackmott’s and thought you had some experience with MG shaders :stuck_out_tongue:

I’ll start over: Welcome to the forums! :slight_smile:

That struct is what you should take as input to your pixel shader.

float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0

Because GLSL does not use semantics (the TEXCOORD0 stuff and so on) the alignment gets messed up if you do not use the same inputs as the vertex shader outputs.

For tutorials, you can use any XNA tutorials which should be a lot easier to find than MG ones. I recommend:

There’s some things to keep in mind when writing shaders. Check out the ‘Effect Writing Tips’ section on this page.

If you’re using Visual Studio, I also recommend installing the HlslTools extension. It adds stuff like autocomplete, live error highlighting and HLSL built-in function documentation.

No problem Sir!

It works like a charm! The VS Extension does really help. Very much appreciated.

So, MonoGame does only use OpenGL? I thought it supports DX and GL. Kinda like Unity. (Transcompiling shader language for both cases) In case of GLSL, I have to stick to those tutorials, right?

All shaders are written in HLSL, that’s the code you’re using above. MonoGame supports DirectX as well as OpenGL. When you target a platform that uses OpenGL, MonoGame translates the HLSL code (to be more specific it compiles it first and translates the bytecode) to GLSL using a tool called MojoShader. So if you’re going with tutorials not specifically for MonoGame or XNA, you’ll want to look at HLSL tutorials.

1 Like

Wow thanks for the tip, glad I found it but how come we have to take ALL the inputs from the VertexShader, even if we don’t need them, seems odd?