当前位置:首页>软件教程>maya教程>教程内容

mel语初解之一-基础和界面篇(2)

来源: 作者:admin 学习:20369人次

"myFullMoon"现在存在一个很大的缺陷,就是只能对那个半边脸(polySurface1)起作用,换个物体就不行了,要是程序里那个"polySurface1"能随意改成其它多边形物体就好了。
呵,要想好好,就要使用变量(variable)。

----------------------------------------
Maya的变量名称必须以一个美元符号($)开头,这是为了和物体名区别开。这很容易接受,如果可以不写"$",Maya会以为你的"polySurface1"也是变量。不过忘写美元符号是视金钱如粪土的mel初学者常犯的错误,我盼望大家少犯这种错误,不要辜负了Alia$Wavefront的一片苦心。

变量名称中不能包含有空格或其它的特殊字符,不能用中文。变量名称是大小写敏感(Case Sensitive)的,不能有大小写错误。mel命令和mel函数也是大小写敏感的,同样不能有大小写错误。

下面把有关变量的一些知识详细介绍一下:
------------------------------------------------------
下面列出了五种数据类型:
类型 含义 例子
int 整数 10 ,-5 ,0
float 小数 392.6 ,7.0 和-2.667
string 一个或多个字母 “What's up, chief?"
Vector 三个浮点数 《3 ,7.7 ,9.1 》
matrix 多个浮点数组 <<1.1, 2, 3; 6.7, 5, 4.9>>

在上面的类型中,除matrix(矩阵)类型外,都可以构成Array(数组)。一个数组是某种数据类型的多个数据的序列。例如,一个包含三个元素的数组就是一个整数,接着一个整数,再接着一个整数。用户可以把矩阵考虑为一个包含多个浮点数组的数组,或是一个二维浮点数组。
------------------------------------------------------
定义变量和为变量赋值
定义变量就是指明变量属于何种数据类型。为变量赋值就是给一个定义的变量以指定的数值。
下面的例子表明了如何使用一个步骤来定义和为变量赋值:
int $temp = 3 ;
float $Temp =222.222;
string $tEmp = “Heya kid.”;
vector $teMp = <<1,2.7,3.2>>;
matrix $temP[2][3]=<<4.5,1,0.2;-13,9911,0.007>>;

当用户精确的定义矩阵时,用户必须指明矩阵的行列数。下面的例子表明如何为整数、浮点、字符串和矢量数组赋值和定义它们。例子:数组的定义和赋值
int $Temp[5]={100, 1000, -70, 2, 9822};
float $TeMp[4]={ 43.3, -10.7, 0, 82.5};
string $TemP[3]={“Lord”,”Flies”,”cool brown fox2.”};
vector $tEmp[2]={<<0,0,0>>,<<0.01,-2,16>>};

如果一个变量被定义,但没有为其赋值,则Maya 为其分配默认的数值0 ,而对字符串变量,Maya 为其分配两个空引号。
------------------------------------------------------
Reserved words (保留字)
保留字是一些在MEL 中带有固定含义的单词。这些保留字可用于指定变量类型、逻辑控制,或描述一个数值。下面就是MEL 中的保留字。break case continue default do
else false float for global
if in int matrix no
off on proc return string
switch true vector while yes

Data type keywords (数据类型关键字)
int float vetor string matrix
Boolean constant keywords(布尔关键字)
yes no on off true false
Flow control keywords(流程控制关键字)
if else for while do in
break continue default switch case

其它的关键字
global return source catch alias proc
就像变量名称,保留字是大小写敏感的。因此,int 是整数类型,而Int 就不是。实际上,alias 、sourcecatch 也是保留字。因为它们使用起来,更像命令,它们没有包含在上面的表中。

关于变量的数据类型(Data Types),还得从int讲起。
int
int是整数(integer)的意思。例如:
int $i = 3;

有一种布尔类型的数据,在mel中也用int表示。布尔数据只有两个值,"是"或"否",mel用"1"或"0"来表示。因此,下面几句代码的作用是相同的。
int $bool = 1;
int $bool = yes;
int $bool = true;
int $bool = on;

