六六の魔法世界

注册

Maya技能 - 技术分享 - 渲染技术贴 - 2022年9月1日

[Maya] 保存文件时自动切换渲染层

在打开一个包含了了多个渲染层,设置了复杂的渲染设定的文件时很容易宕机。甚至有可能出现永远无法打开的情况。如果保存时的当前渲染层设置为默认的masterLayer的话能一定程度上避免宕机的情况。所以做一个在保存文件时自动切换渲染层的脚本。

基于命令的脚本

最简单的做法是做一个切换渲染层,再保存的脚本。切换和读取渲染层的命令是editRenderLayerGlobals,在保存之前先读取当前的渲染层信息,再切换到默认渲染层保存,保存之后再切换回之前读取出来的渲染层。

import maya.cmds as cmds
currentRL = cmds.editRenderLayerGlobals( q = 1, currentRenderLayer = 1 )
cmds.editRenderLayerGlobals( currentRenderLayer = 'defaultRenderLayer' )
cmds.file( force = 1, save = 1 )
cmds.editRenderLayerGlobals( currentRenderLayer = currentRL )

然后给这个脚本指定快捷键ctrl+s,这样在保存的时候就会自动切换了。但是这种方法也有覆盖不到的情况,比如不使用快捷键而是通过菜单保存,或者是保存对话框保存,再或者是maya崩溃时的自动保存。

导入回调函数的脚本

最万无一失的方法应该是利用openmaya 的 MSceneMessage 这个类建立回调。maya.api.OpenMaya.MSceneMessage.addCallback的详细使用方法可以参考这里。MSceneMessage里有很多预设的maya程序的事件,其中有kBeforeSave,kAfterSave这两个事件,分别是保存前和保存后。这两个事件对应maya里所有的保存方式,无论是用命令还是菜单还是自动保存。给这两个事件建立回调以后,maya就会自动在保存前和保存后这两个时间点启动回调函数了。

import maya.cmds as cmds
import maya.api.OpenMaya as OM
 
def switchRLtoDefault(*args):
    global currentRL
    currentRL = cmds.editRenderLayerGlobals( q = 1, currentRenderLayer = 1 )
    cmds.editRenderLayerGlobals( currentRenderLayer = 'defaultRenderLayer' )
 
def switchRLtoCurrent(*args):
    if 'currentRL' in globals():
        cmds.editRenderLayerGlobals( currentRenderLayer = currentRL )
 
def main():
  OM.MSceneMessage.addCallback( OM.MSceneMessage.kBeforeSave, switchRLtoDefault )
  OM.MSceneMessage.addCallback( OM.MSceneMessage.kAfterSave, switchRLtoCurrent )
 
main()

具体的步骤是:

  1. 当然要先导入api 2.0模块。
  2. 把快捷键用的脚本的2~3行放到switchRLtoDefault函数里,作为保存前的切换处理。另外因为把currentRL变量放进了函数里,为了后面再切换回去的处理要把这个变量全局化。
  3. 把快捷键用的脚本的第5行放到switchRLtoCurrent函数里作为保存后的切换处理。
  4. 在main函数里OM.MSceneMessage.addCallback方法建立两个回调,第一个是保存前的处理,调用的函数是switchRLtoDefault,第二个是保存后的处理,调用的函数是switchRLtoCurrent。
  5. 执行main函数。

执行完上面的代码之后,直到关闭maya为止自动切换渲染层的回调函数都是处于被注册的状态。也就是说除非关闭maya,保存时会一直自动切换渲染层。即便这样还是有两个缺点:一个是一旦开启新的maya窗口就需要再手动执行一次。另外一个是在maya运行期间没有办法关闭。

※目前在maya 2018.5的传统渲染层和新式render setup两种模式下测试都没有问题。

userSetup方式

为了解决启动maya后还得要手动执行的问题,可以在maya的python path的任意文件夹(通常是C:\Users\用户名\Documents\maya\版本号\scripts)里创建一个叫useSetup.py的文件,如果已经有了的话就在现有文件上添加内容即可。把上面的整个代码保存为switchRL.py文件 ,在useSetup.py里把switchRL.py作为一个模块导入进去即可。下面是userSetup.py的例子:

import switchRL
switchRL.main()

其实也可以把switchRL.py里的内容复制粘贴到useSetup.py里去,但是useSetup.py的内容太多的话会不太好管理,个人更喜欢把加载的内容一个一个做成外部的python模块再导入到useSetup.py里去。

userSetup.py方法也有它的缺点,一个是一旦加载后想停掉就比较麻烦,要通过另外一段代码来注销掉已经注册的两个回调函数。另外一个是如果要把它从自动加载里去掉的话还得编辑useSetup.py这个文件。对于不是很擅长使用脚本的人来说还是不要碰userSetup.py比较好。理想的状态是能通过图形界面选择是否让切换渲染层功能处于开启状态,以及是否在启动maya时自动加载。

