本文告诉大家如何使用 Vortice 进行 D2D 的离屏渲染功能,本文将在一个纯控制台无窗口的应用下,使用 Direct2D1 进行离屏绘制,将绘制结果保存为本地图片文件

本文属于使用 Vortice 调用 DirectX 系列博客,也属于 DirectX 系列博客,本文属于入门级博客,但在阅读本文之前,期望大家了解了 DirectX 的基础概念

本文使用的 Vortice 是 SharpDx 的代替品,是对 DirectX 的底层 C# 封装。使用 Vortice 底层库,能让 C# 代码比较方便的和 DirectX 对接。尽管本文使用的是 Vortice 库来调用 DirectX 相关的接口,但不代表着只有 Vortice 库能做此实现,可以将 Vortice 换成其他的对 DirectX 封装的库,例如 SharpDx 或者是 Silk.NET 等,更换之后只是调用的方法或者是参数等稍微有点不相同,但是实现思路都是相同的

使用 Direct2D1 离屏渲染技术,可以进行脱离具体的窗口调用渲染,可以不需要占用主线程的时间,采用后台线程驱动执行渲染。可以实现在某些性能敏感的业务上,预先准备好渲染内容,从而提升性能等

新建一个 dotnet 6 的控制台项目,咱将在此新建的项目里面完成一个简单的 Direct2D1 离屏渲染的控制台应用。本文不会贴所有的代码,如果按照本文给出的代码构建不通过或者遇到其他问题,还请到本文末尾获取所有源代码,将源代码拉到本地构建

按照惯例,在开始之前,先通过 NuGet 安装必要的库。在 dotnet 6 项目里,采用 SDK 风格的 csproj 项目文件格式,可以通过编辑项目文件的方式快速安装 NuGet 库。可以在 VisualStudio 里,右击项目,点击编辑项目文件,或者双击项目都可以,替换项目文件为以下代码即可完成安装

<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Vortice.Direct2D1" Version="2.1.32" />
<PackageReference Include="Vortice.Win32" Version="1.6.2" />
</ItemGroup>
</Project>

以上代码安装了 Vortice.Direct2D1 库用来对接 Direct2D1 的逻辑,安装了 Vortice.Win32 用来辅助处理杂项逻辑

打开 Program.cs 文件,开始编写离线渲染逻辑。开始编写代码之前,先引用命名空间

using Vortice.Mathematics;
using Vortice.WIC;
using D2D = Vortice.Direct2D1;
using PixelFormat = Vortice.DCommon.PixelFormat;

大家都知道,使用 D2D 时,最重要的就是获取到 ID2D1RenderTarget 用来作为绘制的画布。创建 ID2D1RenderTarget 的方法有很多个,本文是通过 ID2D1Factory1 工厂调用 CreateWicBitmapRenderTarget 方法,从一个 IWICBitmap 创建的

也就是说想要获取到 ID2D1RenderTarget 进行绘制,就需要能先拿到 IWICBitmap 类型的对象。创建 IWICBitmap 类型的对象需要通过 WIC 工厂进行创建。于是先创建工厂

        using var wicImagingFactory = new IWICImagingFactory();

通过 IWICImagingFactory 工厂创建 IWICBitmap 对象,需要调用 CreateBitmap 方法,传入尺寸和颜色格式。颜色格式里面只有一些是 D2D 支持的,本文这里采用常用的 PixelFormat32bppPBGRA 格式

        using IWICBitmap wicBitmap =
wicImagingFactory.CreateBitmap(1000, 1000, Win32.Graphics.Imaging.Apis.GUID_WICPixelFormat32bppPBGRA);

获取到 IWICBitmap 类型的对象,即可开始通过 D2D 工厂创建 ID2D1RenderTarget 画布。先创建 D2D 工厂

        using D2D.ID2D1Factory1 d2DFactory = D2D.D2D1.D2D1CreateFactory<D2D.ID2D1Factory1>();

接着设置渲染参数

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

创建 ID2D1RenderTarget 对象

        D2D.ID2D1RenderTarget d2D1RenderTarget =
d2DFactory.CreateWicBitmapRenderTarget(wicBitmap, renderTargetProperties);

以上就是最核心的步骤了,获取到 ID2D1RenderTarget 对象,即可开始 D2D 的绘制逻辑,如下面代码,修改画布颜色

        using var renderTarget = d2D1RenderTarget;
// 开始绘制逻辑
renderTarget.BeginDraw(); // 随意创建颜色
var color = new Color4((byte) Random.Shared.Next(255), (byte) Random.Shared.Next(255),
(byte) Random.Shared.Next(255));
renderTarget.Clear(color); renderTarget.EndDraw();

