在上一篇博客里面告诉大家,如何使用 Vortice 从零开始控制台创建 Direct2D1 窗口。上一篇博客采用的是 CreateDxgiSurfaceRenderTarget 的方式拿到了 ID2D1RenderTarget 进行绘制,本文将和大家介绍另一个方式,通过 ID2D1DeviceContext 绘制画面。从底层来说,这两个方式底层都是相同的,只是上层的 API 调用方法不相同而已

本文属于 DirectX 系列博客,更多 DirectX 和 D2D 以及 Vortice 库的博客,请参阅我的 博客导航

上一篇: DirectX 使用 Vortice 从零开始控制台创建 Direct2D1 窗口修改颜色

在上一篇博客里面,咱创建了一个 Win32 空窗口,接着给他挂上了 DirectX 交换链。使用以下代码从交换链里面拿到了 DXGI 平面,拿到的的 DXGI 平面即可被绘制 2D 内容在上面,从而将内容绘制输出到窗口上

        DXGI.IDXGISwapChain1 swapChain = ... // 忽略交换链之前的代码

        D3D11.ID3D11Texture2D backBufferTexture = swapChain.GetBuffer<D3D11.ID3D11Texture2D>(0);

        // 获取到 dxgi 的平面,这个屏幕就约等于窗口渲染内容
DXGI.IDXGISurface dxgiSurface = backBufferTexture.QueryInterface<DXGI.IDXGISurface>();

在上一篇博客里面,在 IDXGISurface 上绘制 2D 内容的方式是通过 CreateDxgiSurfaceRenderTarget 的方式创建 ID2D1RenderTarget 进而进行通过 ID2D1RenderTarget 绘制界面,如代码

        // 对接 D2D 需要创建工厂
D2D.ID2D1Factory1 d2DFactory = D2D.D2D1.D2D1CreateFactory<D2D.ID2D1Factory1>(); // 方法1:
var renderTargetProperties = new D2D.RenderTargetProperties(Vortice.DCommon.PixelFormat.Premultiplied); // 在窗口的 dxgi 的平面上创建 D2D 的画布,如此即可让 D2D 绘制到窗口上
D2D.ID2D1RenderTarget d2D1RenderTarget =
d2DFactory. (dxgiSurface, renderTargetProperties); var renderTarget = d2D1RenderTarget;

本文将替换上面代码的方法1部分,按照官方文档提供的另一个方法,通过创建 ID2D1Device 设备,从 ID2D1Device 设备创建出 ID2D1DeviceContext 对象,设置 ID2D1DeviceContext 的输出 Target 为 DXGI 平面,从而使用 ID2D1DeviceContext 绘制界面

按照上图的描述,从创建出来的 Direct3D Device 设备里面,使用 QueryInterface 获取到 DXGI Device 对象。然后分为两个路线,一个是获取 DXGI 的平面,也就是上一篇博客提供的方法,这一路线已完成。另一个就是通过 DXGI Device 设备在 ID2D1Factory1 工厂里创建出 Direct2D Device 设备。再通过 Direct2D Device 设备创建出 Direct2D Device Context 上下文,将 DXGI 的平面转换为 Direct2D Bitmap 作为 Direct2D Device Context 的输出源。如此即可在 Direct2D Device Context 绘制内容输出到窗口界面上

按照上面描述的方法,咱一步步实现

        // 获取 DXGI 设备,用来创建 D2D 设备
DXGI.IDXGIDevice dxgiDevice = d3D11Device.QueryInterface<DXGI.IDXGIDevice>();

使用工厂创建 D2D 设备

        D2D.ID2D1Factory1 d2DFactory = ...
// 创建 Direct2D Device 设备
ID2D1Device d2dDevice = d2DFactory.CreateDevice(dxgiDevice);

从设备里面创建 Direct2D Device Context 上下文

        // 创建 Direct2D Device Context 上下文
ID2D1DeviceContext d2dDeviceContext = d2dDevice.CreateDeviceContext();