plug-in方式

上面提到的通过图形界面切换开启状态以及切换自动加载,这其实就是plug-in manager的界面里的功能。与其自己做一个界面,还不如把脚本改成插件形式比较快。一开始有点犹豫为了回调函数做插件会不会不符合规范,在查阅了maya官网之后发现在这个链接里有介绍plug-in的几种使用方向:

  • 添加新的节点类型
  • 添加新的命令
  • 添加新的复杂的回调
  • 添加新的渲染流水线

那么既然回调也是在合理的使用方向中,就可以着手把脚本改成插件形式了。 结合maya官网的plug-in范例来简单的说明一下改写的过程。

import sys
import maya.cmds as cmds
import maya.api.OpenMaya as OM
 
def maya_useNewAPI():
    pass
      
def initializePlugin( mobject ):
    mplugin = OM.MFnPlugin( mobject , kPluginAuther , kPluginVersion )
    try:
        global switchRlCallback
        switchRlCallback = OM.MCallbackIdArray()
        switchRlCallback.append( OM.MSceneMessage.addCallback( OM.MSceneMessage.kBeforeSave, switchRLtoDefault ) )
        switchRlCallback.append( OM.MSceneMessage.addCallback( OM.MSceneMessage.kAfterSave, switchRLtoCurrent ) )
    except:
        raise Error( 'Failed to register switchRLn' )
    else:
        sys.stdout.write( 'switchRL registeredn' )
  
def uninitializePlugin( mobject ):
    mplugin = OM.MFnPlugin( mobject )
    try:
        OM.MMessage.removeCallbacks( switchRlCallback )
    except:
        raise Error( 'Failed to unregister switchRLn' )
    else:
        sys.stdout.write( 'switchRL unregisteredn' )
  
def switchRLtoDefault( *args ):
    global currentRL
    currentRL = cmds.editRenderLayerGlobals( q = 1, currentRenderLayer = 1 )
    cmds.editRenderLayerGlobals( currentRenderLayer = 'defaultRenderLayer' )
  
def switchRLtoCurrent( *args ):
    if 'currentRL' in globals():
        cmds.editRenderLayerGlobals( currentRenderLayer = currentRL )

Plug-in的代码是有一个比较严格的格式的。首先是一定要有initializePlugin和uninitializePlugin这两个函数,分别是启用插件之后的动作和停用插件之后的动作。官网上的示例里是启用插件时注册了一个命令,注册不成功的话弹出错误警告,同样停用插件时注销命令,注销不成功的话弹出错误警告。

因为切换渲染层只涉及回调函数,不涉及命令也不涉及节点,所以可以省略定义命令或者节点的类的部分。把一开头的脚本里创建回调的部分放在initializePlugin函数里,因为还要考虑到停用插件时删掉回调函数,所以这里需要用一个全局的OM.MCallbackIdArray类的实例,把回调函数装进去。在uninitializePlugin函数里需要做的事情就是把回调函数都删掉就可以了。删掉回调函数需要用到OM.MMessage.removeCallbacks这个方法,把之前宣言的全局回调函数队列作为参数传递进去。

另外maya_useNewAPI这个函数的作用只是告诉maya这个插件是用api 2.0写的。函数不需要有内容,只要定义了就行。如果用api 2.0写了插件却没有定义这个函数的话插件载入的时候会报错(因为疏忽了这个花了3个多小时一直在debug…)

最后再把回调函数调用的切换渲染层的两个处理加进来这个插件就算完成了。把它保存到plug-ins文件夹里(通常是C:\Users\用户名\Documents\maya\版本号\plug-ins,没有的话就创建一个),再启动maya的话他就会出现在plug-in manager的窗口里了。把加载和自动加载都勾上的话maya保存的时候就会自动切换到默认渲染层,保存完后再切回之前的渲染层了。

总结

到现在总共使用了4种方法来实现保存文件时自动切换渲染层。下面总结了各种方法的优缺点(以代码知识相对少的用户视角)

基于命令的脚本导入回调函数的脚本userSetup方式自动启动plug-in方式
・操作简单
・方便终止
・操作简单
・关闭maya位置都处于启用状态
无需手动执行脚本plug-in管理器里通过图形界面来选择启用还是不启用
・每次保存都需要执行脚本
・不适用于其他情形的保存文件
・不会随maya自动启动
・只有关闭maya才能终止
・需要写userSetup文件、保存管理python文件
・只有关闭maya才能终止
可能没有吧

本文转载自 Tong Si