1
votes

Using the simple shader at Tint Sprite White and the sample code at Sprite Effects Sample, I've loaded the .fx file for the shader into the sample project and replaced one of the sample effects in one of the Draw() calls to use the whitening effect.

What I get is a big white square with the same dimensions as the texture itself. I obviously want only the regions of the texture where the alpha is not 0 to be made white. The shader appears to be working, as I altered the default white color to other test cases and the square does change color.

I tried this in a simple project of my own and got the same result. How can I make sure that only the visible part of the texture is shaded?

The modified call looks like this:

        spriteBatch.Begin(0, null, null, null, null, whiteEffect);

        spriteBatch.Draw(myTexture, CenterOnScreen(myTexture), Color.White);

        spriteBatch.End();
1

1 Answers

5
votes

First, double-check to make sure you have alpha in your image.

That shader assumes you're using non-premultiplied alpha:

batch.Begin(0, BlendState.NonPremultiplied, null, null, null, whiteEffect);

The shader uses the texture's alpha value as a base for the whitening; in other words, the more solid the alpha, the more solid the whitening effect. If you don't want any "in-betweens" (e.g. partially white), it will work if your texture has no "in-between" alpha in it.

Non-premultiplied Partial-White Alpha (Original) Version

   float4 ps_main( PS_INPUT Input ) : COLOR0
   {
       float4 color = tex2D( baseMap, Input.Texcoord );
       return float4(1.0f, 1.0f, 1.0f, color.a);
   }

EDIT: Since a premultiplied version was inquired about, I'll add that version in with an explanation.

From this helpful article:

To convert a non premultiplied color into premultiplied format:

color.rgb *= color.a

So let's do the same here in our shader:

Premultiplied Partial-White Alpha Version

   float4 ps_main( PS_INPUT Input ) : COLOR0
   {
       float4 color = tex2D( baseMap, Input.Texcoord );
       return float4(color.a, color.a, color.a, color.a);
   }

Now you can go ahead and use the default alpha blend state:

batch.Begin(0, BlendState.AlphaBlend, null, null, null, whiteEffect);

I'm still not really sure if you want the hard "white or transparent" ... in that case it doesn't really matter if you do pre-multiplied or not because you could just do a "boolean" style return of pure white (1.0f, 1.0f, 1.0f, 1.0f) or pure transparent (0.0f, 0.0f, 0.0f, 0.0f); these particular colors will both show up the same regardless of blend state:

Hard White-or-Transparent (Ignores partial whites), Premultiplied-Agnostic

float4 ps_main( PS_INPUT Input ) : COLOR0
{
   float4 color = tex2D( baseMap, Input.Texcoord );
   if (color.a > 0.0f)
   {
      return float4(1.0f, 1.0f, 1.0f, 1.0f);
   }
   else
   {
      return float4(0.0f, 0.0f, 0.0f, 0.0f);
   }
}