前几天发布了抄抄《CSS 故障艺术》的动画这篇文章,在这篇文章里介绍了如何使用Win2D绘制文字然后配合BlendEffect制作故障艺术的动画。本来打算就这样收手不玩这个动画了,但后来又发现性能不符合理想。明明只是做做Resize动画和用BlendEffect混合,为什么性能会这么差呢?

1. 分析原因

其实不用分析都知道哪里出问题了,毕竟这个懒是自己偷的,不过这里顺便介绍介绍Visual Studio的性能分析。Visual Studio不停更新它的性能探测器,最近几年我还挺喜欢的的“应用程序时间线”功能,对桌面应用来说这个功能很好用,可以直观地看到帧率、CPU使用、布局消耗、呈现消耗等信息。

要开始性能分析,首先在顶部菜单选择“调试”->“性能探测器”:

在打开的性能探测器配置页面,选中“CPU使用率”和“应用程序时间线”两个工具后点击“开始”按钮:

之后Visual Studio就会启动性能会话并运行程序,切换到打开的应用程序里,一顿操作后关闭程序,稍等一下就可以看到分析报告。

为了凸显性能问题,我复制粘贴了好几个个故障艺术的动画,可以看到后半段的FPS下降了,且“应用程序代码”占了很大的比例。切换到"CPU使用率"选项卡,能看到具体的CPU消耗都在DrawSurfaceCore这个函数附近

双击DrawSurfaceCore这行进去具体代码,这里颜色越红代表CPU占用率越高,并且会在源码左侧显示具体的CPU占用率,很明显这里的代码很糟糕,那么罪魁祸首就是这堆代码了。

2. 使用AlphaMaskEffect优化性能

上面的这段代码是使用Win2D绘制文字和使用GaussianBlurEffect制作阴影。本来这代码性能应该没问题(当然,在这个动画里有优化空间,例如因为我在这里总是使用BlurAmount = 0的阴影所以根本不需要GaussianBlurEffect也不需要DrawImage),但是我使用了Storyboard控制文字的高度,然后每次高度改变都重新调用这个函数绘制文字。从结果上来说我的代码在不停画图,所以小小的动画造成了巨大的性能消耗。

现在我要做什么才可以改善这种状况?当然上面这段代码有很多优化的空间,但最根本要做的是应该少调用这段代码,少重新绘图。一个很复杂的情况是,我需要使用两个这段代码绘制出来的CompositionSurfaceBrush作为BlendEffect的输入,而CompositionSurfaceBrush本质上是一张位图,而作为Brush又没法修改它的尺寸。CompositionSurfaceBrush关联了一个CompositionDrawingSurface,后者虽然有Resize函数,但使用这个函数会令图片在动画过程中移位,明明单独使用Resize效果不错,但用在动画里就总是错,我也没心思去纠结它的原因。

其实要改变Brush的高度,一种很实在的方法是使用遮罩。CompositionApi提供了CompositionMaskBrush,使用它可以实现OpacityMask的效果,复习一下它的源码:

paint-with-a-compositionbrush-with-opacity-mask-applied

Compositor _compositor;
SpriteVisual _maskVisual;
CompositionMaskBrush _maskBrush; _compositor = Window.Current.Compositor; _maskBrush = _compositor.CreateMaskBrush(); CompositionLinearGradientBrush _sourceGradient = _compositor.CreateLinearGradientBrush();
_sourceGradient.ColorStops.Add(_compositor.CreateColorGradientStop(0,Colors.Red));
_sourceGradient.ColorStops.Add(_compositor.CreateColorGradientStop(1,Colors.Yellow));
_maskBrush.Source = _sourceGradient; LoadedImageSurface loadedSurface = LoadedImageSurface.StartLoadFromUri(new Uri("ms-appx:///Assets/circle.png"), new Size(156.0, 156.0));
_maskBrush.Mask = _compositor.CreateSurfaceBrush(loadedSurface); _maskVisual = _compositor.CreateSpriteVisual();
_maskVisual.Brush = _maskBrush;
_maskVisual.Size = new Vector2(156, 156);

