title author date CreateTime categories
win2d CanvasCommandList 使用方法
lindexi
2018-11-9 20:8:4 +0800
2018-11-09 19:20:34 +0800
UWP win2d

在 win2d 可以通过 CanvasCommandList 定义很多命令,这些命令不是直接渲染到 Canvas 上,而是作为一个缓存。可以将 CanvasCommandList 作为输入,输入到其他的特效或参与其他的渲染。
特别在用 Win2d 写一个渲染框架的时候,通过 CanvasCommandList 可以实现内部元素容器的偏移和统一的效果

先安装好 Win2d 的 nuget 如果对于 win2d 的安装有疑问,请看 win10 uwp win2d 入门 看这一篇就够了

在界面加上代码

  1. <Page
  2. x:Class="lindexi.Win2d.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:NekeJivear"
  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="Canvas" Draw="Canvas_OnDraw"></win2d:CanvasControl>
  14. <Button Content="确定" Margin="10,10,10,10" HorizontalAlignment="Center" VerticalAlignment="Bottom" Click="Button_OnClick"></Button>
  15. </Grid>
  16. </Page>

直接显示

在后台的代码需要添加两个函数

  1. private void Canvas_OnDraw(CanvasControl sender, CanvasDrawEventArgs args)
  2. {
  3.  
  4. }
  5.  
  6. private void Button_OnClick(object sender, RoutedEventArgs e)
  7. {
  8.  
  9. }

现在在 Canvas_OnDraw 尝试使用 CanvasCommandList 在看到代码的时候,大家会发现使用 CanvasCommandList 没有什么特殊的

创建 CanvasCommandList 需要传入 ICanvasResourceCreator 通过 sender 传入就可以

  1. private void Canvas_OnDraw(CanvasControl sender, CanvasDrawEventArgs args)
  2. {
  3. var canvasCommandList = new CanvasCommandList(sender);
  4.  
  5. }

在 CanvasCommandList 添加渲染的系列命令的方法是调用 CreateDrawingSession 的方法返回 CanvasDrawingSession 这个值和普通的渲染用到的是相同的

  1. private void Canvas_OnDraw(CanvasControl sender, CanvasDrawEventArgs args)
  2. {
  3. var canvasCommandList = new CanvasCommandList(sender);
  4.  
  5. using (var clds = canvasCommandList.CreateDrawingSession())
  6. {
  7.  
  8. }
  9. }

在 clds 里面添加渲染的命令就可以输入到 CanvasCommandList 作为缓存

现在尝试添加一些文字和元素

  1. var canvasCommandList = new CanvasCommandList(sender);
  2.  
  3. using (CanvasDrawingSession clds = canvasCommandList.CreateDrawingSession())
  4. {
  5. clds.DrawText("lindexi", new Vector2(100, 100), Color.FromArgb(0xFF, 100, 100, 100));
  6. clds.DrawRectangle(new Rect(new Point(10, 10), new Point(20, 15)),
  7. new CanvasSolidColorBrush(sender, Colors.Black));
  8. }

但是如果现在运行软件,是不会在界面看到任何的修改

因为 CanvasCommandList 需要调用 DrawImage 的方法才能画到 win2d 的控件上

  1. using (var ds = args.DrawingSession)
  2. {
  3. ds.DrawImage(canvasCommandList);
  4. }

现在运行软件,可以看到下面图片

相对移动

如果在写一个渲染的框架,很多的时候会使用容器,容器的元素会相对于容器的坐标,而在容器移动的时候,对里面的元素是无法知道的。所以需要将里面的元素进行总体的移动。

通过 CanvasCommandList 可以很容易做到移动整个容器。

将里面的元素全部渲染到一个 CanvasCommandList 然后通过重载的方法移动 CanvasCommandList 的渲染,请看代码

  1. using (var ds = args.DrawingSession)
  2. {
  3. var offset = new Vector2(100, 100);
  4. ds.DrawImage(canvasCommandList, offset);
  5. }

这样就可以做到将这个 canvasCommandList 移动到 (100,100) 同时缓存在里面的命令也就被移动了 (100,100) 运行代码可以看到下面的图片

复用命令

除了可以用来作为元素的移动,还可以作为复用命令,假如有一个元素可以作为组合画出来

那么只需要多次画出的元素输入到 canvasCommandList 然后多次使用 canvasCommandList 也就是复用元素

如在 win2d 画出好看的图形 里面就有很多的好看的图形,想要多次画出这些图形,如果进行每次都来坐标的计算,那么这个代码一点也不好

例如我需要画出下面的图片

