本文将告诉大家如何通过 Vortice 使用 D2D 的特效

本文属于 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>();

接下来咱将创建 D2D 设备,再通过 D2D 设备,从而拿到 ID2D1DeviceContext 对象,设置 DXGI 平面作为 ID2D1DeviceContext 输出,如此即可使用继承自 ID2D1RenderTarget 的 ID2D1DeviceContext 进行绘制界面。此步骤更详细的内容,请参阅 dotnet DirectX 通过 Vortice 控制台使用 ID2D1DeviceContext 绘制画面

        DXGI.IDXGIDevice dxgiDevice = d3D11Device.QueryInterface<DXGI.IDXGIDevice>();
ID2D1Device d2dDevice = d2DFactory.CreateDevice(dxgiDevice);
ID2D1DeviceContext d2dDeviceContext = d2dDevice.CreateDeviceContext(); // 设置 DXGI 平面作为 ID2D1DeviceContext 输出
ID2D1Bitmap1 d2dBitmap = d2dDeviceContext.CreateBitmapFromDxgiSurface(dxgiSurface);
d2dDeviceContext.Target = d2dBitmap;

使用 Direct2D 特效之前,需要先了解一些概念。在 Direct2D 里面,可使用 ID2D1Effect 特效,特效的常用方法就是先使用 SetInput 方法将某个 ID2D1Bitmap 设置为输入源,再通过 SetValue 设置一些参数。最后将特效放入到 ID2D1DeviceContext 的 DrawImage 方法绘制出来

在 Direct2D 里面有许多内建特效,作为入门的博客,咱随便选一个简单的 GaussianBlur 特效作为例子。先通过 ID2D1DeviceContext 创建出特效,代码如下

                var gaussianBlurEffect = d2dDeviceContext.CreateEffect(EffectGuids.GaussianBlur);
using ID2D1Effect d2dEffect = new ID2D1Effect(gaussianBlurEffect);

创建出来的特效现在是缺少输入源的,接下来咱随便写一点代码创建一个 ID2D1Bitmap 作为输入源。为了方便编写例子,我这里采用的是创建放在内存里的 IWICBitmap 作为画布,通过自己绘制的内容作为 ID2D1Bitmap 输出,方法如下

        ID2D1Bitmap CreateBitmap()
{
using var wicImagingFactory = new IWICImagingFactory();
using IWICBitmap wicBitmap =
wicImagingFactory.CreateBitmap(1000, 1000, Win32.Graphics.Imaging.Apis.GUID_WICPixelFormat32bppPBGRA);
var renderTargetProperties = new D2D.RenderTargetProperties(Vortice.DCommon.PixelFormat.Premultiplied);
using D2D.ID2D1RenderTarget wicBitmapRenderTarget =
d2DFactory.CreateWicBitmapRenderTarget(wicBitmap, renderTargetProperties);
wicBitmapRenderTarget.BeginDraw();
using var brush = wicBitmapRenderTarget.CreateSolidColorBrush(color);
wicBitmapRenderTarget.FillEllipse(new Ellipse(new System.Numerics.Vector2(200, 200), 100, 100), brush);
wicBitmapRenderTarget.EndDraw(); ID2D1Bitmap1 intputBitmap = renderTarget.CreateBitmapFromWicBitmap(wicBitmap);
return intputBitmap;
}

以上代码不是本文的重点,大家也可以采用加载本地图片等方式获取到 ID2D1Bitmap 对象。如何加载本机图片,请参阅 WPF 对接 Vortice 在 Direct2D 绘制从 WIC 加载的图片

获取到 ID2D1Bitmap 对象,即可调用 SetInput 方法设置输入源,代码如下

                using ID2D1Bitmap intputBitmap = CreateBitmap();

                d2dEffect.SetInput(0, intputBitmap, new RawBool(true));

接着使用 SetValue 方法设置特效的一些参数,特效的参数都是灵活的。此 SetValue 方法的第一个参数表示的是将要设置特效的哪个参数,第二个参数才是特效参数的值,例如以下代码,设置模糊度

                const int D2D1_GAUSSIANBLUR_PROP_STANDARD_DEVIATION = 0;
d2dEffect.SetValue(D2D1_GAUSSIANBLUR_PROP_STANDARD_DEVIATION, 2.5f);

完成特效的设置之后,即可调用 DrawImage 方法将特效结果绘制出来,代码如下

                renderTarget.DrawImage(d2dEffect);

