DirectX11笔记(三)--Direct3D初始化2

2024-05-11 22:58

本文主要是介绍DirectX11笔记(三)--Direct3D初始化2,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

  • 一 总览 初始化Direct3D的步骤
  • 二 创建设备 ID3D11Device 和上下文 ID3D11DeviceContext
  • 三 检查所支持的4倍MSAA质量等级
  • 四 交换链
    • 描述交换链
    • 创建交换链
  • 五 同时创建设备 上下文和交换链
  • 六 创建Render Target视图
  • 七 创建深度模板缓冲和视图
    • 创建深度模板缓冲
    • 创建深度模板视图
  • 八 绑定视图到渲染管线
  • 九 设置视口 Viewport


  本篇文章将对初始化Direct3D的各个步骤进行详细的讲解, 在文章中只会引用必要的代码, 在文章最后会附带一个完整的代码链接, 希望学习D3D的你能在浏览完本篇内容之后参考示例代码, 构建好自己D3D程序的基础.


一 总览: 初始化Direct3D的步骤

  1. 创建ID3D11Device和ID3D11DeviceContext接口
  2. 检查所支持的4X MSAA的质量等级
  3. 描述交换链的特征
  4. 创建交换链
  5. 创建render target视图
  6. 创建一个深度模板缓冲和视图
  7. 绑定视图到渲染管线
  8. 设置视口( viewport )

二 创建设备( ID3D11Device )和上下文( ID3D11DeviceContext )

  这是初始化Direct3D的第一步, 所谓的设备和上下文实际是ID3D11DeviceID3D11DeviceContext这两个接口, 它们在D3D的接口中处于领导地位, 是显卡在软件层面的控制器.
  ID3D11Device : 检查支持的特性, 分配资源等
  ID3D11DeviceContext : 设置渲染状态, 绑定资源到图形管线, 发送渲染指令等

// 创建设备和上下文
/**
* pAdapter: 显示适配器, 为空时使用主显示适配器
* DriverType: 一般情况下都应该使用D3D_DRIVER_TYPE_HARDWARE
* Software: 因为上一个参数表明我们使用硬件, 这个参数一般都应该为null
* Flags: D3D11_CREATE_DEVICE_DEBUG用于调试, D3D11_CREATE_DEVICE_SINGLETHREADED如果能保证只有单线程这会提升效率, 但是多线程操作便会失败
* pFeatureLevels: 特征等级数组
* FeatureLevels: 特征等级的数量
* SDKVersion: D3D11_SDK_VERSION
* ppDevice: 返回的设备指针
* pFeatureLevel: 返回的第一个支持的特征等级
* ppImmediateContext: 返回的立即的上下文指针
*/
HRESULT D3D11CreateDevice(IDXGIAdapter *pAdapter,D3D_DRIVER_TYPE DriverType,HMODULE Software,UINT Flags,CONST D3D_FEATURE_LEVEL *pFeatureLevels,UINT FeatureLevels,UINT SDKVersion,ID3D11Device **ppDevice,D3D_FEATURE_LEVEL *pFeatureLevel,ID3D11DeviceContext **ppImmediateContext
);

  这是创建设备和上下文的一种方法, 但是在例子中我会使用另外一个接口D3D11CreateDeviceAndSwapChain, 在创建设备和上下文的同时创建交换链, 这个接口的参数和上文说明的基本一致, 只不过多出了交换链的部分.


三 检查所支持的4倍MSAA质量等级

  创建设备之后我们可以检查他支持的4倍MSAA质量等级, 所有的D3D设备都会支持所有格式的4倍MSAA, 所以检查出的质量等级始终应该大于0.
  ( 例子中并没有使用MSAA )

UINT m4xMsaaQuality;
HR(md3dDevice->CheckMultisampleQualityLevels(
DXGI_FORMAT_R8G8B8A8_UNORM, 4, & m4xMsaaQuality));
assert(m4xMsaaQuality > 0 );

四 交换链

描述交换链

  为了创建交换链, 我们先要创建一个交换链描述. 我们使用一个名为DXGI_SWAP_CHAIN_DESC的结构的实例来描述交换链.

/**
* BufferDesc: 描述back buffer
* 描述back buffer: MSAA的采样数
* BufferUsage: 一般为DXGI_USAGE_RENDER_TARGET_OUTPUT
* BufferCount: back buffer的数量
* OutputWindow: 渲染窗口的句柄
* Windowed: true: 窗口模式, false: 全屏模式
* SwapEffect: 一般为DXGI_SWAP_EFFECT_DISCARD, 让硬件使用最高效的方法.
*/
typedef struct DXGI_SWAP_CHAIN_DESC {DXGI_MODE_DESC BufferDesc;DXGI_SAMPLE_DESC SampleDesc;DXGI_USAGE BufferUsage;UINT BufferCount;HWND OutputWindow;BOOL Windowed;DXGI_SWAP_EFFECT SwapEffect;UINT Flags;
} DXGI_SWAP_CHAIN_DESC;// 之前的 DXGI_MODE_DESC 声明如下
typedef struct DXGI_MODE_DESC
{UINT Width;UINT Height;DXGI_RATIONAL RefreshRate;DXGI_FORMAT Format; // back buffer像素格式DXGI_MODE_SCANLINE_ORDER ScanlineOrdering;DXGI_MODE_SCALING Scaling;
} DXGI_MODE_DESC;

  例子中我们一般只会使用基础的, 常用的, 公用的属性值, 最具体的细节还是需要查阅文档.