如果不使用 canvasCommandList 需要计算每个元素的坐标,这样的代码看起来不好,于是在使用了之后就可以十分快速使用下面代码画出

  1. private void Canvas_OnDraw(CanvasControl sender, CanvasDrawEventArgs args)
  2. {
  3. var canvasCommandList = new CanvasCommandList(sender);
  4.  
  5. using (CanvasDrawingSession clds = canvasCommandList.CreateDrawingSession())
  6. {
  7. var pointList = CreateStone(new Point(10, 10), 10, 2, 5);
  8.  
  9. var canvasGeometry = CanvasGeometry.CreatePolygon(sender,
  10. pointList.Select(temp => new Vector2((float) temp.X, (float) temp.Y)).ToArray());
  11.  
  12. clds.DrawGeometry(canvasGeometry, Color.FromArgb(255, 100, 100, 100));
  13. }
  14.  
  15. using (var ds = args.DrawingSession)
  16. {
  17. for (int i = 0; i < sender.ActualWidth / 100; i++)
  18. {
  19. for (int j = 0; j < sender.ActualHeight / 100; j++)
  20. {
  21. var offset = new Vector2(i * 100, j * 100);
  22. ds.DrawImage(canvasCommandList, offset);
  23. }
  24. }
  25. }
  26. }

这里的 CreateStone 是在 win2d 画出好看的图形 写的

所以对于需要重复使用的命令,就不需要使用 CanvasRenderTarget 的方法

与 CanvasRenderTarget 的区别

关于 CanvasRenderTarget 请看 win10 uwp win2d 离屏渲染 这个类可以用来不添加到视觉树的时候将命令画在图片上,可以输出为图片

也就是输入的命令实际上就进行渲染,而 CanvasCommandList 只是一个缓存,里面不会进行渲染。

两个类同时都可以作为 Image 的输入,如果只是需要复用某些元素,建议使用 CanvasCommandList 的方法,这样的速度很快

特效

如果对于很大的元素,如上面画出的元素,需要对整个图片进行特效。

关于特效请看 win10 uwp win2d 特效 这里使用 DirectionalBlurEffect 特效

这个特效可以用来将图片模糊,为了让大家比较容易看到特效,我需要将上面的代码做很小的修改

我将多个元素放在一个 CanvasCommandList 提取代码为一个函数,这个函数就是画出一个元素

  1. private static CanvasCommandList DrawSaJonairqai(CanvasControl sender)
  2. {
  3. var canvasCommandList = new CanvasCommandList(sender);
  4.  
  5. using (CanvasDrawingSession clds = canvasCommandList.CreateDrawingSession())
  6. {
  7. var pointList = CreateStone(new Point(10, 10), 10, 2, 5);
  8.  
  9. var canvasGeometry = CanvasGeometry.CreatePolygon(sender,
  10. pointList.Select(temp => new Vector2((float)temp.X, (float)temp.Y)).ToArray());
  11.  
  12. clds.DrawGeometry(canvasGeometry, Color.FromArgb(255, 100, 100, 100));
  13. }
  14.  
  15. return canvasCommandList;
  16. }

然后将上面的 DrawGeometry 修改为填充

  1. private static CanvasCommandList DrawSaJonairqai(CanvasControl sender)
  2. {
  3. var canvasCommandList = new CanvasCommandList(sender);
  4.  
  5. using (CanvasDrawingSession clds = canvasCommandList.CreateDrawingSession())
  6. {
  7. var pointList = CreateStone(new Point(10, 10), 10, 2, 5);
  8.  
  9. var canvasGeometry = CanvasGeometry.CreatePolygon(sender,
  10. pointList.Select(temp => new Vector2((float)temp.X, (float)temp.Y)).ToArray());
  11.  
  12. clds.FillGeometry(canvasGeometry, Color.FromArgb(255, 100, 100, 100));
  13. }
  14.  
  15. return canvasCommandList;
  16. }

替换渲染到画板为输入到另一个 CanvasCommandList 作为特效输入

  1. private void Canvas_OnDraw(CanvasControl sender, CanvasDrawEventArgs args)
  2. {
  3. var canvasCommandList = new CanvasCommandList(sender);
  4.  
  5. using (var clds = canvasCommandList.CreateDrawingSession())
  6. {
  7. for (int i = 0; i < sender.ActualWidth / 50; i++)
  8. {
  9. for (int j = 0; j < sender.ActualHeight / 50; j++)
  10. {
  11. var offset = new Vector2(i * 50, j * 50);
  12. clds.DrawImage(DrawSaJonairqai(sender), offset);
  13. }
  14. }
  15. }
  16. }

先尝试运行代码,可以看到下面的图片

