[UWP]用Win2D和CompositionAPI实现文字的发光效果,并制作动画
1. 成果

献祭了周末的晚上,成功召唤出了上面的番茄钟。正当我在感慨“不愧是Shadow大人,这难道就是传说中的五彩斑斓的黑?”
“那才不是什么阴影效果,那是发光效果。”被路过的老婆吐槽了。
系系系,老婆说的都系对的。我还以为我在做阴影动画,现在只好改博客标题了?
要实现上面的动画效果,首先使用CompositionDrawingSurface,在它上面用DrawTextLayout画出文字,然后用GaussianBlurEffect模仿成阴影,然后用CanvasActiveLayer裁剪文字的轮廓,然后用这个CompositionDrawingSurface创建出CompositionSurfaceBrush,然后创建一个CompositionMaskBrush,将CompositionSurfaceBrush作为它的Mask,然后用CompositionLinearGradientBrush创建出渐变,再用BlendEffect将它变成四向渐变,再用ColorKeyFrameAnimation和ScalarKeyFrameAnimation在它上面做动画并把它作为CompositionMaskBrush的Source,然后创建SpriteVisual将CompositionMaskBrush应用上去,然后使用两个PointLight分别从左到右和从右到左照射这个SpriteVisual,再创建一个AmbientLight模仿呼吸灯。
仔细想想……好吧,老婆说得对,我还真的没有用到任何Shadow的Api,这里和Shadow大人半毛钱关系都没有。
这个番茄钟源码可以在这里查看:
OnePomodoro_ShadowTextView.xaml at master
也可以安装我的番茄钟应用试玩一下,安装地址:
这篇文章将介绍其中几个关键技术。
2. 使用GaussianBlurEffect模仿阴影
上一篇文章已经介绍过怎么在CompositionDrawingSurface上写字,这里就不再重复。为了可以为文字添加阴影,需要用到CanvasRenderTarget和GaussianBlurEffect。
CanvasRenderTarget是一个可以用来画图的渲染目标。实现文字阴影的步骤如下:将文字画到CanvasRenderTarget,然后用它作为GaussianBlurEffect.Source产生一张高斯模糊的图片,这样看上去就和文字的阴影一样。然后再在这张模糊的图片的前面画上原本的文字。
代码如下所示:
using (var session = CanvasComposition.CreateDrawingSession(drawingSurface))
{
session.Clear(Colors.Transparent);
using (var textLayout = new CanvasTextLayout(session, Text, textFormat, width, height))
{
var bitmap = new CanvasRenderTarget(session, width, height);
using (var bitmapSession = bitmap.CreateDrawingSession())
{
bitmapSession.DrawTextLayout(textLayout, 0, 0, FontColor);
}
var blur = new GaussianBlurEffect
{
BlurAmount = (float)BlurAmount,
Source = bitmap,
BorderMode = EffectBorderMode.Hard
};
session.DrawImage(blur, 0, 0);
session.DrawTextLayout(textLayout, 0, 0, FontColor);
}
}
效果如下(因为我用了白色字体,这时候已经不怎么像阴影了):

关于CavasRenderTaget,死鱼的这篇文章有详细介绍。他的这个专栏的文章都很有趣。
3. 使用CanvasActiveLayer裁剪文字
关于裁剪文字,有几件事需要做。
首先获取需要裁剪的文字的轮廓,这使用上一篇文章介绍过的CanvasGeometry.CreateText就可以了,这个函数的返回值是一个CanvasGeometry。然后使用CanvasGeometry.CreateRectangle获取整个画布的CanvasGeometry,将他们用CombineWith相减得出文字以外的部分,具体代码如下:
var fullSizeGeometry = CanvasGeometry.CreateRectangle(session, 0, 0, width, height);
var textGeometry = CanvasGeometry.CreateText(textLayout);
var finalGeometry = fullSizeGeometry.CombineWith(textGeometry, Matrix3x2.Identity, CanvasGeometryCombine.Exclude);
这里之所以不直接使用textGeometry,是因为我们并不是真的裁剪出文字的部分,而是像WPF的OpacityMask那样用透明度控制显示的部分。CanvasActiveLayer就是用来实现这个功能。CanvasDrawingSession.CreateLayer函数使用透明度和CanvasGeometry创建一个CanvasActiveLayer,在创建Layer后CanvasDrawingSession的操作都会应用这个透明度,直到Layer关闭。
using (var layer = session.CreateLayer(1, finalGeometry))
{
//DrawSth
}
最后效果如下:

