最近在学习怎么用 Shazzam Shader Editor 编写自定义的 Effect,并试着去实现阴影、内阴影和长阴影的效果。结果我第一步就放弃了,因为阴影用到的高斯模糊算法对我来说太太太太太太太太难了,最后只好用些投机取巧的方法来模仿这几种效果。

1. 阴影

WPF 中的 DropShadowEffect 简单来说就是将输入源的图像进行高斯模糊,然后根据 Color、Opacity、Direction、ShadowDepth 这几个属性来修改颜色、透明度和位移,形成一张新的图像作为阴影,平铺在原图像的背后。要自己实现 DropShadowEffect 最大的难点就在高斯模糊这里,既然写不出高斯模糊算法,就只好依赖 WPF 现有的东西。我的做法是用一个 VisualBrush 获取需要做阴影的图像,然后再用 WPF 的 BlurEffect 让它变模糊:

<Grid ClipToBounds="True">
<Grid>
<Grid.Effect>
<BlurEffect Radius="38" />
</Grid.Effect>
<Grid.Background>
<VisualBrush Stretch="None" Visual="{Binding ElementName=ForegroundElement}" />
</Grid.Background>
</Grid>
</Grid>
<Grid x:Name="ForegroundElement">
<TextBlock VerticalAlignment="Center"
FontFamily="Lucida Handwriting"
FontSize="148"
FontWeight="ExtraBold"
Foreground="#f7e681"
TextAlignment="Center">
FAKE<LineBreak />
SHADOW</TextBlock>
</Grid>

现在的它看起来就是这个样子。

然后写一个 FakeDropShadowEffect。它获取输入源的 Alpha 通道,将 RGB 替换为指定的颜色(默认是黑色),组合成新的颜色。再通过 Angle 和 Depth 计算出偏移:

float4 main(float2 uv : TEXCOORD) : COLOR
{
float4 c = 0;
float rad = Angle * 0.0174533f;
float xOffset = cos(rad) * Depth;
float yOffset = sin(rad) * Depth; uv.x += xOffset;
uv.y += yOffset;
c = tex2D(Texture1Sampler, uv);
c.rgb = Color.rgb * c.a * Opacity;
c.a = c.a * Opacity;
return c;
}

最后在应用了 BlurEffect 的元素外面再套一层 Grid,然后在这个 Grid 应用刚刚写的 FakeDrpShadowEffect:

<Grid ClipToBounds="True">
<Grid.Effect>
<effects:FakeDropShadowEffect Angle="225"
Depth="0.03"
Opacity="0.5" />
</Grid.Effect>

成果如上图所示,和 DropShadowEffect 几乎一样了。

2. 内阴影

关于内阴影的实现,我之前写过另一篇文章介绍过:实现 WPF 的 Inner Shadow。现在用 Effect,我首先想到的做法是叠加两个元素,上层的元素根据另一个元素的 VisualBrush 剪切出一个洞,然后在这个洞投下阴影:

<Grid x:Name="BackgroundElement">
<TextBlock x:Name="Text"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="150"
FontWeight="Bold"
Foreground="{StaticResource LightBackground}"
TextAlignment="Center">
INNER<LineBreak />
SHADOW</TextBlock>
</Grid>
<Grid ClipToBounds="True">
<Grid.Effect>
<DropShadowEffect BlurRadius="8"
Opacity="0.7"
ShadowDepth="5" />
</Grid.Effect>
<Grid Background="{StaticResource LightBackground}">
<Grid.Effect>
<effects:ClipEffect>
<effects:ClipEffect.Blend>
<VisualBrush Stretch="None" Visual="{Binding ElementName=BackgroundElement}" />
</effects:ClipEffect.Blend>
</effects:ClipEffect>
</Grid.Effect>
</Grid>
</Grid>

在上面的 XAML 中,ClipEffect 有另一个输入 Blend,这个输入就是要剪切的形状。ClipEffect 的代码很简单,就只是几行,关键的功能是用 input 的Alpha 通道减去 blend 的 Alpha 通道作为结果输出:

sampler2D blend : register(s1);

float4 main(float2 uv : TEXCOORD) : COLOR
{
float4 inputColor = tex2D(input, uv);
float4 blendColor = tex2D(blend, uv);
float4 resultColor = 0;
float opacity = inputColor.a - blendColor.a;
resultColor.rgb = inputColor.rgb * opacity;
resultColor.a = opacity; return resultColor;
}

下图是上面的 XAML 实现的效果:

3. 长阴影

我以前写过一篇在 UWP 实现长阴影的博客:使用GetAlphaMask和ContainerVisual制作长阴影(Long Shadow)。这次在 WPF 里重新用 Effect 实现一次。长阴影的原理是不断向左上角(因为偷懒就只是做向右下的阴影)检查,直到遇到 Alpha 通道为 1 的像素,然后计算这个像素与自身的距离得出阴影的 Alpha,所有代码如下:

float4 main(float2 uv : TEXCOORD) : COLOR
{
float4 srcColor = tex2D(input, uv);
if (srcColor.a == 1)
{
return srcColor;
} float4 tempColor = 0;
float2 offset = 0;
int maxDepth = 400;
float a = 0;
for (float i = 1; i < maxDepth; i++)
{
if (i < ShadowLength)
{
if (a == 0)
{
offset = uv.xy - float2(i / Width, i / Height);
if (offset.x > 0 && offset.y > 0)
{
tempColor = tex2D(input, offset);
if (tempColor.a == 1)
{
a = (1 - i / max(1,ShadowLength));
}
}
}
}
} if (a == 0)
{
return srcColor;
} a = min(1,a);
tempColor.rgb = Color.rgb * a * Opacity;
tempColor.a = a * Opacity;
float4 outColor = (1 - srcColor.a) * tempColor + srcColor;
return outColor;
}

使用起来的 XAML 和效果如下,需要输入 ShadowLength 和 Color,因为 Effect 没法知道输入源的尺寸,所以还需要主动输入 Width 和 Height:

<Grid x:Name="Root" Background="Transparent">
<Grid.Effect>
<effects:LongShadowEffect Width="{Binding ElementName=Root, Path=ActualWidth}"
Height="{Binding ElementName=Root, Path=ActualHeight}
ShadowLength="100"
Color="Red" />
</Grid.Effect>
<TextBlock x:Name="TextBlock"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="150"
FontWeight="Bold"
Text="NEXT" />
</Grid>

4. 源码

https://github.com/DinoChan/wpf_design_and_animation_lab

[WPF] 使用 Effect 玩玩阴影、内阴影、 长阴影的更多相关文章

  1. 扁平化设计的最新趋势 – 长阴影(Long Shadow)

    随着互联网的发展,网页设计变得越来越复杂,如今设计的外观和感觉实现网站功能说使用的开发技术一样重要.互联网的功能远远不只是基本的信息共享,现在人们对网站的期望是远远大于几年前的. 如今,HTML5 & ...

  2. 20款精致的长阴影 LOGO 设计【附免费生成工具】

    长阴影(Long Shadow)概念来自于最新非常流行的扁平化设计(Flat Design).扁平化设计趋势影响最大的是用户界面元素和图标,但它也开始蔓延到其他网页设计的其他部分. 长阴影其实就是扩展 ...

  3. 小教程:自己创建一个jQuery长阴影插件

    长阴影设计是平面设计的一个变体,添加了阴影,产生了深度的幻觉,并导致了三维的设计.在本教程中,我们将创建一个jQuery插件,通过添加完全可自定义的长阴影图标,我们可以轻松地转换平面图标. 戳我查看效 ...

  4. Long Shadows Generate是一款在线使用纯CSS3实现长阴影的效果,一款强大的扁平化长投影制造器。

    Long Shadows Generate是一款在线使用纯CSS3实现长阴影的效果,一款强大的扁平化长投影制造器. Long Shadows Generate 彩蛋爆料直击现场 Long Shadow ...

  5. [UWP]使用GetAlphaMask和ContainerVisual制作长阴影(Long Shadow)

    1. 什么是长阴影 前几年扁平化设计(Flat Design)十分流行,后来在扁平化的基础上又流行起了长阴影(Long Shadow).长阴影其实就是扩展了对象的投影,感觉是一种光线照射下的影子,通常 ...

  6. CSS3+HTML5实现块阴影与文字阴影

    CSS 3 + HTML 5 是未来的 Web,它们都还没有正式到来,虽然不少浏览器已经开始对它们提供部分支持.本教程分5节介绍了 5 个 CSS3 技巧,可以帮你实现未来的 Web,不过,这些技术不 ...

  7. 【HLSL学习笔记】WPF Shader Effect Library算法解读之[BandedSwirl]

    原文:[HLSL学习笔记]WPF Shader Effect Library算法解读之[BandedSwirl] 因工作原因,需要在Silverlight中使用Pixel Shader技术,这对于我来 ...

  8. WPF的Effect效果

    一.阴影效果(DropShadowEffect) <TextBlock Text="> <TextBlock.Effect> <DropShadowEffect ...

  9. HTML连载70-相片墙、盒子阴影和文字阴影

    一. 制作一个相片墙 二. <!DOCTYPE html> <html lang="en"> <head> <meta charset=& ...

