处理WPF像素着色器效果中的Alpha通道

11

在像素着色器中,关于 alpha 分量的处理是否有什么不同寻常的地方?我的艺术家为我的 WPF 应用程序提供灰度图像作为背景,并根据当前状态对这些图像进行着色。因此,我编写了一个像��着色器(使用 WPF 像素着色器效果库基础架构),用作 Image 元素上的效果。该着色器将颜色作为参数,将其转换为 HSL 格式以便于操作亮度。然后,对于每个灰度像素,它计算出一种颜色,其亮度在源像素的亮度比例下在颜色参数和白色之间进行插值。

float4 main(float2 uv : TEXCOORD) : COLOR
{
    float4 src = tex2D(implicitInputSampler, uv);

    // ...Do messy computation involving src brightness and color parameter...

    float4 dst;
    dst.r = ...
    dst.g = ...
    dst.b = ...
    dst.a = src.a;
    return dst;
}

在alpha = 1的像素上运行良好。但是在alpha = 0的情况下,结果像素会变成白色,而不是窗口背景透过来的颜色。所以我做了一个微小的改变:

float4 main(float2 uv : TEXCOORD) : COLOR
{
    float4 src = tex2D(implicitInputSampler, uv);
    if (src.a == 0) 
        return src;
    ...

现在透明部分真正是透明的了。为什么?为什么第一版中的dst.a = src.a语句没有实现这一点?不幸的是,即使这样修复,像我这样的人看起来像是alpha值在0到1之间的像素会变成白色。

有人知道我对alpha理解的哪些方面存在误解吗?

3个回答

25

经过进一步的网络搜索,我发现了我所遗漏的部分。

根据MSDN上的一篇文章:“WPF在内部处处使用预乘α以提高性能,因此这也是我们解释自定义像素着色器中颜色值的方式。”

所以解决方法就是通过α进行乘法运算:

float4 main(float2 uv : TEXCOORD) : COLOR
{
    ...
    dst.rgb *= src.a;
    return dst;
}

现在我的输出看起来和我预期的一样。


-1
“0 < alpha < 1” 出现白色。
“你期望的范围是什么?”
所有值都将在0.0和1.0之间...像素着色器不适用于离散的256种颜色范围,它们是浮点数,其中1.0是最大强度。
如果您的计算最终将r/g/b值设置为>1.0,则会得到白色...

http://www.facewound.com/tutorials/shader1/


请注意,我说的是“<”,而不是“<=”。我知道所有的值都在单位间隔上。由于我已经讨论了a=1的情况(按预期工作)和a=0的情况(只有在我为src.a==0添加短路测试时才起作用),所以0 < a < 1就是所有其他情况,其中源位图部分透明。 - vanmelle
你能够调试着色器输出的实际值吗?从你展示的样例中,我看不出这可能会失败。你只是复制了alpha通道。你使用了哪些图像格式?没有你的着色器时,alpha通道会发生什么变化? - Jack Ukleja

-2
哥们,我正在开发XNA游戏,不得不使用灰度像素着色器,遇到了你现在面临的同样问题。 不知道你是否熟悉XNA环境,但我通过将SpriteBatch绘图的SpriteBlendModeSpriteBlendMode.None更改为SpriteBlendMode.AlphaBlend解决了这个问题,希望这可以帮助你了解原因。
此致敬礼,

谢谢,但我不知道这对WPF意味着什么,或者WPF是否有这样的功能。我在其他地方读到过,WPF不支持所有的directX混合模式。 - vanmelle

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接