与之对应的下面几句代码的作用也是相同的。
int $bool = 0;
int $bool = no;
int $bool = false;
int $bool = off;

float
float是小数,也就是浮点数的意思。例如:
float $f = 3.3333;

浮点运算是3d运算的重点,你一定也注意到了Maya中的大部分物体属性都是浮点数值。从表示颜色这一点就可以明显地看出来。比如说红色,在网页中或平面软件中的表示为FF0000(255, 0, 0)(整数),可在3d软件中,红色就成了(1.0000, 0.0000, 0.0000)(浮点数)。

下面该讲到字符串(string)了,今天的重点就是文字游戏。

"print"命令的用法:
"print"命令可以输出任何变量的值。如:
string $s = "你好世界";
print $s;
=======================
结果为:你好世界

string
string是字符串的意思,变量$a是个字符串,它的值为"你好世界"。
字符串的值要用引号引起来。有些情况下你不打引号Maya也会猜出是字符串,要我把这些情况一一列举可是件很麻烦的事,反正你只须知道是字符串打上引号肯定没错误,而如果你不打引号让Maya猜谜的话,Maya一旦猜不出就会有错误提示信息,你再根据此信息来修正。

转义符(escape character)
引号里面的字如果也有引号,就把"变为\"。和c语言一样,\为mel的转义符(escape character)。例如:
string $s = "你\"好\"世界";
print $s;
=======================
结果为:你"好"世界

除了引号以外,还有一些符号有时也要相应改变。比如把\变为\\,把tab空格变为\t,把换行符变为\n或\r\n等。

数组(array)
一旦你对字符串有了一定的印象,我就可以讲几个字符处理的mel命令了。
不过在这之前,还必须要提一提数组(array)的概念。
一群变量放在一起可以组成一个数组,例如:
int $ia[5]={100, 1000, -70, 2, 9822};

你也可以先弄一个空数组,然后往里填数据。
注意,数组是从零开始的!!!
例如:
string $sa[];
$sa[0] = "你好";
$sa[1] = "世";
$sa[2] = "界";
print $sa;
=======================
结果为:你好

下面来讲几个字符处理的mel命令,当然这几个命令的出场顺序要根据我们的实际需要来安排。这几个命令分别为:
substring
tokenize
size
clear
match
substitute

会了这几个命令,对于字符处理差不多就够用了。

在讲解之前,先把下面一行代码在命令行执行一下:
string $obj = "pSphere1.translateX";
=======================
结果为:pSphere1.translateX

"substring"命令的用法:
现在得到一个字符串$obj和它的值,可是这个值不是我们想要的。我们想要的只是这个物体的名称("pSphere1"),而不包括它的属性(".translateX")。怎样从$obj中提取物体的名称呢?方法很多,第一种方法是先指定你要提取的是"pSphere1.translateX"中的第几个字符到第几个字符。数数看,连猴子也能数出来,"pSphere1"是"pSphere1.translateX"中的第1个字符到第8个字符。好了,现在用"substring"命令:

substring $obj 1 8;
=======================
结果为:pSphere1

获取命令的返回值
这个结果是"substring"命令的返回值,这一点我在第一课里曾提到过。要想把命令值的返回存到一个变量里,以便以后使用,有两种方法:

// 第一种是用"`"的方法,比较常用。
string $objName = `substring $obj 1 8`;
=======================
结果为:pSphere1

// 第二种是用eval的方法,"eval"对于执行字符串中的命令很有用。
string $objName = eval("substring $obj 1 8");
=======================
结果为:pSphere1

对于不需要标志的命令,还有第三种方法:
// 这种方法符合学过c语言的人的习惯,用于一些脚本命令很方便。
string $objName = substring($obj, 1, 8);
=======================
结果为:pSphere1

这三种方法的结果是一样的,具体用哪种方法根据自己的习惯来决定。

"tokenize"命令的用法:
下面接着来讲把"pSphere1"从"pSphere1.translateX"中提取出来的第二种方法,这种方法不用数数,是一种很实用的方法。方法是从一个字符(".")的位置把字符串截成两段,把这两段存到一个字符串数组中。具体方法如下:
string $buffer[];
tokenize "pSphere1.translateX" "." $buffer;
string $objName = $buffer[0];
=======================
结果为:pSphere1

