[WinUI 3] 如何利用D3D11在SwapChainPanel控件上绘制OpenGL(Uwp通用)
预览



技术实现
看过我上篇在 WPF 中实现 OpenGL 与 D3D 渲染的同学应该知道,我是依靠 WGL 中 WGL_NV_DX_interop 扩展与 D3D Surface 关联并在使用该 Surface 实现渲染。
所以我们这次实现也是如此,但与 WPF 不同的是 WinUI 支持 D3D11 并在控件中提供 SwapChainPanel 作为载体。(WPF 中为 D3DImage)
代码部分使用 Silk.Net 和 OpenTK 实现。
有一些关键部分,接下来我会单独讲下。
WGL_NV_DX_interop
WGL_NV_DX_interop是NVIDIA公司提出的一套扩展API(支持OpenGL 2.1及以上版本),该扩展允许 OpenGL 可以直接访问 DirectX 缓冲区与 Surface,并作为 OpenGL 共享纹理或渲染缓冲区对象使用。
扩展支持版本
WGL_NV_DX_interop - Direct3D 9
WGL_NV_DX_interop2 - Direct3D 10、11
D3D11与SwapChainPanel
SwapChainPanel 是用于支持高性能图形和游戏的 Windows 运行时类型,你可以在其中直接管理交换链。
在此情况下,你可以创建自己的 DirectX 交换链并管理所呈现内容的显示。
需要注意的是,为了确保良好的性能 SwapChainPanel 存在一些限制。
- 一个程序中 SwapChainPanel 实例不能超过四个。
- 关联的 DirectX 交换链应要明确设置宽高。
- DirectX 交换链的缩放模式必须设置为 DXGI_SCALING_STRETCH。
- 只能通过 DXGI 中 CreateSwapChainForComposition 函数进行交换链创建。
代码实现 (只存在关键代码,完整代码在文章最下方 GitHub 链接)
D3D
- 创建 DXGI 工厂,用于后续创建 SwapChain(交换链)
IDXGIFactory2* factory;
// 获取该类型 Guid,这跟Com组件有关,本文不多阐述。
// GetTypeInfo 为扩展函数,存在 WinRT 命名空间。
Guid guid = typeof(IDXGIFactory2).GetTypeInfo().GUID;
DXGI.GetApi().CreateDXGIFactory2(0, &guid, (void**)&factory);
- 创建设备
ID3D11Device* device;
ID3D11DeviceContext* devCtx;
// 创建设备
D3D11.GetApi().CreateDevice(null, D3DDriverType.Hardware, 0, 0, null, 0, D3D11.SdkVersion, &device, null, &devCtx);
- 创建 SwapChain (使用 IDXGIFactory2 创建)
IDXGISwapChain1* swapChain;
// SwapChain 配置信息。
SwapChainDesc1 swapChainDesc = new()
{
Width = 宽度,
Height = 高度,
Format = Format.FormatB8G8R8A8Unorm,
Stereo = 0,
SampleDesc = new SampleDesc()
{
Count = 1,
Quality = 0
},
BufferUsage = DXGI.UsageRenderTargetOutput,
BufferCount = 2,
Scaling = Scaling.Stretch,
SwapEffect = SwapEffect.FlipSequential,
Flags = 0,
};
factory->CreateSwapChainForComposition((IUnknown*)device, &swapChainDesc, null, &swapChain);
- 获取 SwapChain 缓冲区(我们需要用它来创建 OpenGL 的渲染缓冲区)
ID3D11Texture2D* colorbuffer;
Guid guid = typeof(ID3D11Texture2D).GetTypeInfo().GUID;
swapChain->GetBuffer(0, &guid, (void**)&colorbuffer);
OpenGL
- 创建 GL 设备与帧缓冲区
nint glDeviceHandle = Wgl.DXOpenDeviceNV((IntPtr)device);
// 创建一个帧缓冲区,后续渲染前需要先进行绑定。
int gLFramebufferHandle = GL.GenFramebuffer();
- 关联 SwapChain 缓冲区
// 创建一个渲染缓冲区。
int gLColorRenderbufferHandle = GL.GenRenderbuffer();
// 关联 SwapChain 缓冲区到指定 Renderbuffer 上。
nint dxInteropColorHandle = Wgl.DXRegisterObjectNV(device, (nint)colorbuffer, (uint)gLColorRenderbufferHandle, (uint)RenderbufferTarget.Renderbuffer, WGL_NV_DX_interop.AccessReadWrite);
- 渲染
// 锁定缓冲区进行操作
Wgl.DXLockObjectsNV(glDeviceHandle, 1, new[] { dxInteropColorHandle });
// 绑定帧缓冲区
GL.BindFramebuffer(FramebufferTarget.Framebuffer, gLFramebufferHandle);
// 重置视口
GL.Viewport(0, 0, 宽度, 高度);
// GL 绘制代码
// 结束绘制
GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
Wgl.DXUnlockObjectsNV(glDeviceHandle, 1, new[] { dxInteropColorHandle });
// 注意:一定要取消注册并删除缓冲区,不然 swapChain 读取不到数据。
Wgl.DXUnregisterObjectNV(glDeviceHandle, dxInteropColorHandle);
GL.DeleteRenderbuffer(gLColorRenderbufferHandle);
swapChain->Present(1, 0);
关联 WinUI
- 创建 ISwapChainPanelNative 接口类
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("63aad0b8-7c24-40ff-85a8-640d944cc325")]
public interface ISwapChainPanelNative
{
[PreserveSig] HResult SetSwapChain([In] IntPtr swapChain);
[PreserveSig] ulong Release();
}
- 与 SwapChain 关联
SwapChainPanel swapChainPanel = new SwapChainPanel();
swapChainPanel.As<ISwapChainPanelNative>().SetSwapChain((IntPtr)swapChain)
基本上,一次的渲染流程到这里就结束了。
但有很多问题需要解决,比如修改控件宽高,重新注册缓冲区等等。。。
完整代码我会放到 GitHub 上,需要的同学可以下载看看,里面包含 WPF、WinUI 的 3D Demo,并解决了刚才说的一些问题。
WPF、WinUI 使用 Silk.Net 绘制示例(OpenGL、DirectX)
[WinUI 3] 如何利用D3D11在SwapChainPanel控件上绘制OpenGL(Uwp通用)的更多相关文章
- 如何在双向绑定的Image控件上绘制自定义标记(wpf)
我们的需求是什么? 答:需要在图片上增加一些自定义标记,例如:2个图片对比时,对相同区域进行高亮. 先上效果图: 设计思路 1.概述 1.通过TargeUpdated事件,重新绘制图片进行替换. 2. ...
- c#在pictureBox控件上绘制多个矩形框及删除绘制的矩形框
在pictureBox上每次只绘制一个矩形框,绘制下一个矩形框时上次绘制的矩形框取消,代码如链接:https://www.cnblogs.com/luxiao/p/5625196.html 在绘制矩形 ...
- 利用foreach对页面控件的遍历 及三目运算符的使用
1.利用foreach对页面控件的遍历 及三目运算符的使用 利用div将一组CheckBox放在一起用于遍历 <body> <form id="form1" ru ...
- 详解如何利用FarPoint Spread表格控件来构造Winform的Excel表格界面输入
我们先来简单了解一下WinForm和FarPoint,WinForm是·Net开发平台中对Windows Form的一种称谓.而FarPoint是一款模拟EXCEL的控件.它可以根据用户的要求实现很大 ...
- 在GridControl控件上绑定图片的几种操作方式
我们知道,基于DevExpress的开发Winform的项目界面的时候,GridControl控件是经常用来绑定数据的,一般以常规的字符内容为主,有时候也会有图片的显示需要,那么如果显示图片,我们应该 ...
- 对话框上动态控件的创建、在Picture Control控件上显示图片
1 MFC对话框之上的动态控件的创建 对话框上的控件是MFC类的一个具体对象. 当在对话框之上使用静态控件时,可以根据类向导来为每个控件添加消息.响应函数以及变量. 当需要在对话框中动态的创建某个控 ...
- Windows 程序设计(4) MFC-02 基本控件-上
1. Button 按钮控件 1.1.按钮控件的基本使用 新建对话框工程,拖拽按钮控件,添加点击事件响应函数! a.双击模版进行添加: b.事件方式进行添加: button的常见事件类型 void C ...
- 在创建窗口句柄之前,不能在控件上调用 Invoke 或 BeginInvoke
今天关闭一个窗体,报出这样的一个错误"在创建窗口句柄之前,不能在控件上调用 Invoke 或 BeginInvoke.",这个不用多想,肯定是那个地方没有释放掉.既然碰到这个问题, ...
- [MFC] MFC 打开HTML资源(用ID版,也可加载到自己的web控件上)
@ ^ @:如果是加载到web控件上,就把注释掉的解除注释(改为web控件点后面的函数),把下一句注释 BOOL Button::LoadFromResource(UINT nRes){//打开网页加 ...
- Cocos2dx 把 glview 渲染到 Qt 控件上(Mac 环境)
本文原链接:http://www.cnblogs.com/zouzf/p/4423256.html 环境:Mac 10.9.2 Xcode5.1.1 Qt5.3 cocos2dx-2.2.4 ...
随机推荐
- Unity算法之A星- A*Pathfind Project插件的使用
先上效果图 首先上 插件地址 (如果没有积分可以评论区联系我) 1.下载完毕后导入unity 导入后可以在Component里面看到多了一个Pathfinding选项 2.场景搭建 首先新建两个层 ...
- rpm制作(简)
yum -y install gcc prec-devel openssl-devel zlib-devel yum -y install rpm-build #生成工作目录 rpmdev-setup ...
- bootstrapTable insertRow 新增行保留原数据
思路:保留原数据,然后新增行. var optionsxx = {//省略xxx: columns: [{ checkbox: true}, { field: 'id', title: '主键', c ...
- mysql 获取表信息 表备注等
select table_name, table_comment, create_time, update_time from information_schema.tables-- where ta ...
- linux系统分类
1.RedHat系列:Redhat.Centos.Fedora等 2.Debian系列:Debian.Ubuntu等 RedHat 系列 1 常见的安装包格式 rpm包,安装rpm包的命令是" ...
- maven资源导出问题
<!--在build中配置resources,来防止我们资源导出失败的问题--> <build> <resources> <resource> < ...
- vivado程序示例
//full_add.v 全加器 module full_add( input a, input b, input carry, output sum, output count ); assign ...
- Call API URL连接拼参数的方法
void TestNTFD() { try { try { ...
- matlab 将某文件夹的内容复制到另一文件下
%% 清空close all;clear;clc; %% 选择文件路径(复制某文件夹下部分文件夹到其他路径)folder = uigetdir('C:\Desktop','请选择文件夹'); %% i ...
- git在linux安装步骤详解!!
linux上安装,以centos 7.x为例 yum命令安装 yum install gityum install 安装的git不是最新版本,如需最新版本需要自行编译 到下面的网站下载合适的版本 ht ...