XNA C中的颜色替换#

时间:2010-07-15 12:00:15

标签: c# xna

我使用

加载纹理
Texture2D.FromFile()

然后使用

绘制它们
spriteBatch.Draw()

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

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

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

  3. 请记住,我是XNA的初学者。 最好的祝福, 千斤顶

    编辑:

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

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

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

    link text

    所以,我只设置了color_from,color_to和range。我认为它是这样的:它检查图像的每种颜色,如果它在color_from的范围内,它会在color_to的色调中变为适当的颜色。

5 个答案:

答案 0 :(得分:11)

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


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

// 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是您要接受的每个颜色通道的更改容差。


要回答您的编辑,没有内置功能,但您可以使用上述两个部分的想法混合:

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

答案 1 :(得分:4)

使用GetData和SetData在GPU和CPU之间移动数据是一项昂贵的操作。如果颜色数量有限,则在渲染到屏幕时可以使用像素着色器效果。您可以将效果传递给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();
    }
}

在LoadContent方法中创建效果:

colorSwapEffect = Content.Load<Effect>(@"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);
}

答案 2 :(得分:3)

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

更容易实现的更有限的解决方案是利用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是您的最爱。

答案 3 :(得分:2)

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

可以使用相同的逻辑进行替换(只需循环遍历图像的像素并检查颜色 - 我可以说在编辑这样的纹理时要小心,因为它们似乎会导致一些相当严重的性能峰值取决于做了什么以及做了多少次。我没有完全调查,但我认为它造成了相当多的垃圾收集。

答案 4 :(得分:1)

这对我有用:

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