创建交换链

  一个交换链的接口IDXGISwapChain 需要通过一个IDXGIFactory实例的CreateSwapChain方法创建.

/**
* pDevice: ID3D11Device 指针
* pDesc: DXGI_SWAP_CHAIN_DESC 指针
* ppSwapChain: 返回的交换链指针
*/
HRESULT IDXGIFactory::CreateSwapChain(IUnknown *pDevice,DXGI_SWAP_CHAIN_DESC *pDesc,IDXGISwapChain **ppSwapChain
);

五 同时创建设备, 上下文和交换链

  之前所说的创建交换链的方法有些麻烦, 需要额外使用一些DXGI的东西, 由于我们的例子中并不使用 MSAA , 所以在这里我使用D3D11CreateDeviceAndSwapChain一同创建设备, 上下文, 交换链. 这个接口相当于上面所说的两个接口的整合, 具体的参数可以去文档查找.

六 创建Render Target视图

  在前一篇文章里我们提到过, D3D不会直接将资源绑定到渲染管线的某个阶段, 而是创建一个资源视图并将这个视图与渲染管线绑定. 为了将back buffer和渲染管线的输出合并阶段绑定, 所以我们会创建这个Render Target视图.

ID3D11Texture2D* pBackBuffer = NULL;
hr = g_pSwapChain->GetBuffer( 0,__uuidof( ID3D11Texture2D ),( LPVOID* )&pBackBuffer
);
hr = g_pd3dDevice->CreateRenderTargetView(pBackBuffer, NULL,&g_pRenderTargetView
);
pBackBuffer->Release();

  通过上面的方法我们会创建出RenderTargetView. 可以看出, 其实我们所说的back buffer就是一张2D纹理. 利用我们之前创建的交换链可以获取到这张纹理, 然后就可以让g_pd3dDevice使用它创建Render Target视图.


七 创建深度模板缓冲和视图

创建深度模板缓冲

  深度模板缓冲之前也已经有过说明, 他是也一张2D纹理, 存储着深度信息. 为了创建这张纹理, 我们首先需要有一个2D纹理的描述D3D11_TEXTURE2D_DESC.

/**
* BindFlags: 表明纹理资源被绑定到渲染管线的什么阶段, 对于深度模板缓冲, 应该是D3D11_BIND_DEPTH_STENCIL
* CPUAccessFlags: 表明CPU将如何访问资源, 但是深度模板缓冲只有GPU会进行读写, 所以这里可以填0
* MiscFlags: 对深度模板缓冲没有影响, 所以也填0
*/
typedef struct D3D11_TEXTURE2D_DESC {UINT Width;UINT Height;UINT MipLevels;UINT ArraySize;DXGI_FORMAT Format;DXGI_SAMPLE_DESC SampleDesc;D3D11_USAGE Usage;UINT BindFlags;UINT CPUAccessFlags;UINT MiscFlags;
} D3D11_TEXTURE2D_DESC;g_pd3dDevice->CreateTexture2D(&descDepth, NULL,&g_pDepthStencil
);

  创建好描述之后, 我们便可以使用这个描述利用CreateTexture2D接口创建纹理, 这个纹理就是深度模板缓冲.

创建深度模板视图

  创建方法和创建RenderTargetView相似, 这里使用CreateDepthStencilView创建深度模板视图. 深度模板视图也有对应的描述D3D11_DEPTH_STENCIL_VIEW_DESC来说明视图信息, 详细信息可以文档查阅, 这里不再多做说明.

D3D11_DEPTH_STENCIL_VIEW_DESC descDSV;
ZeroMemory(&descDSV, sizeof(descDSV));
descDSV.Format = descDepth.Format;
descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
descDSV.Texture2D.MipSlice = 0;
hr = g_pd3dDevice->CreateDepthStencilView(g_pDepthStencil,&descDSV,&g_pDepthStencilView
);

八 绑定视图到渲染管线

  我们创建的视图就是为了让他们成为渲染管线的渲染目标和深度模板缓冲. 经过这步绑定, 我们就可以实现这一需求: 将两个视图绑定到渲染管线的输出合并阶段, 使渲染管线可以使用相应资源.

g_pImmediateContext->OMSetRenderTargets(1, &g_pRenderTargetView,g_pDepthStencilView
);

  第一个参数是RenderTargetView的数目, 我们只使用一个, 但是D3D本身支持多个. 第二个参数之所以要加”&”是因为他表示的其实是RenderTargetView数组的第一个元素( 可以支持多个嘛~ ), 第三参数就是深度模板视图.


