模块在Python 里是个很重要的概念,看到这里你应该对模块概念有所了解,它就好像是Python 与 MAYA 的一个接口一样。
在上一篇中,我主要介绍PYTHON的一些基础知识以及常用语法。在这一篇中,我们要结合MAYA中的命令来编写一些基本PYTHON脚本。其实在上一篇接近尾声的时候,我已经举例了如何导入模块的方法,这是真正使用PYTHON在MAYA中编写脚本的第一步。
import maya.cmds as mc #
这里顺便提一提,as mc可以用任何名词来代替,as cc也可以。这样,如果要调用polyCube()命令的话,就必须有cc.polyCube()作为前缀。基于笔者的个人习惯,我们这里还是用mc
PO
3.1 MEL命令和PYTHON命令之间的转化
我们导入MAYA的模块,现在要运用模块中的命令编写一些东西了。但是大家可能会很疑惑,写什么呢?我们总不见得整天在MAYA里做小学数学题吧- -现在我们需要学习一些MAYA的实用命令(比如上一篇提到的polyCube()创建一个立方体),学习实用命令的最好的途径是通过执行手动操作命令来获取MEL命令语句,然后把MEL命令转换成PYTHON命令。比如我们在MAYA3D视图中用传统的方法建立一个polygon的立方体,我会在脚本编辑器的输出部分得到以下输出信息:
polyCube -ch on -o on -w 9.9 -h 7.1 -d 10 -cuv 4; //注意大小写
这是一句MEL命令,描述了如何创建一个Polycube。MEL命令的结构十分简单,开头的polyCube就是这句MEL命令的主命令,后面的部分全部是参数。其中,带“-”的,是参数名称;没有“-”的,是该参数的值。一般都是一个带“-”号的参数名称,后面再跟一个不带“-”的值。有时后面会不跟值,这说明这个参数不需要值,它只是一个开关,带这个参数,说明这个开关开着,不带说明关着。现在,我们就把这句MEL命令转换成PYTHON可以执行的命令(我们暂时不去理会具体参数的作用,只是学习一个转换过程):
mc.polyCube(ch=1, o=1, w=9.9, h=7.1, d=10, cuv=4)
执行代码后同样得到了一个立方体。我们对比一下,可以发现PYTHON可以完全把MEL的命令转化过来,只是格式不一样。格式不同体现在一下几点:
- 有mc前缀(MEL没有前缀)
- 所有的参数信息需要放在主命令后的括号中(MEL没有括号)
- 参数名和它的值之间用等号隔开(MEL是用空格)
- 每个参数之间用逗号隔开(MEL用空格)
- 有些参数的值是1,而ME是on
关于最后一条,其实MEL的on也可以写成1,原因是,在PYTHON(包括其他程序语言),1这个值往往表示True,on等肯定意义的值,而0则表示False, off等否定意义的值。这样的值叫做布尔值(boolean),这种数据类型只有2种答案要么1,要么0;要么真,要么假;要么ON,要么OFF。例子中的1就是on,说明这个参数是可用的。
关于布尔值(其实你在MAYA中也可以把它理解成一个开关),以后还会讲到它的用法。节下来我们举一反三,熟练掌握MAYA命令转换的方法。
拖一个球出来,得到以下命令:
polySphere -ch on -o on -r 3;
转成PYTHON代码,就是:
mc.polySphere(ch=1, o=1, r=3)
还有一中转化形式:
我们如果在场景中选择了pCube1这个物体,会得到以下MEL命令:
select -r pCube1;
这里我们就不能写成mc.select(r=pCube1)了,因为现在这个命令基本上属于一个动作,一个动词,既然是动词,就必须有一个动作施与的对象,这里这个对象就是pCube1,而r这个参数其实replace的简写。注意这个r不是布尔值,它没有任何数据类型,只是一个开关而已。在MEL中,这个开关是不需要值的,但在PYTHON中,需要像布尔值那样给一个1的值,表示这个开关开启:
mc.select("pCube1", r=1) # 注意:PYTHON中,选择对象放在最前面。
# 注意名字的数据类型是字符,所以必须有双引号
如果要同时选择pCube1和pSphere1的话,需要用到列表,如下:
mc.select(["pCube1","pSphere"]) # 注意如果是选择集合的话,要用列表来表示
# r参数在这里我就不加了,但是不影响执行,体会下“可选”的作用
3.2 读取场景中信息的常用命令:
刚才我们知道了一些如何创建物体,以及如何选择物体的PYTHON命令。下面咱们要学习如何准确获取场景中你想要得到的信息,对于即将要编写的代码而言是十分重要的。比如,你要用命令对“所选的顶点”进行操作,那你就必须先要得到这些顶点信息,比如,这些点的ID号是那些?同样,如果要对“所选的MESH”进行操作,那你至少得让MAYA知道是哪些MESH。
3.2.1 得到所选物体的名字列表
那我们先来得到所选择的物体信息吧,这里用到一个新的命令ls(我这里提到命令绝对是常用的):
mc.select(["pCube1","pSphere"]) # 选择场景中的两个物体
mc.ls(sl=1) # ls就是list的简写,我们要list一些信息
# sl=1表示,我们要列出sl(select)的信息,“=1”就是一个开关,我们打开了它。
执行后,我们会从输出框中得到一个列表:["pCube1","pSphere"]。假如我们把第2行命令的结果赋予一个变量,那这个变量将继承这个命令执行的结果,如下:
sel=mc.ls(sl=1)
print sel
我们同样会得到["pCube1","pSphere"]这个结果,并且我们保存了这个列表结果到sel变量中去。假如你选择了N个物体,那你执行这句命令后会得到N个物体的列表。
3.2.1 得到和设置物体的属性getAttr()和setAttr()
下面再介绍2个非常有用的命令,getAttr()和setAttr()。前面那个是得到节点属性,后面那个是设置节点属性。我们同样可以借助MEL命令来获取一些命令信息。
3.2.1.1 setAttr()
我们选中刚才创建的pCube1,然后Ctrl+A打开属性窗口,找到pCube1节点中的Transform Attributes栏,我们把Translate行中的第一个值打成0,回车。现在我们在输出窗口中得到了一条MEL命令:
setAttr "pCube1.translateX" 0;
"pCube1.translateX"就是表示这个节点的TranslateX参数,后面的0表示它的值。这样我们也就可以把它转成PYTHON可以用的命令:
mc.setAttr("pCube1.translateX", 4) # 现学现用,我们把这个值再改成4
在PYTHON面板中执行后,发觉Translate行中的第一个值神奇地变成了4。同样,视图中的立方体也沿X轴平移了4个单位。同理,我们可以通过改变其他参数来获取其动作的MEL命令,然后把它转换成PYTHON可以用的命令。
3.2.1.2 getAttr()
下面,我给出如果获取属性值的命令:
mc.getAttr("pCube1.translateX") # 获取,pCube1的translateX参数的值。
执行后,我们得到4,也就是前面我们所设的那个数。同样,我们可以把这个值赋给一个变量:
a = mc.getAttr("pCube1.translateX")
print a
打印a的结果就是mc.getAttr("pCube1.translateX")的结果。
3.2.1.3 询问开关q
还有一种查寻其属性的方式,就是利用询问参数q。这里我们以xform命令来举例,如下:
mc.select("pCube1")
mc.xform(q=1, translation=1)
执行结果,返回一个包含了pCube1的XYZ位置信息的列表。我们看到xform命令的参数表中有2个参数,一个是q,一个是translation。其中,q=1表示当前这个命令已经进入询问状态,改命令不会对所选的物体进行任何操作,只会询问;translation=1,表示我们要询问的参数是translation,“=1”相当于一个开关,说明我们要询问这个“=1”的参数值。假如,我们的命令是mc.xform(q=1, translation=1, rotation=1),这样会出错,因为询问状态下,只返回一个参数的值。相反,如果 mc.xform(q=1, translation=1, rotation=0),也就是把rotation改成0,返回结果仍然会正确。
3.3 帮助文档的使用(灰常重要!)
有的人可能回问:我如何才可以知道,一个操作命令有多少个参数可以使用?一个节点到底有多少个属性可以设置?接下来我会给大家介绍下MAYA帮助文档的使用方式。
按F1打开MAYA帮助文档。在Content中找到Technical Documentation(技术文档),在这个技术文档中,我们需要用到的,就是CommandsPython和Nodes。CommandsPython中包含了所有MAYA中的PYTHON命令以及其参数的使用方法;Nodes列出了MAYA中所有的节点以及其属性的用法。
现在我们列举一个xform命令来了解如何结合帮助文档来完成你的操作
3.3.1 Python命令
点CommandsPython进入页面,在By substring中输入xform命令,在下面出现的SubString列表中选择xform,我们就可以进入xform命令页面。我们把该页面往下拖,跳过Notes,Related的内容,在Flags下有个长长表格,表格由3列组成:Long name(short name)长名(缩写), Argument types(数据类型), Properties(属性)。
- 长名(缩写)的意思就是:比如mc.xform(q=1, translation=1) 这条语句中translation是一个参数,我们可以在Flags下的列表中找到这个参数,我们观察它的长名(缩写)一列,translation后有一个(t),这个(t)就是他的缩写,我们可以用缩写来替代长名,如:mc.xform(q=1, t=1),效果完全一样。
- 数据类型就是这个参数所支持的数据类型,如果它的数据类型是Int的话,说明它只能支持整数,你只能把整数作为它的参数,或者在询问时只能得到整数的输出。同样如果是个boolean值的话,它只能支持0或1。
- 属性指的是这个参数的性能。这里的性能有4种,在MAYA帮助文档中用这4个字母表示:。其中C表示这个参数可以在该命令执行操作的时候使用;Q表示这个参数可以在询问状态下使用;E表示这个参数可以在编辑状态下使用;M表示这个参数可以拥有多种数据类型。一般情况下,C Q E用得最多。比如:mc.xform(q=1, t=1)这句命令就是典型的询问状态Q,询问内容是t,也就是translation。
3.3.2 Nodes信息
现在我们进入Nodes页面来了解下如何使用MAYA节点中的属性。
Nodes页面中所罗列出来的其实是MAYA中的所有节点类型。MAYA中充满着节点,我们任意选种场景中的某个节点,它都是属于某个Nodes页面中所罗列出来的类型。比如,我们选择之前在场景里创建的pCube1,它是属于什么类型的节点?是pCube节点吗?不是,我们无法在Nodes页面中搜索到。我们可以通过以下命令来询问节点的类型:
mc.objectType("pCube1") # objectType命令可以得到节点类型,实用推荐!
执行后,得到结果:transform。说明pCube1这个节点是transform节点。同样,我们询问:
mc.objectType("pSphere")
执行后,同样得到结果:transform。所以,虽然pCube1和pSphere节点名称不同,但是他们都是属于transform节点,千万不要认为他们是pCube类型或pSphere节点类型。
得到节点类型后,我们到Nodes页面,输入transform。找到transform,点入。找到Attributes下的长长列表。我们可以看到transform中有的参数。这些参数都可以通过getAttr()和setAttr()来获取和设置。我们来做下测试吧:)
mc.getAttr("pSphere.rz") # rz就是rotationZ的缩写
返回0.0,我们就得到了他的信息了。
关于文档使用的小结:其实我平时用的比较多的还是CommandsPython命令查询页面,因为在场景中很难找到命令及其参数的完整信息(当然,我们可以通过输出窗口中的MEL记录,但这些信息远远不够……)。关于Nodes,当我们需要知道某个节点的类型时,可以用到objectType来查询;或者当我们需要得到节点中某些属性的时候,也会用的到这个页面。
3.4 一个简单的脚本实例
这一节中,我要结合前三篇所讲的一些知识来作一个综合的小范例,并加上适当的注解,以便学习。
import maya.cmds as mc # 导入MAYA模块
def height(h): # 定义函数height,h为这个函数的一个参数
sel=mc.ls(sl=1) # 定义变量sel,把当前所选的内容赋予这个变量
for i in range(0,len(sel)): # 在sel这个选集范围里,对其中的每一个对象进行操作
mc.setAttr(sel[i]+".ty", h*i) # 所做的操作是:把每个对象的Y轴移动一个量。
# 这个量是这个函数的h参数乘以这个for循环的成员变量i
先执行以上这写代码。现在我们在场景中创建一个立方体,然后按Ctrl+D水平复制出若干个成一直线,全部选中这些立方体。如下图:
然后执行:
height(0.4)
执行height函数后,发现这些立方体的高度会发生一些变化,形成一斜线。并且,height的斜率会根据h的值的不同而不同。
代码的简单分析:
代码的结构不是很复杂,只有5行,前面3行应该不用作过多的解释,应该是很好理解的。我主要分析下最后的2行for循环语句。(看下面的文字时请注意对照源代码)
- 第一行for:假设我的场景里有5个pCube,分别叫pCube1, pCube2, pCube3, pCube4, pCube5,如果我选择的他们的话,那么sel变量会是这样一个列表:["pCube1", "pCube2", "pCube3", "pCube4", "pCube5"];len(sel)的值就是5;range(0,len(sel)) 就等于range(0,5),也就是[0,1,2,3,4]这样一个列表。所以说成员变量i的取值范围就在这个列表中,i将逐个被列表中的每一个成员替代。
- 第二行for:由于i有5个值可以取,所以setAttr会执行5次,每次执行时,就会把range范围列表中的值代入i。比如,当i=0的时候,sel[0]就是指范围列表中的第一个值,也就是"pCube1",sel[i]+".ty"指的就是"pCUbe1.ty",也就是pCube1的Y轴的移动值;h*i指的就是这个移动值的具体数字,其中i是在这里就是0,h的值取决于你在调用函数时在参数中所输入的数字,把整句话连接起来就是:当i=0时,并且h=2时(h值在我们调用函数时得到),执行mc.setAttr("pCube1.ty", 2*0),pCube1的Y的位移值等于0;以次类推,当i=4时,并且h=2时,执行mc.setAttr("pCube5.ty", 2*5),pCube5的Y的位移值等于10。