XNA C中的颜色替换#

我使用加载我的纹理

Texture2D.FromFile() 

然后使用它们绘制

 spriteBatch.Draw() 

但重点是:我想将图像的某些颜色更改为另一种颜色。 所以我的问题:

  1. 如何将图像的单色更改为另一种颜色(例如蓝色到红色)。

  2. 事实上,我真正想做的是将一组颜色改为另一组颜色。 例如红色和类似色调,红色到蓝色,类似色调,蓝色。 例如,您可以在Corel PHOTO-PAINT(“替换颜色”)中执行此操作。

请记住,我是XNA的初学者。 最好的问候,杰克

编辑:

伙计们,非常感谢你的帮助。 Callum的回答确实非常有用。 但我想知道是否有内置函数来解决我的第二个问题,因为编写自己的函数可能非常耗时。 我认为,这种function可能非常有用。 就像是:

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

正如我之前所说,这种function是用Corel PHOTO-PAINT构建的。 为了更好地解释它,这里是我正在谈论的例子:

链接文字

所以,我只设置color_from,color_to和range。 我觉得它的作用是这样的:它检查图像的每种颜色,如果它在color_from的范围内,它会在color_to的色调中变为足够的颜色。

我猜你的意思是改变个别像素? 在这种情况下,使用Texture2D类的GetData()SetData()方法。


例如,您可以通过执行以下操作获取包含各个像素颜色的数组:

 // 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); 

请注意,您可以使用GetData()的其他重载来仅选择一个节。


因此,要将指定颜色的每个像素替换为另一种颜色:

 // 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); 

要查看色调是否相似,请尝试以下方法:

 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; } 

其中* delta是您要接受的每个颜色通道的更改容差。


要回答您的编辑,没有内置function,但您可以使用上述两个部分的混合思路:

 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); 

使用GetData和SetData在GPU和CPU之间移动数据是一项昂贵的操作。 如果颜色数量有限,则在渲染到屏幕时可以使用像素着色器效果。 您可以将效果传递给SpriteBatch.Begin:

 sampler2D input : register(s0); /// The color used to tint the input. /// White float4 FromColor : register(C0); /// The color used to tint the input. /// Red float4 ToColor : register(C1); /// Explain the purpose of this variable. /// 05/minValue> /// 10 /// 3.5 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(); } } 

在LoadContent方法中创建效果:

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

并将效果传递给您对SpriteBatch.Begin()的调用:

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

对于您真正想做的事情,您可以更轻松地交换红色和蓝色通道。 将像素着色器的main()函数更改为此,交换b(蓝色)和r(红色):

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

Callum的解决方案function强大且灵活。

更容易实现的更有限的解决方案是利用spriteBatch颜色参数。

变量

 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 

绘图代码

 //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(); 

如果您的精灵全部为白色,那么使用此方法会将您的精灵变为红色。 此外,请确保您使用的是具有透明度的文件格式,PNG是您的最爱。

如果你正在改变2D图像的颜色,Callum会把它击中头部 – 但正如你所看到的,你实际上需要确定你想要修改和编辑它的实际像素而不是“用黄色替换黄色”例。

可以使用相同的逻辑来替换(简单地循环图像的像素并检查颜色 – 我可以说在编辑这样的纹理时要小心,因为它们似乎会导致一些非常严重的性能峰值取决于什么已经完成了多久。我没有完全调查,但我认为它造成了相当多的垃圾收集。

这对我有用:

  protected override void Initialize() { sprite = Content.Load("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(data); posicaoNinja = new Vector2(0, 200); base.Initialize(); }