智能DropShadowEffect

时间:2014-10-06 13:07:28

标签: wpf

渲染阴影时,是否可以让DropShadowEffect 忽略某些颜色?有某种蒙面(颜色选择性)阴影?

我的问题是可以将阴影分配给整个视觉元素(图形)。它看起来像这样:

我想要

注意没有阴影的网格线(0,0除外)。这可以通过在缩放/偏移图中具有2个同步来实现,一个没有阴影效果包含网格而另一个阴影包含其余部分。但我对这个解决方案并不是很满意(我预测未来会有很多问题)。所以我宁愿以某种方式修改DropShadowEffect

我可以创建和使用ShaderEffect,但我不知道如何对着色器进行编程以获得实际的阴影效果(如果它可以由着色器生成)。

也许使用DropShadowEffect本身更简单的方法?任何人吗?

修改

我试图制作着色器效果:

sampler2D _input : register(s0);
float _width : register(C0);
float _height : register(C1);
float _depth : register(C2); // shadow depth

float4 main(float2 uv : TEXCOORD) : COLOR
{
    // get pixel size
    float2 pixel = {1 / _width, 1 / _height};

    // find color at offset
    float2 offset = float2(uv.x - pixel.x * _depth, uv.y - pixel.y * _depth);
    float4 color = tex2D(_input, offset);

    // convert to gray?
    //float gray = dot(color, float4(0.1, 0.1, 0.1, 0));
    //color = float4(gray, gray, gray, 1);

    // saturate?
    //color = saturate(color);

    return tex2D(_input, uv) + color;
}

但一切都失败了。

修改

以下是图形外观的截图,我喜欢(对那些试图说服我不要这样做的人):

目前通过具有模板

的特殊Graph来实现
<Border x:Name="PART_Border" BorderThickness="1" BorderBrush="Gray" CornerRadius="4" Background="White">
    <Grid>
        <Image x:Name="PART_ImageBack" Stretch="None"/>
        <Image x:Name="PART_ImageFront" Stretch="None">
            <Image.Effect>
                <DropShadowEffect Opacity="0.3"/>
            </Image.Effect>
        </Image>
    </Grid>
</Border>

所有内容都渲染到PART_ImageFront(带阴影),而网格渲染到PART_ImageBack(没有阴影)。在性能方面,它仍然

2 个答案:

答案 0 :(得分:2)

我没有使用像素着色器的经验,但是这是我对阴影效果的快速而肮脏的尝试,忽略了&#34;无色&#34;像素:

sampler2D _input : register(s0);
float _width : register(C0);
float _height : register(C1);
float _depth : register(C2);
float _opacity : register(C3);

float3 rgb_to_hsv(float3 RGB) {
    float r = RGB.x;
    float g = RGB.y;
    float b = RGB.z;

    float minChannel = min(r, min(g, b));
    float maxChannel = max(r, max(g, b));

    float h = 0;
    float s = 0;
    float v = maxChannel;

    float delta = maxChannel - minChannel;

    if (delta != 0) {
        s = delta / v;

        if (r == v) h = (g - b) / delta;
        else if (g == v) h = 2 + (b - r) / delta;
        else if (b == v) h = 4 + (r - g) / delta;
    }

    return float3(h, s, v);
}

float4 main(float2 uv : TEXCOORD) : COLOR {
    float width = _width; // 512;
    float height = _height; // 512;
    float depth = _depth; // 3;
    float opacity = _opacity; // 0.25;

    float2 pixel = { 1 / width, 1 / height };

    float2 offset = float2(uv.x - pixel.x * depth, uv.y - pixel.y * depth);
    float4 srcColor = tex2D(_input, offset);

    float3 srcHsv = rgb_to_hsv(srcColor);
    float4 dstColor = tex2D(_input, uv);

    // add shadow for colored pixels only
    // tweak saturation threshold as necessary
    if (srcHsv.y >= 0.1) {
        float gray = dot(srcColor, float4(0.1, 0.1, 0.1, 0.0));
        float4 multiplier = float4(gray, gray, gray, opacity * srcColor.a);
        return dstColor + (float4(0.1, 0.1, 0.1, 1.0) * multiplier);
    } 

    return dstColor;
}

这是针对我在Blend中使用铅笔工具绘制的(完全合法的)图表的行动:

Chart

着色器效果应用于包含轴,网格线和系列线的根面板,并且仅为系列线生成阴影。

我不认为着色器能够在忽略网格线的同时将阴影应用于轴和标签是不现实的。文本上的抗锯齿必然与网格线的颜色/饱和度范围相交。我认为将影子应用于系列线条无论如何都更清晰,更美观。

答案 1 :(得分:1)

sampler2D input : register(s0);
float4 main(float2 uv : TEXCOORD) : COLOR  {

    float4 Color;
    Color = tex2D( input , uv.xy);
    return Color;
}

这是一个基本的“无所事事”着色器。带有text2D调用的行采用通常在当前位置绘制的颜色。 (在这种情况下只返回它)

您可以向uv.xy添加偏移矢量并返回该颜色,而不是对uv.xy进行采样。这会使整个图像在偏移矢量的方向上移动。

你可以将这两者结合起来:

  1. 对uv.xy进行采样,如果设置为可见颜色的颜色(这将使所有线条在正确的位置保持可见)
  2. 如果它是透明的,请向左上方采样一点。如果它设置为你想要有阴影的颜色:返回阴影颜色。
  3. 步骤2.可以更改为:如果设置为您不想要阴影的颜色,则返回透明色。

    要测试和用作阴影颜色的偏移量和颜色可能是效果的参数。

    我强烈建议您使用Shazzam,它将允许您测试着色器,它将为您生成C#代码。

    请注意,uv坐标不是以像素为单位,而是缩放为0.0到1.0。

    <强>加成

    可以通过在偏移周围采样更多像素并计算应该导致阴影的颜色的平均值来获得穷人的模糊(抗锯齿)。这将导致更多像素接收阴影。

    要计算阴影颜色,您可以通过将其乘以0.0(黑色)和1.0(原始颜色)之间的因子来简化现有颜色

    通过使用模糊的平均值,您可以再次将阴影颜色相乘,从而使模糊与原始颜色混合。

    更精确(和昂贵)将rgb值转换为hls值,并使用“官方”变暗公式来确定阴影颜色。