现在添加 DirectionalBlurEffect 特效

  1. var directionalBlurEffect = new DirectionalBlurEffect()
  2. {
  3. Source = canvasCommandList,
  4. BlurAmount = 3,
  5. };

将特效渲染到控件,运行代码可以看到下面图片

  1. using (var ds = args.DrawingSession)
  2. {
  3. ds.DrawImage(directionalBlurEffect);
  4. }

所有代码

  1. private void Canvas_OnDraw(CanvasControl sender, CanvasDrawEventArgs args)
  2. {
  3. var canvasCommandList = new CanvasCommandList(sender);
  4.  
  5. using (var clds = canvasCommandList.CreateDrawingSession())
  6. {
  7. for (int i = 0; i < sender.ActualWidth / 50; i++)
  8. {
  9. for (int j = 0; j < sender.ActualHeight / 50; j++)
  10. {
  11. var offset = new Vector2(i * 50, j * 50);
  12. clds.DrawImage(DrawSaJonairqai(sender), offset);
  13. }
  14. }
  15. }
  16.  
  17. var directionalBlurEffect = new DirectionalBlurEffect()
  18. {
  19. Source = canvasCommandList,
  20. BlurAmount = 3,
  21. };
  22.  
  23. using (var ds = args.DrawingSession)
  24. {
  25. ds.DrawImage(directionalBlurEffect);
  26. }
  27. }
  28.  
  29. private static CanvasCommandList DrawSaJonairqai(CanvasControl sender)
  30. {
  31. var canvasCommandList = new CanvasCommandList(sender);
  32.  
  33. using (CanvasDrawingSession clds = canvasCommandList.CreateDrawingSession())
  34. {
  35. var pointList = CreateStone(new Point(10, 10), 10, 2, 5);
  36.  
  37. var canvasGeometry = CanvasGeometry.CreatePolygon(sender,
  38. pointList.Select(temp => new Vector2((float) temp.X, (float) temp.Y)).ToArray());
  39.  
  40. clds.FillGeometry(canvasGeometry, Color.FromArgb(255, 100, 100, 100));
  41. }
  42.  
  43. return canvasCommandList;
  44. }
  45.  
  46. public static Point[] CreateStone(Point center, int outerRadius, int innerRadius, int arms)
  47. {
  48. int centerX = (int) center.X;
  49. int centerY = (int) center.Y;
  50. Point[] points = new Point[arms * 2];
  51. double offset = Math.PI / 2;
  52. double arc = 2 * Math.PI / arms;
  53. double half = arc / 2;
  54. for (int i = 0; i < arms; i++)
  55. {
  56. Random randomOuter = new Random((int) DateTime.Now.Ticks);
  57. outerRadius = outerRadius -
  58. randomOuter.Next((int) (innerRadius * 0.06 * new Random().Next(-20, 20) / 30d),
  59. (int) (innerRadius * 0.08));
  60. Random randomInner = new Random(Guid.NewGuid().GetHashCode());
  61. innerRadius = innerRadius +
  62. randomInner.Next((int) (innerRadius * 0.02 * new Random().Next(-100, 100) / 150d),
  63. (int) (innerRadius * 0.08));
  64. if (innerRadius > outerRadius)
  65. {
  66. int temp = outerRadius;
  67. outerRadius = innerRadius;
  68. innerRadius = temp;
  69. }
  70.  
  71. double angleTemp = arc * randomInner.Next(-5, 5) / 10d;
  72. var angle = i * arc;
  73. angle += angleTemp;
  74. points[i * 2].X = (float) (centerX + Math.Cos(angle - offset) * outerRadius) + 20;
  75. points[i * 2].Y = (float) (centerY + Math.Sin(angle - offset) * outerRadius) + 20;
  76. points[i * 2 + 1].X = (float) (centerX + Math.Cos(angle + half - offset) * innerRadius) + 20;
  77. points[i * 2 + 1].Y = (float) (centerY + Math.Sin(angle + half - offset) * innerRadius) + 20;
  78. }
  79.  
  80. return points;
  81. }

