前言
本来要肝 Houdini 教程的,但是最近一直不在状态(:з」∠)
然后工作上遇到这个需求,本来是打算从 RenderDoc 导出 csv 文件,然后读取 csv 文件在 Maya API 将相关信息写到模型里面。
但是 RenderDoc 的 ID 序号和 Maya 的 FaceVertex 无法关联到一起。
在 Maya 里面顺序被打乱了。
由于这个问题不急,所以也就搁置了,没有进行下一步的处理。
直到最近在 KM 上找到了一篇 RenderDoc 插件开发的文章,瞬间觉得可以调用 RenderDoc API 来解决这个问题。
于是才有了本篇文章的探索。
最后的实现效果已经开源在 Github 上 链接
RenderDoc 是啥
RenderDoc 是业内大名鼎鼎的 截帧软件, 用来分析游戏渲染数据的利器。不过我不是图形向 TA , 使用上还是一知半解(:з」∠)。
RenderDoc 是结余 Qt 框架开发,内置 Python API ,可以通过 Python 脚本实现插件开发。

插件开发
RenderDoc 的文档里面有很详细关于插件开发的内容 链接
1 | # windows |
在上面的路径下创建目录
然后添加一个__init__.py和extension.json的文件
1 | { |
extension_api 固定为 1
RenderDoc 会读取
extension.json的信息显示在 Extension Mananger 的面板上。

启用插件之后就可以通过 API 扩展界面功能了

RenderDoc 调试 Python 代码

RenderDoc 有 Python Shell 面板
这里编写代码有完整的 renderdoc 环境, 方便测试代码。
毕竟上面的插件流程测试代码都需要 reload 一下,非常不方便
RenderDoc 使用 Qt 编写界面
虽然 RenderDoc 自带 PySide 模块
但是 Qt 界面开发上并没有 Maya 那么灵活
用 Maya 的传统思路构建 UI 会让 UI 一闪而过,即便使用 global 变量也不行。
1 | from PySide2 import QtWidgets |

RenderDoc 的主线程不能被 PySide 创建的界面所阻塞,否则就会导致 RenderDoc 卡死。
RenderDoc Python API 提供了 Mini-Qt Helper
1 | from PySide2 import QtWidgets |


这里使用全局变量
pyrenderdoc获取 Helper ,然后调用 Helper 显示 Dialog
不过有个缺点这是个 阻塞 Dialog , RenderDoc 的界面就无法响应了。
关于 RenderDoc 一些内置变量和库需要进行区分
renderdoc 是自身的 API 模块
qrenderdoc 是Qt相关的 API 模块
pyrenderdoc 则是默认自带的全局变量,属于 CaptureContext 类型,可以在文档中查阅相关的信息。 文档链接
根据上面的文档上面, RenderDoc 推荐在 Python 环境下使用
pyrenderdoc.Replay().BlockInvoke(myCallback)来进行处理操作。
BlockInvoke 会调用非 UI 现成进行处理,避免 UI 无响应,并且只有激活的 controller 下才会触发。
也就是没有截帧数据的情况下, BlockInvoke 的函数是不会被调用到的。
但是这样会导致 BlockInvoke 的调用函数不在 Qt 线程里面,如果触发 Qt 相关的界面 API 依然不行。
1 | manager = pyrenderdoc.Extensions() |
比较神奇的情况就出现了,我也不太搞懂,理论上上面的代码无法执行的,但是在代码调试界面是可以执行的。
但是如果在 插件环境 下执行这个代码就会卡死,使用需要慎重。
2021-4-10 更新
最近抽空来修复 renderdoc2fbx 工具的 一些 BUG ,想要用 Qt Designer 写个界面接入到 renderdoc 里面。
我发现上面的测试还是差了一步,我只是生成界面,却没有生成按钮到界面里面。
结果 renderdoc 的 API 需要用GetMiniQtHelper的 API 来创建组件。
单纯使用 PySide2 库创建组件并不可行,因为 renderdoc 的 Python 和 PySide2 都是经过魔改的。
打开 renderdoc 的安装目录可以看到 PySide2 模块 以及 Python 都是缺失的。
python.exe 都找不到,在renderdoc 下import socket库还会报错。
1 | Traceback (most recent call last): |
因此在 renderdoc 创建界面只能使用
IMiniQtHelper类里面提供的方法。
1 | manager = pyrenderdoc.Extensions() |
基于上面的 API 和文档,返回都是 QWidget 类型,简单的界面编写可以如下参考。
1 | manager = pyrenderdoc.Extensions() |

因此在 renderdoc 用 Python 写界面会有诸多限制,我这里开发了一个属性输入窗口,倒是能够符合我的需求。

虽然有诸多限制,不过还有一些功能可以使用,比如
QSettings
2021-4-14 更新
获取的 QWidget 组件可以转换为 Qt 的对应组件然后用 PySide2 的 API 进行交互。
比如说上面通过 mqt.CreateComboBox 生成下来选项, renderdoc 的 API 无法修改显示的 index
可以将获取的 QWidget 传入到 QtWidgets.QComboBox ,通过setCurrentText进行修改。
1 | manager = pyrenderdoc.Extensions() |
还是可以基于 Qt 的 API 进行修改,灵活性上并没有想象那么差。
2021-4-17附注: 这个用法只能在 插件环境下生效 , RenderDoc 自带的 Python shell 不起作用。
FBX 导出插件编写
关于扩展的相关命令可以在 Extension Manager 相关的 API 文档里面找到 链接
注册 Mesh Viewer 菜单
1 | pyrenderdoc.Extensions().RegisterPanelMenu( |

上面的代码可以在
Mesh Viewer的插件按钮下扩展一个 menu item ,触发相应的函数功能。
具体编写方式可以参照官方文档 链接
1 | def register(version: str, ctx: qrd.CaptureContext): |

官方文档的案例是扩展到 Tools 菜单下
解析 模型 数据
官方提供了很详细的数据解析案例 链接
官方使用 struct 库解析二进制数据,从中提取出我们需要的信息。

基于官方提供的数据就可以获取到
VertexNormalUVTangentVertexColor的数据了。
接下来就是将这些数据更具 FBX ASCII 的形式组装到文本里面。
具体操作我是从 Maya 导出一个简单的面片 ASCII FBX 去测试的。
其中比较坑的地方是, FBX 组装位置信息是有一个规则来区分三角面和四边面的。
在网上查到了不错文章解决了我这个头疼的问题 https://www.codenong.com/cs105411312/

所以 PolygonVertexIndex 按照这个规范去构建数据就不会导致模型显示不出来。
另外考虑到导出都是单个模型, 也不带材质,所以我导出的时候也将 FBX 无关的信息统统清理掉了。
总结
以上就是 RenderDoc 开发 FBX 导出工具的记录。
2021-4-17 性能优化
官方给出的 API 需要用 Python 进行 2进制解码获取模型数据。
但是这个获取方案效率实在是太低了。
经过我的摸索,可以通过 PySide2 模块获取 renderdoc UI 里面的数据。 链接
直接获取出 QTableView 里面的信息,这样导出速度可以提升数十倍。
另外使用插件的 Python 调用可以直接使用 PySide2 构建组件,但是在 Python Shell 下却不起作用。