使用CompositionMaskBrush之前首先要有一张作为Mask的图片,用Paint.Net两三下就做好了,比奥特曼打到怪兽还快。

接下来只要用显示文字的CompositionSurfaceBrush作为CompositionMaskBrush的Source,用上面这张图片制作的CompositionSurfaceBrush作为Mask,再对Mask做Scale的动画,高度改变的动画就…………

就报错了。

好吧,我想起来了文档里就说明了CompositionMaskBrush不能玩BlendEffect。

不过幸运的是Win2D本来就提供了AlphaMaskEffect这个类,它的作用几乎和CompositionMaskBrush一样,我之前都没想到会有使用它的一天。使用它的代码大同小异,两三下就写完了:

private (CompositionBrush, CompositionSurfaceBrush) CreateMaskedBrush(CompositionBrush source)
{
var compositor = Window.Current.Compositor;
var effect = new AlphaMaskEffect()
{
Source = new CompositionEffectSourceParameter("Source"),
AlphaMask = new CompositionEffectSourceParameter("Mask"),
}; var opacityMaskSurface = LoadedImageSurface.StartLoadFromUri(new Uri("ms-appx:///Assets/Images/mask.Png"));
var opacityBrush = Compositor.CreateSurfaceBrush(opacityMaskSurface);
opacityBrush.Stretch = CompositionStretch.UniformToFill; var effectFactory = compositor.CreateEffectFactory(effect);
var compositionBrush = effectFactory.CreateBrush();
compositionBrush.SetSourceParameter("Source", source);
compositionBrush.SetSourceParameter("Mask", opacityBrush);
return (compositionBrush, opacityBrush);
}

3. 结果

左边是旧的代码(每次改变高度重新绘图),右边是新的代码(对作为Mask的CompositionSurfaceBrush进行Scale动画),可以看到……嗯,好像新动画是刘畅了些。

看起来再玩大些都还撑得住,GPU占用率还算满意,CPU占用率也不高。其实还有不少优化空间,但我还是完全想不到这个动画实际应用场景(恕我想象力贫乏),所以就到吃为止吧。

4. 参考

CompositionMaskBrush Class (Windows.UI.Composition) - Windows UWP applications Microsoft Docs

AlphaMaskEffect Class

合成画笔 - UWP applications Microsoft Docs