因为数组是从0开始的,$buffer[0]是"pSphere1.translateX"的第一段,它的值是"pSphere1",$buffer[1]是第二段,它的值是"translateX"。

"tokenize"是一个很有用的命令,我需要再举几个例子把它的用法讲明白。
"tokenize"的返回值是把字符串分成的段数,例如用"/"可以把"1/2/3/4/5"分成5份,"tokenize"的返回值就是5。如下:
string $buffer[];
int $numTokens = `tokenize "1/2/3/4/5" "/" $buffer`;
=======================
结果为:5

如果不指定分割字符,"tokenize"会根据一个默认的空格字符来分割。例如:
string $buffer[];
tokenize "How are you?" $buffer;
print $buffer;
=======================
结果为:How
are
you?
也就是: $buffer[0]=="How"; $buffer[1]=="are"; $buffer[2]=="you?";

"size"命令的用法:
"tokenize"的返回值可以表示字符串被分成的段数,通过衡量这个字符串的大小也可以得知字符串被分成的段数,这就要用到"size"命令:

string $buffer[];
tokenize "1/2/3/4/5" "/" $buffer;
int $numTokens = `size $buffer`;
=======================
结果为:5

"size"命令可以求出一个数组是由多少个元素组成,也可以求出一个字符串是由多少个字符组成。刚才说道猴子能数出"pSphere1"是由8个符组成,现在你不用数也会知道这一点,你知道我的意思当然不是指你就是猴子:
int $size = `size "pSphere1"`;
=======================
结果为:8

要注意的是一个中文字占用两个字节,"size"为2!
int $size = `size "中文"`;
=======================
结果为:4

"clear"命令的用法:
对于一些"size"很大的数组,会占用很多内存,你不用时要用"clear"把它清空。清空后它的"size"为0。
int $buffer[5]={1, 2, 3, 4, 5};
clear $buffer;
=======================
结果为:0

"match"命令的用法:
"match"是字符串中的查找功能,返回值是一个字符串。如果找到了,就返回要找的字符串,没找到,就返回""。例如:
match "this" "this is a test";
=======================
结果为:this

match "that" "this is a test";
=======================
结果为:

"match"命令可以使用通配符,以下是使用规则:
. 代表任何一个单独的字符
* 代表0个或多个字符
+ 代表1个或多个字符
^ 代表一行中第一个字符的位置
$ 代表一行中最后一个字符的位置
\ 转义符(escape character). 把它写在特殊的字符前面(如 '*')
[...] 代表指定范围内的任意一个字符
(...) 用于把部分通配符表述组织在一起

例:
match "a*b*" "abbcc";
=======================
结果为:abb

match "a*b*" "bbccc";
=======================
结果为:bb

match "a+b+" "abbcc";
=======================
结果为:abb

match "^the" "the red fox";
=======================
结果为:the

match "fox$" "the red fox";
=======================
结果为:fox

match "[0-9]+" "sceneRender019.iff";
=======================
结果为:019

match "(abc)+" "123abcabc456";
=======================
结果为:abcabc

match("\\^.", "ab^c");
=======================
结果为:^c

"substitute"命令的用法:
"substitute"是字符串中的替换功能,返回值是一个字符串,返回替换后的结果。例如:
string $text = "ok?";
$text = `substitute "?" $text "!"`;
=======================
结果为:ok!

也可以通过此方法把不想要的字符去掉。例如:
string $text = "ok?";
$text = `substitute "?" $text ""`;
=======================
结果为:ok

下面是"substitute"使用通配符的方法:
string $test = "Hello ->there<-";
string $regularExpr = "->.*<-";
string $s1 = `substitute $regularExpr $test "Mel"`;
=======================
结果为:Hello Mel

字符串的联合(unite)
最后讲一下字符串的联合(unite)。
字符串可以做加法,但不能做减法:
string $s1 = "你好";
string $s2 = "世界";
string $text = $s1 + $s2;
=======================
结果为:你好世界

字符串的加法跟数字的加法不同:
int $i = 1 + 2 + 3;
=======================
结果为:6

