前言

  你永远也不知道制作人员会对软件做出怎样的操作,这次我就遇到了坑爹的问题。
  制作人员居然在引用的文件上进行了了各种模型处理的操作。
  结果导致UV乱了,源模型无法更新到引用的文件里面。
  因此我就要想办法来收拾这些烂摊子。

  引用文件的大小通常不会很大的,因为里面只记录相关的关键帧信息,尽管 maya 可以进行模型编辑,但也绝对不推荐这种操作。
  结果导致这个引用文件居然有 100+ M
  于是我就想尽办法来解决这个问题。

解决方案

alt

alt

  遇到这个问题其实也可以通过上面的方法进入到 reference 内部然后查看所有的编辑信息的。

alt

  当然也可以将 文件 保存为 ma 也可以看到模型的编辑信息


  但是由于数据量过于庞大,这个操作非常卡顿,而且这中间掺杂了很多额外编辑信息还需要逐一过滤。
  于是我要想办法用代码来清理这里的操作命令。

基于 mel 命令找到 Maya 的操作逻辑

  首先还是得从 mel 命令的执行开始入手研究怎么操作。
  从 reference 窗口的 GUI 界面可以快速在 Maya 自带的 scripts 目录下找到脚本的位置。
  可以直接搜索 List Reference Edits … 可以直接搜索出 referenceEditorPanel.res.mel 脚本
  通过 res 可以定位到这个语句对应的变量是 m_referenceEditorPanel.kItemListReference
  再通过这个变量去搜索 referenceEditorPanel.mel 就可以很快定位到 右键菜单执行的功能代码了 (Maya2017 在 referenceEditorPanel.mel 198 行)

1
2
3
4
5
6
menuItem 
-label (uiRes("m_referenceEditorPanel.kItemListReference"))
-annotation (uiRes("m_referenceEditorPanel.kListModifications"))
-command ("string $referenceFile[] = `sceneEditor -q -si $gReferenceEditorPanel`;" +
"referenceEditsWindow $referenceFile[0] false;")
listEditsToReference;

  这个脚本就是 Reference 编辑面板生成的 mel 脚本。
  可以看到这里通过 $gReferenceEditorPanel 获取到了 reference 面板,从而获取到面板上显示的文件路径。
  下面就是 referenceEditsWindow 命令的代码查阅。

  这部分的代码又可以在 referenceEditsWindow.mel 这个文件中找到。(Maya2017 在 referenceEditorPanel.mel 433 行)
  到了这里进一步查阅代码逐渐就可以找到 reference 去除编辑的按钮的功能代码了。

1
2
3
4
5
6
7
8
9
10
11
string $refreshButton = `button -label (uiRes("m_referenceEditsWindow.kRefreshEdit")) ($window + "_refreshButton")`;

string $removeButton = `button -label (uiRes("m_referenceEditsWindow.kRemoveEdit")) ($window + "_removeButton")`;

button -edit -command ($windowRefreshCmd) $refreshButton;

button -edit
-command ("referenceEditsWindowRemoveSelectedEdits \"" +
($referenceFile) + "\" " + ($referenceNode) + " " + ($textScrollList) +
" " + ($queryCmdString) + " " + ($unknownEdits) )
$removeButton;

  上面的 refreshButton removeButton 是不是很熟悉了。

alt

  已经是对应到了上图下方的两个按钮了。
  而删除编辑的按钮已经找到了调用的代码,执行的是 referenceEditsWindowRemoveSelectedEdits 命令
  于是我又去进一步研究这个 referenceEditsWindowRemoveSelectedEdits 命令调用逻辑是怎样的。

  由于这个函数的名字很长,可以很轻松地在同一个文件下找到这个函数的调用 (Maya2017 在 referenceEditorPanel.mel 49 行)

1
2
3
4
5
6
7
8
9
// 省略无数代码

string $cmd = "referenceEdit -failedEdits true ";
$cmd += "-successfulEdits true -editCommand ";

// 省略无数代码

evalEcho($cmd);

  可以看到 mel 的主要在这里调用了 底层的 referenceEdit 的命令来实现的。
  于是又可以去查 Maya 的命令文档查看相关的命令是怎么实现的了。 文档
  其实从 mel 的去除功能也可以看到这里的删除处理是非常繁琐的。
  后面我花了一些时间将这些 mel 代码转成了 python 来写。
  可以参考 github


  当然上面的脚本其实在实际运行起来还有很多问题,我当时运行的时候最大的问题就是运行效率极其缓慢。
  由于文件的修改信息都达到 100+ M, ma 文件也是几十万行的量级,所以我等了大概1个小时才遍历完。
  因此在遍历的过程中,我直接就开始着手用 OpenMaya 来提高运行效率了。

OpenMaya 处理 reference edit

  这次查询了 OpenMaya1.0 的命令,没想到发现了个有意思的MitEdits 遍历器
  通过这个就可以快速遍历引用的 edit 操作,也可以对 assembly reference 起作用。


  通过上面的遍历器就可以快速遍历引用节点里面的操作然后批量去掉无关的处理。
  遍历器的使用参考 github

  上面是我经过改良的版本,原本是想通过 OpenMaya 来清理掉 edit 的,但是貌似只有遍历器有 removeCurrentEdit 的方法
  然而这个方法需要加载的 reference 的才可以使用。
  如果要在不加载的 reference 的情况下清理掉 edit 貌似就只有通过 cmds.referenceEdit 的方法,这样清理速度还是比较慢(:з」∠)


总结

  通过上面的方法可以清理掉大部分 reference edit ,但仍不可避免地还是有很多操作需要人工处理。
  第一次接触 MitEdits 遍历器还是挺有趣的~