XNA ColorMatrix Equivalent

In XNA, how can I achieve the same effect of applying System.Drawing.Imaging.ColorMatrix? The following article shows how I would like to render my sprites, but it uses GDI +:

http://www.c-sharpcorner.com/UploadFile/mahesh/Transformations0512192005050129AM/Transformations05.aspx

How can this be done in XNA? Can I use a general purpose shader? Any help would be appreciated.

+2


source to share


3 answers


OK, depending on your code ( here ), which isn't quite the same as ColorMatrix (but that should give you an idea of ​​how to add the full matrix functionality you want), here's a version that will work in XNA:

First of all download the sample sprites . This will save me from tweaking. I'm just going to replace the Desaturate effect.

Here's a pixel shader that's pretty much the same as your own. Replace the contents of "desaturate.fx" with the following:

sampler TextureSampler : register(s0);

float4 colorMultiply = float4(1, 1, 1, 1);
float4 colorAdd = float4(0, 0, 0, 0);

float4 PixelShader(float4 color : COLOR0, float2 texCoord : TEXCOORD0) : COLOR0
{
    // Look up the texture color.
    float4 tex = tex2D(TextureSampler, texCoord);

    // Perform scaling and addition and return
    return color * tex * colorMultiply + colorAdd;
}

technique ColorMatrix { pass Pass1 { PixelShader = compile ps_2_0 PixelShader(); } }

      

Now replace the function DrawDesaturate

like this:

(As Joel Martinez says, in XNA 4, this code gets a lot neat .)



void DrawDesaturate(GameTime gameTime)
{
    Effect colorMulAddEffect = desaturateEffect; // reusing desaturateEffect to keep this short!
    float pulsate = Pulsate(gameTime, 4, 0, 1);

    spriteBatch.Begin(SpriteBlendMode.None, SpriteSortMode.Immediate, SaveStateMode.None);

    colorMulAddEffect.Parameters["colorMultiply"].SetValue(new Vector4(1.5f, 1f, pulsate, 1f));
    colorMulAddEffect.Parameters["colorAdd"].SetValue(new Vector4(-0.5f, 1-pulsate, 0f, 0f));
    colorMulAddEffect.Begin();
    colorMulAddEffect.CurrentTechnique.Passes[0].Begin();

    spriteBatch.Draw(glacierTexture, FullscreenRectangle(), Color.White);

    spriteBatch.End();
    colorMulAddEffect.CurrentTechnique.Passes[0].End();
    colorMulAddEffect.End();
}

      

Now there is one major caveat with this code - you cannot run sprites with different colorMultiply and colorAdd values! (In fact, colorMultiply is a bit overkill, as you can simply use the sprite's color as colorMultiply, which you can change for each sprite.)

So, if each sprite has a different add / multiply value, you have to do the whole SpriteBatch.Begin, Effect.Begin, draw the material, SpriteBatch.End, Effect.End for each sprite.

The reason for this is that the pixel shader and its parameters can only be set once per package as described in this blog post .

Executing one sprite per batch will be slow if you have a lot of sprites!

The solution to this (if you need that kind of performance) would be to make a custom doser sprite with a custom vertex shader that can pass more than one color to the pixel shader. It is possible, although not trivial. A good starting point would be the source code for the shaders used by SpriteBatch .

+2


source


You can use a custom pixel shader to make this kind of color manipulation very easy. For example, take a pixel shader like this:

sampler2D sampler;

float4 PixShader( float2 tex : TEXCOORD0 ) : COLOR0
{
    float4 color;
    color = tex2D( sampler, tex);

    //do anything you want to the colors
    color.r = color.r * 2; // intensify the red component
    color.g = color.g * 0.5; // cut all green values in half
    // etc.

    return color;
}

      



And using custom shaders with the SpriteBatch class in XNA 4.0 is much easier :
SpriteBatch and Custom Shaders in XNA Game Studio 4.0 by Shawn Hargreaves

+1


source


Here's a solution that works with Silverlight and WPF:

sampler2D input : register(s0);

/// <defaultValue>1.0</defaultValue>
float RMul : register(C0);
/// <defaultValue>1.0</defaultValue>
float GMul : register(C1);
/// <defaultValue>1.0</defaultValue>
float BMul : register(C2);
/// <defaultValue>1.0</defaultValue>
float AMul : register(C3);

/// <defaultValue>0</defaultValue>
float RAdd : register(C4);
/// <defaultValue>0</defaultValue>
float GAdd : register(C5);
/// <defaultValue>0</defaultValue>
float BAdd : register(C6);
/// <defaultValue>0</defaultValue>
float AAdd : register(C7);

float4 main(float2 uv : TEXCOORD) : COLOR 
{
   float4 color = tex2D(input, uv);
   color = color.rgba * float4(RMul, GMul, BMul, AMul) + float4(RAdd, GAdd, BAdd, AAdd);
   return color;
}

      

I'll give the answer to the first person to tweak it to work on XNA.

+1


source







All Articles