WPF 使用 Direct2D1 画图入门

本文来告诉你们如何在 WPF 使用 D2D 画图。html

本文是一个系列git

什么是 D2D

实际上如今不少小伙伴对于渲染性能就是听到 DirectX 才会去搜索这个博客。我在博客园看到不多的博客讲到这个。即便有也不多会说如何使用 WPF 的。this

那么 D2D 是一个提升性能的方法,具体是怎么作?基于 Direct3D 可使用硬件加速的功能,即便在没有显卡,进行软渲染的性能也是比 GDI 快,可是渲染静态的仍是建议使用 GDI。.net

如今的 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——简介及首个例子 - 万仓一黍 - 博客园

全部代码:WPF Direct2D 入门-CSDN下载

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();

更多博客

为什么使用 DirectComposition

C++ 的 Direct2D 请看 Direct2D

我搭建了本身的博客 https://lindexi.gitee.io/ 欢迎你们访问,里面有不少新的博客。只有在我看到博客写成熟以后才会放在csdn或博客园,可是一旦发布了就再也不更新

若是在博客看到有任何不懂的,欢迎交流,我搭建了 dotnet 职业技术学院 欢迎你们加入

知识共享许可协议
本做品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、从新发布,但务必保留文章署名林德熙(包含连接:http://blog.csdn.net/lindexi_gd ),不得用于商业目的,基于本文修改后的做品务必以相同的许可发布。若有任何疑问,请与我联系

相关文章
相关标签/搜索