mel語(yǔ)初解之一-基礎(chǔ)和界面篇(2)
"myFullMoon"現(xiàn)在存在一個(gè)很大的缺陷,就是只能對(duì)那個(gè)半邊臉(polySurface1)起作用,換個(gè)物體就不行了,要是程序里那個(gè)"polySurface1"能隨意改成其它多邊形物體就好了。
呵,要想好好,就要使用變量(variable)。
----------------------------------------
Maya的變量名稱必須以一個(gè)美元符號(hào)($)開(kāi)頭,這是為了和物體名區(qū)別開(kāi)。這很容易接受,如果可以不寫(xiě)"$",Maya會(huì)以為你的"polySurface1"也是變量。不過(guò)忘寫(xiě)美元符號(hào)是視金錢(qián)如糞土的mel初學(xué)者常犯的錯(cuò)誤,我盼望大家少犯這種錯(cuò)誤,不要辜負(fù)了Alia$Wavefront的一片苦心。
變量名稱中不能包含有空格或其它的特殊字符,不能用中文。變量名稱是大小寫(xiě)敏感(Case Sensitive)的,不能有大小寫(xiě)錯(cuò)誤。mel命令和mel函數(shù)也是大小寫(xiě)敏感的,同樣不能有大小寫(xiě)錯(cuò)誤。
下面把有關(guān)變量的一些知識(shí)詳細(xì)介紹一下:
------------------------------------------------------
下面列出了五種數(shù)據(jù)類型:
類型 含義 例子
int 整數(shù) 10 ,-5 ,0
float 小數(shù) 392.6 ,7.0 和-2.667
string 一個(gè)或多個(gè)字母 “What's up, chief?"
Vector 三個(gè)浮點(diǎn)數(shù) 《3 ,7.7 ,9.1 》
matrix 多個(gè)浮點(diǎn)數(shù)組 <<1.1, 2, 3; 6.7, 5, 4.9>>
在上面的類型中,除matrix(矩陣)類型外,都可以構(gòu)成Array(數(shù)組)。一個(gè)數(shù)組是某種數(shù)據(jù)類型的多個(gè)數(shù)據(jù)的序列。例如,一個(gè)包含三個(gè)元素的數(shù)組就是一個(gè)整數(shù),接著一個(gè)整數(shù),再接著一個(gè)整數(shù)。用戶可以把矩陣考慮為一個(gè)包含多個(gè)浮點(diǎn)數(shù)組的數(shù)組,或是一個(gè)二維浮點(diǎn)數(shù)組。
------------------------------------------------------
定義變量和為變量賦值
定義變量就是指明變量屬于何種數(shù)據(jù)類型。為變量賦值就是給一個(gè)定義的變量以指定的數(shù)值。
下面的例子表明了如何使用一個(gè)步驟來(lái)定義和為變量賦值:
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>>;
當(dāng)用戶精確的定義矩陣時(shí),用戶必須指明矩陣的行列數(shù)。下面的例子表明如何為整數(shù)、浮點(diǎn)、字符串和矢量數(shù)組賦值和定義它們。例子:數(shù)組的定義和賦值
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>>};
如果一個(gè)變量被定義,但沒(méi)有為其賦值,則Maya 為其分配默認(rèn)的數(shù)值0 ,而對(duì)字符串變量,Maya 為其分配兩個(gè)空引號(hào)。
------------------------------------------------------
Reserved words (保留字)
保留字是一些在MEL 中帶有固定含義的單詞。這些保留字可用于指定變量類型、邏輯控制,或描述一個(gè)數(shù)值。下面就是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 (數(shù)據(jù)類型關(guān)鍵字)
int float vetor string matrix
Boolean constant keywords(布爾關(guān)鍵字)
yes no on off true false
Flow control keywords(流程控制關(guān)鍵字)
if else for while do in
break continue default switch case
其它的關(guān)鍵字
global return source catch alias proc
就像變量名稱,保留字是大小寫(xiě)敏感的。因此,int 是整數(shù)類型,而Int 就不是。實(shí)際上,alias 、source和catch 也是保留字。因?yàn)樗鼈兪褂闷饋?lái),更像命令,它們沒(méi)有包含在上面的表中。
關(guān)于變量的數(shù)據(jù)類型(Data Types),還得從int講起。
int
int是整數(shù)(integer)的意思。例如:
int $i = 3;
有一種布爾類型的數(shù)據(jù),在mel中也用int表示。布爾數(shù)據(jù)只有兩個(gè)值,"是"或"否",mel用"1"或"0"來(lái)表示。因此,下面幾句代碼的作用是相同的。
int $bool = 1;
int $bool = yes;
int $bool = true;
int $bool = on;
與之對(duì)應(yīng)的下面幾句代碼的作用也是相同的。
int $bool = 0;
int $bool = no;
int $bool = false;
int $bool = off;
float
float是小數(shù),也就是浮點(diǎn)數(shù)的意思。例如:
float $f = 3.3333;
浮點(diǎn)運(yùn)算是3d運(yùn)算的重點(diǎn),你一定也注意到了Maya中的大部分物體屬性都是浮點(diǎn)數(shù)值。從表示顏色這一點(diǎn)就可以明顯地看出來(lái)。比如說(shuō)紅色,在網(wǎng)頁(yè)中或平面軟件中的表示為FF0000(255, 0, 0)(整數(shù)),可在3d軟件中,紅色就成了(1.0000, 0.0000, 0.0000)(浮點(diǎn)數(shù))。
下面該講到字符串(string)了,今天的重點(diǎn)就是文字游戲。
"print"命令的用法:
"print"命令可以輸出任何變量的值。如:
string $s = "你好世界";
print $s;
=======================
結(jié)果為:你好世界
string
string是字符串的意思,變量$a是個(gè)字符串,它的值為"你好世界"。
字符串的值要用引號(hào)引起來(lái)。有些情況下你不打引號(hào)Maya也會(huì)猜出是字符串,要我把這些情況一一列舉可是件很麻煩的事,反正你只須知道是字符串打上引號(hào)肯定沒(méi)錯(cuò)誤,而如果你不打引號(hào)讓Maya猜謎的話,Maya一旦猜不出就會(huì)有錯(cuò)誤提示信息,你再根據(jù)此信息來(lái)修正。
轉(zhuǎn)義符(escape character)
引號(hào)里面的字如果也有引號(hào),就把"變?yōu)閈"。和c語(yǔ)言一樣,\為mel的轉(zhuǎn)義符(escape character)。例如:
string $s = "你\"好\"世界";
print $s;
=======================
結(jié)果為:你"好"世界
除了引號(hào)以外,還有一些符號(hào)有時(shí)也要相應(yīng)改變。比如把\變?yōu)閈\,把tab空格變?yōu)閈t,把換行符變?yōu)閈n或\r\n等。
數(shù)組(array)
一旦你對(duì)字符串有了一定的印象,我就可以講幾個(gè)字符處理的mel命令了。
不過(guò)在這之前,還必須要提一提數(shù)組(array)的概念。
一群變量放在一起可以組成一個(gè)數(shù)組,例如:
int $ia[5]={100, 1000, -70, 2, 9822};
你也可以先弄一個(gè)空數(shù)組,然后往里填數(shù)據(jù)。
注意,數(shù)組是從零開(kāi)始的!!
例如:
string $sa[];
$sa[0] = "你好";
$sa[1] = "世";
$sa[2] = "界";
print $sa;
=======================
結(jié)果為:你好
世
界
下面來(lái)講幾個(gè)字符處理的mel命令,當(dāng)然這幾個(gè)命令的出場(chǎng)順序要根據(jù)我們的實(shí)際需要來(lái)安排。這幾個(gè)命令分別為:
substring
tokenize
size
clear
match
substitute
會(huì)了這幾個(gè)命令,對(duì)于字符處理差不多就夠用了。
在講解之前,先把下面一行代碼在命令行執(zhí)行一下:
string $obj = "pSphere1.translateX";
=======================
結(jié)果為:pSphere1.translateX
"substring"命令的用法:
現(xiàn)在得到一個(gè)字符串$obj和它的值,可是這個(gè)值不是我們想要的。我們想要的只是這個(gè)物體的名稱("pSphere1"),而不包括它的屬性(".translateX")。怎樣從$obj中提取物體的名稱呢?方法很多,第一種方法是先指定你要提取的是"pSphere1.translateX"中的第幾個(gè)字符到第幾個(gè)字符。數(shù)數(shù)看,連猴子也能數(shù)出來(lái),"pSphere1"是"pSphere1.translateX"中的第1個(gè)字符到第8個(gè)字符。好了,現(xiàn)在用"substring"命令:
substring $obj 1 8;
=======================
結(jié)果為:pSphere1
獲取命令的返回值
這個(gè)結(jié)果是"substring"命令的返回值,這一點(diǎn)我在第一課里曾提到過(guò)。要想把命令值的返回存到一個(gè)變量里,以便以后使用,有兩種方法:
// 第一種是用"`"的方法,比較常用。
string $objName = `substring $obj 1 8`;
=======================
結(jié)果為:pSphere1
// 第二種是用eval的方法,"eval"對(duì)于執(zhí)行字符串中的命令很有用。
string $objName = eval("substring $obj 1 8");
=======================
結(jié)果為:pSphere1
對(duì)于不需要標(biāo)志的命令,還有第三種方法:
// 這種方法符合學(xué)過(guò)c語(yǔ)言的人的習(xí)慣,用于一些腳本命令很方便。
string $objName = substring($obj, 1, 8);
=======================
結(jié)果為:pSphere1
這三種方法的結(jié)果是一樣的,具體用哪種方法根據(jù)自己的習(xí)慣來(lái)決定。
"tokenize"命令的用法:
下面接著來(lái)講把"pSphere1"從"pSphere1.translateX"中提取出來(lái)的第二種方法,這種方法不用數(shù)數(shù),是一種很實(shí)用的方法。方法是從一個(gè)字符(".")的位置把字符串截成兩段,把這兩段存到一個(gè)字符串?dāng)?shù)組中。具體方法如下:
string $buffer[];
tokenize "pSphere1.translateX" "." $buffer;
string $objName = $buffer[0];
=======================
結(jié)果為:pSphere1
因?yàn)閿?shù)組是從0開(kāi)始的,$buffer[0]是"pSphere1.translateX"的第一段,它的值是"pSphere1",$buffer[1]是第二段,它的值是"translateX"。
"tokenize"是一個(gè)很有用的命令,我需要再舉幾個(gè)例子把它的用法講明白。
"tokenize"的返回值是把字符串分成的段數(shù),例如用"/"可以把"1/2/3/4/5"分成5份,"tokenize"的返回值就是5。如下:
string $buffer[];
int $numTokens = `tokenize "1/2/3/4/5" "/" $buffer`;
=======================
結(jié)果為:5
如果不指定分割字符,"tokenize"會(huì)根據(jù)一個(gè)默認(rèn)的空格字符來(lái)分割。例如:
string $buffer[];
tokenize "How are you?" $buffer;
print $buffer;
=======================
結(jié)果為:How
are
you?
也就是: $buffer[0]=="How"; $buffer[1]=="are"; $buffer[2]=="you?";
"size"命令的用法:
"tokenize"的返回值可以表示字符串被分成的段數(shù),通過(guò)衡量這個(gè)字符串的大小也可以得知字符串被分成的段數(shù),這就要用到"size"命令:
string $buffer[];
tokenize "1/2/3/4/5" "/" $buffer;
int $numTokens = `size $buffer`;
=======================
結(jié)果為:5
"size"命令可以求出一個(gè)數(shù)組是由多少個(gè)元素組成,也可以求出一個(gè)字符串是由多少個(gè)字符組成。剛才說(shuō)道猴子能數(shù)出"pSphere1"是由8個(gè)符組成,現(xiàn)在你不用數(shù)也會(huì)知道這一點(diǎn),你知道我的意思當(dāng)然不是指你就是猴子:
int $size = `size "pSphere1"`;
=======================
結(jié)果為:8
要注意的是一個(gè)中文字占用兩個(gè)字節(jié),"size"為2!
int $size = `size "中文"`;
=======================
結(jié)果為:4
"clear"命令的用法:
對(duì)于一些"size"很大的數(shù)組,會(huì)占用很多內(nèi)存,你不用時(shí)要用"clear"把它清空。清空后它的"size"為0。
int $buffer[5]={1, 2, 3, 4, 5};
clear $buffer;
=======================
結(jié)果為:0
"match"命令的用法:
"match"是字符串中的查找功能,返回值是一個(gè)字符串。如果找到了,就返回要找的字符串,沒(méi)找到,就返回""。例如:
match "this" "this is a test";
=======================
結(jié)果為:this
match "that" "this is a test";
=======================
結(jié)果為:
"match"命令可以使用通配符,以下是使用規(guī)則:
. 代表任何一個(gè)單獨(dú)的字符
* 代表0個(gè)或多個(gè)字符
+ 代表1個(gè)或多個(gè)字符
^ 代表一行中第一個(gè)字符的位置
$ 代表一行中最后一個(gè)字符的位置
\ 轉(zhuǎn)義符(escape character). 把它寫(xiě)在特殊的字符前面(如 '*')
[...] 代表指定范圍內(nèi)的任意一個(gè)字符
(...) 用于把部分通配符表述組織在一起
例:
match "a*b*" "abbcc";
=======================
結(jié)果為:abb
match "a*b*" "bbccc";
=======================
結(jié)果為:bb
match "a+b+" "abbcc";
=======================
結(jié)果為:abb
match "^the" "the red fox";
=======================
結(jié)果為:the
match "fox$" "the red fox";
=======================
結(jié)果為:fox
match "[0-9]+" "sceneRender019.iff";
=======================
結(jié)果為:019
match "(abc)+" "123abcabc456";
=======================
結(jié)果為:abcabc
match("\\^.", "ab^c");
=======================
結(jié)果為:^c
"substitute"命令的用法:
"substitute"是字符串中的替換功能,返回值是一個(gè)字符串,返回替換后的結(jié)果。例如:
string $text = "ok?";
$text = `substitute "?" $text "!"`;
=======================
結(jié)果為:ok!
也可以通過(guò)此方法把不想要的字符去掉。例如:
string $text = "ok?";
$text = `substitute "?" $text ""`;
=======================
結(jié)果為:ok
下面是"substitute"使用通配符的方法:
string $test = "Hello ->there<-";
string $regularExpr = "->.*<-";
string $s1 = `substitute $regularExpr $test "Mel"`;
=======================
結(jié)果為:Hello Mel
字符串的聯(lián)合(unite)
最后講一下字符串的聯(lián)合(unite)。
字符串可以做加法,但不能做減法:
string $s1 = "你好";
string $s2 = "世界";
string $text = $s1 + $s2;
=======================
結(jié)果為:你好世界
字符串的加法跟數(shù)字的加法不同:
int $i = 1 + 2 + 3;
=======================
結(jié)果為:6
string $s = "1" + "2" + "3";
=======================
結(jié)果為:123
+=
以下兩種寫(xiě)法的結(jié)果是相同的:
string $s = "你好";
$s = $s + "世界";
=======================
結(jié)果為:你好世界
string $s = "你好";
$s += "世界";
=======================
結(jié)果為:你好世界
添加注釋
為了增加mel程序的可讀性,你可以在你的mel代碼中添加注釋。注釋可起到解釋、提示或描述腳本的作用,程序執(zhí)行時(shí)會(huì)跳過(guò)這些注釋,執(zhí)行注釋以外的代碼。mel的注釋跟c語(yǔ)言是一樣的。
--------------------------------------------
單行注釋
如果要?jiǎng)?chuàng)建單行的注釋,輸入兩個(gè)反斜線(//),然后輸入注釋:
int $locator = 7; //Default locator number is lucky.
--------------------------------------------
多行注釋
如果要?jiǎng)?chuàng)建多行的注釋,輸入一個(gè)反斜線加一個(gè)星號(hào)(/*)。在注釋的結(jié)束,輸入一個(gè)星號(hào)加反斜線(*/)。
用戶可以在一行或多行的某部分中使用這種注釋。
/*This is an example of a
variable-line comment.*/
--------------------------------------------
注意,在表達(dá)式中不能使用多行注釋技術(shù),表達(dá)式中只能使用單行注釋(//)。
上一課講到了獲取命令的返回值,有了這種方法,就可以繼續(xù)我們的"myFullMoon"了。我們可以把選中的物體名稱存入一個(gè)變量,再根據(jù)物體名稱對(duì)物體進(jìn)行處理。
--------------------------------------------
獲取選中物體的名稱
"ls"命令的用法:
ls -sl的意思就是獲得選擇物體的名稱,要想對(duì)物體進(jìn)行操作這是必然的一步。
我來(lái)具體演示一下方法,以便大家更好的掌握。
實(shí)例5:選擇物體清單
新建一個(gè)場(chǎng)景,創(chuàng)建一盞直射燈、一個(gè)多邊形球,一個(gè)多邊形方塊,一個(gè)Nurbs平面,一個(gè)Nurbs圓柱,一個(gè)細(xì)分方塊。如圖。
選中所有物體,然后執(zhí)行"ls -sl"命令:
ls -sl;
=======================
結(jié)果為:pSphere1 pCube1 nurbsCylinder1 subdivCube1 directionalLight1 nurbsPlane1
下面編個(gè)程序以清單的形式輸出物體名稱:
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不能寫(xiě)成"$num"
$output += "個(gè)物體\n";
$output += "它們分別是:\n";
$output += $objNameSheet;
print $output;
}
printObjNameSheet;
--------------------------------------------
把上面的代碼拉到Shelf上,隨便選擇幾個(gè)物體,然后執(zhí)行這些代碼,就會(huì)看到mel歷史窗中輸出的物體名稱清單。
由于上一課已經(jīng)講過(guò)了字符處理的方法,相信你上面的大部分代碼都看得懂。不過(guò),"for($i=0; $i<$num; $i++)"這種語(yǔ)法以前沒(méi)講過(guò),現(xiàn)在來(lái)具體講講。
$i++
$i++的意思就是$i=$i+1或$i+=1。
for語(yǔ)句
for語(yǔ)句是一個(gè)典型的循環(huán)語(yǔ)句。我下面具體分析一下。
string $objects[] = `ls -sl`;
int $num = `size $objects`;
如圖,已知我們選中了三個(gè)物體,物體名分別存入了$objects數(shù)組中。
跟據(jù)我們所知的,用代數(shù)的方法把所知的值代入變量中,就有了以下結(jié)果:
$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";
}
繼續(xù)用代數(shù)的方法:
//當(dāng)$i=0時(shí):
$objNameSheet += 0+1;
//這時(shí):$objNameSheet == "1"
$objNameSheet += ")";
//這時(shí):$objNameSheet == "1)"
$objNameSheet += $objects[0];
//這時(shí):$objNameSheet == "1)nurbsPlane1"
$objNameSheet += "\n";
//這時(shí):$objNameSheet == "1)nurbsPlane1\n"
//當(dāng)$i=1時(shí):
$objNameSheet += 1+1;
//這時(shí):$objNameSheet == "1)nurbsPlane1\n2"
$objNameSheet += ")";
//這時(shí):$objNameSheet == "1)nurbsPlane1\n2)"
$objNameSheet += $objects[1];
//這時(shí):$objNameSheet == "1)nurbsPlane1\n2)directionalLight1"
$objNameSheet += "\n";
//這時(shí):$objNameSheet == "1)nurbsPlane1\n2)directionalLight1\n"
//當(dāng)$i=2時(shí):
$objNameSheet += 2+1;
//這時(shí):$objNameSheet == "1)nurbsPlane1\n2)directionalLight1\n3"
$objNameSheet += ")";
//這時(shí):$objNameSheet == "1)nurbsPlane1\n2)directionalLight1\n3)"
$objNameSheet += $objects[2];
//這時(shí):$objNameSheet == "1)nurbsPlane1\n2)directionalLight1\n3)pSphere1"
$objNameSheet += "\n";
//這時(shí):$objNameSheet == "1)nurbsPlane1\n2)directionalLight1\n3)pSphere1\n"
//當(dāng)$i=3時(shí):
// $i = $num 結(jié)束循環(huán)
--------------------------------------------
因?yàn)閙el不能設(shè)斷點(diǎn)進(jìn)行調(diào)試分析,我只好用這種笨辦法來(lái)分析了,但愿你能看懂。
注意for語(yǔ)句分號(hào)的位置,初學(xué)者常會(huì)在這里出錯(cuò),不要把分號(hào)寫(xiě)在那個(gè)小括號(hào)的后面。大括號(hào)后面也不要寫(xiě)分號(hào)。
關(guān)于獲取選中物體的名稱,再舉一個(gè)例子。例如,你想把所有選中的物體沿x軸移動(dòng)5:最簡(jiǎn)單的方法當(dāng)然是: move -r -x 5;
不過(guò),為了演示ls -sl的用法,請(qǐng)看下面的代碼:
string $objects[] = `ls -sl`; // 獲取選擇物體名稱
int $num = `size $objects`; // 獲得物體的數(shù)量
for($i=0; $i<$num; $i++)
{
select -r $object;
move -r -x 5;
}
in
還有一種方法可以達(dá)到同樣的效果:
string $objects[] = `ls -sl`; // 獲取選擇物體名稱
for($object in $objects)
{
select -r $object;
move -r -x 5;
}
"filterExpand"命令的用法:
不過(guò)"ls -sl"是獲得所有選擇物體的名稱,如果你只想對(duì)選擇物體中的多邊形物體進(jìn)行操作,最好的方法是不用"ls",而用"filterExpand"。
// -sm 12是多邊形物體, -sm 10是Nurbs表面,其它的請(qǐng)
// 參看filterExpand命令的幫助文檔(help -doc filterExpand;)。
string $polygons[] = `filterExpand -sm 12`;
for($polygon in $polygons)
{
select -r $polygon;
move -r -x 5;
}
--------------------------------------------
[注]
用"ls"命令也有辦法達(dá)到與"filterExpand"類似的效果,為了減輕你們的學(xué)習(xí)復(fù)擔(dān),我就不多講了。用"filterExpand"更簡(jiǎn)便一些。
選中剛才那個(gè)場(chǎng)景的全部物體,下面的代碼分類輸出選擇物體的名稱:
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 + "個(gè)多邊形物體\n它們是:\n";
print $output;
print $polygons;
$output = "\n一共選擇了";
$num = `size $nurbs`;
$output += $num + "個(gè)Nurbs物體\n它們是:\n";
print $output;
print $nurbs;
$output = "\n選擇的物體中Nurbs物體和多邊形物體共有";
$num = `size $polyNNurbs`;
$output += $num + "個(gè)\n它們是:\n";
print $output;
print $polyNNurbs;
}
printObjNameSheet;
學(xué)習(xí) · 提示
相關(guān)教程