Color swap in XNA C #

I load my textures with

Texture2D.FromFile() 

then draw them using

 spriteBatch.Draw() 

But here is the point: I want to change some colors of the image to others. So my questions are:

  • How to change a single image color to another color (for example, blue to red).

  • In fact, I really want to change the color group to another color group. For example, red and similar shades from red to blue and similar shades to blue. You can do this, for example, in Corel PHOTO-PAINT ("Replace Color").

Please keep in mind that I am new to XNA. Regards Jack

EDIT:

Thanks so much for the help guys. Callum response is very helpful. But I wonder if there is a built-in function to solve my second problem, because writing your own can take a lot of time. And I think that such a function can be very useful. Something like:

 color.SetNewColor(Color color_from, Color color_to, int range) 

This function, as I said, is built into Corel PHOTO-PAINT. To explain this better, here is an example of what I am saying:

link text

So, I set only color_from, color_to and range. I think it works like this: it checks every color of the image, if it is in the color_from range, it changes to the corresponding color with a touch of color_to.

+6
c # xna
source share
5 answers

I assume you mean changing individual pixels? In this case, use the GetData() and SetData() Texture2D class.


For example, you can get an array containing the colors of individual pixels by doing the following:

 // Assume you have a Texture2D called texture Color[] data = new Color[texture.Width * texture.Height]; texutre.GetData(data); // You now have a packed array of Colors. // So, change the 3rd pixel from the right which is the 4th pixel from the top do: data[4*texture.Width+3] = Color.Red; // Once you have finished changing data, set it back to the texture: texture.SetData(data); 

Note that you can use other GetData() overloads to select only the section.


So, to replace each pixel of a specified color with a different color:

 // Assume you have a Texture2D called texture, Colors called colorFrom, colorTo Color[] data = new Color[texture.Width * texture.Height]; texutre.GetData(data); for(int i = 0; i < data.Length; i++) if(data[i] == colorFrom) data[i] = colorTo; texture.SetData(data); 

To see if the shades are similar, try this method:

 private bool IsSimilar(Color original, Color test, int redDelta, int blueDelta, int greenDelta) { return Math.Abs(original.R - test.R) < redDelta && Math.Abs(original.G - test.G) < greenDelta && Math.Abs(original.B - test.B) < blueDelta; } 

where * delta is the tolerance for each color channel you want to accept.


To answer your edit, there is no built-in function, but you can just use the mixture of ideas from the two sections above:

 Color[] data = new Color[texture.Width * texture.Height]; texutre.GetData(data); for(int i = 0; i < data.Length; i++) if(IsSimilar(data[i], colorFrom, range, range, range)) data[i] = colorTo; texture.SetData(data); 
+10
source share

Callum's solution is powerful and flexible.

A more limited solution, which is slightly easier to implement, is to use the spriteBatch color parameter.

Variables

 Texture2D sprite; //Assuming you have loaded this somewhere Color color = Color.Red; //The color you want to use Vector2 position = new Vector2(0f, 0f); //the position to draw the sprite 

Drawing code

 //Start the spriteBatch segment, enable alpha blending for transparency spriteBatch.Begin(SpriteBlendMode.AlphaBlend); //Draw our sprite at the specified position using a specified color spriteBatch.Draw(sprite, position, color); //end the spritebatch spriteBatch.End(); 

If your sprite is completely white, then using this method will turn your sprite into red. Also, make sure you use a file format with transparency in it, PNG is a favorite.

+3
source share

Moving data between the GPU and the CPU using GetData and SetData is an expensive operation. If there is a limited number of colors, you can use the pixel shader effect when rendering to the screen. You can convey the effect of SpriteBatch.Begin:

 sampler2D input : register(s0); /// <summary>The color used to tint the input.</summary> /// <defaultValue>White</defaultValue> float4 FromColor : register(C0); /// <summary>The color used to tint the input.</summary> /// <defaultValue>Red</defaultValue> float4 ToColor : register(C1); /// <summary>Explain the purpose of this variable.</summary> /// <minValue>05/minValue> /// <maxValue>10</maxValue> /// <defaultValue>3.5</defaultValue> float4 main(float2 uv : TEXCOORD) : COLOR { float4 Color; Color= tex2D(input , uv.xy); if (Color.r == FromColor.r && Color.g == FromColor.g && Color.b == FromColor.b) return ToColor; return Color; } technique Technique1 { pass Pass1 { PixelShader = compile ps_2_0 main(); } } 

Create your effect in the LoadContent method:

 colorSwapEffect = Content.Load<Effect>(@"Effects\ColorSwap"); colorSwapEffect.Parameters["FromColor"].SetValue(Color.White); colorSwapEffect.Parameters["ToColor"].SetValue(Color.Red); 

And pass the effect to your SpriteBatch.Begin () call:

 sprite.Begin(0, BlendState.Opaque, SamplerState.PointWrap, DepthStencilState.Default, RasterizerState.CullNone, colorSwapEffect); 

For what you really want to do, you can more easily switch with red and blue channels. Change the main () function of your pixel shader to this, which swaps b (blue) and r (red):

 float4 main(float2 uv : TEXCOORD) : COLOR { float4 Color; Color= tex2D(input , uv.xy); return float4(Color.b, Color.g, Color.r, Color.a); } 
+3
source share

Callum hit it on the head if you change the color of the 2D images as you see fit, but as you can see, you really need to determine the actual pixel that you want to change and edit, instead of replacing yellow green. "

The same logic could be used for this replacement (just scroll through the pixels of the image and check the color - I can say that be careful when editing such textures, although they seem to cause some pretty serious performance spikes depending on what was done and how often ... I didn’t fully research, but I think it caused quite a lot of garbage collection.

+2
source share

this works for me:

  protected override void Initialize() { sprite = Content.Load<Texture2D>("Parado"); Color[] data = new Color[sprite.Width * sprite.Height]; sprite.GetData(data); // new color Color novaCor =Color.Blue; for (int i = 0; i < data.Length; i++) { // cor roxa no desenho if (data[i].R == 142 && data[i].G == 24 && data[i].B == 115) { data[i] = novaCor; } } sprite.SetData<Color>(data); posicaoNinja = new Vector2(0, 200); base.Initialize(); } 
+1
source share

All Articles