【问题标题】:Desaturate effect is not letting me set custom colors去饱和效果不允许我设置自定义颜色
【发布时间】:2013-12-02 11:04:43
【问题描述】:

我对如何创建着色器知之甚少,因此我对如何制作去饱和效果进行了一些研究,并为此借用了着色器代码。我现在遇到的一个问题是,当我尝试设置自定义颜色时,它似乎忽略了我给出的任何值。我想画一些完全黑色的东西,但 Color.Blacknew Color(0, 0, 0, screen.SATURATION) 没有用。事实上,无论我输入什么 RGB 值,它看起来都是一样的。

这是着色器的代码:

sampler TextureSampler : register(s0);

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

    // Convert it to greyscale. The constants 0.3, 0.59, and 0.11 are because
    // the human eye is more sensitive to green light, and less to blue.
    float greyscale = dot(tex.rgb, float3(0.3, 0.59, 0.11));

    // The input color alpha controls saturation level.
    tex.rgb = lerp(greyscale, tex.rgb, color.a * 4);

    return tex;
}


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

我的开始是这样的:

ScreenManager.SpriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, null, null, null, desaturateEffect, Resolution.getTransformationMatrix() * cam.get_transformation(graphics.GraphicsDevice));

着色器的另一个副作用是,当我通过color * float 淡出某些东西时,它似乎也会去饱和。我有点理解,因为颜色的第三个变量是 a: alpha,这是我放置去饱和变量以发挥其效果的位置。也许有人可以帮助我了解这里发生了什么,也许我可以做些什么来重新获得修改颜色的能力以及保持对饱和度的动态控制。

【问题讨论】:

  • 我与 HLSL 没什么关系,但是看着你的 main(...) 着色器函数让我想到:不只使用 colora 元素,即 Alpha?我没有看到你在任何地方使用 rgb
  • 因为你正在你的纹理颜色和它的灰度之间进行线性插值(lerp 函数,不是吗?),当然它会变成灰色,而不是黑色或红色或任何你想。我不确定它是否会起作用,但请尝试将您的greyscale 乘以color.rgb。如果color 是白色的,即(1, 1, 1),那么什么都不会发生。如果是黑色,你的灰度应该变成(0, 0, 0),那么黑。如果是例如红色,你的灰度应该只在 r 元素中,所以:'(grayscale, 0, 0)`,从而给你“redscale”,而不是灰度。
  • 显然,如果支持语句,那么可能是我添加 if(color.a != 999) 之类的东西作为它调整颜色的条件的一种方式。一些条件语句让我从效果中排除某些东西,而不是让它与我设置的 RGB 值混淆。
  • 我想最好的办法是把它画在一个没有应用效果的单独区域,我只是想把它画在那里是出于层/位置的原因。

标签: c# xna shader effects


【解决方案1】:

当您在SpriteBatch.Draw() 中指定颜色值时,它会以COLOR0 语义传递给输入参数。也就是说,这里:

float4 main(float4 color : COLOR0, float2 texCoord : TEXCOORD0) : COLOR0

float4 color 参数将被赋予您通过SpriteBatch.Draw() 传入的值,因为它被标记为COLOR0

除了输出着色纹理颜色之外什么都不做的沼泽标准像素着色器如下所示:

float4 main(float4 color : COLOR0, float2 texCoord : TEXCOORD0) : COLOR0
{
    return tex2D(TextureSampler, texCoord) * color;
}

注意乘以color。这将纹理的 R 乘以颜色的 R,将纹理的 G 乘以颜色的 G,以此类推,通过 B 和 A,为纹理提供的原始颜色着色。

所以你可能想要做的是:

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

    // Convert it to greyscale. The constants 0.3, 0.59, and 0.11 are because
    // the human eye is more sensitive to green light, and less to blue.
    float greyscale = dot(tex.rgb, float3(0.3, 0.59, 0.11));

    // The input color alpha controls saturation level.
    tex.rgb = lerp(greyscale, tex.rgb, color.a * 4);

    return tex;
}

这将在计算灰度值或执行 lerp 之前对原始纹理颜色进行着色 - 但仅对 RGB 通道进行着色。

【讨论】:

  • 感谢您对它的作用的解释。我现在遇到的一个问题是我不能通过new Color(r, g, b, SATURATION) * 0.5f 淡出一些东西,例如让它半透明。唯一的变化是tex.rgb *= color.rgb;,所以我不明白为什么这会影响淡出效果。
  • 不幸的是,您无法使用此着色器将 Alpha 与饱和度分离。您必须在乘法步骤中包含 alpha 分量:tex *= color; 这会导致某些内容越饱和越淡。您可以在着色器参数中指定 alpha 或(最好)饱和度因子,但批次中的每个精灵都必须具有相同的值。
  • 嗯,我在游戏画面中将饱和度作为变量。我可以从效果文件中引用该变量吗?
  • 问题在于没有构造函数来传递对游戏画面的引用,因为您只是 Content.Load 去饱和效果。我明白为什么这种效果会通过 alpha 变量传递到饱和度级别,因为它似乎是在其中获取变量的少数几种方法之一!
  • 可以在调用SpriteBatch.Begin()的同时设置shader参数。只需执行myShader.Parameters["Saturation"].SetValue(value); 并确保在着色器文件的顶部声明float Saturation;
猜你喜欢
  • 1970-01-01
  • 2012-10-30
  • 2011-05-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-09
  • 1970-01-01
相关资源
最近更新 更多