2018-8-10-WPF-使用-Direct2D1-画图入门
title | author | date | CreateTime | categories |
---|---|---|---|---|
WPF 使用 Direct2D1 画图入门
|
lindexi
|
2018-08-10 19:16:53 +0800
|
2018-04-18 20:46:45 +0800
|
WPF D2D DirectX 渲染
|
本文来告诉大家如何在 WPF 使用 D2D 画图。
本文是一个系列
什么是 D2D
实际上现在很多小伙伴对于渲染性能就是听到 DirectX 才会去搜索这个博客。我在博客园看到很少的博客讲到这个。即使有也很少会说如何使用 WPF 的。
那么 D2D 是一个提高性能的方法,具体是怎么做?基于 Direct3D 可以使用硬件加速的功能,即使在没有显卡,进行软渲染的性能也是比 GDI 快,但是渲染静态的还是建议使用 GDI。
现在的 WPF 底层使用的渲染是 Dx9 渲染 或使用 Dx11 Dx12 优化 fl9 渲染,所以性能实际上和直接使用 D2D 是差不多,但是 WPF 没有充分使用DX,所以如果自己写的性能会比较高。
因为 WPF 渲染使用的是 Dx9 或虽然使用了 Dx11 Dx12 但是优化是 fl9 ,所以在现在很多设备无法使用全部的性能。
Direct2D运行需求
这是我从大神的博客看到,如果需要运行 Direct2D 那么就需要在 win7 之后才可以。所以在现在几乎可以直接运行,很少有人会使用 win7 以下的设备。
安装
下面是我从 Nuget 安装,这个是很老的库,不太建议大家使用。
Nuget 搜索 WindowsAPICodePackDirectX 就可以安装,如果不知道安装哪个,请点击WindowsAPICodePackDirectX
这个库只是 x64 的库,所以想要运行还需要设置环境。
环境
如果直接使用这个库是无法运行,下面的代码只是作为大家快速入门,不能用于产品。安装这个库可以用在 x64 的进程,但是不能用在 x86 进程。
而且这个库不能直接在 dot net framework 4.5 的环境运行,需要创建 App.config 文件添加下面代码。需要注意,请修改创建项目使用 dot net framework 4.5 而不是更高的版本。
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup useLegacyV2RuntimeActivationPolicy="true">
<supportedRuntime version="v4.0" sku = ".NETFramework,Version=v4.5"/>
<supportedRuntime version="v2.0.50727"/>
</startup>
</configuration>
那么如何让软件使用 x64 进程?尝试右击项目点击属性,在生成页面就可以看到平台目标,选择 x64 就会编译 x64 的软件。
如果对于平台目标感觉有兴趣,请看WPF 编译为 AnyCPU 和 x86 有什么区别
创建工厂
首先打开 MainPage 的代码,添加下面代码
using D2D = Microsoft.WindowsAPICodePack.DirectX.Direct2D1;
这样下面就不需要写那么多代码,因为所有使用Microsoft.WindowsAPICodePack.DirectX.Direct2D1
的都可以使用 D2D
来找到,这样下面的代码大家直接复制就可以运行。
在使用 Direct2D1 的第一步就是创建工厂。
虽然工厂有很多重载,不过这里不会告诉大家,因为只是快速入门,如果需要知道参数的意思就请自己多看文章。
public MainWindow()
{
InitializeComponent(); Loaded += (s, e) =>
{
var d2DFactory = D2D.D2DFactory.CreateFactory(D2D.D2DFactoryType.Multithreaded);
};
}
把代码写在 Loaded 是因为下面需要拿到窗口。
获得窗口
从上面代码大家也许会说为什么需要在 Load 才写,因为需要拿到窗口,在 Load 之后拿才不会是空。窗口创建虽然不是只在 Loaded 拿才可以,不过为了代码比较简单,于是写在 Loaded ,这时拿到一般就是可以使用。
使用下面代码就可以拿到窗口
var windowHandle = new WindowInteropHelper(this).Handle;
渲染目标
最主要就是创建 RenderTarget ,请使用下面代码
var renderTarget = d2DFactory.CreateHwndRenderTarget(new D2D.RenderTargetProperties(),
new D2D.HwndRenderTargetProperties(windowHandle,
new D2D.SizeU((uint) ActualWidth, (uint) ActualHeight),
D2D.PresentOptions.RetainContents));
实际上上面的代码不可以用在实际项目,因为写入的大小,如果窗口修改了大小,那么显示的就一般不是期望。
在渲染的时候还需要使用 RenderTarget ,先创建一个字段保存
public MainWindow()
{
InitializeComponent(); Loaded += (s, e) =>
{
var d2DFactory = D2D.D2DFactory.CreateFactory(D2D.D2DFactoryType.Multithreaded); var windowHandle = new WindowInteropHelper(this).Handle;
var renderTarget = d2DFactory.CreateHwndRenderTarget(new D2D.RenderTargetProperties(),
new D2D.HwndRenderTargetProperties(windowHandle,
new D2D.SizeU((uint) ActualWidth, (uint) ActualHeight),
D2D.PresentOptions.RetainContents)); _renderTarget = renderTarget;
};
} private D2D.RenderTarget _renderTarget;
写线段
上面说了主要就是拿 RenderTarget ,因为拿到 RenderTarget 就和拿到 DrawContext 一样,自己尝试点一下 RenderTarget 就可以看到很多画图的方法,在里面画图的性能很高。
那么尝试对RenderTarget写入线段
因为需要知道在什么时候才进行渲染,所以先添加下面代码。在 CompositionTarget 拿到渲染就是一个耗性能的过程,但是为了让 DX 渲染和 WPF 时间一样,所以需要在这个事件进行渲染。主要不要让这个方法执行时间比较长,除了画出来就不要做其他的。
CompositionTarget.Rendering += OnRendering;
想要画出一条线,需要知道线的两个点,和线的颜色,宽度。但是在 RenderTarget 传入线的样式需要使用下面的方法。注意传入的值是 ColorF 而且三个值都是[0,1],所以对普通的颜色传入需要计算。
创建笔刷的方法
var brush = _renderTarget.CreateSolidColorBrush(new D2D.ColorF(0, 1, 0));
进行渲染
if (_renderTarget == null)
{
return;
} _renderTarget.BeginDraw();
var brush = _renderTarget.CreateSolidColorBrush(new D2D.ColorF(0, 1, 0)); _renderTarget.DrawLine(new D2D.Point2F(10, 10), new D2D.Point2F(100, 100), brush, 10); _renderTarget.EndDraw();
渲染需要先 BeginDraw 然后画出,最后调用 EndDraw 画出来。注意,如果运行看不到画出的,那么请先看一下是不是调了多次 BeginDraw 没有匹配 EndDraw 。
尝试运行就可以看到下面界面
这时看一下 CPU ,几乎不需要。
下面来做很小修改,写出一个会动的图,下面的代码放在最后。
Direct2D教程I——简介及首个例子 - 万仓一黍 - 博客园
public MainWindow()
{
InitializeComponent(); CompositionTarget.Rendering += OnRendering; Loaded += (s, e) =>
{
var d2DFactory = D2D.D2DFactory.CreateFactory(D2D.D2DFactoryType.Multithreaded); var windowHandle = new WindowInteropHelper(this).Handle;
var renderTarget = d2DFactory.CreateHwndRenderTarget(new D2D.RenderTargetProperties(),
new D2D.HwndRenderTargetProperties(windowHandle,
new D2D.SizeU((uint) ActualWidth, (uint) ActualHeight),
D2D.PresentOptions.RetainContents)); _redBrush = renderTarget.CreateSolidColorBrush(new D2D.ColorF(1, 0, 0, 1)); _greenBrush = renderTarget.CreateSolidColorBrush(new D2D.ColorF(0, 1, 0, 1)); _blueBrush = renderTarget.CreateSolidColorBrush(new D2D.ColorF(0, 0, 1, 1)); _renderTarget = renderTarget;
};
} private D2D.RenderTarget _renderTarget; private D2D.SolidColorBrush _redBrush; private D2D.SolidColorBrush _greenBrush; private D2D.SolidColorBrush _blueBrush; private void OnRendering(object sender, EventArgs e)
{
if (_renderTarget == null)
{
return;
} D2D.SolidColorBrush brush = null; switch (ran.Next(3))
{
case 0:
brush = _redBrush;
break;
case 1:
brush = _greenBrush;
break;
case 2:
brush = _blueBrush;
break;
} _renderTarget.BeginDraw();
_renderTarget.DrawRectangle(new D2D.RectF(_x, _y, _x + 10, _y + 10), brush, 1);
_renderTarget.EndDraw(); _x = _x + _dx;
_y = _y + _dy;
if (_x >= ActualWidth - 100 || _x <= 0)
{
_dx = -_dx;
} if (_y >= ActualHeight - 100 || _y <= 0)
{
_dy = -_dy;
}
} private float _dx = 1;
private float _dy = 1;
private float _x;
private float _y; private Random ran = new Random();
更多博客
C++ 的 Direct2D 请看 Direct2D
2018-8-10-WPF-使用-Direct2D1-画图入门的更多相关文章
- WPF 使用 Direct2D1 画图入门
本文来告诉大家如何在 WPF 使用 D2D 画图. 本文是一个系列 WPF 使用 Direct2D1 画图入门 WPF 使用 Direct2D1 画图 绘制基本图形 WPF 使用 SharpDX WP ...
- WPF 使用 Direct2D1 画图 绘制基本图形
本文来告诉大家如何在 Direct2D1 绘制基本图形,包括线段.矩形.椭圆 本文是一个系列 WPF 使用 Direct2D1 画图入门 WPF 使用 Direct2D1 画图 绘制基本图形 本文的组 ...
- WPF 像素着色器入门:使用 Shazzam Shader Editor 编写 HLSL 像素着色器代码
原文:WPF 像素着色器入门:使用 Shazzam Shader Editor 编写 HLSL 像素着色器代码 HLSL,High Level Shader Language,高级着色器语言,是 Di ...
- 不用搭环境的10分钟AngularJS指令简易入门01(含例子)
不用搭环境的10分钟AngularJS指令简易入门01(含例子) `#不用搭环境系列AngularJS教程01,前端新手也可以轻松入坑~阅读本文大概需要10分钟~` AngularJS的指令是一大特色 ...
- 申请Office 365一年免费的开发者账号攻略(2018年10月份版本)
要进行Office 365开发,当然需要有完整的Office 365环境才可以.为了便于广大开发人员快速地启动这项工作,微软官方给所有开发人员提供了免费的一年开发者账号 那么如何申请Office ...
- IntelliJ IDEA 最新激活码(截止到2018年10月14日)
IntelliJ IDEA 注册码: EB101IWSWD-eyJsaWNlbnNlSWQiOiJFQjEwMUlXU1dEIiwibGljZW5zZWVOYW1lIjoibGFuIHl1IiwiYX ...
- 新手C#SQL Server使用记录2018.08.10
主键(PrimaryKey):主键就是每个数据行(记录)的唯一标识,不会有重复值的列(字段)才能当做主键.一个表可以没有主键,但是这样会很难处理表,因此一般情况表都要设置主键. 主键有两张选用策略,分 ...
- Prism(WPF) 拐着尝试入门
原文:Prism(WPF) 拐着尝试入门 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/s261676224/article/details/852 ...
- HTML5 Canvas 画图入门
HTML5 Canvas 画图入门 HTML5 Canvas 画图入门,仅供学习參考 <!DOCTYPE html> <html> <head> <meta ...
- 01 mybatis框架整体概况(2018.7.10)-
01 mybatis框架整体概况(2018.7.10)- F:\廖雪峰 JavaEE 企业级分布式高级架构师课程\廖雪峰JavaEE一期\第一课(2018.7.10) maven用的是3.39的版本 ...
随机推荐
- golang 运行时死锁排查和检测
当运行的系统发生goroutine等待获取锁时间超过预期时,判定为发生了死锁.因目前代码中使用了一些公开的锁实例,调用链也比较长,对问题排查带来了很大困扰.为了便于问题排查,需要借助工具来实现. 1. ...
- 记录--没有await,如何处理“回调地狱”
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 太长不看 不要嵌套使用函数.给每个函数命名并把他们放在你代码的顶层 利用函数提升.先使用后声明. 处理每一个异常 编写可以复用的函数,并把 ...
- 记录--服务端推送到Web前端有哪几种方式?
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 这个问题? 这个问题一般会出现在面试题里面,然后回答一些诸如轮询.WebSocket之类的答案.当然,实际开发中,也会遇到类似别人给你赞了 ...
- 记录--微信小程序获取用户信息(附代码、流程图)
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 本篇文章主要总结了微信小程序开发,获取用户信息的整个流程步骤.补充了网上很多碎片化的代码,本人梳理了思路写下了这篇文章. 思路 1.在js ...
- IDEA 突然无法打开 解决办法
如果实在没有方法了可以试一试 删除所有的配置文件,默认位置C:\Users\${你的用户名}\${.IntelliJIdea+版本} 注意:删除配置后之前所有的设置都会失效,谨慎操作.
- python爬虫反爬之快速配置免费IP代理池(ProxyPool)
关注我的公众号[靠谱杨阅读人生]回复ProxyPool可以免费获取网盘链接. 也可自行搜索下载:https://github.com/Python3WebSpider/ProxyPool.git 1. ...
- SpringBoot配置启动页(首页)控制台打印项目访问入口url
一.SpringBootApplication 1 package com.reliable.yang; 2 3 /** 4 * @author Administrator 5 * @date 202 ...
- hadoop集群查看所有主机的jps进程情况脚本文件
jpsall代码 #!/bin/bash for host in hadoop102 hadoop103 hadoop104 do echo =============== $host ======= ...
- #最大密度子图,0/1分数规划#UVA1389 Hard Life
题目 \(n\) 个点,\(m\) 条边的一个无向图,问导出子图的边数除以点数的最大值 分析 考虑二分这个答案,也就是0/1分数规划之后转换成 \(E-mid*V>0\) 这个问题虽然可以精确到 ...
- #构造#洛谷 6470 [COCI2008-2009#6]CUSKIJA
题目 给定一个长度为 \(n\) 的序列 \(a\),请将其重新排序, 新序列中任意相邻两个数之和都不能被 \(3\) 整除. 分析 分类讨论,如果只有3的倍数多于1个无解 没有 \(3k+1\) 或 ...