关于CanvasActiveLayer的更多用法, 可以参考Lindexi的这篇文章。
4. 制作有复杂颜色的阴影

如上图所示,UWP中的DropShadow的Color只能有一种颜色,所以DropShadow不能使用复杂的颜色。这时候就要用到CompositionMaskBrush,CompositionMaskBrush有两个主要属性:Mask和Source。其中Mask是一个CompositionBrush类型的属性,它指定不透明的蒙板源。简单来说,CompositionMaskBrush的形状就是它的Mask的形状。而Source属性则是它的颜色,这个属性可以是 CompositionColorBrush、CompositionLinearGradientBrush、CompositionSurfaceBrush、CompositionEffectBrush 或 CompositionNineGridBrush 类型的任何 CompositionBrush。可以使用前面创建的CompositionDrawingSurface创建出CompositionSurfaceBrush,最后创建一个CompositionMaskBrush,将CompositionSurfaceBrush作为它的Mask。
var maskBrush = Compositor.CreateMaskBrush();
maskBrush.Mask = Compositor.CreateSurfaceBrush(DrawingSurface);
maskBrush.Source = Compositor.CreateLinearGradientBrush();
本来还想做到大紫大红的,但被吐槽和本来低调内敛的目的不符合,所以复用了以前这篇文章的配色,CompositionLinearGradientBrush加BlendEffect做成了有些复杂的配色(但实际上太暗了看不出来):

这时候效果如下:

5. 使用PointLight和AmbientLight制作动画
我在使用PointLight并实现动画效果这篇文章里介绍了PointLight的用法及基本动画,这次豪华些,同时有从左到右的红光以及从右到左的蓝光,这两个PointLight的动画效果大致是这样:

因为PointLight最多只能叠加两个,所以再使用AmbientLight并对它的Intensity属性做动画,这样动画就会变得复杂些,最终实现了文章开头的动画。
var compositor = Window.Current.Compositor;
var ambientLight = compositor.CreateAmbientLight();
ambientLight.Intensity = 0;
ambientLight.Color = Colors.White;
var intensityAnimation = compositor.CreateScalarKeyFrameAnimation();
intensityAnimation.InsertKeyFrame(0.2f, 0, compositor.CreateLinearEasingFunction());
intensityAnimation.InsertKeyFrame(0.5f, 0.20f, compositor.CreateLinearEasingFunction());
intensityAnimation.InsertKeyFrame(0.8f, 0, compositor.CreateLinearEasingFunction());
intensityAnimation.Duration = TimeSpan.FromSeconds(10);
intensityAnimation.IterationBehavior = AnimationIterationBehavior.Forever;
ambientLight.StartAnimation(nameof(AmbientLight.Intensity), intensityAnimation);
6. 参考
CompositionMaskBrush Class (Windows.UI.Composition) - Windows UWP applications _ Microsoft Docs
组合照明 - Windows UWP applications Microsoft Docs
[UWP]用Win2D和CompositionAPI实现文字的发光效果,并制作动画的更多相关文章
- [UWP]用Win2D实现镂空文字
1. 前言 之前用PointLight做了一个番茄钟,效果还不错,具体可见这篇文章: [UWP]使用PointLight并实现动画效果 后来试玩了Win2D,这次就用Win2D实现文字的镂空效果,配合 ...
- [UWP]使用Win2D的BorderEffect实现图片的平铺功能
1. WPF有,而UWP没有的图片平铺功能 在WPF中只要将ImageSource的TileMode属性设置为Tile即可实现图片的平铺,具体可见WPF的这些文档: ImageBrush 类 (Sys ...
- win10 uwp 通过 Win2d 完全控制笔迹绘制逻辑
本文来告诉大家如何通过 Win2d 完全控制笔迹绘制逻辑,本文适合用来实现复杂的自定义逻辑,可以完全控制笔迹的行为.包括在书写过程中切换模式,如进行手势擦除切换为橡皮擦模式 本文提供的方法适合用来做复 ...
- j-query应用---鼠标悬停不同文字显示不同背景图片banner动画
源代码部分:注意事项:样式表的引用的路径要一致. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" ...
- Js制作点击输入框时默认文字消失的效果
(从已经死了一次又一次终于挂掉的百度空间人工抢救出来的,发表日期 2014-02-17) 为了提高用户体验和易用度,一些设计师会对网页中用户经常用的东西进行优化,比如输入框.一般的输入框是怎样优化的呢 ...
- 基于jquery实现的文字淡入淡出效果
这篇文章介绍了jquery实现的文字淡入淡出效果实例,有需要的朋友可以参考一下 复制代码代码如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1 ...
- Android - 文字向上翻滚效果的实现
本文转载https://xwc2013.iteye.com/blog/1976051 今天看到了一种文字翻滚的效果,感觉非常实用.所以就自己试着做出了这种效果,现在把它分享给大家! 首先在res目录下 ...
- CSS3实现文字折纸效果
CSS3实现文字折纸效果 效果图: 代码如下,复制即可使用: <!DOCTYPE html> <html> <head> <title></tit ...
- 利用css3的text-shadow属性实现文字阴影乳白效果
现在CSS3+html5的网页应用的越来越广泛了.很多网页中的字体同样可以用CSS3来实现炫酷的效果. 下面就介绍一下利用css3的text-shadow属性实现文字阴影乳白效果.这是在设计达人上面看 ...
随机推荐
- 以np.concatenate为主题,谈谈numpy数组按维度合并的问题
1.引言 最近在做多模态融合的图像问题,其中最需要解决的就是不同模态的图像用什么方法进行融合,最简单也最直观的方法就是采用合并数组的方法,将不同模态的图像合并为多通道进行处理.在一些论文中,比如< ...
- redis集群之Codis
在大数据高并发场景下,单个 Redis 实例往往会显得捉襟见肘.首先体现在内存上,单个 Redis 的内存不宜过大,内存太大会导致 rdb 文件过大,进一步导致主从同步时全量同步时间过长,在实例重启恢 ...
- js静态属性,实例属性,封装性,prototype,__proto__综合解析
原创作品,转载请注明来源,sogeisetsu,我的csdn上也有这篇文章csdn js静态属性,实例属性,封装性,prototype,__proto__综合解析 下面是我在写博客的源代码,您可以先不 ...
- 一起来刷《剑指Offer》——不修改数组找出重复的数字(思路及Python实现)
数组中重复的数字 在上一篇博客中<剑指Offer>-- 题目一:找出数组中重复的数字(Python多种方法实现)中,其实能发现这类题目的关键就是一边遍历数组一边查满足条件的元素. 然后我们 ...
- 不需要怎么修改配置的Mybatis整合Spring要点
首先对于Mybatis的主配置文件,只需要修改一处地方,将事务交给Spring管理,其它地方可以原封不动. <?xml version="1.0" encoding=&quo ...
- MySQL计划任务(事件调度器)
原文:http://www.cnblogs.com/c840136/articles/2388512.html 备忘; MySQL5.1.x版本中引入了一项新特性EVENT,顾名思义就是事件.定时任务 ...
- Lab_1:练习3——分析bootloader进入保护模式的过程
文章链接:https://www.cnblogs.com/cyx-b/p/11809742.html 作者:chuyaoxin 一.实验内容 BIOS将通过读取硬盘主引导扇区到内存,并转跳到对应内存中 ...
- [考试反思]0929csp-s模拟测试55:消逝
菜得过分. 面对T1的大板子不知所措,然后T2的贪心不小心把排序语句删了... T1这种大模板啊...其实我是觉得我能打出来的,然后先用一个小时码了一个2k. 然后做T2想贪心就出来了.十分钟码完T3 ...
- CSP-S模拟57
这次的T1是来送温暖的. T2T3挺神的. T1. 不会 T2. 容斥,挺神的 T3. 考场上被卡常卡掉10分让我很难受.....(虽然说$O(n)$过$1e8$本来就不太行) 考场上:疯狂化简式子, ...
- python学习之【第三篇】:Python中的字符串及其所具有的方法
1.前言 字符串str是Python中最常用的数据类型.我们可以使用单引号''或双引号""包裹一段字符来创建字符串. 2.字符串创建 str1 = 'hello world' st ...