如何使用HLSL制作外发光效果?

5
在WPF中,Net4.0不再支持或渲染OuterGlowBitmapEffect。DropShadow与我的情况几乎没有共同点,也不可接受。我的初衷是为黑色ClearType文本在AeroGlass窗口上创建一个白色模糊的背景,以使其在暗场景中更易读。我开始尝试使用fx和HLSL。这非常有趣和强大,但我仍然无法接近OuterGlowBitmapEffect。

我的当前虚拟版本反映了这个想法:

sampler2D  Sampler : register(S0);
#define PI 3.14f
float4 main(float2 uv : TEXCOORD) : COLOR
{
    float4 px = tex2D(Sampler, uv);

    /*
    if (px.a > 0.9)
    {
        return px;
    }
    */

    const float d = 3;

    int cnt = 0;
    float a = 0;
    for (float x = -0.1*d; x < 0.1*d; x += 0.05*d)
    {
        a += tex2D(Sampler, uv + float2(x, 0)).a;
        a += tex2D(Sampler, uv + float2(0, x)).a;
        a += tex2D(Sampler, uv + x).a;
        cnt += 3;
    }
    a /= cnt;

    float4 s = a;

    float4 r = float4(px.rgb*px.a + s.rgb*(1-px.a), max(px.a, a));

    return r;
}

顺便问一下:我能否获得一个HLSL源代码,以便将其用作参考?有人能指向任何语言中的OuterGlowEffect算法吗?

注意:Windows 7 Aero Glass标题栏具有此效果,使标题更易读!这正是我想在窗口其他部分的文本上拥有的效果(应用了DwmExtendFrameIntoClientArea)Aero Glass Window Title

1个回答

3

基本思路是先渲染白色文本,然后模糊处理。最后将模糊的白色文本作为黑色文本的背景图像。

您的着色器实现了正确的模糊处理,但效率不高(例如,在x=0时出现了冗余的采样)。通过两次处理(水平和垂直模糊),可以创建一个良好的大型模糊效果。HLSL 代码:

float4 PS_BlurHorizontal( float2 Tex : TEXCOORD0 ) : COLOR0
{
    float Color = 0.0f;

    Color += tex2D(sampler, float2(Tex.x - 3.0*blurSizeX, Tex.y)) * 0.09f;
    Color += tex2D(sampler, float2(Tex.x - 2.0*blurSizeX, Tex.y)) * 0.11f;
    Color += tex2D(sampler, float2(Tex.x - blurSizeX, Tex.y)) * 0.18f;
    Color += tex2D(sampler, Tex) * 0.24f;
    Color += tex2D(sampler, float2(Tex.x + blurSizeX, Tex.y)) * 0.18f;
    Color += tex2D(sampler, float2(Tex.x + 2.0*blurSizeX, Tex.y)) * 0.11f;
    Color += tex2D(sampler, float2(Tex.x + 3.0*blurSizeX, Tex.y)) * 0.09f;

    return Color;
}

float4 PS_BlurVertical( float2 Tex : TEXCOORD0 ) : COLOR0
{
    float Color = 0.0f;

    Color += tex2D(sampler, float2(Tex.x, Tex.y - 3.0*blurSizeY)) * 0.09f;
    Color += tex2D(sampler, float2(Tex.x, Tex.y - 2.0*blurSizeY)) * 0.11f;
    Color += tex2D(sampler, float2(Tex.x, Tex.y - blurSizeY)) * 0.18f;
    Color += tex2D(sampler, Tex) * 0.24f;
    Color += tex2D(sampler, float2(Tex.x, Tex.y + blurSizeY)) * 0.18f;
    Color += tex2D(sampler, float2(Tex.x, Tex.y + 2.0*blurSizeY)) * 0.11f;
    Color += tex2D(sampler, float2(Tex.x, Tex.y + 3.0*blurSizeY)) * 0.09f;

    return Color;
}
// weights: 0.09 + 0.11 + 0.18 + 0.24 + 0.18 + 0.11 + 0.9 = 1
// By default, weigths are symmetrical and sum up to 1,
// but they don't necessarily have to.
// You can change the weights to create more fancy results.

这两个7样本的通道模拟了一个7x7的高斯模糊(只有14个样本,而不是49个)。你可以使用更多的样本来改善结果(使模糊变宽),或者只需调整权重来创建更柔和的外观。


太棒了!但是在WPF位图效果中通常不可能有多次渲染着色器 :( 这里有一些提示和说明:http://www.codeproject.com/Articles/71617/Getting-Started-with-Shader-Effects-in-WPF 目前性能不是问题,因为我需要渲染的文本和位图数量很少。如果你可以帮忙创建一个单次通道函数来渲染带模糊背景的文本将会非常好。 - Dmitry Gusarov
2
你不需要创建一个多通道着色器,而是需要:
  1. 使用PS_BlurHorizontal模糊原始图像,
  2. 对上一步的结果使用PS_BlurVertical进行模糊处理。
如果你需要单通道处理,请查看这个链接:http://code.google.com/p/sbip/source/browse/trunk/SBIPFramework/Resources/GaussianBlur.fx?r=76
- miloszmaki

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