随机推荐

  1. 【漏洞复现】CVE-2022–21661 WordPress核心框架WP_Query SQL注入漏洞原理分析与复现

    影响版本 wordpress < 5.8.3 分析 参考:https://blog.csdn.net/qq_46717339/article/details/122431779 在 5.8.3 ...

  2. C语言字幕从外向中间汇聚

    演示数据中多个字符,从两端向中间移动,向中间汇聚 简单,粗暴,先上代码: Sleep()函数属于<windows.h>头文件中. sizeof()函数求右下标:数组内是数字时,求右下标要- ...

  3. 开源数据可视化BI工具SuperSet(安装)

    本次安装教程共分两大步骤,因为Superset 基于python3编写的web应用(flask) 所以要求python3环境,故首先要将linux系统自带的环境进行升级,已经是python3的可跳过- ...

  4. 《剑指offer》面试题59 - II. 队列的最大值

    问题描述 请定义一个队列并实现函数 max_value 得到队列里的最大值,要求函数max_value.push_back 和 pop_front 的均摊时间复杂度都是O(1). 若队列为空,pop_ ...

  5. 开发 IDEA Plugin 引入探针,基于字节码插桩获取执行SQL

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 片面了! 一月三舟,托尔斯泰说:"多么伟大的作家,也不过就是在书写自己的片 ...

  6. 极客大挑战2019 http

    极客大挑战 http referer 请求头 xff 1.查看源码,发现secret.php 2.提示要把来源改成Sycsecret.buuoj.cn,抓包,添加Referer Referer:htt ...

  7. 打印十字码 DataMatrix

    nuget 安装 DataMatrix.net //示例 DmtxImageEncoder Die = new DmtxImageEncoder(); DataMatrix.net.DmtxImage ...

  8. Windows和Linux关闭占用端口

    关闭端口的方式有很多种,但是常用的就是这种比较来的快一点 如果通过以下方式解决不了,可以通过关闭服务来解决 Windows 1.查看端口占用的进程 netstat -ano | findstr 800 ...

  9. Java 给Word每一页设置不同图片水印效果

    Word中设置水印时,可加载图片设置为水印效果,但通常添加水印效果时,会对所有页面都设置成统一效果,如果需要对每一页或者某个页面设置不同的水印效果,则可以参考本文中的方法.下面,将以Java代码为例, ...

  10. Network Kit与三七游戏共创流畅游戏体验,无惧网络延迟

    本文分享于HMS Core联盟论坛<[开发者说]无惧高网络吞吐量,HMS Core Network Kit与三七游戏共创流畅游戏体验>的采访整理. 三七游戏拥有<斗罗大陆·魂师对决& ...