将 DXGI 平面转换为 ID2D1Bitmap1 用于设置到 ID2D1DeviceContext 的输出

        ID2D1Bitmap1 d2dBitmap = d2dDeviceContext.CreateBitmapFromDxgiSurface(dxgiSurface);

设置 ID2D1Bitmap1 为 ID2D1DeviceContext 的输出

        d2dDeviceContext.Target = d2dBitmap;

接着将 ID2D1DeviceContext 当成 RenderTarget 即可进行绘制,如以下代码

                // 开始绘制逻辑
renderTarget.BeginDraw(); // 清空画布
renderTarget.Clear(new Color4(0xFF, 0xFF, 0xFF)); // 随意创建颜色
var color = new Color4((byte) Random.Shared.Next(255), (byte) Random.Shared.Next(255),
(byte) Random.Shared.Next(255));
using var brush = renderTarget.CreateSolidColorBrush(color);
renderTarget.FillEllipse(new Ellipse(new System.Numerics.Vector2(200, 200), 100, 100), brush); renderTarget.EndDraw();

以上代码即可在窗口绘制一个有趣颜色的形状

以下是创建 ID2D1DeviceContext 的全部代码

       // 获取到 dxgi 的平面,这个屏幕就约等于窗口渲染内容
DXGI.IDXGISurface dxgiSurface = ... // 对接 D2D 需要创建工厂
D2D.ID2D1Factory1 d2DFactory = D2D.D2D1.D2D1CreateFactory<D2D.ID2D1Factory1>(); // 方法1:
//var renderTargetProperties = new D2D.RenderTargetProperties(PixelFormat.Premultiplied); //// 在窗口的 dxgi 的平面上创建 D2D 的画布,如此即可让 D2D 绘制到窗口上
//D2D.ID2D1RenderTarget d2D1RenderTarget =
// d2DFactory.CreateDxgiSurfaceRenderTarget(dxgiSurface, renderTargetProperties);
//var renderTarget = d2D1RenderTarget; // 方法2:
// 创建 D2D 设备,通过设置 ID2D1DeviceContext 的 Target 输出为 dxgiSurface 从而让 ID2D1DeviceContext 渲染内容渲染到窗口上
// 如 https://learn.microsoft.com/en-us/windows/win32/direct2d/images/devicecontextdiagram.png 图
// 获取 DXGI 设备,用来创建 D2D 设备
DXGI.IDXGIDevice dxgiDevice = d3D11Device.QueryInterface<DXGI.IDXGIDevice>();
ID2D1Device d2dDevice = d2DFactory.CreateDevice(dxgiDevice);
ID2D1DeviceContext d2dDeviceContext = d2dDevice.CreateDeviceContext(); ID2D1Bitmap1 d2dBitmap = d2dDeviceContext.CreateBitmapFromDxgiSurface(dxgiSurface);
d2dDeviceContext.Target = d2dBitmap; var renderTarget = d2dDeviceContext;

本文以上代码放在githubgitee 欢迎访问

可以通过如下方式获取本文的源代码,先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码

git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin afe737c0adf4ed0ef32b4c708d172d63afeaa0ef

以上使用的是 gitee 的源,如果 gitee 不能访问,请替换为 github 的源。请在命令行继续输入以下代码

git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git
git pull origin afe737c0adf4ed0ef32b4c708d172d63afeaa0ef

获取代码之后,进入 VorticeD2DConsoleRender1 文件夹

根据官方文档,继承 ID2D1RenderTarget 的 ID2D1DeviceContext 有更多的功能,比如创建特效等

从这个方面上,其实上一篇博客拿到的 ID2D1RenderTarget 其实和本文所拿到的 ID2D1DeviceContext 是相同的东西,至少从底层上是相同的,也就是在上一篇博客的基础上,通过 QueryInterface 即可从 ID2D1RenderTarget 拿到 ID2D1DeviceContext 对象,如以下代码

        var renderTargetProperties = new D2D.RenderTargetProperties(Vortice.DCommon.PixelFormat.Premultiplied);

        // 在窗口的 dxgi 的平面上创建 D2D 的画布,如此即可让 D2D 绘制到窗口上