九 设置视口( Viewport )

  我们一般都会把场景画到整个back buffer中, 但是我们也不能排除需要将场景画到back buffer一部分的可能性. 这个”back buffer的一部分“便是所谓的视口Viewport.
  我们使用一个结构体D3D11_VIEWPORT来说明视口的信息.

typedef struct D3D11_VIEWPORT {FLOAT TopLeftX;FLOAT TopLeftY;FLOAT Width;FLOAT Height;FLOAT MinDepth;FLOAT MaxDepth;
} D3D11_VIEWPORT;

  这里需要注意的是 D3D 的深度缓冲的取值范围是[0, 1], MinDepth和MaxDepth在没有特别需求的时候应该设置为这些值.
  最后我们会通过ID3D11DeviceContextRSSetViewports 方法设置视口.


示例代码

这篇关于DirectX11笔记(三)--Direct3D初始化2的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/980895

相关文章

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

【学习笔记】 陈强-机器学习-Python-Ch15 人工神经网络(1)sklearn

系列文章目录 监督学习:参数方法 【学习笔记】 陈强-机器学习-Python-Ch4 线性回归 【学习笔记】 陈强-机器学习-Python-Ch5 逻辑回归 【课后题练习】 陈强-机器学习-Python-Ch5 逻辑回归(SAheart.csv) 【学习笔记】 陈强-机器学习-Python-Ch6 多项逻辑回归 【学习笔记 及 课后题练习】 陈强-机器学习-Python-Ch7 判别分析 【学

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识

c++的初始化列表与const成员

初始化列表与const成员 const成员 使用const修饰的类、结构、联合的成员变量,在类对象创建完成前一定要初始化。 不能在构造函数中初始化const成员,因为执行构造函数时,类对象已经创建完成,只有类对象创建完成才能调用成员函数,构造函数虽然特殊但也是成员函数。 在定义const成员时进行初始化,该语法只有在C11语法标准下才支持。 初始化列表 在构造函数小括号后面,主要用于给

论文阅读笔记: Segment Anything

文章目录 Segment Anything摘要引言任务模型数据引擎数据集负责任的人工智能 Segment Anything Model图像编码器提示编码器mask解码器解决歧义损失和训练 Segment Anything 论文地址: https://arxiv.org/abs/2304.02643 代码地址:https://github.com/facebookresear

数学建模笔记—— 非线性规划

数学建模笔记—— 非线性规划 非线性规划1. 模型原理1.1 非线性规划的标准型1.2 非线性规划求解的Matlab函数 2. 典型例题3. matlab代码求解3.1 例1 一个简单示例3.2 例2 选址问题1. 第一问 线性规划2. 第二问 非线性规划 非线性规划 非线性规划是一种求解目标函数或约束条件中有一个或几个非线性函数的最优化问题的方法。运筹学的一个重要分支。2

【C++学习笔记 20】C++中的智能指针

智能指针的功能 在上一篇笔记提到了在栈和堆上创建变量的区别,使用new关键字创建变量时,需要搭配delete关键字销毁变量。而智能指针的作用就是调用new分配内存时,不必自己去调用delete,甚至不用调用new。 智能指针实际上就是对原始指针的包装。 unique_ptr 最简单的智能指针,是一种作用域指针,意思是当指针超出该作用域时,会自动调用delete。它名为unique的原因是这个

查看提交历史 —— Git 学习笔记 11

查看提交历史 查看提交历史 不带任何选项的git log-p选项--stat 选项--pretty=oneline选项--pretty=format选项git log常用选项列表参考资料 在提交了若干更新,又或者克隆了某个项目之后,你也许想回顾下提交历史。 完成这个任务最简单而又有效的 工具是 git log 命令。 接下来的例子会用一个用于演示的 simplegit

记录每次更新到仓库 —— Git 学习笔记 10

记录每次更新到仓库 文章目录 文件的状态三个区域检查当前文件状态跟踪新文件取消跟踪(un-tracking)文件重新跟踪(re-tracking)文件暂存已修改文件忽略某些文件查看已暂存和未暂存的修改提交更新跳过暂存区删除文件移动文件参考资料 咱们接着很多天以前的 取得Git仓库 这篇文章继续说。 文件的状态 不管是通过哪种方法,现在我们已经有了一个仓库,并从这个仓

忽略某些文件 —— Git 学习笔记 05

忽略某些文件 忽略某些文件 通过.gitignore文件其他规则源如何选择规则源参考资料 对于某些文件,我们不希望把它们纳入 Git 的管理,也不希望它们总出现在未跟踪文件列表。通常它们都是些自动生成的文件,比如日志文件、编译过程中创建的临时文件等。 通过.gitignore文件 假设我们要忽略 lib.a 文件,那我们可以在 lib.a 所在目录下创建一个名为 .gi