title author date CreateTime categories
win10 uwp win2d 离屏渲染
lindexi
2018-08-10 19:17:19 +0800
2018-5-29 11:6:30 +0800
UWP win2d 渲染

离屏渲染(Offscreen drawing)是一个不错的科技,在系统有空的时候,提前先画出部分界面。这样在需要直接渲染的时候就可以直接拿出来而不需要等待进行渲染的时候才画出来。

实际上之前我已经写过一篇博客关于 CanvasRenderTarget ,离屏渲染需要使用到 CanvasRenderTarget 。

先来写一个简单的界面,在写之前,请安装 Win2d 。

  1. <Page
  2. x:Class="SairkaDeebowhar.MainPage"
  3. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  4. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  5. xmlns:local="using:SairkaDeebowhar"
  6. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  7. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  8. xmlns:win2d="using:Microsoft.Graphics.Canvas.UI.Xaml"
  9. mc:Ignorable="d"
  10. Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
  11.  
  12. <Grid>
  13. <win2d:CanvasControl x:Name="CanvasControl" Draw="CanvasControl_OnDraw"></win2d:CanvasControl>
  14. <Button Content="确定" HorizontalAlignment="Center" VerticalAlignment="Center" Click="Button_OnClick"></Button>
  15. </Grid>
  16. </Page>

在点击确定的时候开始进行离屏渲染,因为如果需要让CanvasControl开始渲染需要调用Invalidate,但是调用这个函数不是立刻就渲染,而且在下一个无法控制的时间进行渲染。

所以在 按钮点击的时候可以进行离屏渲染,这时CanvasControl在渲染的时候直接拿按钮点击下去画的就可以。

离屏渲染也叫离线渲染,为了让用户看到炫酷的界面,要求渲染的时间小于 16 毫秒,也就是一秒钟至少60刷新。

渲染的时间是很有限的,如果在渲染中需要耦合计算,那么会让渲染的性能降低。

例如下面的代码,在按钮点击下去的时候,经过很长时间的计算才能知道写入我的名字,如果把代码放在CanvasControl画的时候计算,那么会影响性能。

建议的方法是在按钮点击的时候,在按钮点击那里做计算,这时CanvasControl还可以画其他的东西。

因为我写的是呆磨,很简单,没有让大家看到CanvasControl在空闲的时候做的事情。

  1. private void Button_OnClick(object sender, RoutedEventArgs e)
  2. {
  3. CanvasDevice device = CanvasDevice.GetSharedDevice();
  4. CanvasRenderTarget offscreen = new CanvasRenderTarget(device, width: 100, height: 100, dpi: 96);
  5. using (CanvasDrawingSession ds = offscreen.CreateDrawingSession())
  6. {
  7. //经过很多时间的计算,才知道需要写我的名字
  8. ds.DrawText("lindexi", new Vector2(10, 10), Colors.Black);
  9. }
  10.  
  11. _offscreen = offscreen;
  12.  
  13. // 调用这个函数,会在无法控制的时间调用 CanvasControl_OnDraw ,这时可以发出已经画出来的
  14. CanvasControl.Invalidate();
  15. }
  16.  
  17. private CanvasRenderTarget _offscreen;

CanvasControl_OnDraw 就判断 _offscreen 不是空就显示

  1. private void CanvasControl_OnDraw(CanvasControl sender, CanvasDrawEventArgs args)
  2. {
  3. if (_offscreen != null)
  4. {
  5. args.DrawingSession.DrawImage(_offscreen,
  6. new Rect(50, 50, _offscreen.Bounds.Width, _offscreen.Bounds.Height));
  7. }
  8. }

为什么需要判断_offscreen不是空?因为在xaml加载的时候,就会触发CanvasControl_OnDraw,如果传入DrawImage是一个空,那么会出现参数异常。

通过离屏渲染的图可以使用特效,请看代码

  1. private void Button_OnClick(object sender, RoutedEventArgs e)
  2. {
  3. CanvasDevice device = CanvasDevice.GetSharedDevice();
  4. CanvasRenderTarget offscreen = new CanvasRenderTarget(device, width: 100, height: 100, dpi: 96);
  5. using (CanvasDrawingSession ds = offscreen.CreateDrawingSession())
  6. {
  7. //经过很多时间的计算,才知道需要写我的名字
  8. ds.DrawText("lindexi", new Vector2(10, 10), Colors.Black);
  9. }
  10.  
  11. GaussianBlurEffect effect = new GaussianBlurEffect()
  12. {
  13. Source = offscreen,
  14. BlurAmount = 1.0f
  15. };
  16.  
  17. _offscreen = offscreen;
  18.  
  19. _effect = effect;
  20.  
  21. // 调用这个函数,会在无法控制的时间调用 CanvasControl_OnDraw ,这时可以发出已经画出来的
  22. CanvasControl.Invalidate();
  23. }
  24.  
  25. private CanvasRenderTarget _offscreen;
  26.  
  27. private GaussianBlurEffect _effect;

