当前位置: 首页 > news >正文

哈尔滨建站公司模板销售平台有哪些

哈尔滨建站公司模板,销售平台有哪些,网站策划资料方案,电商购物网站模板下载引言 查看龙书时发现#xff0c;第四章介绍预备知识的代码不太利于学习。因为它不像是LearnOpenGL那样从头开始一步一步教你敲代码#xff0c;导致你没有一种整体感。如果你把它当作某一块的代码进行学习#xff0c;你跟着敲会发现#xff0c;总有几个变量是没有定义的。这…引言 查看龙书时发现第四章介绍预备知识的代码不太利于学习。因为它不像是LearnOpenGL那样从头开始一步一步教你敲代码导致你没有一种整体感。如果你把它当作某一块的代码进行学习你跟着敲会发现总有几个变量是没有定义的。这是因为书上的代码都是把框架里的某一部分粘过来缺少上文中对变量的定义也根本不利于学习。学习图形学API就是为了使用GPU进行图形运算说白了我们学习的DirectX就是一个工具因此熟练掌握工具、能使用工具生产作品才是最重要的。因此不妨从4.3开始学习学到那块不会再查了解前面的预备知识就会好很多。由于现在学习的代码都是框架中的一部分因此我的学习方法是  1. 看书学习理论并查看书中代码。  2. 在VS中CtrlF搜索书中代码对照搜索到的代码框架跟着敲。如果遇到哪个变量是未定义的直接Ctrl鼠标左键(点击未定义的变量)跳转到这个变量的定义后复制定义到我的代码里。  3. 如果遇到书中未详细介绍的内容直接在MSDN查询相关信息。下图展示了我从4.3章节开始根据龙书源代码框架学习书本示例代码的过程 本文包含的核心英文单词和释义如下 英文单词中文含义Create创建Fence围栏Factory工厂Controller控制器Failed失败FEATURE特性Level级别Adapter适配器Enable启用Enum枚举Descriptor描述符Handle句柄Increment增量HEAP堆TYPE LESS无类型Support支持Quality质量Sample Count采样数NORM规范MULTI多Flags标志command命令Queue队列DESC描述Allocator分配器DIRECT直接的Address住址Refresh Rate刷新率numerator分子Denominator分母Scanline Ordering扫描线排序MODE模式SCANLINE扫描线UNSPECIFIED未指明Scaling缩放RENDER TARGET OUTPUT渲染目标输出 一、初始化Direct3D 初始化Direct3D的9个步骤如下 步骤序号步骤内容1用 D3D12CreateDevice 函数创建 ID3D12Device 接口实例2创建一个 ID3D12Fence 对象并查询描述符的大小3检测用户设备对 4X MSAA 质量级别的支持4依次创建命令队列、命令列表分配器和主命令列表5描述并创建交换链6创建应用程序所需的描述符堆7调整后台缓冲区的大小并为它创建渲染目标视图8创建深度/模板缓冲区及与之关联的深度/模板视图9设置视口和裁剪矩形 书中的代码没有上下文和完整框架不妨跟着我一起学先看书中4.3章对每一个步骤的描述再查看我提供的完整代码二者对照岂不美哉本文第一章分为九个小节对应初始化Direct3d的九个步骤每个小节第一部分提供了完整可运行代码第二部分提供代码涉及的知识点。 1创建设备 1.1 完整示例 要初始Direct3D必须先创建Direct3D设备ID3D12Device。Direce3D设备代表着一个显示适配器显示适配器一般指3D图形硬件即显卡。但是显示适配器也可以用软件来代替通过模拟硬件显卡的计算处理过程软件也可以作为适配器如WARP适配器。Direct3D设备既可以检测系统环境对功能的支持情况又能创建所有其他的Direct3D接口对象如资源、视图和命令列表。创建Direct3D设备使用函数D3D12CreateDevice。话不多说直接上代码 #includewindows.h // windows API编程所需 #includewrl.h // 提供了ComPtr类它是COM对象的智能指针使我们无需手动Release #included3d12.h // Direct3D12头文件ID3D12开头类型始于此 #includedxgi1_4.h // DirectX图形基础设施头文件IDXGI开头类型始于此 #includestring // 提供wsring类,在Windows平台上应该使用wstring和wchar_tusing namespace Microsoft::WRL; // 方便使用Microsoft::WRL::ComPtr类 // AnsiToWString函数将字符串映射到 UTF-16 (宽字符) 字符串 inline std::wstring AnsiToWString(const std::string str) {WCHAR buffer[512];MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, buffer, 512);return std::wstring(buffer); }// 定义异常类 class DxException { public:DxException() default;// 显示异常函数的返回值、函数名、代码所处文件名所处代码行数DxException(HRESULT hr, const std::wstring functionName, const std::wstring filename, int lineNumber);std::wstring ToString()const;HRESULT ErrorCode S_OK;std::wstring FunctionName;std::wstring Filename;int LineNumber -1; };// 如果发生异常抛出一个异常实例 #ifndef ThrowIfFailed #define ThrowIfFailed(x) \ { \HRESULT hr__ (x); \std::wstring wfn AnsiToWString(__FILE__); \if(FAILED(hr__)) { throw DxException(hr__, L#x, wfn, __LINE__); } \ } #endif// IDXGIFactory: DXGI中最关键的接口之一可以枚举显示适配器 ComPtrIDXGIFactory4 mdxgiFactory;// ID3D12Device: 代表一个显示适配器显卡 ComPtrID3D12Device md3dDevice;// 初始化Direct3D bool InitDirect3D() { #if defined(DEBUG) || defined(_DEBUG) // 如果在Debug模式启用D3D12的调试层// 启用调试后D3D会在错误发生时向VC的输出窗口发送调试信息{ComPtrID3D12Debug debugController;ThrowIfFailed(D3D12GetDebugInterface(IID_PPV_ARGS(debugController)));debugController-EnableDebugLayer();} #endif// 创建可用于生成其他 DXGI 对象的 DXGI 1.0 FactoryThrowIfFailed(CreateDXGIFactory1(IID_PPV_ARGS(mdxgiFactory)));// 尝试创建一个D3D硬件适配器// D3D12CreateDevice参数为(适配器指针应用程序所需最低功能级别// 所建ID3D12Device接口的COM ID返回所创建的D3D12设备HRESULT hardwareResult D3D12CreateDevice(nullptr,D3D_FEATURE_LEVEL_12_0,IID_PPV_ARGS(md3dDevice));// 适配器指针传入空代表使用主显示适配器// 可以分析出需要COM指针即riid的地方通过使用IID_PPV_ARGS即可// 如果创建失败应用程序回退至WARP软件适配器if (FAILED(hardwareResult)){ComPtrIDXGIAdapter pWarpAdapter;ThrowIfFailed(mdxgiFactory-EnumWarpAdapter(IID_PPV_ARGS(pWarpAdapter)));// 不同windows版本的WARP最高支持的功能级别也不同// 再次创建D3D设备时仅适配器指针参数不同传入WARP适配器指针ThrowIfFailed(D3D12CreateDevice(pWarpAdapter.Get(),D3D_FEATURE_LEVEL_12_0,IID_PPV_ARGS(md3dDevice)));} }int WINAPI WinMain(_In_ HINSTANCE hInstance,_In_opt_ HINSTANCE hPrevInstance,_In_ LPSTR lpCmdLine,_In_ int nShowCmd) {// 在主函数中调用Direct3D的初始化函数InitDirect3D(); }代码如上大致过一遍有个记忆就行。如果对其中哪些地方有疑问或者好奇可以在MSDN上搜索相关类型或函数查看相关信息。 1.2 相关知识 组件对象模型Component Object ModelCOM是一种令DirectX不受编程语言束缚并且使之向后兼容的技术。我们通常将COM对象视为一种接口但由于我们的编程目的我们可以把它当作一个C类来使用。当我们使用C编写DirectX程序时COM帮我们隐藏了大量的底层细节。我们只需要知道要获取指向某COM接口的指针需借助特定函数或另一COM接口的方法。Windows运行时库Windows Runtime LibraryWRL为COM对象提供了Microsoft::WRL::ComPtr类它位于wrl.h头文件中它是COM对象的智能指针。当一个COM对象超出作用域范围时智能指针会调用相应COM对象的Release方法省去了我们手动调用的麻烦。书中的COM接口、对象和指针让我晕头转向因为我并没有接触过COM技术。分析一下上文示例代码中有 // IDXGIFactory: DXGI中最关键的接口之一可以枚举显示适配器 ComPtrIDXGIFactory4 mdxgiFactory;// ID3D12Device: 代表一个显示适配器显卡 ComPtrID3D12Device md3dDevice;无论是IDXGIFactory4还是ID3D12Device这两种Direct3D中的对象都是通过COM指针来表示的。因此我们现在可以知道的是  使用C开发Direct3D应用程序时每个Direct3D对象都是一种COM对象或者说COM接口我们要记录对象就要使用COM指针我们要获取这种对象就要使用特定函数或另一COM对象的方法。不必迷茫只需要知道Direct3D对象的记录和获取方法如下即可 // Direct3D对象的记录方法 ComPtrDirect3D对象类型 对象名。// Direct3d对象的获取方法 对象名 特定函数(); 对象名 其他Direct3D对象.函数();ComPtr类的三个常用函数如下 函数名描述Get返回指向此底层COM对象的指针GetAddressOf返回指向此底层COM对象的指针的地址Rest将ComPtr实例设置为nullptr释放与之相关的所有引用 注意  Rest函数的作用和将ComPtr对象赋值为nullptr的效果相同。  COM对象都以大写字母 “I” 开头例如表示设备的COM对象为ID3D12Device。  COM对象、COM接口、COM实例都是一个意思。读到这里就清楚了吧为了使DirectX不受语言束缚DirectX中的对象都被定义为一种以 “I” 开头的COM对象。而使用COM对象最方便的方法就是使用COM指针即ComPtr类因此我们使用ComPtr类记录每个DirectX对象即可。如果读者对Windows平台为什么要使用wstring等问题感兴趣可以查找MSDN或其他搜索。如果对IID_PPV_ARGS宏感兴趣可以查看书籍4.2.1即95页中间对其描述这个宏会展开为两项第一项根据__uuidof获取了COM对象的ID全局唯一标识符GUID。IID_PPV_ARGS辅助函数本质是把指针强制转换为void类型。 #define IID_PPV_ARGS(ppType) __uuidof(**(ppType)), IID_PPV_ARGS_Helper(ppType)2创建围栏并获取描述符的大小 2.1 完整示例 CPU和GPU的同步需要使用到围栏第一步中我们创建好设备第二步就可以创建围栏了。另外如果使用描述符进行工作需要获取描述符的大小。描述符在不同GPU平台上的大小不同因此我们需要将获取的描述符大小信息缓存起来方便需要时直接引用。话不多说直接上代码 // ID3D12Fence: 表示围栏ComPtrID3D12Fence mFence;// 创建围栏ThrowIfFailed(md3dDevice-CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(mFence)));// RTV描述符大小RTV描述符: 渲染目标视图资源UINT mRtvDescriptorSize 0;// DSV描述符大小DSV描述符: 深度/模板视图资源UINT mDsvDescriptorSize 0;// CbvSrvUav描述符大小CBV描述符: 常量缓冲区视图资源...UINT mCbvSrvUavDescriptorSize 0;// 获取描述符大小mRtvDescriptorSize md3dDevice-GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);mDsvDescriptorSize md3dDevice-GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_DSV);mCbvSrvUavDescriptorSize md3dDevice-GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);上述代码直接放在第一步 InitDirect3D 函数末尾即可需要注意的是mFence、mRtvDescriptorSize和mDsvDescriptorSize等变量应该定义为全局变量上文为易于理解才写在函数内部。可以看到新出现的四个变量都是通过 md3dDevice 对象获取到的印证了  1. “Direct3D12 设备对象能创建所有其他的Direct3D接口对象”。  2. “COM对象需要使用特定方法或通过其他COM对象的方法获取”。 2.2 相关知识 资源与描述符详见4.1.6节。在渲染过程中GPU需要对资源进行读和写。但是GPU和资源并不是直接绑定的而是通过一个媒婆 “描述符” 这个中间人进行绑定的。描述符是一种对送往GPU的资源进行描述的轻量级结构它是一个中间层。当GPU需要对资源进行读或写时GPU就会问媒婆“资源在哪里我应该按照哪种数据格式进行读写”。可见描述符的作用有两点  1. 指定资源数据。  2. 为GPU解释资源信息。创建资源时可用无类型格式如DXGI_FORMAT_R8G8B8A8_TYPELESS类型我们知道它是4个分量组成每个分量占8个位但是我们不知道每个分量的8个位应该解析为整数、浮点数还是无符号整数如果某个资源在创建时采用了无类型格式那么在为它创建描述符时必须指明其具体类型。注意视图和描述符的含义是等价的。每个描述符都有一种具体类型此类型指明了资源的具体作用。常用的描述符如下 描述符含义CBV常量缓冲区视图SRV着色器资源视图UAV无序访问视图sampler采样器资源描述符RTV渲染目标视图资源DSV深度/模板视图资源 描述符堆中存有一系列描述符本质上是存放用户程序中某特定类型描述符的一块内存。我们需要为每一种类型的描述符创建出单独的描述符当然同一种描述符也可以创建多个描述符堆。我们可以用不同的描述符来描述同一个资源达到以不同的数据格式或内容部分去读写资源的目的。由于创建描述符的过程中需要执行一些类型的检测和验证工作索引最好不要在运行时才创建描述符创建描述符的最佳时机为初始化期间。当然有时确实需要使用无类型资源所带来的灵活性此时在一定限度内可以考虑在运行时创建描述符。 3检测对4X MSAA 质量级别的支持 3.1 完整示例 本书中我们要使用4X MSAA之所以选择4X是因为借助此采样数量就可以获取开销不高但性能非凡的效果。而使用4X MSAA之前我们要先检查设备是否支持4X MSAA 质量级别的图像。话不多说直接上代码 #includewindows.h // windows API编程所需 #includewrl.h // 提供了ComPtr类它是COM对象的智能指针使我们无需手动Release #included3d12.h // Direct3D12头文件ID3D12开头类型始于此 #includedxgi1_4.h // DirectX图形基础设施头文件IDXGI开头类型始于此 #includestring // 提供wsring类,在Windows平台上应该使用wstring和wchar_t #includeassert.husing namespace Microsoft::WRL; // 方便使用Microsoft::WRL::ComPtr类 // AnsiToWString函数将字符串映射到 UTF-16 (宽字符) 字符串 inline std::wstring AnsiToWString(const std::string str) {WCHAR buffer[512];MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, buffer, 512);return std::wstring(buffer); }// 定义异常类 class DxException { public:DxException() default;// 显示异常函数的返回值、函数名、代码所处文件名所处代码行数DxException(HRESULT hr, const std::wstring functionName, const std::wstring filename, int lineNumber);std::wstring ToString()const;HRESULT ErrorCode S_OK;std::wstring FunctionName;std::wstring Filename;int LineNumber -1; };// 如果发生异常抛出一个异常实例 #ifndef ThrowIfFailed #define ThrowIfFailed(x) \ { \HRESULT hr__ (x); \std::wstring wfn AnsiToWString(__FILE__); \if(FAILED(hr__)) { throw DxException(hr__, L#x, wfn, __LINE__); } \ } #endif// IDXGIFactory: DXGI中最关键的接口之一可以枚举显示适配器 ComPtrIDXGIFactory4 mdxgiFactory;// ID3D12Device: 代表一个显示适配器显卡 ComPtrID3D12Device md3dDevice;// 初始化Direct3D bool InitDirect3D() { #if defined(DEBUG) || defined(_DEBUG) // 如果在Debug模式启用D3D12的调试层// 启用调试后D3D会在错误发生时向VC的输出窗口发送调试信息{ComPtrID3D12Debug debugController;ThrowIfFailed(D3D12GetDebugInterface(IID_PPV_ARGS(debugController)));debugController-EnableDebugLayer();} #endif// 创建可用于生成其他 DXGI 对象的 DXGI 1.0 FactoryThrowIfFailed(CreateDXGIFactory1(IID_PPV_ARGS(mdxgiFactory)));// 第一步// 创建一个D3D设备// D3D12CreateDevice参数为(适配器指针应用程序所需最低功能级别// 所建ID3D12Device接口的COM ID返回所创建的D3D12设备HRESULT hardwareResult D3D12CreateDevice(nullptr,D3D_FEATURE_LEVEL_12_0,IID_PPV_ARGS(md3dDevice));// 适配器指针传入空代表使用主显示适配器// 可以分析出需要COM指针即riid的地方通过使用IID_PPV_ARGS即可// 如果创建失败应用程序回退至WARP软件适配器if (FAILED(hardwareResult)){ComPtrIDXGIAdapter pWarpAdapter;ThrowIfFailed(mdxgiFactory-EnumWarpAdapter(IID_PPV_ARGS(pWarpAdapter)));// 不同windows版本的WARP最高支持的功能级别也不同// 再次创建D3D设备时仅适配器指针参数不同传入WARP适配器指针ThrowIfFailed(D3D12CreateDevice(pWarpAdapter.Get(),D3D_FEATURE_LEVEL_12_0,IID_PPV_ARGS(md3dDevice)));}// 第二步// ID3D12Fence: 表示围栏ComPtrID3D12Fence mFence;// 创建围栏ThrowIfFailed(md3dDevice-CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(mFence)));// RTV描述符大小RTV描述符: 渲染目标视图资源UINT mRtvDescriptorSize 0;// DSV描述符大小DSV描述符: 深度/模板视图资源UINT mDsvDescriptorSize 0;// CbvSrvUav描述符大小CBV描述符: 常量缓冲区视图资源...UINT mCbvSrvUavDescriptorSize 0;// 获取描述符大小mRtvDescriptorSize md3dDevice-GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);mDsvDescriptorSize md3dDevice-GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_DSV);mCbvSrvUavDescriptorSize md3dDevice-GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);// 第三步// DXGI_FORMAT: 资源数据的格式一种枚举类型 DXGI_FORMAT mBackBufferFormat DXGI_FORMAT_R8G8B8A8_UNORM;// 检测对4X MASS质量级别的支持D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS msQualityLevels;msQualityLevels.Format mBackBufferFormat; // 纹理格式msQualityLevels.SampleCount 4; // 采样次数msQualityLevels.Flags D3D12_MULTISAMPLE_QUALITY_LEVELS_FLAG_NONE; // 默认选项msQualityLevels.NumQualityLevels 0; // 质量级别// 使用ID3D12Device::CheckFeatureSupport函数查询我们设置的这种图像质量的级别ThrowIfFailed(md3dDevice-CheckFeatureSupport(D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS,msQualityLevels,sizeof(msQualityLevels)));// 使用无符号整数存储我们查询的图像质量所对应的质量级别不为零则说明支持UINT m4xMsaaQuality 0;// 我们查询的采样数为4因此返回的质量级别即为达到4X MSAA的质量级别m4xMsaaQuality msQualityLevels.NumQualityLevels;// 只要返回的质量级别不为零则表示支持此种图像质量在该处即支持4X MSAAassert(m4xMsaaQuality 0 Unexpected MSAA quality level.); }int WINAPI WinMain(_In_ HINSTANCE hInstance,_In_opt_ HINSTANCE hPrevInstance,_In_ LPSTR lpCmdLine,_In_ int nShowCmd) {InitDirect3D(); }在此给出完整代码若读者对第二步的完整代码不清楚也可以在此查看。可以看到我们先定义了一种资源类型的格式那就是要查询的纹理格式。你可以把代码复制到你的项目里运行试试当然你要记得使用Windows API开发项目如果只会创建控制台项目你可以看看我之前文章中的第六步。详细的讲解都在代码里了我就不多说了。我的显卡不是很好但运行后依旧不会报错你可以试试运行如果报错就说明你的显卡不支持这种4X MSAA 的图像质量级别了。你可以将纹理资源的格式改为DXGI_FORMAT_R16G16B16A16_UNORM这样的纹理显然更精细点然后再运行试试。多次运行你发现都不会报错你觉得要么是程序错了要么是你的显卡太棒了那不妨试试修改采样数量即msQualityLevels.SampleCount将它改为8、16和32呢 3.2 相关知识 多重采样技术的原理位于4.1.7小节在书籍85页我就不做过多阐述了。需要注意的是ID3DDevice-CheckFeatureSupport方法的第二个参数兼具输入和输出的属性。如果不希望使用多重采样可以将采用数量设置为1并将质量级别设为0。在创建交换链缓冲区和深度缓冲区时都需要填写DXGI_SAMPLE_DESC结构体。当创建后台缓冲区和深度缓冲区时多重采样的有关设置必须相同。功能支持的检测位于4.1.11小节。函数ID3D12Device::CheckFeatureSupport可以对许多功能进行检测其第一个参数的类型是一个枚举类D3D12_FEATURE第二个参数是枚举类对应的数据结构指针第三个参数是传入的数据结构变量所占字节数。使用ID3D12Device::CheckFeatureSupport检测系统支持Direct3D最高版本的代码为 #includewindows.h // windows API编程所需 #includewrl.h // 提供了ComPtr类它是COM对象的智能指针使我们无需手动Release #included3d12.h // Direct3D12头文件ID3D12开头类型始于此 #includedxgi1_4.h // DirectX图形基础设施头文件IDXGI开头类型始于此 #includestring // 提供wsring类,在Windows平台上应该使用wstring和wchar_t #includeassert.husing namespace Microsoft::WRL; // 方便使用Microsoft::WRL::ComPtr类 // AnsiToWString函数将字符串映射到 UTF-16 (宽字符) 字符串 inline std::wstring AnsiToWString(const std::string str) {WCHAR buffer[512];MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, buffer, 512);return std::wstring(buffer); }// 定义异常类 class DxException { public:DxException() default;// 显示异常函数的返回值、函数名、代码所处文件名所处代码行数DxException(HRESULT hr, const std::wstring functionName, const std::wstring filename, int lineNumber);std::wstring ToString()const;HRESULT ErrorCode S_OK;std::wstring FunctionName;std::wstring Filename;int LineNumber -1; };// 如果发生异常抛出一个异常实例 #ifndef ThrowIfFailed #define ThrowIfFailed(x) \ { \HRESULT hr__ (x); \std::wstring wfn AnsiToWString(__FILE__); \if(FAILED(hr__)) { throw DxException(hr__, L#x, wfn, __LINE__); } \ } #endif// IDXGIFactory: DXGI中最关键的接口之一可以枚举显示适配器 ComPtrIDXGIFactory4 mdxgiFactory;// ID3D12Device: 代表一个显示适配器显卡 ComPtrID3D12Device md3dDevice;// 初始化Direct3D bool InitDirect3D() { #if defined(DEBUG) || defined(_DEBUG) // 如果在Debug模式启用D3D12的调试层// 启用调试后D3D会在错误发生时向VC的输出窗口发送调试信息{ComPtrID3D12Debug debugController;ThrowIfFailed(D3D12GetDebugInterface(IID_PPV_ARGS(debugController)));debugController-EnableDebugLayer();} #endif// 创建可用于生成其他 DXGI 对象的 DXGI 1.0 FactoryThrowIfFailed(CreateDXGIFactory1(IID_PPV_ARGS(mdxgiFactory)));// 创建一个D3D设备// D3D12CreateDevice参数为(适配器指针应用程序所需最低功能级别// 所建ID3D12Device接口的COM ID返回所创建的D3D12设备HRESULT hardwareResult D3D12CreateDevice(nullptr,D3D_FEATURE_LEVEL_12_0,IID_PPV_ARGS(md3dDevice));// 适配器指针传入空代表使用主显示适配器// 可以分析出需要COM指针即riid的地方通过使用IID_PPV_ARGS即可// 如果创建失败应用程序回退至WARP软件适配器if (FAILED(hardwareResult)){ComPtrIDXGIAdapter pWarpAdapter;ThrowIfFailed(mdxgiFactory-EnumWarpAdapter(IID_PPV_ARGS(pWarpAdapter)));// 不同windows版本的WARP最高支持的功能级别也不同// 再次创建D3D设备时仅适配器指针参数不同传入WARP适配器指针ThrowIfFailed(D3D12CreateDevice(pWarpAdapter.Get(),D3D_FEATURE_LEVEL_12_0,IID_PPV_ARGS(md3dDevice)));}// ID3D12Fence: 表示围栏ComPtrID3D12Fence mFence;// 创建围栏ThrowIfFailed(md3dDevice-CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(mFence)));// RTV描述符大小RTV描述符: 渲染目标视图资源UINT mRtvDescriptorSize 0;// DSV描述符大小DSV描述符: 深度/模板视图资源UINT mDsvDescriptorSize 0;// CbvSrvUav描述符大小CBV描述符: 常量缓冲区视图资源...UINT mCbvSrvUavDescriptorSize 0;// 获取描述符大小mRtvDescriptorSize md3dDevice-GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);mDsvDescriptorSize md3dDevice-GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_DSV);mCbvSrvUavDescriptorSize md3dDevice-GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);// DXGI_FORMAT: 资源数据的格式一种枚举类型 DXGI_FORMAT mBackBufferFormat DXGI_FORMAT_R8G8B8A8_UNORM;// 检测对4X MASS质量级别的支持D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS msQualityLevels;msQualityLevels.Format mBackBufferFormat; // 纹理格式msQualityLevels.SampleCount 4; // 采样次数msQualityLevels.Flags D3D12_MULTISAMPLE_QUALITY_LEVELS_FLAG_NONE; // 默认选项msQualityLevels.NumQualityLevels 0; // 质量级别// 使用ID3D12Device::CheckFeatureSupport函数查询我们设置的这种图像质量的级别ThrowIfFailed(md3dDevice-CheckFeatureSupport(D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS,msQualityLevels,sizeof(msQualityLevels)));// 使用无符号整数存储我们查询的图像质量所对应的质量级别不为零则说明支持UINT m4xMsaaQuality 0;// 我们查询的采样数为4因此返回的质量级别即为达到4X MSAA的质量级别m4xMsaaQuality msQualityLevels.NumQualityLevels;// 只要返回的质量级别不为零则表示支持此种图像质量在该处即支持4X MSAAassert(m4xMsaaQuality 0 Unexpected MSAA quality level.);// 检测支持的Direct3D最高版本// 需要检测的版本D3D_FEATURE_LEVEL feature[3] {D3D_FEATURE_LEVEL_12_0,D3D_FEATURE_LEVEL_12_1,D3D_FEATURE_LEVEL_12_2,};// 枚举类型对应的数据结构D3D12_FEATURE_DATA_FEATURE_LEVELS featureLevelsInfo;featureLevelsInfo.NumFeatureLevels 3; // 检测三种版本featureLevelsInfo.pFeatureLevelsRequested feature; // 检测的版本// 执行检测函数md3dDevice-CheckFeatureSupport(D3D12_FEATURE_FEATURE_LEVELS,featureLevelsInfo,sizeof(featureLevelsInfo));// 返回支持的最高版本可以打个断点查看一下featureLevelsInfo.MaxSupportedFeatureLevel; }int WINAPI WinMain(_In_ HINSTANCE hInstance,_In_opt_ HINSTANCE hPrevInstance,_In_ LPSTR lpCmdLine,_In_ int nShowCmd) {InitDirect3D(); }我最高支持的版本是D3D_FEATURE_LEVEL_12_1。真是太捞了等工作有钱了去买一台intel i9 4090那时候估计就不贵了释放性能 4创建命令队列和列表 4.1 完整示例 我们需要使用命令队列来存储GPU需要执行的命令用命令列表来存储CPU想要提交的命令。过程非常简单让我们直接来做吧代码如下 #includewindows.h // windows API编程所需 #includewrl.h // 提供了ComPtr类它是COM对象的智能指针使我们无需手动Release #included3d12.h // Direct3D12头文件ID3D12开头类型始于此 #includedxgi1_4.h // DirectX图形基础设施头文件IDXGI开头类型始于此 #includestring // 提供wsring类,在Windows平台上应该使用wstring和wchar_t #includeassert.husing namespace Microsoft::WRL; // 方便使用Microsoft::WRL::ComPtr类 // AnsiToWString函数将字符串映射到 UTF-16 (宽字符) 字符串 inline std::wstring AnsiToWString(const std::string str) {WCHAR buffer[512];MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, buffer, 512);return std::wstring(buffer); }// 定义异常类 class DxException { public:DxException() default;// 显示异常函数的返回值、函数名、代码所处文件名所处代码行数DxException(HRESULT hr, const std::wstring functionName, const std::wstring filename, int lineNumber);std::wstring ToString()const;HRESULT ErrorCode S_OK;std::wstring FunctionName;std::wstring Filename;int LineNumber -1; };// 如果发生异常抛出一个异常实例 #ifndef ThrowIfFailed #define ThrowIfFailed(x) \ { \HRESULT hr__ (x); \std::wstring wfn AnsiToWString(__FILE__); \if(FAILED(hr__)) { throw DxException(hr__, L#x, wfn, __LINE__); } \ } #endif// IDXGIFactory: DXGI中最关键的接口之一可以枚举显示适配器 ComPtrIDXGIFactory4 mdxgiFactory;// ID3D12Device: 代表一个显示适配器显卡 ComPtrID3D12Device md3dDevice;// ID3D12Fence: 表示围栏 ComPtrID3D12Fence mFence;// RTV描述符大小RTV描述符: 渲染目标视图资源 UINT mRtvDescriptorSize 0; // DSV描述符大小DSV描述符: 深度/模板视图资源 UINT mDsvDescriptorSize 0; // CbvSrvUav描述符大小CBV描述符: 常量缓冲区视图资源... UINT mCbvSrvUavDescriptorSize 0;// DXGI_FORMAT: 资源数据的格式一种枚举类型 DXGI_FORMAT mBackBufferFormat DXGI_FORMAT_R8G8B8A8_UNORM;// 使用无符号整数存储我们查询的图像质量所对应的质量级别不为零则说明支持 UINT m4xMsaaQuality 0;// 第四步: 创建命令队列和命令列表 void CreateCommandObjects() {// 声明一个命令队列ComPtrID3D12CommandQueue mCommandQueue;// 调用ID3D12Device::CreateCommandQueue方法创建队列前// 需要填写D3D12_COMMAND_QUEUE_DESC结构体来描述队列D3D12_COMMAND_QUEUE_DESC queueDesc {};// 定义队列中的命令类型queueDesc.Type D3D12_COMMAND_LIST_TYPE_DIRECT;// 设置其他选项为空queueDesc.Flags D3D12_COMMAND_QUEUE_FLAG_NONE;// 调用ID3D12Device::CreateCommandQueue方法创建命令队列ThrowIfFailed(md3dDevice-CreateCommandQueue(queueDesc, IID_PPV_ARGS(mCommandQueue)));// 声明ID3D12CommandAllocator命令内存管理对象ComPtrID3D12CommandAllocator mCommandAllocator;// 记录在命令列表内的命令实际上是存储在与之关联的命令分配器上// 通过ID3D12Device创建命令分配器ID3D12CommandAllocatorThrowIfFailed(md3dDevice-CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, // 与此命令分配器关联的命令列表类型IID_PPV_ARGS(mCommandAllocator.GetAddressOf()) ));// 通过ID3D12Device创建命令列表ID3D12GraphicsCommandListComPtrID3D12GraphicsCommandList mCommandList;ThrowIfFailed(md3dDevice-CreateCommandList(0, // 指定与所建命令列表相关联的物理GPU对于仅有一个GPU的系统而言设为0D3D12_COMMAND_LIST_TYPE_DIRECT, // 命令列表的类型mCommandAllocator.Get(), // 关联的命令分配器nullptr, // 打包和初始化无绘制命令时传nullptrIID_PPV_ARGS(mCommandList.GetAddressOf())// 输出指向所建列表的指针));// 在关闭状态下启动// 这是因为当我们第一次引用命令列表时我们会重置它并且在调用Reset之前需要关闭它。mCommandList-Close(); }// 初始化Direct3D bool InitDirect3D() { #if defined(DEBUG) || defined(_DEBUG) // 如果在Debug模式启用D3D12的调试层// 启用调试后D3D会在错误发生时向VC的输出窗口发送调试信息{ComPtrID3D12Debug debugController;ThrowIfFailed(D3D12GetDebugInterface(IID_PPV_ARGS(debugController)));debugController-EnableDebugLayer();} #endif/*第一步创建Direct3D设备*/ // 创建可用于生成其他 DXGI 对象的 DXGI 1.0 FactoryThrowIfFailed(CreateDXGIFactory1(IID_PPV_ARGS(mdxgiFactory)));// 创建一个D3D设备// D3D12CreateDevice参数为(适配器指针应用程序所需最低功能级别// 所建ID3D12Device接口的COM ID返回所创建的D3D12设备HRESULT hardwareResult D3D12CreateDevice(nullptr,D3D_FEATURE_LEVEL_12_0,IID_PPV_ARGS(md3dDevice));// 适配器指针传入空代表使用主显示适配器// 可以分析出需要COM指针即riid的地方通过使用IID_PPV_ARGS即可// 如果创建失败应用程序回退至WARP软件适配器if (FAILED(hardwareResult)){ComPtrIDXGIAdapter pWarpAdapter;ThrowIfFailed(mdxgiFactory-EnumWarpAdapter(IID_PPV_ARGS(pWarpAdapter)));// 不同windows版本的WARP最高支持的功能级别也不同// 再次创建D3D设备时仅适配器指针参数不同传入WARP适配器指针ThrowIfFailed(D3D12CreateDevice(pWarpAdapter.Get(),D3D_FEATURE_LEVEL_12_0,IID_PPV_ARGS(md3dDevice)));}/*第二步创建围栏并计算描述符大小*/// 创建围栏ThrowIfFailed(md3dDevice-CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(mFence)));// 获取描述符大小mRtvDescriptorSize md3dDevice-GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);mDsvDescriptorSize md3dDevice-GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_DSV);mCbvSrvUavDescriptorSize md3dDevice-GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);/*第三步检测系统对4X MSAA的支持*/// 检测对4X MSAA质量级别的支持D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS msQualityLevels;msQualityLevels.Format mBackBufferFormat; // 纹理格式msQualityLevels.SampleCount 4; // 采样次数msQualityLevels.Flags D3D12_MULTISAMPLE_QUALITY_LEVELS_FLAG_NONE; // 默认选项msQualityLevels.NumQualityLevels 0; // 质量级别// 使用ID3D12Device::CheckFeatureSupport函数查询我们设置的这种图像质量的级别ThrowIfFailed(md3dDevice-CheckFeatureSupport(D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS,msQualityLevels,sizeof(msQualityLevels)));// 我们查询的采样数为4因此返回的质量级别即为达到4X MSAA的质量级别m4xMsaaQuality msQualityLevels.NumQualityLevels;// 只要返回的质量级别不为零则表示支持此种图像质量在该处即支持4X MSAAassert(m4xMsaaQuality 0 Unexpected MSAA quality level.);CreateCommandObjects(); }int WINAPI WinMain(_In_ HINSTANCE hInstance,_In_opt_ HINSTANCE hPrevInstance,_In_ LPSTR lpCmdLine,_In_ int nShowCmd) {InitDirect3D(); }可以看到在函数CreateCommandObjects()中我们完成了命令队列和命令列表的创建当然为了易于理解我将命令队列、命令列表和命令分配器声明为了局部变量你应该把它们放到函数外面作为全局变量如下所示 // 声明一个命令队列 ComPtrID3D12CommandQueue mCommandQueue;// 声明ID3D12CommandAllocator命令内存管理对象 ComPtrID3D12CommandAllocator mCommandAllocator;// 通过ID3D12Device创建命令列表ID3D12GraphicsCommandList ComPtrID3D12GraphicsCommandList mCommandList;void CreateCommandObjects() {// 调用ID3D12Device::CreateCommandQueue方法创建队列前// 需要填写D3D12_COMMAND_QUEUE_DESC结构体来描述队列D3D12_COMMAND_QUEUE_DESC queueDesc {};// 定义队列中的命令类型queueDesc.Type D3D12_COMMAND_LIST_TYPE_DIRECT;// 设置其他选项为空queueDesc.Flags D3D12_COMMAND_QUEUE_FLAG_NONE;// 调用ID3D12Device::CreateCommandQueue方法创建命令队列ThrowIfFailed(md3dDevice-CreateCommandQueue(queueDesc, IID_PPV_ARGS(mCommandQueue)));// 记录在命令列表内的命令实际上是存储在与之关联的命令分配器上// 通过ID3D12Device创建命令分配器ID3D12CommandAllocatorThrowIfFailed(md3dDevice-CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, // 与此命令分配器关联的命令列表类型IID_PPV_ARGS(mCommandAllocator.GetAddressOf()) ));ThrowIfFailed(md3dDevice-CreateCommandList(0, // 指定与所建命令列表相关联的物理GPU对于仅有一个GPU的系统而言设为0D3D12_COMMAND_LIST_TYPE_DIRECT, // 命令列表的类型mCommandAllocator.Get(), // 关联的命令分配器nullptr, // 打包和初始化无绘制命令时传nullptrIID_PPV_ARGS(mCommandList.GetAddressOf())// 输出指向所建列表的指针));// 在关闭状态下启动// 这是因为当我们第一次引用命令列表时我们会重置它并且在调用Reset之前需要关闭它。mCommandList-Close(); }现在你就不会感觉好像什么都没有得到了吧从这里我们也可以看出初始化Direct3D工作的一大重点就是声明一系列核心的Direct3D变量并且在初始化时获取它们 4.2 相关知识 在进行图形学编程的时候有两种处理器在参与工作CPU和GPU。两者并行运行但有时也需要同步。为了获得最佳性能理想的情况下是不进行同步但许多时候同步是必须要进行的。每个GPU都至少维护着一个命令队列本质上是环形缓冲区即ring buffer。使用Direct3D APICPU可利用命令列表将命令提交到这个队列中去。当一系列命令被提交至命令队列之时它们并不会被GPU立即执行。由于GPU可能正在处理先前插入命令队列因此新到达的命令常常会先等待再执行。如果命令队列全空会浪费GPU大量的运算能力。如果命令队列全满会导致CPU不可避免的等待因此会浪费CPU大量的运算能力。对于游戏这样的高性能应用程序来说应该充分利用硬件资源保持CPU和GPU的同时忙碌。ExecuteCommandLists是一种常用的ID3D12CommandQueue接口对象方法利用它可将命令列表里的命令添加到命令队列中。它包含两个参数第一个参数是UINT型变量代表命令列表中命令的数量第二个参数是命令列表数组的首指针。GPU会从数组中的第一个命令开始顺序执行。ID3D12GraphicsCommandList接口封装了一系列图形渲染命令它实际上继承于ID3D12CommandList接口。调用其方法即可向命令列表添加命令但需要注意的是命令并不会立即执行其方法仅仅是将命令加入了命令列表而已。调用ExecuteCommandLists方法才会将命名真正地送入命令队列供GPU在合适的时机处理。随着内容不断深入我们将逐步掌握D3D12GraphicsCommandList所支持的各种命令。当命令被加入命令列表后我们必须调用D3D12GraphicsCommandList::Close()方法来结束命令的记录。在调用ExecuteCommandLists方法将命令提交给命令列表之前一定要先将其关闭即调用Close方法。我们可以通过ID3D12Device-GetNodeCount()方法查询系统中GPU适配器节点物理GPU的数量。很明显每个命令列表对应一个命令分配器那么一个命令分配器是否可以对应多个命令列表呢答案是可以的我们可以让一个命令分配器关联多个命令列表但必须关闭同一命令分配器的其他命令列表即任何时候只能有一个命令列表处于打开状态。这保证了命令列表中的所有命令都会按顺序连续地添加到命令分配器内即只有当正在使用的命令列表使用完已关闭时其他命令列表才可以使用。注意当创建或重置一个命令列表时它会处于 “打开” 的状态因此你如果为同一个命令分配器连续创建或重置两个命令列表时就会得到报错信息。在调用ExecuteCommandLists方法将命令列表中的命令提交给命令队列后我们就可以通过D3D12GraphicsCommandList::Reset方法将命令列表恢复为刚创建时的初态。此方法功能类似于std::vector::clear方法仅使得存储元素的数量归零但是仍保持其当前的容量。借助此方法我们就可以继续复用其底层内存避免释放列表再新建的繁琐操作。命令队列可能会引用命令分配器中的数据但是重置命令列表却不会影响命令队列这是因为相关的命令分配器仍在维护着其内存中被命令队列引用的一系列命令。因此当调用ExecuteCommandLists方法后就可以重置命名列表。但是注意在没有确定GPU执行完命令分配器中的所有命令之前千万不要重置命令分配器因此差不多会在每一帧重置命令列表但命令分配器却不一定。 5描述并创建交换链 5.1 完整示例 #includewindows.h // windows API编程所需 #includewrl.h // 提供了ComPtr类它是COM对象的智能指针使我们无需手动Release #included3d12.h // Direct3D12头文件ID3D12开头类型始于此 #includedxgi1_4.h // DirectX图形基础设施头文件IDXGI开头类型始于此 #includestring // 提供wsring类,在Windows平台上应该使用wstring和wchar_t #includeassert.husing namespace Microsoft::WRL; // 方便使用Microsoft::WRL::ComPtr类 // AnsiToWString函数将字符串映射到 UTF-16 (宽字符) 字符串 inline std::wstring AnsiToWString(const std::string str) {WCHAR buffer[512];MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, buffer, 512);return std::wstring(buffer); }// 定义异常类 class DxException { public:DxException() default;// 显示异常函数的返回值、函数名、代码所处文件名所处代码行数DxException(HRESULT hr, const std::wstring functionName, const std::wstring filename, int lineNumber);std::wstring ToString()const;HRESULT ErrorCode S_OK;std::wstring FunctionName;std::wstring Filename;int LineNumber -1; };// 如果发生异常抛出一个异常实例 #ifndef ThrowIfFailed #define ThrowIfFailed(x) \ { \HRESULT hr__ (x); \std::wstring wfn AnsiToWString(__FILE__); \if(FAILED(hr__)) { throw DxException(hr__, L#x, wfn, __LINE__); } \ } #endif// IDXGIFactory: DXGI中最关键的接口之一可以枚举显示适配器 ComPtrIDXGIFactory4 mdxgiFactory;// ID3D12Device: 代表一个显示适配器显卡 ComPtrID3D12Device md3dDevice;// ID3D12Fence: 表示围栏 ComPtrID3D12Fence mFence;// RTV描述符大小RTV描述符: 渲染目标视图资源 UINT mRtvDescriptorSize 0; // DSV描述符大小DSV描述符: 深度/模板视图资源 UINT mDsvDescriptorSize 0; // CbvSrvUav描述符大小CBV描述符: 常量缓冲区视图资源... UINT mCbvSrvUavDescriptorSize 0;// DXGI_FORMAT: 资源数据的格式一种枚举类型 DXGI_FORMAT mBackBufferFormat DXGI_FORMAT_R8G8B8A8_UNORM;// 使用无符号整数存储我们查询的图像质量所对应的质量级别不为零则说明支持 UINT m4xMsaaQuality 0;// 声明一个命令队列 ComPtrID3D12CommandQueue mCommandQueue;// 声明ID3D12CommandAllocator命令内存管理对象 ComPtrID3D12CommandAllocator mCommandAllocator;// 通过ID3D12Device创建命令列表ID3D12GraphicsCommandList ComPtrID3D12GraphicsCommandList mCommandList;// 定义缓冲区分辨率的高度和宽度 int mClientWidth 800; int mClientHeight 600;// 定义交换链中的缓冲区数目这里使用双缓冲 const int SwapChainBufferCount 2;// 存储窗口句柄 HWND mhMainWnd nullptr;// 声明交换链接口对象IDXGISwapChain ComPtrIDXGISwapChain mSwapChain;/*第五步描述并创建交换链 */ void CreateSwapChain() {// 释放我们将要重新创建的上一个交换链。mSwapChain.Reset();// 使用DXGI_SWAP_CHAIN_DESC结构体描述交换链的特性DXGI_SWAP_CHAIN_DESC sd;sd.BufferDesc.Width mClientWidth; // 缓冲区分辨率宽度sd.BufferDesc.Height mClientHeight; // 缓冲区分辨率高度sd.BufferDesc.RefreshRate.Numerator 60; // 设置刷新率分子sd.BufferDesc.RefreshRate.Denominator 1; // 设置刷新率分母sd.BufferDesc.Format mBackBufferFormat; // 设置缓冲区格式sd.BufferDesc.ScanlineOrdering DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; // 设置扫描线顺序为未指定sd.BufferDesc.Scaling DXGI_MODE_SCALING_UNSPECIFIED; // 设置缩放为未指定sd.SampleDesc.Count 1; // 设置采样数目为1sd.SampleDesc.Quality 0; // 设置质量级别为0sd.BufferUsage DXGI_USAGE_RENDER_TARGET_OUTPUT;// 设置后台缓冲区为渲染目标输出sd.BufferCount SwapChainBufferCount; // 设置交换链中的缓冲区数量sd.OutputWindow mhMainWnd; // 设置渲染窗口的句柄sd.Windowed true; // 设置为true程序将在窗口模式运行否则为全屏sd.SwapEffect DXGI_SWAP_EFFECT_FLIP_DISCARD; sd.Flags DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;// 可选标志设为此项表示程序切换为全屏时选择最适合于当前应用程序窗口尺寸的显示模式// 若无该标志则采用当前桌面的显示模式。// 使用IDXGIFactory::CreateSwapChain方法创建交换链接口ThrowIfFailed(mdxgiFactory-CreateSwapChain(mCommandQueue.Get(),sd,mSwapChain.GetAddressOf())); }/*第四步创建命令队列和命令列表 */ void CreateCommandObjects() {// 调用ID3D12Device::CreateCommandQueue方法创建队列前// 需要填写D3D12_COMMAND_QUEUE_DESC结构体来描述队列D3D12_COMMAND_QUEUE_DESC queueDesc {};// 定义队列中的命令类型queueDesc.Type D3D12_COMMAND_LIST_TYPE_DIRECT;// 设置其他选项为空queueDesc.Flags D3D12_COMMAND_QUEUE_FLAG_NONE;// 调用ID3D12Device::CreateCommandQueue方法创建命令队列ThrowIfFailed(md3dDevice-CreateCommandQueue(queueDesc, IID_PPV_ARGS(mCommandQueue)));// 记录在命令列表内的命令实际上是存储在与之关联的命令分配器上// 通过ID3D12Device创建命令分配器ID3D12CommandAllocatorThrowIfFailed(md3dDevice-CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, // 与此命令分配器关联的命令列表类型IID_PPV_ARGS(mCommandAllocator.GetAddressOf()) ));ThrowIfFailed(md3dDevice-CreateCommandList(0, // 指定与所建命令列表相关联的物理GPU对于仅有一个GPU的系统而言设为0D3D12_COMMAND_LIST_TYPE_DIRECT, // 命令列表的类型mCommandAllocator.Get(), // 关联的命令分配器nullptr, // 打包和初始化无绘制命令时传nullptrIID_PPV_ARGS(mCommandList.GetAddressOf())// 输出指向所建列表的指针));// 在关闭状态下启动// 这是因为当我们第一次引用命令列表时我们会重置它并且在调用Reset之前需要关闭它。mCommandList-Close();md3dDevice-GetNodeCount(); }// 初始化Direct3D bool InitDirect3D() { #if defined(DEBUG) || defined(_DEBUG) // 如果在Debug模式启用D3D12的调试层// 启用调试后D3D会在错误发生时向VC的输出窗口发送调试信息{ComPtrID3D12Debug debugController;ThrowIfFailed(D3D12GetDebugInterface(IID_PPV_ARGS(debugController)));debugController-EnableDebugLayer();} #endif/*第一步创建Direct3D设备*/ // 创建可用于生成其他 DXGI 对象的 DXGI 1.0 FactoryThrowIfFailed(CreateDXGIFactory1(IID_PPV_ARGS(mdxgiFactory)));// 创建一个D3D设备// D3D12CreateDevice参数为(适配器指针应用程序所需最低功能级别// 所建ID3D12Device接口的COM ID返回所创建的D3D12设备HRESULT hardwareResult D3D12CreateDevice(nullptr,D3D_FEATURE_LEVEL_12_0,IID_PPV_ARGS(md3dDevice));// 适配器指针传入空代表使用主显示适配器// 可以分析出需要COM指针即riid的地方通过使用IID_PPV_ARGS即可// 如果创建失败应用程序回退至WARP软件适配器if (FAILED(hardwareResult)){ComPtrIDXGIAdapter pWarpAdapter;ThrowIfFailed(mdxgiFactory-EnumWarpAdapter(IID_PPV_ARGS(pWarpAdapter)));// 不同windows版本的WARP最高支持的功能级别也不同// 再次创建D3D设备时仅适配器指针参数不同传入WARP适配器指针ThrowIfFailed(D3D12CreateDevice(pWarpAdapter.Get(),D3D_FEATURE_LEVEL_12_0,IID_PPV_ARGS(md3dDevice)));}/*第二步创建围栏并计算描述符大小*/// 创建围栏ThrowIfFailed(md3dDevice-CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(mFence)));// 获取描述符大小mRtvDescriptorSize md3dDevice-GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);mDsvDescriptorSize md3dDevice-GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_DSV);mCbvSrvUavDescriptorSize md3dDevice-GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);/*第三步检测系统对4X MSAA的支持*/// 检测对4X MSAA质量级别的支持D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS msQualityLevels;msQualityLevels.Format mBackBufferFormat; // 纹理格式msQualityLevels.SampleCount 4; // 采样次数msQualityLevels.Flags D3D12_MULTISAMPLE_QUALITY_LEVELS_FLAG_NONE; // 默认选项msQualityLevels.NumQualityLevels 0; // 质量级别// 使用ID3D12Device::CheckFeatureSupport函数查询我们设置的这种图像质量的级别ThrowIfFailed(md3dDevice-CheckFeatureSupport(D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS,msQualityLevels,sizeof(msQualityLevels)));// 我们查询的采样数为4因此返回的质量级别即为达到4X MSAA的质量级别m4xMsaaQuality msQualityLevels.NumQualityLevels;// 只要返回的质量级别不为零则表示支持此种图像质量在该处即支持4X MSAAassert(m4xMsaaQuality 0 Unexpected MSAA quality level.);/*第四步创建命令队列和命令列表*/CreateCommandObjects();/*第五步描述并创建交换链*/CreateSwapChain(); }#includeWindows.h#define WINDOW_WIDTH 800 #define WINDOW_HEIGHT 600 #define WINDOW_TITLE LGameEngineLRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);int WINAPI WinMain(_In_ HINSTANCE hInstance,_In_opt_ HINSTANCE hPrevInstance,_In_ LPSTR lpCmdLine,_In_ int nShowCmd) {SetProcessDPIAware();int cx GetSystemMetrics(SM_CXSCREEN);int cy GetSystemMetrics(SM_CYMAXTRACK);WNDCLASSEX wndClass { 0 };wndClass.cbSize sizeof(WNDCLASSEX);wndClass.style CS_DBLCLKS | CS_NOCLOSE | CS_VREDRAW | CS_HREDRAW;wndClass.lpfnWndProc WndProc;wndClass.cbClsExtra 0;wndClass.cbWndExtra 0;wndClass.hInstance hInstance;wndClass.hIcon (HICON)::LoadImage(NULL, LImage.ico, IMAGE_ICON, 0, 0,LR_DEFAULTSIZE | LR_LOADFROMFILE);wndClass.hCursor LoadCursor(NULL, IDC_ARROW);wndClass.hbrBackground (HBRUSH)GetStockObject(GRAY_BRUSH);wndClass.lpszMenuName NULL;wndClass.lpszClassName LForTheDreamOfGameDevelop;if (!RegisterClassEx(wndClass))return -1;mhMainWnd CreateWindow(LForTheDreamOfGameDevelop,WINDOW_TITLE,WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, WINDOW_WIDTH,WINDOW_HEIGHT, NULL, NULL, hInstance, NULL);InitDirect3D();MoveWindow(mhMainWnd, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, true);ShowWindow(mhMainWnd, nShowCmd);UpdateWindow(mhMainWnd);MSG msg { 0 };while (msg.message ! WM_QUIT){if (PeekMessage(msg, 0, 0, 0, PM_REMOVE)){TranslateMessage(msg);DispatchMessage(msg);}}UnregisterClass(LForTheDreamOfGameDevelop, wndClass.hInstance);return 0; }LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {switch (message){case WM_PAINT:ValidateRect(hwnd, NULL);break;case WM_KEYDOWN:if (wParam VK_ESCAPE)DestroyWindow(hwnd);break;case WM_DESTROY:PostQuitMessage(0);break;default:return DefWindowProc(hwnd, message, wParam, lParam);}return 0; }
http://www.tj-hxxt.cn/news/141628.html

