本文主要是介绍D3D调试必看-小白PIX篇,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
引言
- 本人小白,目前学习D3D一个多月,正在独立开发一款图像引擎,本博客主要记录D3D的学习心得和微软工具PIX的使用方法。
一、PIX的使用方法
(1)为什么使用PIX?
- 如果你踏上了这条路,那么总有一天你会开发属于自己的图形引擎。想象当你的项目已经大致完成时,你迫不及待的按下了vs stdio的运行程序按钮,但回应你的确实一个“空荡荡”的窗口,它大概率要是全白、要么是全黑,这取决于你清空后台颜色缓冲区的值是什么。总之你大概率会遇到类似下面这样一个窗口:
- 试想你此时会想什么:
1. 是着色器写错了? 会不会是顶点着色器中的MVP变换出错了? 还是片段着色器中的PBR光照模型计算错了? 又或者二者都有?
2. 是常量缓冲区没有上传到GPU? 会不会是忘记初始化物体的矩阵值了? 还是摄像机的位置等信息有问题? 是不是摄像机的观察矩阵计算错了?
… - 上述是图形开发中经常会遇到的难题,根本原因在于图形计算过程的隐蔽性,即我们只知道自己的代码调用了DrawIndexedInstanced,我们无法查询到Shader中的值,导致我们无法确认顶点、索引、常量缓冲区是否正确上传到GPU中,也无法确认GPU执行Shader代码时每个变量的值是多少。要是我们能像CPU端开发那样,直接查询GPU端的资源和变量情况就好了!
- PIX是微软开发的一款辅助D3D进行图形开发的软件,它可以捕获程序的渲染帧信息,让我们查询到GPU端的资源和变量情况。有了PIX,我们可以直接核对顶点和索引、常量缓冲区、渲染管线状态等一系列信息,从根源排查渲染结果的成因。
(2)怎样使用PIX?
1. 下载PIX,下载链接点这里,看不懂英文的小朋友请看下图:
2. 我下载版本的PIX的大小约为170M。下载好后同意其条款,安装时的选项也只是统计你在大公司开发3A大作还是独立开发小游戏,因此随便一路点点点就可以完成安装了,这个软件貌似无法修改语言,安装好后可以在windows的开始菜单看到它,如下图所示:
3. 由于一些原因,它需要你开启Windows的开发者模式,才能对帧进行捕获,下面介绍Win11打开开发者模式的方法:打开Windows开始菜单,再打开设置,在设置的搜索栏按下图搜索。
点击上图中搜索到的选项,就会看到下图的画面,将开发者模式打开即可。
4. 打开PIX,一些基本操作信息如下图所示:
5. 点击捕获帧的图片后,即可打开新的界面,查看捕获帧的详细信息,如下图所示:
6. 点击右上角的运行按钮,成功运行后就可以查询更详细的GPU端信息,如下图所示:
下面是一个常规顶点缓冲区的示例,如果你的界面中缺少了一些属性,比如你预设了纹理坐标却没有显示,说明你的顶点输入布局可能写错了,可以见检查一下纹理坐标的偏移值是否正确。如果你的界面顶点很少或者都为0,说明你的数据没有上传或者上传错误。后面我会介绍一些自己踩过的坑告诉大家。
如果顶点缓冲区没有问题,那么可以见检查一下索引缓冲区中的索引数据是否正确,一个常规的索引缓冲区显示情况如下:
如果以上二者都正确,那么可以点击CBV检查不同的常量缓冲区中的数据是否正确。如果最后都没问题了,可以点击Output查看渲染输出,我的渲染输出示例如下:
由于我未处理模型的材质,因此请不要在意其颜色。再这个界面点击鼠标左键拖动鼠标即可围绕渲染物体渲染,点击鼠标右键拖动鼠标即可进行平移,滚动鼠标滚轮可以进行放大和缩小(即沿着摄像机观察方向移动)。
本人才疏学浅,所以对PIX的介绍到此为止,可参考PIX官方文档和Unity-轻松学会PIX。英文的东西国内很少人翻译,少有的PIX相关博客内容又太过高端,我在此呼吁大家在CG领域学了好东西不妨写一篇通俗的CSDN博客,发布时点个仅粉丝可见权当多交朋友,这样D3D和中国游戏的未来才会更加光明!
二、心得体会
- 渲染效果没有达到预期不一定是GPU端的问题,可能CPU端对D3D应用程序的构建就不到位,比如根签名、命令列表、渲染状态等是否设置正确,这些虽然一般会有调试信息输出提醒错误,但是我们还是要注意。对于小白而言,多看看D3D龙书第四章的源代码,把D3D应用程序初始化烂熟于心。要想绘制自己想要的内容,那就要把第六章的源代码反复阅读,在自己开发程序达不到预期时看看正确的示例代码,想想:有什么是它做到了我还没做到的?带着这样的疑问去看源码,慢慢自己的水平就会提升,慢慢自己的项目也会查漏补缺起来。
- 我之前是通过GAMES101和LearnOpenGL入门图形学的,我的项目也是如LearnOpenGL中使用Assimp库导入模型的。但导入模型并非易事!假设我们定义的顶点类型为Vertex,则Mesh的核心数据就是std::vector< Vertex >,可见不同Mesh的顶点数据是离散的,则模型Model的核心数据就是std::vector< Mesh >。对于D3D而言,我们可以将顶点整合到一块CPU内存中,然后创建缓冲区存储顶点数据,通过vector< T >.data()即可获取vector连续内存的首地址,但这里可能出错,比如以下函数:
void LoadModel(std::vector<Model>& res,std::wstirng modelFilePath)
{ Model model = Model::LoadModelFromFile(modelFilePath); // 解析模型文件生成Model对象model.BuildVIView(); // 构建模型的顶点和索引描述res.push_back(model); // 将模型压入要返回的模型数组
}
- 上述代码可能导致你在PIX中的顶点缓冲区中看到全是0,因为如果model类中包含VIView类作为成员,而VIView包含void成员指向顶点数据的首地址,以便后续创建GPU缓冲区。则model.BuildVIView()就会将model的mesh的std::vector< Vertex >成员的data()赋值给void。而当res.push_back(model);执行时,如果没有特别处理,则类实例间仅进行简单的值赋值,则返回的res中的最后一个模型的void*指针是无效的,因为其值来源于局部变量model,而函数结束后model被释放。因此对于指针、vecctor,尤其是怎样将Model、Mesh对象存入vector,是很值得思考的问题,是先构建一个临时的Model?临时的变量只不过是数据传递的中间者而已,因此要头脑清晰的对很多问题进行思考分析才行。
- 本人学疏才浅也无法帮大家解决问题,但有兴趣的可以加入QQ: DirectX交流群,一起学习和发展!
这篇关于D3D调试必看-小白PIX篇的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!