【问题标题】:Color Replacement in XNA C#XNA C# 中的颜色替换
【发布时间】:2010-07-15 12:00:15
【问题描述】:

我使用

加载我的纹理
Texture2D.FromFile()

然后使用

绘制它们
spriteBatch.Draw()

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

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

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

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

编辑:

非常感谢你们的帮助,伙计们。卡勒姆的回答确实很有帮助。但我想知道是否有一个内置函数可以解决我的第二个问题,因为自己编写可能很耗时。而且我认为,这种功能可能非常有用。比如:

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

正如我之前所说,这种功能是内置在 Corel PHOTO-PAINT 中的。为了更好地解释它,这是我正在谈论的示例:

link text

所以,我只设置了 color_from、color_to 和 range。我认为它是这样工作的:它检查图像的每种颜色,如果它在 color_from 范围内,则将其更改为 color_to 色调中的适当颜色。

【问题讨论】:

    标签: c# xna


    【解决方案1】:

    我假设您的意思是更改单个像素?在这种情况下,请使用 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 是您想要接受的每个颜色通道的变化容差。


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

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

    【讨论】:

    • "要回答您的编辑,没有内置函数,但您可以混合使用上面两个部分的想法:"嗯,这绝对不是那么容易,但我'当我找到一些时间时,我会尝试编写我正在谈论的函数。如果有人能发布一些有用的东西,我将不胜感激。
    【解决方案2】:

    使用 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);
    }
    

    【讨论】:

      【解决方案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 是最受欢迎的。

      【讨论】:

        【解决方案4】:

        如果您要更改 2D 图像的颜色,就像您看起来一样,Callum 会一针见血 - 但正如您所见,您实际上需要确定要修改和编辑它的实际像素,而不是“将黄色替换为绿色”例如。

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

        【讨论】:

        • 你是正确的垃圾收集导致性能峰值,因为Color[] 数组被分配和分配数据。您可以通过创建自己的类型来解决此问题,该类型存储当前的Color[] 数据数组及其来源的纹理,然后只需更改数组,然后每次使用SetData() - 它明显更快,但以增加内存为代价用法。
        【解决方案5】:

        这对我有用:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-03-28
          • 1970-01-01
          • 2012-04-09
          • 1970-01-01
          • 1970-01-01
          • 2018-11-23
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多