[UWP]使用AlphaMaskEffect提升故障艺术动画的性能(顺便介绍怎么使用性能探测器分析UWP程序)的更多相关文章

  1. CSS动画属性性能详细介绍

    CSS动画属性会触发整个页面的重排relayout.重绘repaint.重组recomposite Paint通常是其中最花费性能的,尽可能避免使用触发paint的CSS动画属性,这也是为什么我们推荐 ...

  2. [UWP]抄抄《CSS 故障艺术》的动画

    1. 前言 什么是故障艺术(Glitch Art 风)?我们熟知的抖音的 LOGO 正是故障艺术其中一种表现形式.它有一种魔幻的感觉,看起来具有闪烁.震动的效果,很吸引人眼球.故障艺术它模拟了画面信号 ...

  3. CSS 故障艺术

    本文的主题是 Glitch Art,故障艺术. 什么是故障艺术?我们熟知的抖音的 LOGO 正是故障艺术其中一种表现形式.它有一种魔幻的感觉,看起来具有闪烁.震动的效果,很吸引人眼球. 故障艺术它模拟 ...

  4. 抖音抖一抖-SVG和CSS视觉故障艺术小赏

    故障艺术,英文名称叫glitch,在很多赛博朋克作品中经常看到,其实就是故意表现一种显示设备的小故障效果,抖音的图标其实就是这种的效果,我们看下这个图标 这个图标中的红色和蓝色的偏移其实就是一种故障艺 ...

  5. [UWP]使用SpringAnimation创建有趣的动画

    1. 什么是自然动画 最近用弹簧动画(SpringAnimation)做了两个番茄钟,关于弹簧动画官方文档已经介绍得够详细了,这篇文章就摘录一些官方文档核心内容. 在传统UI中,关键帧动画(KeyFr ...

  6. 使用CSS3开启GPU硬件加速提升网站动画渲染性能

    遇到的问题: 网站本身设计初衷就没有打算支持IE8及以下版本浏览器,并不是因为代码兼容性问题,而是真的不想迁就那些懒得更新自己操作系统和浏览器的用户,毕竟是我自己的网站,所以我说了算!哈哈~ 没有了低 ...

  7. CoreAnimation6-基于定时器的动画和性能调优

    基于定时器的动画 定时帧 动画看起来是用来显示一段连续的运动过程,但实际上当在固定位置上展示像素的时候并不能做到这一点.一般来说这种显示都无法做到连续的移动,能做的仅仅是足够快地展示一系列静态图片,只 ...

  8. 通过硬件层提高Android动画的性能

    曾有许多人问我为什么在他们开发的应用中,动画的性能表现都很差.对于这类问题,我往往会问他们:你们有尝试过在硬件层解决动画的性能问题么? 我们都知道,在播放动画的过程中View在每一帧动画的显示时重绘自 ...

  9. CSS动画的性能分析和浏览器GPU加速

    此文已由作者袁申授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 有数的数据大屏可以在一块屏幕上展示若干张不同的图表,以炫酷的方式展示各种业务数据.其中有些图表使用CSS实现了 ...

随机推荐

  1. uniq命令使用方法

    uniq命令的作用:显示唯一的行,对于那些连续重复的行只显示一次! 接下来通过实践实例说明: [root@stu100 ~]# cat test boy took bat home boy took ...

  2. GRE阅读

    界面和托福差不多,就是反一反 GRE先读文章!因为出题顺序不一致.另外,不能跳读!!每一句都要读,即使不是观点. 考察能力: 1 三秒版本 边读边概括 解决前面的抗遗忘能力 2 句间关系 取同 取反 ...

  3. 疫情期,如何用A/B测试快速迭代你的产品?

    作者:友盟+数据科学家 杨玉莲.陆子骏 冠状病毒来袭牵动着每个人的心,但是病毒影响的不仅仅是我们的健康,也以极快的速度极深远地影响了整个移动互联网的发展.主流阵地原本在线下的需求,如医疗和生鲜电商,快 ...

  4. sqlserver取分组数据的最后一条数据

    SQL Server中ROW_NUMBER()函数的使用 参考文章:https://blog.csdn.net/pan_junbiao/article/details/79941162 业务中的问题: ...

  5. DvaJS入门课

    不管是Vue还是React,他们都没解决组件间的通信和数据流问题.当然,这个说法不是很准确,准确的说法是他们都没很好的处理这些问题.我们是可以用一些烂手段去解决这个问题,但是当应用比较大.数据多的时候 ...

  6. Flutter的盒子约束

    由Expanded widget引发的思考 设计稿如下 布局widget分解 很常见的一种布局方式:Column的子widget中包含ListView @override Widget build(B ...

  7. Resource interpreted as Stylesheet but transferred with MIME type text/html: css失效

    异常信息: Resource interpreted as Stylesheet but transferred with MIME type text/html: 可能原因 过滤器或者某个地方对所有 ...

  8. django 从零开始 5 数据库模型创建

    进入应用项目下的models.py文件 自带一个导入的包 from django.db import models 使用这个包创建models模型 我这是要创建一个图站 ,所以模型设置并不复杂(路径配 ...

  9. 开源项目在闲鱼、b 站上被倒卖?这是什么骚操作?

    起因 - 又是一封邮件 2020 年 3 月 2 日,收到了一封邮件,对,这次故事的起因又是一封邮件,和上次写个bug被国家信息安全漏洞共享平台抓到了一样. 这是一条评论通知邮件,一开始我以为只是正常 ...

  10. ggplot2(11) 总结回顾&案例练习

    从2020年2月20到2月27日,3月13日到2020年3月16日,学习了ggplot2:数据分析与图形艺术(哈德利·威克姆 著 统计之都 译),历时12天.另外,3月6日到3月9日参加了美赛,也用到 ...