如此即可将内容绘制到 IWICBitmap 上

接下来是将 IWICBitmap 的内容保存到本地的图片,保存 IWICBitmap 需要先对 IWICBitmap 进行编码,编码时需要使用 WIC 工厂创建编码器,接着传入编码的格式和编码的输出

先打开一个文件用来存放编码的输出

        var file = @"D2D.png";
using (var fileStream = File.OpenWrite(file))
{
// 忽略代码
}

通过 WIC 工厂创建编码器,设置编码的格式是 png 格式

            using var wicBitmapEncoder =
wicImagingFactory.CreateEncoder(Win32.Graphics.Imaging.Apis.GUID_ContainerFormatPng);

设置编码的输出到文件

            wicBitmapEncoder.Initialize(fileStream);

从编码器创建出一张图片

            using var wicFrameEncode = wicBitmapEncoder.CreateNewFrame(out var _);
wicFrameEncode.Initialize();

将上文完成绘制的 IWICBitmap 输入到编码器里面

            wicFrameEncode.WriteSource(wicBitmap);

完成逻辑之后提交一下

            wicFrameEncode.Commit();
wicBitmapEncoder.Commit();

如此执行完成,即可将绘制的内容保存到本地文件里。这就是本文的采用 D2D 进行离屏绘制的方法

想不开的话,可以测试一下调用渲染时是否能跑满 GPU 资源,稍微更改一下渲染的代码,从原本的调用 Clear 修改颜色,修改为以下逻辑

        using var renderTarget = d2D1RenderTarget;
var stopwatch = Stopwatch.StartNew();
while (true)
{
// 开始绘制逻辑
renderTarget.BeginDraw(); // 随意创建颜色
var color = new Color4((byte) Random.Shared.Next(255), (byte) Random.Shared.Next(255),
(byte) Random.Shared.Next(255));
renderTarget.Clear(color);
color = new Color4(GetRandom(), GetRandom(), GetRandom());
using var brush = renderTarget.CreateSolidColorBrush(color); for (int i = 0; i < 1000; i++)
{
renderTarget.DrawEllipse(new D2D.Ellipse(new Vector2(GetRandom(), GetRandom()), 5, 5), brush, 2);
} stopwatch.Stop();
Console.WriteLine($"Draw: {stopwatch.ElapsedMilliseconds}");
stopwatch.Restart(); renderTarget.EndDraw(); stopwatch.Stop();
Console.WriteLine($"EndDraw: {stopwatch.ElapsedMilliseconds}");
stopwatch.Restart(); byte GetRandom() => (byte) Random.Shared.Next(255);
}

尝试运行代码,看看任务管理器里面,显示当前进程是否有用到 GPU 资源,以及占用了多少 GPU 资源

本文的代码放在githubgitee 欢迎访问

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

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

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

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

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

渲染部分,关于 SharpDx 使用,包括入门级教程,请参阅:

在 WPF 框架的渲染部分,请参阅: WPF 底层渲染_lindexi_gd的博客-CSDN博客

更多关于我博客请参阅 博客导航

交流 Vortice 技术,欢迎加群: 622808968