string $s = "1" + "2" + "3";
=======================
结果为:123

+=
以下两种写法的结果是相同的:
string $s = "你好";
$s = $s + "世界";
=======================
结果为:你好世界

string $s = "你好";
$s += "世界";
=======================
结果为:你好世界

添加注释
为了增加mel程序的可读性,你可以在你的mel代码中添加注释。注释可起到解释、提示或描述脚本的作用,程序执行时会跳过这些注释,执行注释以外的代码。mel的注释跟c语言是一样的。
--------------------------------------------
单行注释
如果要创建单行的注释,输入两个反斜线(//),然后输入注释:
int $locator = 7; //Default locator number is lucky.
--------------------------------------------
多行注释
如果要创建多行的注释,输入一个反斜线加一个星号(/*)。在注释的结束,输入一个星号加反斜线(*/)。
用户可以在一行或多行的某部分中使用这种注释。
/*This is an example of a
variable-line comment.*/
--------------------------------------------
注意,在表达式中不能使用多行注释技术,表达式中只能使用单行注释(//)。

上一课讲到了获取命令的返回值,有了这种方法,就可以继续我们的"myFullMoon"了。我们可以把选中的物体名称存入一个变量,再根据物体名称对物体进行处理。
--------------------------------------------
获取选中物体的名称
"ls"命令的用法:
ls -sl的意思就是获得选择物体的名称,要想对物体进行操作这是必然的一步。
我来具体演示一下方法,以便大家更好的掌握。

实例5:选择物体清单
新建一个场景,创建一盏直射灯、一个多边形球,一个多边形方块,一个Nurbs平面,一个Nurbs圆柱,一个细分方块。如图。
选中所有物体,然后执行"ls -sl"命令:
ls -sl;
=======================
结果为:pSphere1 pCube1 nurbsCylinder1 subdivCube1 directionalLight1 nurbsPlane1

下面编个程序以清单的形式输出物体名称:
global proc printObjNameSheet()
{
string $objects[] = `ls -sl`;
int $num = `size $objects`;

string $objNameSheet;
for($i=0; $i<$num; $i++)
{
$objNameSheet += $i+1;
$objNameSheet += ")";
$objNameSheet += $objects[ $i ];
$objNameSheet += "\n";
}

string $output = "\n*******************\n";
$output += "一共选择了";
$output += $num; // 注意$num不能写成"$num"
$output += "个物体\n";
$output += "它们分别是:\n";
$output += $objNameSheet;

print $output;
}
printObjNameSheet;
--------------------------------------------
把上面的代码拉到Shelf上,随便选择几个物体,然后执行这些代码,就会看到mel历史窗中输出的物体名称清单。

由于上一课已经讲过了字符处理的方法,相信你上面的大部分代码都看得懂。不过,"for($i=0; $i<$num; $i++)"这种语法以前没讲过,现在来具体讲讲。
$i++
$i++的意思就是$i=$i+1或$i+=1。

for语句
for语句是一个典型的循环语句。我下面具体分析一下。

string $objects[] = `ls -sl`;
int $num = `size $objects`;

如图,已知我们选中了三个物体,物体名分别存入了$objects数组中。
跟据我们所知的,用代数的方法把所知的值代入变量中,就有了以下结果:
$num == 3;
$objects[0] == nurbsPlane1;
$objects[1] == directionalLight1;
$objects[2] == pSphere1;

--------------------------------------------
string $objNameSheet;
for($i=0; $i<$num; $i++)
{
$objNameSheet += $i+1;
$objNameSheet += ")";
$objNameSheet += $objects&i;;
$objNameSheet += "\n";
}


继续用代数的方法:
//当$i=0时:
$objNameSheet += 0+1;
//这时:$objNameSheet == "1"
$objNameSheet += ")";
//这时:$objNameSheet == "1)"
$objNameSheet += $objects[0];
//这时:$objNameSheet == "1)nurbsPlane1"
$objNameSheet += "\n";
//这时:$objNameSheet == "1)nurbsPlane1\n"

//当$i=1时:
$objNameSheet += 1+1;
//这时:$objNameSheet == "1)nurbsPlane1\n2"
$objNameSheet += ")";
//这时:$objNameSheet == "1)nurbsPlane1\n2)"
$objNameSheet += $objects[1];
//这时:$objNameSheet == "1)nurbsPlane1\n2)directionalLight1"
$objNameSheet += "\n";
//这时:$objNameSheet == "1)nurbsPlane1\n2)directionalLight1\n"

//当$i=2时:
$objNameSheet += 2+1;
//这时:$objNameSheet == "1)nurbsPlane1\n2)directionalLight1\n3"
$objNameSheet += ")";
//这时:$objNameSheet == "1)nurbsPlane1\n2)directionalLight1\n3)"
$objNameSheet += $objects[2];
//这时:$objNameSheet == "1)nurbsPlane1\n2)directionalLight1\n3)pSphere1"
$objNameSheet += "\n";
//这时:$objNameSheet == "1)nurbsPlane1\n2)directionalLight1\n3)pSphere1\n"

//当$i=3时:
// $i = $num 结束循环


--------------------------------------------
因为mel不能设断点进行调试分析,我只好用这种笨办法来分析了,但愿你能看懂。

注意for语句分号的位置,初学者常会在这里出错,不要把分号写在那个小括号的后面。大括号后面也不要写分号。

关于获取选中物体的名称,再举一个例子。例如,你想把所有选中的物体沿x轴移动5:最简单的方法当然是: move -r -x 5;
不过,为了演示ls -sl的用法,请看下面的代码:
string $objects[] = `ls -sl`; // 获取选择物体名称
int $num = `size $objects`; // 获得物体的数量
for($i=0; $i<$num; $i++)
{
select -r $object;
move -r -x 5;
}

in
还有一种方法可以达到同样的效果:
string $objects[] = `ls -sl`; // 获取选择物体名称
for($object in $objects)
{
select -r $object;
move -r -x 5;
}

"filterExpand"命令的用法:
不过"ls -sl"是获得所有选择物体的名称,如果你只想对选择物体中的多边形物体进行操作,最好的方法是不用"ls",而用"filterExpand"。
// -sm 12是多边形物体, -sm 10是Nurbs表面,其它的请
// 参看filterExpand命令的帮助文档(help -doc filterExpand;)。
string $polygons[] = `filterExpand -sm 12`;
for($polygon in $polygons)
{
select -r $polygon;
move -r -x 5;
}

--------------------------------------------
[注]
用"ls"命令也有办法达到与"filterExpand"类似的效果,为了减轻你们的学习复担,我就不多讲了。用"filterExpand"更简便一些。

选中刚才那个场景的全部物体,下面的代码分类输出选择物体的名称:

global proc printObjNameSheet()
{
int $num;
string $polygons[] = `filterExpand -sm 12`;
string $nurbs[] = `filterExpand -sm 10`;
string $polyNNurbs[] = `filterExpand -sm 10 -sm 12`;

string $output = "\n*******************\n";
$output += "一共选择了";
$num = `size $polygons`;
$output += $num + "个多边形物体\n它们是:\n";

print $output;
print $polygons;

$output = "\n一共选择了";
$num = `size $nurbs`;
$output += $num + "个Nurbs物体\n它们是:\n";

print $output;
print $nurbs;

$output = "\n选择的物体中Nurbs物体和多边形物体共有";
$num = `size $polyNNurbs`;
$output += $num + "个\n它们是:\n";

print $output;
print $polyNNurbs;
}
printObjNameSheet;

学习 · 提示

  • 一定要打开PS,跟着教程做一遍,做完的图到这交作业:提交作业
  • 建议练习时,大家自己找素材,尽量不要用教程提供的素材。
  • 教程有看不懂的地方,可以到论坛发帖提问:新手求助
  • 加官方微信,随时随地,想学就能学:ps_bbs,或扫右侧二维码!
  • 关注我们学更多,每天都有新教程:新浪微博 抖音视频 微信小程序
- 发评论 | 交作业 -
最新评论
42017-01-13 04:08
42017-01-13 03:52
挺牛逼的
2016-03-14 07:30
超赞的文章
陈军波2015-12-14 12:59
竟然没人评论

关注大神微博加入>>

网友求助,请回答!