相关文章:

  • 做电影网站被告版权为企业策划一次网络营销活动
  • 高安市网站建设公司通州网站建设站开发评价
  • 深圳网站建设设计公司厦门模板网站建设
  • 网站建设制作设计开发关键词排名优化系统
  • 网站可不可以做自己的专利网络推广合同
  • 网站建设现在市场大不大网站做推广 建设哪种类型合适
  • 建站公司杭州做羞羞的专门网站
  • 哪一个网站可以做任务拿佣金网站建设维护费合同
  • 青海省教育厅门户网站官网新乡网站优化公司推荐
  • seo站长优化工具在线是免费生成器
  • dedecms导航网站做网站能设置关键词在百度中搜索到
  • 企业网站模板下载网站模板下载word 发布 wordpress
  • 加上强机关网站建设管理的通知建湖人才网官网登录
  • 泉州网站建设网站建设我要表白网站
  • 功能型网站建设时间深圳市手机网站建设哪家好
  • 厦门网络公司网站网站做程序员
  • 6成都网站建设微信如何开发自己的小程序
  • 网站建设网页设计小江泉州网站建设价钱
  • 苏州吴江太湖新城建设局网站装修网站怎么做的好
  • 网站建设小组的运营模式2023网站分享
  • 同一虚拟主机 2个网站有没有做线播放网站
  • 网站定制开发优点wordpress iis 中文
  • 网站开发前景如何大兴网站开发公司
  • 做室内设计兼职的网站wordpress建站
  • 做企业网站有哪些系统建筑工地招聘网站
  • 英迈思网站建设建筑工程网 装修
  • 网站广告下悬浮代码怎么做wordpress博客建设与经营
  • 江苏常州武进区建设局网站如何把自己电脑做网站服务器吗
  • 外贸建站与推广如何做吉林做网站多少钱
  • 珠海工商年检到哪个网站做网站开发 英文文章