D2D.ID2D1RenderTarget d2D1RenderTarget =
d2DFactory.CreateDxgiSurfaceRenderTarget(dxgiSurface, renderTargetProperties); var d2dDeviceContext = d2D1RenderTarget.QueryInterface<ID2D1DeviceContext>();

如此可以看到这两篇博客其实只是创建的路线不相同,实际原理是相同的

有伙伴好奇为什么我最近写的是通过 Vortice 调用 DirectX 的博客,而不是通过 SharpDx 或 Silk.NET 调用 DirectX 的博客。这不是我收了 Vortice 的钱或者是和 Vortice 有什么 py 交易哈。其原因是 SharpDx 不维护了,作为 SharpDx 的接任者 Vortice 的行为和 API 都会靠近 SharpDx 许多,我编写起来比较顺手。而 Silk.NET 是对 DirectX 的底层封装,由于是直接底层封装,导致使用 Silk.NET 比较繁琐。尽管使用 Silk.NET 的性能从理论分析上能够比 Vortice 和 SharpDx 更好,但从定量上说,其实好不了多少。我所遇到的几乎所有性能问题,基本都卡在渲染上,而不是调用上,调用上的损耗基本可以忽略。那 Silk.NET 是不是就无用武之地?其实不然,在一些情况下,机器的性能不够业务的需求情况下,能省多少就应该省多少。而且在熟悉整个过程之后,即使将 Vortice 换成 Silk.NET 也只不过是一个体力活而已,将各个 API 进行替换即可。而且有趣的是,可以混合着 Vortice 和 Silk.NET 一起用,只有某些模块才使用 Silk.NET 编写

我创建了专门聊 Vortice 的 QQ 群: 622808968 欢迎加入交流技术

