【Maya教程】在Maya使用Python进行开发

15 九月, 2016
18
0

pymelSmallBanner_v002

写在前面

为什么要使用 Pymel ?对于一般的 artist 来说,他们可能不需要掌握特别高深的编程能力,但是如果会简单的编程应用,这在工作生活中还是能节约很多时间, 从而提高自己的工作效率,把更多的时间放在效果上,这是我一直所推荐的:

  能用程序解决的问题就没有必要进行人工操作,让artist们能更加专注于效果和艺术的提升。而不是把时间和精力浪费在大量的重复劳动之上。

那么在 maya 中我们该选择哪种编程手段来提高呢?大家也许听说过 maya 的 MEL,以及基本上的三维软件中都支持的python?那么 Pymel 呢?为什么在这推荐 artist 学习一下 Pymel 呢?最简单粗暴的来说,就是因为方便上手。如何方便上手,下面会通过几个案例来简单说明,我相信看完之后大家基本上都能使用来进行使用和上手。

Pymel是什么?

PyMEL makes python scripting in Maya work the way it should. Maya’s command module is a direct translation of MEL commands into python functions. The result is a very awkward and unpythonic syntax which does not take advantage of python’s strengths – particularly, a flexible, object-oriented design. PyMEL builds on the cmds module by organizing many of its commands into a class hierarchy, and by customizing them to operate in a more succinct and intuitive way.

所以这一堆英文讲的啥? Pymel又到底是啥呢?在这我不会讲太多关于Pymel的历史以及由来,因为在这我只是希望大家能最直接最简单的上手这东西,产生兴趣之后, 那么这东西到底是什么?在之后的分享中会慢慢和大家谈论与分享。

Pymel 是 maya python 中的一个模块,那么我们将如何使用以及快速上手呢?我们先在 maya 中打开 Script Editor 窗口,进行简单的 MEL , cmds ,以及 Pymel 对于同一个命令的几种不同用法。来讲一下我们为什么要用 pymel 。Script Editor 窗口在 maya 的 windows 菜单下可以打开如图:
Python for CG(2)
不过这是比较麻烦的一种打开方式,下面说说其他的方法。我们在可以在 maya 的右下角直接点击图标打开,如图:
Python for CG(2)

以及我们还可以在 panels 下面选择,如图:
Python for CG(2)

还有其他的使用方式可以打开和使用,也可以使用外部的 IDE 进行编辑然后 send 到 maya 内部来,如 Pycharm 等。不过这个方法暂时不会在这讲解,因为在这这是做个最简单的使用介绍。打开之后我们就能看到这么一个界面了。如图:
Python for CG(2)

上面密密麻麻写了一堆东西,这些是 maya 启动时会把你的预加载的插件加载进来的消息记录。就是 Plug-in Manager 里面的东西,加载的越多,开启 maya 的速度也就越慢,这上面的记录也就越多:
Python for CG(2)

废话不多说,我们来对比一下 MEL , cdms ,以及 Pymel 的区别;

MEL

string $sel[] = `ls -sl`; for($i in $sel) {     setAttr ($i+".sy") (rand(1,4)); }

cmds

import maya.cmds as cmds import random sel = cmds.ls(sl = True) for i in sel:     cmds.setAttr(i+".sy",random.randrange(1,4))

Pymel

import pymel.core as pm import random sel = pm.selected() for i in sel:     i.sy.set(random.uniform(1,4))

这三段代码都是把选择的物体的y轴进行批量的随机放大,效果基本如下:
执行前
Python for CG(2)

执行后
Python for CG(2)

很简单明了的看出效果了吧,那么先说说怎么执行代码。 Scpript Editor 窗口中这两个都是执行命令,不过一般我们会是有快捷键来进行操作,这两个命令的区别在于,一个能保留当前窗口的代码,快捷方式是选择需要执行的代码, Ctrl 回车, 另一个是执行完毕代码之后清理当前窗口的代码,快捷键不选择任何代码直接Ctrl 回车,不过一般建议是选择需要的代码在进行执行,这样方便测试,以及保留自己的代码。
Python for CG(2)