2018-11-9-win2d-CanvasCommandList-使用方法的更多相关文章

  1. 【译】ASP.NET MVC 5 教程 - 11:Details 和 Delete 方法详解

    原文:[译]ASP.NET MVC 5 教程 - 11:Details 和 Delete 方法详解 在教程的这一部分,我们将研究一下自动生成的 Details 和Delete 方法. Details ...

  2. SQLMAP注入教程-11种常见SQLMAP使用方法详解

    sqlmap也是渗透中常用的一个注入工具,其实在注入工具方面,一个sqlmap就足够用了,只要你用的熟,秒杀各种工具,只是一个便捷性问题,sql注入另一方面就是手工党了,这个就另当别论了.今天把我一直 ...

  3. OI生涯回忆录 2018.11.12~2019.4.15

    上一篇:OI生涯回忆录 2017.9.10~2018.11.11 一次逆风而行的成功,是什么都无法代替的 ………… 历经艰难 我还在走着 一 NOIP之后,全机房开始了省选知识的自学. 动态DP,LC ...

  4. China Intelligent Office Summit(2018.11.21)

    时间:2018.11.21地点:中关村软件园国际会议中心

  5. International Programming Retreat Day(2018.11.17)

    时间:2018.11.17地点:北京国华投资大厦

  6. Intel Artificial Intelligence Conference(2018.11.14)

    时间:2018.11.14地点:北京国贸大酒店

  7. [转]11种常见sqlmap使用方法详解

    sqlmap也是渗透中常用的一个注入工具,其实在注入工具方面,一个sqlmap就足够用了,只要你用的熟,秒杀各种工具,只是一个便捷性问题,sql注入另一方面就是手工党了,这个就另当别论了.今天把我一直 ...

  8. 2018.11.23 浪在ACM 集训队第六次测试赛

    2018.11.23 浪在ACM 集训队第六次测试赛 整理人:刘文胜 div 2: A: Jam的计数法 参考博客:[1] 万众 B:数列 参考博客: [1] C:摆花 参考博客: [1] D:文化之 ...

  9. 2018.11.16 浪在ACM 集训队第五次测试赛

    2018.11.16 浪在ACM 集训队第五次测试赛 整理人:李继朋 Problem A : 参考博客:[1]朱远迪 Problem B : 参考博客: Problem C : 参考博客:[1]马鸿儒 ...

  10. 2018.11.9浪在ACM集训队第四次测试赛

    2018.11.9浪在ACM集训队第四次测试赛 整理人:朱远迪 A 生活大爆炸版 石头剪刀布           参考博客:[1] 刘凯 B 联合权值            参考博客: [1]田玉康 ...

随机推荐

  1. docker出现如下错误:Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?

    在docker中配置deepo时出现了错误: 在出现这个错误之前,我是先用如下命令查看NVIDIA-docker是否安装成功. docker run --runtime=nvidia --rm nvi ...

  2. spoj Distinct Substrings 后缀数组

    给定一个字符串,求不相同的子串的个数. 假如给字符串“ABA";排列的子串可能: A B A AB  BA ABA 共3*(3+1)/2=6种; 后缀数组表示时: A ABA BA 对于A和 ...

  3. Java练习 SDUT-2400_高中数学?

    高中数学? Time Limit: 1000 ms Memory Limit: 65536 KiB Problem Description 高中数学大家都学过数列,其中一个重要的概念就是数列的通项,可 ...

  4. BZOJ 1500 洛谷2042维护序列题解

    BZ链接 洛谷链接 这道题真是丧心病狂.... 应该很容易就可以看出做法,但是写代码写的....... 思路很简单,用一个平衡树维护一下所有的操作就好了,重点讲解一下代码的细节 首先如果按照常规写法的 ...

  5. ros自定义消息

    ros自定义消息可以根据自身项目需求定义和封装想要的数据类型和数据结构.具体可以参考维基百科关于ros自定义消息部分 这里我只是记录自定义消息的要点部分: 1.首先要在工作空间下功能包中创建一个msg ...

  6. genymotion 和genymotion eclipse 插件安装 !

    昨天天有好心网友在群里共享了一个好用的 android 模拟器 genymotion 昨天就试用了下 真心流畅 各位不妨一试 http://www.genymotion.com/ doc https: ...

  7. POJ2663 Tri Tiling

    思路: 设a[i]为N=i时的方法数.i为奇数的时候肯定为0. 如果i为偶数,a[i]可以看成a[i-2]加上两个单位组成的,此时多出来的2单位有3种方法. 也可以看成a[i-4]加上四个单位组成的, ...

  8. 全文索引——CONTAINS 语法

    Like直接在数据据中查找可以查到所有所需记录但是会扫描整个表会影响性能CONTAINS是基于全文索引进行查询,查询结果受系统全文索引分词的方法影响查询结果会不全.Select * FROM A Wh ...

  9. NSDate 格式化含有毫秒

    [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss.SSS"]; 版权声明:本文为博主原创文章,未经博主允许不得转载.

  10. python selenium处理JS只读(12306)

    12306为例 js = "document.getElementById('train_date').removeAttribute('readonly');" driver.e ...