以上就是特效的入门玩法,可以通过高性能的 Direct2D 特效,绘制出绚丽的界面

下面是特效使用部分的代码

        // 创建 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; var stopwatch = Stopwatch.StartNew();
var count = 0; // 随意创建颜色
var color = new Color4((byte) Random.Shared.Next(255), (byte) Random.Shared.Next(255),
(byte) Random.Shared.Next(255)); Task.Factory.StartNew(() =>
{
while (true)
{
// 开始绘制逻辑
renderTarget.BeginDraw(); // 清空画布
renderTarget.Clear(new Color4(0xFF,0xFF,0xFF)); // 随便创建一张图片
using var inputBitmap = CreateBitmap(); var gaussianBlurEffect = d2dDeviceContext.CreateEffect(EffectGuids.GaussianBlur);
using ID2D1Effect d2dEffect = new ID2D1Effect(gaussianBlurEffect); d2dEffect.SetInput(0, inputBitmap, new RawBool(true));
const int D2D1_GAUSSIANBLUR_PROP_STANDARD_DEVIATION = 0;
d2dEffect.SetValue(D2D1_GAUSSIANBLUR_PROP_STANDARD_DEVIATION, count / 60f * 3f); renderTarget.DrawImage(d2dEffect); renderTarget.EndDraw(); swapChain.Present(1, DXGI.PresentFlags.None);
// 等待刷新
d3D11DeviceContext.Flush(); // 统计刷新率
count++;
if (stopwatch.Elapsed >= TimeSpan.FromSeconds(1))
{
Console.WriteLine($"FPS: {count / stopwatch.Elapsed.TotalSeconds}");
stopwatch.Restart();
count = 0;
}
}
}, TaskCreationOptions.LongRunning); ID2D1Bitmap CreateBitmap()
{
using var wicImagingFactory = new IWICImagingFactory();
using IWICBitmap wicBitmap =
wicImagingFactory.CreateBitmap(1000, 1000, Win32.Graphics.Imaging.Apis.GUID_WICPixelFormat32bppPBGRA);
var renderTargetProperties = new D2D.RenderTargetProperties(Vortice.DCommon.PixelFormat.Premultiplied);
using D2D.ID2D1RenderTarget wicBitmapRenderTarget =
d2DFactory.CreateWicBitmapRenderTarget(wicBitmap, renderTargetProperties);
wicBitmapRenderTarget.BeginDraw();
using var brush = wicBitmapRenderTarget.CreateSolidColorBrush(color);
wicBitmapRenderTarget.FillEllipse(new Ellipse(new System.Numerics.Vector2(200, 200), 100, 100), brush);
wicBitmapRenderTarget.EndDraw(); ID2D1Bitmap1 inputBitmap = renderTarget.CreateBitmapFromWicBitmap(wicBitmap);
return inputBitmap;
}

以上代码将可以动态绘制一个模糊度不断变化的圆,代码省略和没有写的部分,我放在了 githubgitee 上,可以通过以下方式获取整个项目的代码

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

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

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

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

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

