D3D12 快速 C/C++ 教程导航以及调试指南

📅 发布时间:2026/7/7 16:38:10 👁️ 浏览次数:
D3D12 快速 C/C++ 教程导航以及调试指南
快速导航基础篇Assimp 篇进阶篇调试指南D3D12 调试层shader 编译调试选项逐步调试PIX 调试补一关于 DirectX 12 的各种逆天对齐要求补二关于围栏同步与 CreateEvent 的紧急修正补三善用 AI 这个新兴的超级工具鸣谢教程代码资源dgaf 的 《DirectX 12 快速教程》配套代码 (A Sample of dgaf’s DirectX 12 Quick Beginner Tutorial)基础篇教程名实现效果示例知识点难度评级(☆表示半颗星)DX12 快速教程(1) —— 做窗口Win32 API 窗口、消息循环★☆DX12 快速教程(2) —— 渲染天蓝色窗口DX12 初始化、描述符堆、描述符、资源命令三件套、围栏、资源屏障、渲染更新原理RTV 渲染目标描述符★★★DX12 快速教程(3) —— 画矩形现代渲染管线、PSO、管线渲染原理着色器、HLSL 高级着色语言顶点着色器、像素着色器VertexBufferView、上传堆★★★★★DX12 快速教程(4) —— 画钻石原矿WIC 解码图片、图片数据解析纹理映射、纹理采样根签名及资源绑定、默认堆SRV 着色器资源描述符★★★★★DX12 快速教程(5) —— 画方块线性代数及其在图形学的应用MVP 矩阵、常量缓冲、根描述符CBV 常量缓冲描述符★★★★★DX12 快速教程(6) —— 第一人称视角第一人称摄像机、平移、视角旋转DX12 资源绑定、更新与传递★★☆DX12 快速教程(7) —— 渲染火柴盒深度测试与深度缓冲、模型矩阵IA 多槽并行输入、着色器同语义拆分DSV 深度模板描述符★★★DX12 快速教程(8) —— 画玻璃透明测试与混合★Assimp 篇教程名实现效果示例知识点难度评级(☆表示半颗星)DX12 快速教程(9) —— 初识 Assimp 库Assimp 库的编译与使用骨骼模型简史、GLTF 文件结构骨骼树、材质、网格、AABB 包围盒★DX12 快速教程(10) —— 渲染模型模型导入与渲染★★★DX12 快速教程(11) —— 渲染骨骼模型骨骼偏移矩阵、骨骼索引、骨骼权重骨骼空间、网格空间、蒙皮网格渲染★★★★DX12 快速教程(12) —— Blinn-Phong 光照模型光照模型简史Blinn-Phong 光照模型、根常量★★★DX12 快速教程(13) —— 蒙皮骨骼动画蒙皮骨骼动画原理及应用欧拉数、万向锁、旋转矩阵四元数及其插值、四元数转旋转矩阵★★★☆DX12 快速教程(14) —— 屏幕空间天空盒天空盒、屏幕空间天空盒等距圆柱投影、根签名重载★★进阶篇教程名实现效果示例知识点难度评级(☆表示半颗星)DX12 快速教程(15) —— 多实例渲染纹理数组、SRV 结构化缓冲硬件实例化、IA 多槽并行输入★★★☆DX12 快速教程(16) —— D2D 与 D3D12 互操作D3D11On12、D2D 1.3包装层资源D2D 命令同步★★★DX12 快速教程(17) —— 立体图标与合并渲染D2D 矩阵变换、等轴测变换预渲染图标、合并渲染★★DX12 快速教程(18) —— 屏幕射线相交检测屏幕射线相交检测IA 输入布局复用、鼠标捕获深度冲突及深度偏移动态资源初步★★★☆DX12 快速教程(19) —— 柏林噪声柏林噪声算法计算着色器、无序访问资源回读堆、CPU 回读显存数据UAV 无序访问描述符★★★★★调试指南学会各种 Debug 调试技能非常、非常重要。没有 Debug 技能在 DirectX 12 学习中是寸步难行的辛苦写了那么多的代码却找不到报错/报异常/渲染错误的来源就会产生严重的心理负反馈。我们主要有四种方法D3D12 调试层ID3D12Debug 调试层设备接口无疑是报错查错的第一功臣DX12 将渲染层与调试层分离这两层可同时工作调试运行时调试层会拼尽全力在下面的输出窗口给出可能会有的WARNING和ERROR通过这些信息可以查阅资料、询问编程论坛、也可以尝试问 AI抛出异常的时候可以根据调试层的信息快速定位还有一种情况是调试层输出了信息但信息只写着报错源是“Unnamed ID3D12xxx Object”的情况COM 接口有一个成员函数叫SetName它是设置组件名称方便调试用的。遇到这种情况我们把引用这个 Object 的全部组件创建完成后全部 SetName就可以找到报错源了shader 编译调试选项对于根签名以及 shader它们序列化/编译之后生成的ErrorBlob错误字节码也是值得关注的DX API 内部和 fxc 编译器本身就是一个黑盒而这些错误字节码可以成为我们改错与优化的救命稻草不容忽视。D3DCompileFromFile的第六个参数Flag1可以设置编译选项与标志D3DCOMPILE_DEBUG (shader 进入调试状态)和D3DCOMPILE_SKIP_OPTIMIZATION (shader 跳过优化)可以帮助我们更好的调试强烈建议设置。逐步调试断点与逐步调试仍然是万金油重要程度不言而喻学会逐步运行、断点查值、变量监视、堆栈回溯、进程/线程回溯等等各种通用调试方法能对现在以及将来的 DirectX 12 学习带来立竿见影的效果。PIX 调试官网地址https://devblogs.microsoft.com/pix/download/Windows PIX是一款由微软官方推出的性能调优与图形调试可视化工具对 DirectX 12 程序的学习与开发也能有所脾益。如果你实在是没辙了实在是因为不知名错误而焦头烂额或者你实在是不理解 DX API 内部的交互与运行过程想要一探究竟不妨试试 PIX 看看。D3D调试必看-小白PIX篇https://blog.csdn.net/qq_51563654/article/details/136311848D3D12调试工具——pixhttps://www.cnblogs.com/chenglixue/p/17293046.html有些旧独显/集显不支持 PIX 调试的主要特性会导致 PIX 一些主要功能无法显示与使用而报错具体需要查看相关的官方文档请留意。补一关于 DirectX 12 的各种逆天对齐要求很多人可能会栽在资源管理这一块不明白纹理行和常量资源对齐的 256子资源对齐的 512UAV 计数器资源对齐的 4096 这些逆天常数是从哪里来的常常因为 DirectX12 API 各种逆天对齐要求而怨声载道。输入D3D12_ALIGNMENT然后按CtrlJ就会弹出 IntelliSense它会提示 DX12 API 内置的所有资源对齐宏定义请妥善利用哦我们的教程涉及到的时候也会讲解。补二关于围栏同步与 CreateEvent 的紧急修正多线程永远是最难而且最坑的一点CreateEvent的第二、三参数哎呀哎呀我真的是。。。对不起各位读者我今天 (2026.2.12) 在写第 15 章纹理数组的时候发现初始状态设置 true之前一直都没发现的惊天 BUG 终于爆了由于初始状态是有信号状态GPU Copy Engine 会在第一个纹理复制的时候直接进行下一个纹理复制而复制纹理数组恰好共用的是同一个上传堆和默认堆资源(之前一直都是一个纹理对应一对资源不共用的所以我这边调试层没报错)结果导致 GPU In-Flight 资源竞争了哈哈哈。。。第二个参数击中围栏会激发预定事件使事件进入有信号状态ID3D12CommandQueue::Signal 是在 GPU 上设置预期值 (围栏值 FenceValue)内置围栏对象会为每一个围栏值创建 Event Slot 事件槽只要 GPU 做到了某些事情就会自动增加到对应的预期值。一个围栏是可以有多个预期值的也就是说你可以同时发布不同的任务给 GPU然后给 GPU 不同的任务设置不同的预期值GPU 做到了会自动发信号给你。所以 ID3D12CommandQueue::Signal 需要两个参数一个pFence 围栏对象一个FenceValue 围栏值 (预期值)GPU 怎么发信号给 CPU 呢答案是ID3D12Fence::SetEventOnCompletion这个函数的意思是将 CPU 端接收信号的 hEvent根据 GPU 不同任务的预期值绑定到围栏的对应位置 (Event Slot 事件槽) 上围栏做到了某些任务会根据任务的预期值将对应的 hEvent 设置为有信号状态这就是为什么 SetEventOnCompletion 需要两个参数一个FenceValue 围栏值 (预期值)一个hEvent CPU 信号事件句柄这两个缺一不可缺了/填错其中一个都会绑定失败导致调试层报错渲染无法进行。这样 GPU 就能告诉 CPU 我哪些任务做完了。。。我也是刚刚才完全理解这两个函数的意思的别骂我了后面到多线程那里再补动图而 CreateEvent 那第二个参数 bManualReset 其实是帮你善后用的。。。很多开发者抱怨每次击中围栏事件变成有信号状态想要进行下一次 GPU 命令传输就要再进行ResetEvent重置到无信号状态特别麻烦。因此第二个参数设 false 就表示开发者不需要再手动写 ResetEvent 了系统帮你做复位的事。只要 CPU 上的 hEvent 变成有信号状态经过某些等待函数 (WaitForSingleObject、MsgWaitForMultiObjects、GetOverlappedResult 等等)就自动变成无信号事件露头就打。我之前一直以为把 hEvent 从有信号变无信号是 ID3D12Fence::SetEventOnCompletion 做的现在才发现不是它其实是CreateEvent 和 WaitForSingleObject/MsgWaitForMultiObjects做的。不过很重要的一点你要掌握好时机不然系统也无力回天。最后一个 Copy 动作 (第 10-13 章的STEP17_CopyMeshToDefaultResource和第 14 章的STEP23_CopyHDRResource) 别再写WaitForSingleObject了不然等会过完这个函数就要送到渲染循环那里又不小心把事件复位到无状态事件导致下面的MsgWaitForMultiObjects一直在等待你发渲染信号一直返回 1 结果导致窗口白屏完全渲染不出来case 0 的 Render 函数一次都没进去过。。。多线程必定会加入进阶篇而且是最难教程它的难度直接上六星不亚于《滚动的天空》霓虹三冠补三善用 AI 这个新兴的超级工具不得不感慨那些为 AI 发展前仆后继、奔波不停的计算机科学家我愿称他们为真神对自己好一点善用 AI我这里用的是网页端的 DeepSeek如果你们在 Console 端直接用 API Key 调用更聪明的 AI (如 Gemini、Claude 等等)善于和 AI 交流你们学习 DX12 的速度一定会突飞猛进总会成功的鸣谢真的要感谢 littletoxic百忙之中能提供宝贵的建议甚至还将鄙人的拙作翻译成 C# 版本不胜感激(大家有需要也可以 clone 并且给个 star)项目链接https://github.com/littletoxic/DXPractice其次是 GameBabyRockSun 大佬没有他就没有现在的我项目链接https://github.com/GamebabyRockSun/GRSD3D12Sample知乎的众多大佬也给了我很大帮助由衷感谢。还有很多就不逐一列举了感激不尽最后我由衷希望各位吃水不忘挖井人吸取众多前人的经验走出自己的一条路写出最好的东西加油