这时尝试在Win2d显示效果

  1. private void CanvasControl_OnDraw(CanvasControl sender, CanvasDrawEventArgs args)
  2. {
  3. if (_offscreen != null)
  4. {
  5. args.DrawingSession.DrawImage(_offscreen,
  6. new Rect(50, 50, _offscreen.Bounds.Width, _offscreen.Bounds.Height));
  7. }
  8.  
  9. if (_effect != null)
  10. {
  11. args.DrawingSession.DrawImage(_effect);
  12. }
  13. }

需要注意,这时的特效的计算是在CanvasControl_OnDraw这时渲染才计算特效。

离线渲染的意思是可以在其他线程渲染,虽然渲染都是在GPU渲染,都是渲染是包括告诉如何渲染和把图片画出来,可以看到如何渲染就可能需要在CPU做很多计算。上面的代码,我经过很多计算才知道需要写 lindexi ,因为本渣叫金鱼,金鱼的意思就是记忆力很差,经常不知道自己叫什么。计算出名字需要的时间是很长的。

如果在按钮按下需要很长时间的计算,那么性能也是很差,这时建议在其他线程做。

  1. private async void Button_OnClick(object sender, RoutedEventArgs e)
  2. {
  3. await Task.Run(() =>
  4. {
  5. // 下面代码可能在 CanvasControl_OnDraw 画出 CanvasRenderTarget 会出现 0x88990012 异常,解决方法请看文章最后
  6. CanvasDevice device = CanvasDevice.GetSharedDevice();
  7. CanvasRenderTarget offscreen = new CanvasRenderTarget(device, width: 100, height: 100, dpi: 96);
  8. using (CanvasDrawingSession ds = offscreen.CreateDrawingSession())
  9. {
  10. //经过很多时间的计算,才知道需要写我的名字
  11. ds.DrawText("lindexi", new Vector2(10, 10), Colors.Black);
  12. }
  13.  
  14. GaussianBlurEffect effect = new GaussianBlurEffect()
  15. {
  16. Source = offscreen,
  17. BlurAmount = 1.0f
  18. };
  19.  
  20. _offscreen = offscreen;
  21.  
  22. _effect = effect;
  23. });
  24.  
  25. // 调用这个函数,会在无法控制的时间调用 CanvasControl_OnDraw ,这时可以发出已经画出来的
  26. CanvasControl.Invalidate();
  27. }

这就是离屏渲染的使用方法,在其他线程做耗时的渲染,在显示的时候可以快速画出

Offscreen drawing

win2d CanvasRenderTarget vs CanvasBitmap

注意,暗影吉他手告诉我,在 Button_OnClick 的第一句话CanvasDevice device = CanvasDevice.GetSharedDevice();,使用 CanvasDevice.GetSharedDevice() 是错误写法。在CanvasControl_OnDraw里面使用用这个device创建的 CanvasRenderTarget 会弹 0x88990012 异常(Objects used together must be created from the same factory instance)。应该在CreateResources里面得到device。在我的设备上面的代码是可以运行,所以暂时不修改。

多谢暗影吉他手发现问题

参见:Win2D 官方文章系列翻译 - 幕后绘制 - void² - 博客园