那么这三个不同的方式有什么区别呢?其实我们可以看到 MEL 与 cdms 基本上的方式是一样的,都是使用 setAttr 这个命令去对物体的 sy ,也就是 scaleY 的缩写进行控制,而 Pymel 则是调用了自身的方法去修改自身的 sy 属性。这可能有点绕口,其实这和 Pymel 的返回数据的类型是有关系的,Pymel 一般来说返回的都是一个 PyNode 类对象,什么叫做类的对象,这其实是 python 里面面向对象编程的一个重要的概念,在 python 中,可以认为一切都是对象,对象就会有自身的属性以及方法,是通过调用自身的方法去修改自身。而 MEL 和 cmds 基本上都是返回字符串,那么这样会有什么区别呢?

MEL 和 cmds 就好像每次执行都给你一个标签,然后你再使用各种手段去修改这个标签所对应的物体。而pymel每次执行都会给你生成一个对象,你可以理解这个对象就好像是一个人,然后你告诉这个人要去做什么,而且我们并不需要知道这个人是谁。不知道我这样说会不会说的明白,如果不明白的可以留言和我继续讨论。 不过pymel这样的话,因为每次返回的都是对象,所以在速度上, 很多情况上没有mel以及cmds要快。不过对于简单的操作,以及不是大数据的开发的时候,这并不会影响太多。那么这样为什么就方便了呢?下面再列举一个例子, 比如说我想要获取物体的轴心点位置,在 MEL 与 cmds 中就需要使用 xform 这个命令去求,而 PymelP则不是。

MEL

string $sel[] = `ls -sl`; for($i in $sel) {     vector $piv[] =  `xform -q -piv -ws $i`;     print $piv; }

cmds

import maya.cmds as cmds sel = cmds.ls(sl = True) for i in sel:     piv = cmds.xform(i,q = True,piv = True,ws = True)     print piv

Pymel

import pymel.core as pm sel = pm.selected() for i in sel:     piv = i.getPivots(worldSpace = True)     print piv

看到区别了么?我们来看看三组代码分别返回的是什么:

MEL

Python for CG(2)

cmds

Python for CG(2)

Pymel

Python for CG(2)
好吧,这能明显的看到 PymelP返回的都是 dt.Vector 这个类对象了吧,其实这样最大的好处是,我们可以通过 dir 这个命令去获取类上面的方法,以及通过 listAttr 去获取这个对象的属性,返回可以直接运用,而属性可以通过 get 去获取值,set 去修改值。而如像 MEL 和 cmds 一般每次返回的都是字符串或者数值, 那么我们就必须通过不同的函数命令去操作了,例子如下:

sel = pm.selected()

这我们就能获取了你选择物体的对象指向 sel 这个变量了,那么我们使用 dir 这个命令去执行他会返回什么呢?

dir(sel)

返回的将是:
Python for CG(2)

但是这貌似并不是我们想要的东西,是因为什么呢?那是因为 selected() 这个命令返回的是一个对象数组,所有的对象都在一个数组里,那么怎么才能正确的获得我们想要的呢?在这我们只选择了一个物体,那么我们就可以通过 sel[0] 数组切片的方法去获得第一个物体。

print dir(sel[0])

那么现在返回的数据基本上是我们现在需要的了:   Python for CG(2)

密密麻麻返回了一堆东西,那么这些东西我们有什么用?你们可以自己测试一下,比如说现在我们看到有 getScale 这个方法,那么我们就可以这样使用:

print sel[0].getScale()

看看会返回什么,这时应该会返回下面的数值:
Python for CG(2)

其他的另外的各种方法大家都可以尝试一下。然后我们说一下 listAttr 这个命令,因为有很多时候只是通过类方法去对物体修改是达不到我们想要实现的目的的,我们可能要去修改物体上的属性,这时我们就要获得我们想要修改属性的名称,例如如果我们有一盏 Arnold 的 aiAreaLight ,这时我们想要修改它的 Exposure 曝光度为 3 ,如果这时我们选择了这盏灯使用这个命令去修改的话是报错的:

sel = pm.selected() sel[0].Exposure.set(3)

这里其实有两错误,首先 Exposure 的属性名是错的,那么正确的属性名是什么?我们可以试着先修改物体,获得mel的反馈后改写成我们所需要的格式。
Python for CG(2)

通过这个我们可以看到其实我们需要的是 aiExposure 而不是 Exposure ,然后我们还可以看到其实这个属性是在 aiAreaLightShape1 上的,也就是物体的 shape 节点上的,而我们选择的 aiAreaLight1 是 transform 节点,关于这个节点的关系,我们会在以后的分享中进行讨论分析。那么我们如何通过pymel来获得选择问题的 shape 节点呢?其实我们可以在上面通过 dir 这个函数获得一堆数据中找到,就是 getShape 这个方法,那么现在我们改成;

sel = pm.selected() selShape = sel[0].getShape() selShape.aiExposure.set(3)

就能获得我们想要的正确的结果了,可是有时候我们并不能获得想要的返回值怎么办?比如说:
Python for CG(2)

我想获取这个开关,在 Script Editor 窗口中并没有返回信息,就算我们把显示全部返回数据打开也没有找到想要的信息,如果我们把这个打开,可能获得的是这样的信息:
Python for CG(2)
我们还是没有得到想要的数据,那么我们这时候就可以通过 listAttr 来获得全部属性了;

sel = pm.selected() print pm.listAttr(sel[0].getShape())

这时候我们貌似找到了我们需要的属性名称了:
Python for CG(2)

在这说一下,如果你通过上面的 print 输出 listAttr 的话,这些属性可能就会在同一列出现,如:
Python for CG(2)

这样的话就不是特别好查找了,我通常的方法是单独运行 listAttr 以及 dir 这样的命名获得返回值,或者你们也可以通过 for 循环进行逐个输出, 不过由于我们只是为了获得查找某个属性的而已,并不需要那么麻烦,只要单独运行即可,如单独运行:

pm.listAttr(sel[0].getShape())

那么这时我们已经获得我们想要知道的正确的属性名是什么了,那么代码应该为:

sel = pm.selected() selShape = sel[0].getShape() selShape.aiUseColorTemperature.set(1)

如果没出错的话我们已经通过代码把 aiUseColorTemperature 这个开关打开了,可以使用色温去控制灯光了。当然在这你会问,如果只是打开这个开关, 手动去点一下不是更快?对,是的,如果只是单个的话,手动的话是会更快。但是我们在项目生产中,打灯光往往并不只有这么一盏灯,而是十几盏到几十盏甚至几百盏,那么这时你手动去调整, 就真的太浪费时间了!

然后在最后我再说一下,是不是每次我们想要修改物体属性都需要去选择它呢?有些时候可能选择到一个物体很困难,比如说想要修改渲染设置的时候,我们又不想通过 MEL 或者 cmds 去修改,那么我们要怎么办?这时候 PyNode 这个东西就出现了。比如说我想要去修改 Arnold 渲染器的 AA 采样成 4 :
Python for CG(2)

我们就可以把代码写成这样:

pm.PyNode(`defaultArnoldRenderOptions`).AASamples.set(4)

这在我们进行某些预设定制的时候还是挺管用的,在快速打灯测试的时候使用低精度的采样,等出片前在进行一下高精度的采样测试。好了,这次主要就是分享了一下 Pymel 的简单使用,以及通过 dir , listAttr 获得我们想要的信息,最后是 PyNode 这个只有在 Pymel 下才有的函数方法,我觉得通过这几个函数,以及 for 循环,大家应该能把 Pymel 运用在工作学习中减少大量的重复劳动了。如果在其中我有讲的不正确或者对于此有疑问和困惑的朋友,可以给我留言,谢谢大家。