dotnet C# 使用 Vortice 支持 Direct2D1 离屏渲染的更多相关文章

  1. iOS 离屏渲染的研究

    GPU渲染机制: CPU 计算好显示内容提交到 GPU,GPU 渲染完成后将渲染结果放入帧缓冲区,随后视频控制器会按照 VSync 信号逐行读取帧缓冲区的数据,经过可能的数模转换传递给显示器显示. G ...

  2. iOS离屏渲染简书

    更详细地址https://zsisme.gitbooks.io/ios-/content/chapter15/offscreen-rendering.html(包含了核心动画) GPU渲染机制: CP ...

  3. 离屏渲染学习笔记 /iOS圆角性能问题

    离屏渲染学习笔记 一.概念理解 OpenGL中,GPU屏幕渲染有以下两种方式: On-Screen Rendering 意为当前屏幕渲染,指的是GPU的渲染操作是在当前用于显示的屏幕缓冲区中进行. O ...

  4. 腾讯优测优分享 | 探索react native首屏渲染最佳实践

    腾讯优测是专业的移动云测试平台,旗下的优分享不定时提供大量移动研发及测试相关的干货~ 此文主要与以下内容相关,希望对大家有帮助. react native给了我们使用javascript开发原生app ...

  5. [ios]离屏渲染优化

    原文链接:https://mp.weixin.qq.com/s?__biz=MjM5NTIyNTUyMQ==&mid=2709544818&idx=1&sn=62d0d2e9a ...

  6. 探索react native首屏渲染最佳实践

    文 / 腾讯 龚麒 0.前言 react native给了我们使用javascript开发原生app的能力,在使用react native完成兴趣部落安卓端发现tab改造后,我们开始对由react n ...

  7. iOS性能优化中的离屏渲染

    GPU屏幕渲染有以下两种方式: On-Screen Rendering意为当前屏幕渲染,指的是GPU的渲染操作是在当前用于显示的屏幕缓冲区中进行. Off-Screen Rendering意为离屏渲染 ...

  8. OpenGL于MFC使用汇总(三)——离屏渲染

    有时直接创建OpenGL形式不适合,或者干脆不同意然后创建一个表单,正如我现在这个项目,创建窗体不显示,它仅限于主框架.而我只是ActiveX里做一些相关工作,那仅仅能用到OpenGL的离屏渲染技术了 ...

  9. opengl离屏渲染(不需要和窗口绑定,仅当作一个可以渲染一张图片的API使用)+ opencv显示

    具体过程参考的是这篇BLOG: http://wiki.woodpecker.org.cn/moin/lilin/swig-glBmpContext 这一片BLOG的代码有个 BOOL SaveBmp ...

  10. IOS 中openGL使用教程4(openGL ES 入门篇 | 离屏渲染)

    通常情况下,我们使用openGL将渲染好的图片绘制到屏幕上,但有时候我们不想显示处理结果,这时候就需要使用离屏渲染了. 正常情况下,我们将屏幕,也就是一个CAEAGLLayer对象作为渲染目标,离屏渲 ...

随机推荐

  1. 一天涨 23k Star 的开源项目「GitHub 热点速览」

    ​在 GitHub 上做过开源项目的小伙伴,可能都经历过截图自己项目 100 Star.1000 Star 的时刻,但有些时候事情发生的太快来不及截图,因为可能一觉醒来就破万了.这件事看似有些天方夜谭 ...

  2. Solon Web 文件上传的最佳实践

    文件上传是 Web 开发中最常见的一个应用场景.一般在处理数据时,会有两种常见的方案:直接把文件流放在内存里,或者把文件流先缓冲到磁盘. 1.如果是高频且文件极小 使用纯内存模式,默认即可.如果高频小 ...

  3. vue三种插槽

    1. 作用:让父组件可以向子组件指定位置插入html结构,也是一种组件间通信的方式,适用于 父组件 ===> 子组件 . 2. 分类:默认插槽.具名插槽.作用域插槽 3. 使用方式: a.默认插 ...

  4. KingbaseES V8R3 运维案例 -- 单实例环境升级用户认证sha-256

    案例说明: 默认KingbaseES V8R3用户认证采用md5加密,有的生产环境对安全要求较高,需要将md5升级到sha-256:如果口令使用 scram-sha-256 设置加密,那么它可以被用于 ...

  5. C++代码实现OnComponentHit事件粒子消失蓝图--斯坦福

    蓝图节点 OnComponentBeginOverlap,OnComponentHit等等之类如何迁移到C++中 方法 这些蓝图节点实际上就是一个UE4已经定义好的事件,在蓝图中使用模块的连接来实现事 ...

  6. Amazon免费CE2基于docker部署nginx,并实现访问

    在部署之前,请确保你已经申请好了CE2免费的服务器,网上的相关教程很多,可以自由参考. 一.使用xshell+公钥连接实例 1.打开xshell,导入密钥, 选择"工具" -> ...

  7. 新零售SaaS架构:客户管理系统的应用架构设计

    客户管理系统的应用架构设计 应用层定义了软件系统的应用功能,负责接收用户的请求,协调领域层能力来执行任务,并将结果返回给用户,功能模块包括: 客户管理:核心功能模块,负责收集和更新客户信息,包括个人资 ...

  8. 七月练习:杀完NOIP全集

    注:标记☆的是我未理解透彻的,标记★的是已经理解完的重点. 7.31:所有题目已经上传! 7.1 CF581A Vasya the Hipster 水.随便找规律.(CF 乱入) P1199 [NOI ...

  9. JWT 安全令牌

    1 package com.reliable.yang.utils; 2 3 import io.jsonwebtoken.Jwt; 4 import io.jsonwebtoken.JwtBuild ...

  10. set集合的HashSet 类

    set是一个没有重复元素, 没有存储顺序的集合,它主要有三个实现类,如下: HashSet 类 HashSet 类是按照哈希算法来存储集合中的元素,当向 Set 集合中添加一个元素时,HashSet ...