dotnet DirectX 通过 Vortice 控制台使用 ID2D1DeviceContext 绘制画面的更多相关文章

  1. DirectX 使用 Vortice 从零开始控制台创建 Direct2D1 窗口修改颜色

    本文将告诉大家如何使用 Vortice 底层库从零开始,从一个控制台项目,开始搭建一个最简单的使用 Direct2D1 的 DirectX 应用.本文属于入门级博客,期望本文能让大家了解 Vortic ...

  2. Directx 3D编程实例:随机绘制的立体图案旋转

    最近朋友建议我写一些关于微软云技术的博客留给学校下一届的学生们看,怕下一届的MSTC断档.于是我也觉的有这个必要. 写了几篇博客之后,我觉得也有必要把这一年的学习内容放在博客做个纪念,就这样写了本篇博 ...

  3. Docker制作dotnet core控制台程序镜像

    (1)首先我们到某个目录下,然后在此目录下打开visual studio code. 2.编辑docker file文件如下: 3.使用dotnet new console创建控制台程序; 4.使用d ...

  4. dotnet run是如何启动asp.net core站点的

    在曾经的 asp.net 5 过渡时期,运行 asp.net 5 站点的命令是dnx web:在如今即将到来的 asp.net core 时代,运行 asp.net core 站点的命令是dotnet ...

  5. DirectX API 编程起步 #02 窗口的诞生

    在这篇文章里我们先用 windows API 制作一个窗口出来,以后再用 DirectX API 渲染的东西就会显示在这里,控制台那黑白的画面肯定是没法用的. 每次的代码都会更新到Github 首先贴 ...

  6. EntityFramework Core 运行dotnet ef命令迁移背后本质是什么?(EF Core迁移原理)

    前言 终于踏出第一步探索EF Core原理和本质,过程虽然比较漫长且枯燥乏味还得反复论证,其中滋味自知,EF Core的强大想必不用我再过多废话,有时候我们是否思考过背后到底做了些什么,到底怎么实现的 ...

  7. ASP.NET Core知多少(7):对重复编译说NO -- dotnet watch

    ASP.NET Core知多少系列:总体介绍及目录 1. 引言 我们一般的开发过程,就是编码-->编译-->运行-->调试-->定位问题--->修改代码-->编译- ...

  8. Cookies 初识 Dotnetspider EF 6.x、EF Core实现dynamic动态查询和EF Core注入多个上下文实例池你知道有什么问题? EntityFramework Core 运行dotnet ef命令迁移背后本质是什么?(EF Core迁移原理)

    Cookies   1.创建HttpCookies Cookie=new HttpCookies("CookieName");2.添加内容Cookie.Values.Add(&qu ...

  9. 2019-8-31-dotnet-core-隐藏控制台

    title author date CreateTime categories dotnet core 隐藏控制台 lindexi 2019-08-31 16:55:58 +0800 2019-2-1 ...

  10. Shell、命令行界面、控制台什么区别

    Shell 是什么?Shell 是一个命令解释器,它为用户提供了一个向 操作系统内核发送请求以便运行程序界面系统级程序,它的作用就是遵循一定的语法将输入的命令加以解释并传给系统,他大意是指对系统的操控 ...

随机推荐

  1. CSS(精灵图、字体图标、三角、用户界面样式、vertical-align、溢出省略号、常用布局技巧、初始化 )

    一. 精灵图(重点) 1.1 为什么需要精灵图 一个网页中往往会应用很多小的背景图像作为修饰,当网页中的图像过多时,服务器就会频繁地接收和发送请求图片,造成服务器请求压力过大,这将大大降低页面的加载速 ...

  2. 记录--vue 拉伸指令

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 前言 在我们项目开发中,经常会有布局拉伸的需求,接下来 让我们一步步用 vue指令 实现这个需求 动手开发 在线体验 codesandbo ...

  3. Word文档最后一页空白页中换行符无法删除

    Word文档最后一页空白页中换行符无法删除 问题如题: 尝试了delete.backspace.backspace+delete都不行. 找到了这个方法: 选中最后一页的换行符,然后段落--间距--行 ...

  4. 假期做了一项调研:大厂为啥都自研RPC?结果合乎情理!

    大家好,我是冰河~~ 五一假期过的可真快,今天开始,又要搬砖了.在五一假期当中,冰河做了一项调研,感觉结果还是挺合乎情理的. 翻看招聘信息 先来看我在某招聘网站上随便搜索了下Java招聘的岗位,看到的 ...

  5. S2DNAS:北大提出动态推理网络搜索,加速推理,可转换任意网络 | ECCV 2020 Oral

    S2DNAS最核心的点在于设计了丰富而简洁的搜索空间,从而能够使用常规的NAS方法即可进行动态推理网络的搜索,解决了动态推理网络的设计问题,可进行任意目标网络的转换   来源:晓飞的算法工程笔记 公众 ...

  6. 【已解决】启动Hmaster失败 master.HMaster: Unhandled exception. Starting shutdown.

  7. ET8.1(一)简介

    此系列文章逐个内容讲解ET8.1的新特性. ET8.1 发布,带来以下新特性: 1. 多线程多进程架构,架构更加灵活强大,多线程设计详细内容请看多线程设计课程   2. 抽象出纤程(Fiber)的概念 ...

  8. #整体二分 or 主席树#洛谷 7424 [THUPC2017] 天天爱射击

    题目 给定\(n\)条线段\(x_i,y_i,k_i\)和\(m\)个点(点有顺序), 对于每个点,问有多少条线段是第\(k_i\)次被该点经过. 分析(主席树) 将点按坐标排序建主席树那么就是一道静 ...

  9. #dp#洛谷 5774 [JSOI2016]病毒感染

    题目 分析 此题肯定不是绿题,哪有这么恶心的dp 试想这样的情形:假设当 JYY 第一次抵达村庄 \(i\),未作救治并直接前往了另一个村庄.那么由于 \(i\) 村庄的人们求生心切, 一旦当 JYY ...

  10. #容斥,排列组合#U138404 选数字

    题目 给定长度为\(n,n\leq 10^5\)的序列\(a,a_i,m\leq 255\),多组询问求 \[\sum_{i=l}^{r-2}\sum_{j=i+1}^{r-1}\sum_{k=j+1 ...