有伙伴好奇为什么我最近写的是通过 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 C# 通过 Vortice 使用 Direct2D 特效入门的更多相关文章

  1. [Direct2D1.1教程] Direct2D特效概览

    转载请注明出处:http://www.cnblogs.com/Ray1024 一.概述 Direct2D是一个基于Direct3D的2D图形API,可以利用硬件加速特性来提供高性能高质量的2D渲染.但 ...

  2. 【Direct2D1.1初探】Direct2D特效概览

    转载请注明出处:http://www.cnblogs.com/Ray1024 一.概述 Direct2D是一个基于Direct3D的2D图形API,可以利用硬件加速特性来提供高性能高质量的2D渲染.但 ...

  3. dotnet OpenXML 转换 PathFillModeValues 为颜色特效

    在 OpenXml 预设形状,有一些形状设置了 PathFillModeValues 枚举,此枚举提供了亮暗的蒙层特效.具体的特效是让形状选择一个画刷,在画刷上加上特效.如立体几何 Cube 形状,在 ...

  4. dotnet core on Linux 环境搭建及入门demo

    首先感谢张善友大大提供的腾讯云实验室链接(https://www.qcloud.com/developer/labs/list). 以下是整个搭建过程及简单demo实例 1.搭建 .NET Core ...

  5. Unity3D特效入门教学视频教程合集

    目录 大小25GB,Mp4格式,语言:中文 扫码时备注或说明中留下邮箱 付款后如未回复请至https://shop135452397.taobao.com/ 联系店主

  6. WPF 像素着色器入门:使用 Shazzam Shader Editor 编写 HLSL 像素着色器代码

    原文:WPF 像素着色器入门:使用 Shazzam Shader Editor 编写 HLSL 像素着色器代码 HLSL,High Level Shader Language,高级着色器语言,是 Di ...

  7. 在 WinForm 中使用 Direct2D

    在 C# 的 WinForm 应用中,界面的绘制使用的是 GDI+.不过在一些特别的应用中,可能需要用硬件加速来提高绘制的效率.下面就来介绍两种在 WinForm 应用中嵌入 Direct2D 的方法 ...

  8. Event Hub小白入门指南

    Event Hub事件中心 本文的目的在于用最白的大白话,让你从“完全不懂”开始,理解什么是分布式大数据流平台Event Hub,并且理解它的关键概念,并且初步理解其收发数据API. 定义,Event ...

  9. Aure Event Hubs小白完全入门指南

    refer to https://www.cnblogs.com/mysunnytime/p/11634815.html?from=groupmessage&isappinstalled=0 ...

  10. unity博文搜集

    一.综合篇 1. 脚本 unity3d脚本编程基础 2.Mecanim 使用Mecanim实现连击 3. 数学图形学 U3D需要用到的数学基础  2 4. shader 猫都能学会的Unity3D S ...

随机推荐

  1. 重新记录一下ArcGisEngine安装的过程

    前言 好久不用Arcgis,突然发现想用时,有点不会安装了,所以这里记录一下安装过程. 下载Arcgis 首先,下载一个arcgis版本,我这里下的是10.1. 推荐[ gis思维(公众号)],[麻辣 ...

  2. 基础教材系列:编译原理——B站笔记

    一.编译器是什么 源程序→预处理器→经过预处理的源程序→编译器→汇编语言程序→汇编器→可重定位的机器代码→链接器/加载器→目标机器代码. 编译器的结构: 与源语言相关:字符流→词法分析器→词法单元流→ ...

  3. Avalonia项目生成银河麒麟操作系统安装包

    1 在项目根目录添加xxx.desktop文件,文件内容: [Desktop Entry] Name=xxx Type=Application Exec=/usr/share/xxx/xxx Icon ...

  4. Oracle 触发器迁移至KingbaseES常见的问题

    oracle数据库的触发器迁移到KingbaseES的时候经常会出现一下两类错误: 1.SQL 错误 [42809]: 错误: "xxxxxxxx" 是一个视图.Detail: 视 ...

  5. Scala打印输出

    1 package com.atguigu.chapter02 2 object TestCharType { 3 def main(args: Array[String]): Unit = { 4 ...

  6. 【已解决】Hadoop_03 解决Hadoop输入jps没有NameNode的问题

    问题描述: 解决方案: 1.先运行 stop-all.sh 2.格式化 namdenode(在这之前要先删除原目录,即core-site.xml下配置的<name>hadoop.tmp.d ...

  7. 鸿蒙HarmonyOS实战-ArkUI组件(Progress)

    一.Progress Progress组件是一种用户界面(UI)元素,用于向用户显示某些任务的进度.它通常以进度条的形式出现,显示任务完成的百分比.Progress组件可以在确定任务持续时间未知的情况 ...

  8. #2-SAT,平面图#洛谷 3209 [HNOI2010] 平面图判定

    题目传送门 分析 首先一张图是平面图的必要条件为 \(m\leq 3*n-6\), 然后考虑到这题的图存在哈密尔顿回路,也就是说非环边因为跨立形成奇环即为无解 那么直接拆点跑2-SAT就可以了 代码 ...

  9. #线性基#LOJ 114 k大异或和

    题目 分析 建出线性基后,但是要求最小所以要重建线性基让大的尽量小, 然后第k小就是拼凑 代码 #include <cstdio> #include <cctype> #inc ...

  10. 深入了解 Python MongoDB 操作:排序、删除、更新、结果限制全面解析

    Python MongoDB 排序 对结果进行排序 使用 sort() 方法对结果进行升序或降序排序. sort() 方法接受一个参数用于"字段名",一个参数用于"方向& ...