2018-8-10-win10-uwp-win2d-离屏渲染的更多相关文章

  1. win10 uwp win2d CanvasVirtualControl 与 CanvasAnimatedControl

    本文来告诉大家 CanvasVirtualControl ,在什么时候使用这个控件. 在之前的入门教程win10 uwp win2d 入门 看这一篇就够了我直接用的是CanvasControl,实际上 ...

  2. win10 uwp 通过 Win2d 完全控制笔迹绘制逻辑

    本文来告诉大家如何通过 Win2d 完全控制笔迹绘制逻辑,本文适合用来实现复杂的自定义逻辑,可以完全控制笔迹的行为.包括在书写过程中切换模式,如进行手势擦除切换为橡皮擦模式 本文提供的方法适合用来做复 ...

  3. win10 uwp 渲染原理 DirectComposition 渲染

    本文来告诉大家一个新的技术DirectComposition,在 win7 之后(实际上是 vista),微软正在考虑一个新的渲染机制 在 Windows Vista 就引入了一个服务,桌面窗口管理器 ...

  4. win10 uwp 萤火虫效果

    原文:win10 uwp 萤火虫效果 本文在Nukepayload2指导下,使用他的思想用C#写出来. 本文告诉大家,如何使用 win2d 做出萤火虫效果. 安装 win2d 安装win2d的方法请使 ...

  5. win10 uwp 毛玻璃

    毛玻璃在UWP很简单,不会和WPF那样伤性能. 本文告诉大家,如何在 UWP 使用 win2d 做毛玻璃. 毛玻璃可以使用 win2D 方法,也可以使用 Compositor . 使用 win2d 得 ...

  6. win10 uwp 使用 Microsoft.Graph 发送邮件

    在 2018 年 10 月 13 号参加了 张队长 的 Office 365 训练营 学习如何开发 Office 365 插件和 OAuth 2.0 开发,于是我就使用 UWP 尝试使用 Micros ...

  7. Win10 UWP开发系列:实现Master/Detail布局

    在开发XX新闻的过程中,UI部分使用了Master/Detail(大纲/细节)布局样式.Win10系统中的邮件App就是这种样式,左侧一个列表,右侧是详情页面.关于这种 样式的说明可参看MSDN文档: ...

  8. Win10 UWP开发实现Bing翻译

    微软在WP上的发展从原来的Win7到Win8,Win8.1,到现在的Win10 UWP,什么是UWP,UWP即Windows 10 中的Universal Windows Platform简称.即Wi ...

  9. Win10/UWP开发—使用Cortana语音与App后台Service交互

    上篇文章中我们介绍了使用Cortana调用前台App,不熟悉的移步到:Win10/UWP开发—使用Cortana语音指令与App的前台交互,这篇我们讲讲如何使用Cortana调用App的后台任务,相比 ...

随机推荐

  1. 手机端 echarts使用 svg渲染器

    // 使用 Canvas 渲染器(默认) var chart = echarts.init(containerDom, null, {renderer: 'canvas'}); // 等价于: var ...

  2. BZOJ4241历史研究题解

    题目连接 很显然可以想到分块,用f[i][j]表示块i到块j的ans,然后发现答案一定是f[i][j] 或者其他在边角出现的数字 我们在记下g[i][j]从开头到块i中的数字j出现的次数 这样就每一次 ...

  3. activemq入门demo

    创建maven工程,pom文件如下 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="ht ...

  4. 【错误收集】SVN冲突解决 标签: 错误收集 2016-03-13 08:44 624人阅读 评论(24) 收藏

    最近在倒代码,这真的是一件挺低效率的事情的,但是为了之后工作的进行,必须把这些已经做好的界面,做好的功能搬到新的框架上来,所以安排了10来个同学一起倒代码,因为大家共用一个解决方案,所以使用svn来进 ...

  5. UVa 926【简单dp,递推】

    UVa 926 题意:给定N*N的街道图和起始点,有些街道不能走,问从起点到终点有多少种走法. 很基础的dp.递推,但是有两个地方需要注意,在标记当前点某个方向不能走时,也要同时标记对应方向上的对应点 ...

  6. @atcoder - CODE FESTIVAL 2017 Final - J@ Tree MST

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 给定 N 个点,第 i 点有一个点权 Xi,再给定一棵边带权的树 ...

  7. 你真的知道你看到的UTF-8字符是什么吗?

    翻译自http://www.pixelstech.net/article/1397877200-You-know-what-UTF-8-is-when-you-see-it- Source : son ...

  8. @noi - 172@ 追捕大象

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 在一块平原上有一头大象. 平原被分成 n×m 个格子.初始时大象 ...

  9. Pytorch学习记录-torchtext和Pytorch的实例( 使用神经网络训练Seq2Seq代码)

    Pytorch学习记录-torchtext和Pytorch的实例1 0. PyTorch Seq2Seq项目介绍 1. 使用神经网络训练Seq2Seq 1.1 简介,对论文中公式的解读 1.2 数据预 ...

  10. Element-ui学习笔记1

    1.col,row布局注意事项 el-row el-col gutter就是css,span的时候宽度是按boder-box来计算. 将 type 属性赋值为 'flex',可以启用 flex 布局, ...