數碼資源網

文章頻道 軟件下載 安卓下載 蘋果下載

當前位置:首頁文章中心建模專欄Maya → mel語初解之二-多邊型建模篇

mel語初解之二-多邊型建模篇

時間:2005-07-29 10:53:03人氣:289作者:網友整理
東航MEL手冊管理係統v1.4.5
東航MEL手冊管理係統v1.4.5 for Android
  • 類型:安卓學習閱讀大小:17.60M語言:簡體中文 評分:3.1
  • 東航MEL手冊管理係統是一款專用於中國東方航空公司的培訓學習軟件,員工可以通過這...
立即下載
宮殿100日公主路易篇(十分甜美的戀愛之旅)  v1.2 安卓手機版
宮殿100日公主路易篇(十分甜美的戀愛之旅) v1.2 安卓手機版 for Android
  • 類型:角色扮演大小:487.60M語言:簡體中文 評分:3.0
  • 小編找到的宮殿100日公主路易篇是一款可以讓你跟路易開啟了十分甜美的戀愛之旅,並...
立即下載
點兔鬧鍾紗路篇安卓版(動漫鬧鍾app) v1.3.0 手機版
點兔鬧鍾紗路篇安卓版(動漫鬧鍾app) v1.3.0 手機版 for Android
  • 類型:安卓日常應用大小:56.15M語言:簡體中文 評分:3.0
  • 請問您今天要來點兔子嗎這部動漫裏麵的人物都是非常可愛的,而點兔鬧鍾紗路篇安卓版就...
立即下載

眾所周知,maya的多邊形建模能力是不如人意的,因此這時mel會派上很大的用場。相信很多人都用過一些輔助性的建模工具,例如MJPolyTools、BPT、icePolyTools、CPS、drawSplit、rockGen...我在教程中會對這些程序的關鍵功能的編寫方法作出詳細說明,希望大家能在掌握這些功能的基礎之上編寫出自己稱心如意的Poly工具。

mel作為腳本語言使用非常方便,在工作中會很容易地把你的一些簡單想法付諸實踐。

講Poly建模之前,需要複習一下以前的知識。

首先要複習一下數組(Array)
一群變量放到了一起,這群變量就成了一個數組變量。
不過這些變量不是隨便放的,每個變量都有一個房間,每個房間都有順次的門牌號,我們就是根據門牌號來訪問任何一個數組成員的。請看這個字符串數組的例子:

選擇幾個場景中的物體。

// 獲取場景中的每一個物體,分別放入數組$objects的每個房間中
string $objects[] = `ls -sl`;


這時數組的狀態如圖所示。
$objects可以看作是公寓的名稱,[]裏的紅色數字為房間的門牌號,也叫作索引號(index)。數組的索引號總是從0開始的。也就是說$objects[0]為數組的第一個成員,它的值為"pSphere1";而$objects[1]為數組的第二個成員,他的值為"pCube1";以此類推。

我們可以從數組中取值,例如:

string $obj = $objects[0];
// 此時變量$obj的值為"pSphere1"


也可以給數組的成員賦值,例如:

$objects[1] = "pBox1";
// 此時數組$objects的值為{"pSphere1", "pBox1", "pCone1"}



要想遍曆數組中的每個成員,可以用for語句,有兩種方法。

// 方法一
string $objects[] = `ls -sl`;
for ($i = 0; $i < size($objects); $i++)
{
string $obj = $objects[$i];
// do something ...
}

// 方法二
string $objects[] = `ls -sl`;
for ($obj in $objects)
{
// do something ...
}


[注] mel的for...in語句和JavaScript有所不同,$obj是字符串,指的是
當前的數組成員,等同於"string $obj = $objects[$i];"

再複習一下函數(Function)

如果你編寫比較複雜的程序,就會發現有很多經常用到的語句,這些語句經常以相同的組合出現。這樣的語句編寫起來有些麻煩,看起來也不太直觀。為了提高工作效率,增加可讀性,我們可以使用函數把它們封裝起來。下麵舉例說明。

還記得前麵講過的filterExpand獲取多邊形麵的方法吧?

string $faces[] = `filterExpand -ex 1 -sm 34`;


對初學者來說,看到"-sm 34"後,總是很難聯想到多邊形的麵。當然你可以用maya的全局變量$gSelectMeshFaces來替代34,不過這樣做有些麻煩。我們編一個新的函數來做與上麵代碼同樣的事情。

proc string[] getSelFaces()
{
return `filterExpand -ex true -sm 34`;
}
// [注] Sel為Selected的縮寫


有了這個函數,我們以後再獲取多邊形的麵時,就可以這樣寫:

string $faces[] = `getSelFaces`;


也可以這樣寫:

string $faces[] = getSelFaces();


return為返回的意思,proc後麵的字代表返回值的類型,return後麵的字(變量或表達式)代表返回值,也就是函數的輸出值。

再看一個例子:

proc string[] getPolySel(string $type)
{
if ($type == "vert")
return `filterExpand -ex true -sm 31`;

if ($type == "edge")
return `filterExpand -ex true -sm 32`;

if ($type == "face")
return `filterExpand -ex true -sm 34`;

// 假如輸入參數是非預期的,就返回一個空數組
string $null[];
return $null;
}


想要獲取多邊形的麵時,可以這樣寫:

string $faces[] = getSelFaces("face");


或:

string $faces[] = `getPolySel "face"`;


這回用到了函數的輸入參數(string $type),根據輸入參數的不同,產成不同的返回值。

一個函數可以既沒有輸入參數也沒有返回值,也可以隻有其一。參數可以是多個,返回值隻能是一個。

return語句執行之後,後麵的語句將不再執行。例如:

proc myProc()
{
// 獲取選擇的物體
string $objects[] = `ls -sl`;
// 如果什麼都沒選擇,就返回(什麼也不做)。
if (!size($objects))
return;

// do something ...
}



global procproc的區別

proc局部函數,局部函數隻能在編寫這個函數的mel文件中使用,不能在其他mel文件中使用,不能作為菜單和按鈕命令,不占用內存空間。

global proc全局函數,沒有proc那些局限。使用全局函數應注意,函數名不能與Maya中已有的全局函數或mel命令相同,否則會把原來的覆蓋掉,可以通過使用函數名前綴來避免重複命名。關於全局函數的使用,最好了解一些Maya的運行方式。Maya啟動時一般隻把指定scripts路徑中的*.mel文件名(*)載入內存,這樣Maya運行時就可以調用這個文件中的同名函數,而當調用這個同名函數時,這個mel文件中的所有全局函數將被載入內存,直到Maya退出。

如果還不明白,那就統統使用global proc好了,沒什麼大不了的。

下麵提供幾個多邊形建模常用到的函數,因為後麵經常用到,所以應該熟練掌握,至少對於每個函數做什麼事要很清楚。

// 獲取選擇的多邊形頂點
proc string[] getSelVerts()
{
return `filterExpand -ex true -sm 31`;
}

// 獲取選擇的多邊形邊
proc string[] getSelEdges()
{
return `filterExpand -ex true -sm 32`;
}

// 獲取選擇的多邊形麵
proc string[] getSelFaces()
{
return `filterExpand -ex true -sm 34`;
}

// 獲取選擇的多邊形UV點
proc string[] getSelUVs()
{
return `filterExpand -ex true -sm 35`;
}


用法範例:

// 獲取選擇的所有麵,存放到數組$faces[]中
string $faces[] = getSelFaces();



這四個函數是maya內置的,也是菜單命令,經常用到。

// 菜單命令:Edit Polygons->Selection->Convert Selection to Vertices
// 轉換當前選擇為頂點

ConvertSelectionToVertices();

// 菜單命令:Edit Polygons->Selection->Convert Selection to Edges
// 轉換當前選擇為邊

ConvertSelectionToEdges();

// 菜單命令:Edit Polygons->Selection->Convert Selection to Faces
// 轉換當前選擇為麵

ConvertSelectionToFaces();

// 菜單命令:Edit Polygons->Selection->Convert Selection to UVs
// 轉換當前選擇為UV點

ConvertSelectionToUVs();


這四個函數在maya的scripts/others目錄中,可以直接調用。

// 轉換當前選擇為頂點,並獲取這些頂點的名稱
global proc string[] getVerts()
{
select -r `polyListComponentConversion -tv`;
string $result[]=`filterExpand -ex true -sm 31`;
return $result;
}

// 轉換當前選擇為邊,並獲取這些點的名稱
global proc string[] getEdges()
{
select -r `polyListComponentConversion -te`;
string $result[]=`filterExpand -ex true -sm 32`;
return $result;
}

// 轉換當前選擇為麵,並獲取這些麵的名稱
global proc string[] getFaces()
{
select -r `polyListComponentConversion -tf`;
string $result[]=`filterExpand -ex true -sm 34`;
return $result;
}

// 轉換當前選擇為UV點,並獲取這些UV點的名稱
global proc string[] getUVs()
{
string $uvs[];
$uvs=`polyListComponentConversion -tuv`;
if (size($uvs) == 0) return $uvs;
select -r $uvs;
string $result[]=`filterExpand -ex true -sm 35`;
return $result;
}


// 根據點、邊、麵、UV點的名稱得出多邊形的名稱
// 例如多邊形一條邊的名稱為"pSphere1.e[637]",則這個多邊形的
// 名稱為"pSphere1"

proc string getBaseName(string $item)
{
string $buffer[];
if ($item != "")
{
tokenize($item, ".", $buffer);
}
return $buffer[0];
}


用法範例:

string $polyName = getBaseName("pSphere1.e[637]");
// 返回值:pSphere1


// 根據點、邊、麵、UV點的名稱得出它們的索引號
// 例如多邊形一條邊的名稱為"pSphere1.e[637]",則這個多邊形的
// 索引號為637

proc int getIndex(string $indexString)
{
string $buffer[];
tokenize($indexString, "[]", $buffer);
int $index = (int)$buffer[1];
return $index;
}


用法範例:

int $index = getIndex("pSphere1.e[637]");
// 返回值:637


下麵我為大家講解一下函數的幾個具體類型在大師麵前獻醜了)
a:有參函數
所謂有參函數是:
proc MyFn(int $a,$int $b);
{
.......
}
這樣的函數就是有參函數,因為在MyFn的後麵括號裏有參數...
如果調用MyFn函數的話:
proc MyFn1()
{
MyFn();
.......
}
這樣即可調用

b:無參函數就是
proc MyFn()
{

}
這個就稱為過程了吧,反正是這樣的,就是沒有參數,也沒有返回值,例如你要寫個UI的話,裏麵有菜單的話,假如很多很多,你可以單獨建一個函數專用來建菜單的函數,然後在主函數裏調用即可...

c:有返回值的函數,
有返回值的函數也可以有參數,也可以沒參數,
global proc int MyFn($int a,$int b)
{
return $a+$b;
}
這個就是含參數有返回值的函數,注意在定義函數的返回類型時要時刻小心,假如你的返回值是float型,而定義的是int型的函數,那他就會舍去小數點後麵的數了雖然看上去不會出錯的,但是還是注意為好的..

價如有個有返回值的函數是返回的一個場景裏所有物體名稱的函數,那該如何調用呢:
global proc string[] GetList()//
{
string $sel[]=`ls -sl`;
return $sel;
}
//
global proc MyFn()
{
string $print[]=`GetList()`;//這樣就調用了函數GetList,並把返回值賦予$print;
.....
}

其實mel裏的函數還是和c++裏的函數有點類似的...
獻醜了,希望各位前輩不要恥笑,在下也是為了大家能夠更好的學好mel
.....
下麵在說說maya的API吧

我想說的是其實api並非是多麼困難的事情,為什麼外國人能編寫那麼nb的軟件呢,外國人能作到的,我門也能作到的......
說道api,就是程序接口的意思,幾乎所有的大型軟件,可能都有api借口,什麼是接口呀,還不是軟件專家為了更好的擴展自己的程序,也為了第三方軟件生產商能夠混上口飯吃.
我門想擴展程序的功能,就要借助api,他是有一係列的頭文件組成的, 就是以h為後綴的文件,他裏麵把所有的類列舉出來,每個類是幹什麼的,他隻把類的名稱寫出來,但不會把具體的代碼寫出來,不然的話,就泄密了....
大家都知道c++的類是可以繼承的,我們編寫的maya插件就是以maya的各種類作為基類來擴展到我們想要的類,但是我門編寫的所有的類都是以MpxCommod為基類來擴展的....

關於MayaApi做一點補充。

MPxCommand不是所有類的基類,不過任何命令都是通過MPxCommand類的doIt()函數觸發的。

MayaApi其實就是Maya提供的5個dll文件的編譯庫。這些庫中包含控製Maya的大量類和函數,我們通過這些類和函數用vc++編寫自己的dll(mll)文件,這些函數通過Maya的方式(比如用mel命令的形式)來調用。

MayaApi比mel更強大,更複雜,效率更高,能做到許多mel做不到的事情。MayaApi類的功能主要體現在以下幾點:
1. 編寫mel命令。
2. 執行mel命令。
3. 進行創建物體,選擇、縮放、刪除等基本操作。
4. 編寫manipulator。
5. 編寫contexts(tool)。
6. 編寫屬性節點。
7. 編寫材質節點。
8. 文件輸入輸出。
9. 編寫獨立的exe控製台程序。

MayaApi程序看起來是無所限製,因為使用vc++,可以使用WinApi,MFC,還有很多SDK。不過不能更改Maya底層的東西,不能更改Maya的運作方式。

美工最好不要學MayaApi,因為編寫mel有可能提高你的工作效率,但編寫mll隻可能提高別人的工作效率。想對MayaApi做一些常識性的了解倒是沒什麼壞處。

學習MayaApi,一定要先學vc++,最好先學WinApi+OpenGL編程。Alias在範例代碼中隻提供了一些很基礎的、大家都知道的算法,價值不大。但由於MayaApi的學習資料甚少,這些代碼卻都是需要掌握的。如果你學了MFC,可以編寫Maya的外殼、Maya的播放器、Maya透明窗口、Maya窗口中玩遊戲,不過這些好像對工作沒什麼益處。

[注] 以上指的是Windows版的Maya。

上一節講的函數看起來不太好懂,我也沒對代碼多作解釋,其實隻要記住函數名和做什麼用的就行了,也就是記住那些紅字和對應的綠字。

繼續今天的課程,首先介紹一個有用的函數(intersectStringArray)。這個函數可以找到兩個數組的共同部分,比如數組1為{"兔子", "老虎", "山羊", "蟲子"},數組2為{"蟲子", "刀子", "梳子", "兔子", "珠子"},你可以獲得一個新數組包含它們的共同部分{"兔子", "蟲子"}。

// 獲得兩個數組的共同部分
proc string[] intersectStringArray(string $array1[], string $array2[])
{
global string $m_arrayIntersector;
if ($m_arrayIntersector == "")
$m_arrayIntersector = `stringArrayIntersector`;

stringArrayIntersector -edit -intersect $array1 $m_arrayIntersector;
stringArrayIntersector -edit -intersect $array2 $m_arrayIntersector;
string $result[] = `stringArrayIntersector -query $m_arrayIntersector`;
stringArrayIntersector -edit -reset $m_arrayIntersector;
return $result;
}


[注] global string代表一個全局字符串變量,以前講過全局變量應當盡量避免命名衝突。maya中的全局變量都是以小寫字母"g"開頭,為避免衝突,本教程中的全局變量一律使用"m_"作為前綴。

前麵介紹過的函數可以看作是工具函數,這些函數幾乎在以後的每個程序中都要用到。如果編寫某一功能,還需要編寫一些有針對性的專用函數

現在我們來編一個多邊形的導角功能,來看看一個完整的程序是怎樣完成的。

這是一些必須記住的單詞,相信所有學過Maya的人都不會感到陌生。

單詞 縮寫 解釋
polygon poly 多邊形
vertex v;ver;vert;vtx 多邊形頂點
edge e;ed 多邊形邊線
face f 多邊形麵
split 切割
index idx 索引

要編寫一個比較複雜的程序,我們首先考慮的是應該怎樣把這個程序做最大程度的簡化,要把一個龐大的東西拆成一小塊一小塊的分別去處理。

今天我們需要完成第一小塊,就是當你選擇一條邊時,程序可以在這條邊的兩側各切一刀,如圖。

要做到這一點,需要分成四步。

第一步,我們需要做一點準備工作,要了解一下切割命令polySplit和邊的構造順序。

為了更直觀的說明程序的原理,我盡量多放一些插圖。

選擇菜單Polygons->Create Polygon Tool,從左上角開始,畫一個正方形。
這時看看mel曆史窗,可以看到polyCreateFacet命令,這個命令目前還用不到,先不去管他。

依次選擇正方形的四個頂點,看看每個頂點的名稱和索引號。

可以發現索引號是按照創建時的順序指定的。分別為0,1,2,3。

再看看每條邊的索引號,也是按照創建時的順序指定的。一條邊有兩個點,分別為起點和終點,這兩個點決定了邊的構造順序。

使用Edit Polygons->Split Polygon Tool在正方形上切一刀。

我們看一下polySplit的用法,-ep後麵有兩個參數,第一個參數(3)是邊的索引號,第二個參數(0.263489)是百分比,如果邊的長度為1,切割點在邊的0.263489處。

切割點位置的受到邊的構造順序的影響,以polySurface1.e[3]這條邊為例,從邊的起點開始,沿著邊的終點方向量出整條邊的約26%的長度,這個位置就是切割點的位置。


使用polySplit的一大難點就是判斷邊的構造順序,也就是分清邊的起點和終點。為了做到這一點,我們需要用到一個mel命令 - polyInfo

選擇一條邊線(e[3]),在命令行執行"polyInfo -ev;",可以看到輸出結果"// Result: EDGE 3: 3 0 Hard",其中"EDGE 3:"代表邊線(e[3]),3和0分別代表組成這條邊的兩個點(vtx[3]和vtx[0])的索引號。注意,這兩個點的順序不是按大小排列的,而是按照邊線的構造順序。

我們把polyInfo按照自己的需要封裝起來。主要是用字符處理的方法實現的,注意這裏用到了一個前麵講過的工具函數getBaseName()。你會發現這個函數的用途與getVerts()很像,但getVerts()無法得知邊線的構造順序。

// 根據一條邊,得到這條邊的按構造順序排列的兩個端點。
proc string[] edge2Vertex(string $edge)
{
string $verts[], $buffer[];
string $edgeInfo[] = `polyInfo -ev $edge`;
int $nbVertex = tokenize($edgeInfo[0], $buffer);

string $polyName = getBaseName($edge);
$verts[0] = $polyName + ".vtx[" + $buffer[2] + "]";
$verts[1] = $polyName + ".vtx[" + $buffer[3] + "]";
return $verts;
}


第二步,我們要找到需要切割的兩條邊。

我們可以根據選擇的一條邊,和要切割的那個麵來判斷。

選擇一條邊。

Mel曆史窗中的代碼:

select -r polySurface1.e[6] ;


Edit Polygons->Selection->Convert Selection to Vertices,轉換成頂點。
[注] 這一步mel曆史窗中可能看不到變化,按z鍵undo一下就看到了。

Mel曆史窗中的代碼:

ConvertSelectionToVertices;


再選擇Edit Polygons->Selection->Convert Selection to Edges,轉換成邊。

Mel曆史窗中的代碼:

ConvertSelectionToEdges;


去掉開始那條邊的選擇。

Mel曆史窗中的代碼:

select -tgl polySurface1.e[6] ;


[注] select -d polySurface1.e[6] ;也可。

現在剩下四條邊,可以用getSelEdges()把它們存到一個數組中。
數組1:
{"polySurface1.e[1]",
"polySurface1.e[3]",
"polySurface1.e[4]",
"polySurface1.e[5]"}

選擇要切割的麵。

Mel曆史窗中的代碼:

select -r polySurface1.f[1] ;


getEdges()把屬於麵的四條邊存到另一個數組中。
{polySurface1.e[0],
polySurface1.e[1],
polySurface1.e[4],
polySurface1.e[6]}

用intersectStringArray()可以找到兩個數組的共同部分,就是我們將要切割的兩條邊。
{polySurface1.e[1],
polySurface1.e[4]}


把前麵Mel曆史窗中記錄下的代碼整理一下,就成了:

// 已知一個麵,這個麵的一條邊,求與(這個麵的)這條邊相鄰的兩條邊
proc string[] adjacentEdgesInFace(string $face, string $edge)
{
// 獲取所有相鄰的邊線
select -r $edge;
ConvertSelectionToVertices();
ConvertSelectionToEdges();
select -d $edge;
string $edges_vert[] = getSelEdges();

// 獲取已知麵的所有邊線
select -r $face;
string $edges_face[] = getEdges();

// 求兩個數組的共同部分
string $edges[] = intersectStringArray($edges_vert, $edges_face);
return $edges;
}


第三步,切割一個麵。

我們可以先把切割的百分比設置一個固定的數值,設為0.2(20%)。

我們可以通過edge2Vertex()來得到要切割的一條邊的起點和終點,如果起點恰好是當初選擇的那條邊線的一個端點(兩條邊的公共點),那麼這條線的構造順序是正的,可以直接使用20%;但如果構造順序是反的,那就要使用1-20%=80%了。

這個函數應該這麼寫:

proc splitByPercent(string $edge1, string $edge2, string $inputEdge)
{
// 預設值,百分比為0.2
float $percent = 0.2;
float $percent1 = $percent; // 0.2
float $percent2 = $percent; // 0.2

// 分別獲得三條邊所包含的頂點
string $verts1[], $verts2[], $vInput[];
$vInput = edge2Vertex($inputEdge);
$verts1 = edge2Vertex($edge1);
$verts2 = edge2Vertex($edge2);

// 求$edge1與$inputEdge的公共點
string $startVert[] = intersectStringArray($verts1, $vInput);
// 如果公共點不是$edge1的起點
if ($startVert[0] != $verts1[0])
// 百分比變為80%,即1-0.2
$percent1 = 1 - $percent;

// 求$edge2與$inputEdge的公共點
string $startVert[] = intersectStringArray($verts2, $vInput);
if ($startVert[0] != $verts2[0])
$percent2 = 1 - $percent;

// 獲得兩條邊的索引號
string $index1 = getIndex($edge1);
string $index2 = getIndex($edge2);

// 準備命令字符串
string $cmd = "polySplit -ch on -s 1 ";
$cmd += "-ep " + $index1 + " " + $percent1 + " ";
$cmd += "-ep " + $index2 + " " + $percent2 + " ";
$cmd += ";";

// 選擇整個多邊形物體
string $polyName = getBaseName($edge1);
select -r $polyName;

// 執行命令
evalEcho($cmd);
}

[注] 使用evalEcho執行命令可以把命令字符串在mel曆史窗中顯示出來。

第四步,切割邊線兩邊的麵。

有了前麵的準備工作,最後一步就顯得比較容易了。

global proc myEdgeChamfer()
{
// 獲取選擇的一條邊
string $edges[] = getSelEdges();
string $inputEdge = $edges[0];

// 獲取選擇的邊相鄰的兩個麵
string $faces[] = getFaces();

// 等比切割第1個麵
string $splitEdges[];
$splitEdges = adjacentEdgesInFace($faces[0], $inputEdge);
splitByPercent($splitEdges[0], $splitEdges[1], $inputEdge);

// 等比切割第2個麵
$splitEdges = adjacentEdgesInFace($faces[1], $inputEdge);
splitByPercent($splitEdges[0], $splitEdges[1], $inputEdge);
}


附全部源代碼。

///////////////////////////////////////////////////////////
// myEdgeChamfer.mel
// myEdgeChamfer v1

// 獲取選擇的多邊形頂點
proc string[] getSelVerts()
{
return `filterExpand -ex true -sm 31`;
}

// 獲取選擇的多邊形邊
proc string[] getSelEdges()
{
return `filterExpand -ex true -sm 32`;
}

// 獲取選擇的多邊形麵
proc string[] getSelFaces()
{
return `filterExpand -ex true -sm 34`;
}

// 根據點、邊、麵、UV點的名稱得出多邊形的名稱
// 例如多邊形一條邊的名稱為"pSphere1.e[637]",則這個多邊形的
// 名稱為"pSphere1"
proc string getBaseName(string $item)
{
string $buffer[];
if ($item != "")
{
tokenize($item, ".", $buffer);
}
return $buffer[0];
}

// 根據點、邊、麵、UV點的名稱得出它們的索引號
// 例如多邊形一條邊的名稱為"pSphere1.e[637]",則這個多邊形的
// 索引號為637
proc int getIndex(string $indexString)
{
string $buffer[];
tokenize($indexString, "[]", $buffer);
int $index = (int)$buffer[1];
return $index;
}

// 獲得兩個數組的共同部分
proc string[] intersectStringArray(string $array1[], string $array2[])
{
global string $m_arrayIntersector;
if ($m_arrayIntersector == "")
$m_arrayIntersector = `stringArrayIntersector`;

stringArrayIntersector -edit -intersect $array1 $m_arrayIntersector;
stringArrayIntersector -edit -intersect $array2 $m_arrayIntersector;
string $result[] = `stringArrayIntersector -query $m_arrayIntersector`;
stringArrayIntersector -edit -reset $m_arrayIntersector;
return $result;
}

///////////////////////////////////////////////////////////
// 第一步,根據一條邊,得到這條邊的按構造順序排列的兩個端點。
proc string[] edge2Vertex(string $edge)
{
string $verts[], $buffer[];
string $edgeInfo[] = `polyInfo -ev $edge`;
int $nbVertex = tokenize($edgeInfo[0], $buffer);

string $polyName = getBaseName($edge);
$verts[0] = $polyName + ".vtx[" + $buffer[2] + "]";
$verts[1] = $polyName + ".vtx[" + $buffer[3] + "]";
return $verts;
}

// 已知一個麵,這個麵的一條邊,求與(這個麵的)這條邊相鄰的兩條邊
proc string[] adjacentEdgesInFace(string $face, string $edge)
{
// 獲取所有相鄰的邊線
select -r $edge;
ConvertSelectionToVertices();
ConvertSelectionToEdges();
select -d $edge;
string $edges_vert[] = getSelEdges();

// 獲取已知麵的所有邊線
select -r $face;
string $edges_face[] = getEdges();

// 求兩個數組的共同部分
string $edges[] = intersectStringArray($edges_vert, $edges_face);
return $edges;
}

// 第三步,等比切割一個麵
proc splitByPercent(string $edge1, string $edge2, string $inputEdge)
{
// 預設值,百分比為0.2
float $percent = 0.2;
float $percent1 = $percent; // 0.2
float $percent2 = $percent; // 0.2

// 分別獲得三條邊所包含的頂點
string $verts1[], $verts2[], $vInput[];
$vInput = edge2Vertex($inputEdge);
$verts1 = edge2Vertex($edge1);
$verts2 = edge2Vertex($edge2);

// 求$edge1與$inputEdge的公共點
string $startVert[] = intersectStringArray($verts1, $vInput);
// 如果公共點不是$edge1的起點
if ($startVert[0] != $verts1[0])
// 百分比變為80%,即1-0.2
$percent1 = 1 - $percent;

// 求$edge2與$inputEdge的公共點
string $startVert[] = intersectStringArray($verts2, $vInput);
if ($startVert[0] != $verts2[0])
$percent2 = 1 - $percent;

// 獲得兩條邊的索引號
string $index1 = getIndex($edge1);
string $index2 = getIndex($edge2);

// 準備命令字符串
string $cmd = "polySplit -ch on -s 1 ";
$cmd += "-ep " + $index1 + " " + $percent1 + " ";
$cmd += "-ep " + $index2 + " " + $percent2 + " ";
$cmd += ";";

// 選擇整個多邊形物體
string $polyName = getBaseName($edge1);
select -r $polyName;

// 執行命令
evalEcho($cmd);
}

// 第四步,切割選擇的一條邊線兩邊的麵。
global proc myEdgeChamfer()
{
// 獲取選擇的一條邊
string $edges[] = getSelEdges();
string $inputEdge = $edges[0];

// 獲取選擇的邊相鄰的兩個麵
string $faces[] = getFaces();

// 等比切割第1個麵
string $splitEdges[];
$splitEdges = adjacentEdgesInFace($faces[0], $inputEdge);
splitByPercent($splitEdges[0], $splitEdges[1], $inputEdge);

// 等比切割第2個麵
$splitEdges = adjacentEdgesInFace($faces[1], $inputEdge);
splitByPercent($splitEdges[0], $splitEdges[1], $inputEdge);
}


寫到大括號裏就成了局部變量。

寫到大括號外麵就是全局變量,不過這時 float $bb = 5 ; 和 global float $bb = 5 ; 還是有一點點差別的,很容易讓人忽略。就是如果不寫global,包含這句代碼的mel文件如果不被source,隻是執行了mel文件的同名函數,那麼$bb載入內存時將不被賦值,這時$bb的值為 0。所以說最好寫上global。

下麵我想講一下關於全局變量和局部變量的區別吧.
如何定義全局變量呢,定義全局變量必須在所有自定義函數的外邊,不能定義在{}裏麵:
global int $a;//定義了全局變量,默認值是0
如果要調用的話:
proc myfn()
{
global int $a;//在調用全局變量的時候必須在自己的函數裏麵在定義一下
$a=10;
.....
}
//這樣就是調用的過程
強調一點的是,要想調用全局變量就必須在自己的函數裏麵在重新定義一邊.不燃的話,你試試看...嗬嗬

局部變量就是:
int $a;// 不加global 的
但是所有的變量都有生命期的,所謂的生命期就是在一定的範圍內有效...
proc myfn()
{
int $a=10;
if($a<20)
{
$a++;
.........
print $a;//reslut 11;
}
print $a;//result 11,而不是10了
.........
}
這樣就是生命期,如果你在後麵還調用的話,$a就不是10了,就是11了....

我還想講一下的就是,正如七月冰兒講的一樣,如果想得到幾個邊的名稱的話,
你會發現所有的名稱都是按照從小到大的順序進行排序的來的,這樣有好處也有壞處,壞處就是有時後我不想得到是排列之後的名稱,我之想得到不排列的名稱...
這也是多邊形的切割工具一直很麻煩的原因,總不能想3dmax那樣隨心所欲的進行切割了....
但是辦法是有的,目前我沒有想好,也許七月冰兒在他以後的版本裏會出現這樣的功能的....
我也在思索這個問題,其實大家在使用的過程當中,完全可以作出好多的快捷的功能的,就想在調權重值一樣,雖然maya提供了cmeditor,但還是很不方便的...
以後接著說,希望大家都能夠參與近來呀

假如你有一個mel文件,文件名為myTest.mel,文件內容如下:

float $bb = 5;
global proc myTest()
{
// do nothing
}


啟動Maya,使用env命令查看一下當前的全局變量,可以發現此時變量$bb不存在。當執行myTest命令時,這時$bb作為全局變量載入內存,再用env命令查看一下,發現$bb已經存在了。但是執行print $bb;會看到結果為0。

重新啟動Maya,啟動後執行source myTest.mel;這時再執行print $bb;可以看到輸出了正確的結果5,這時$bb已經作為全局變量載入了內存。

這就是我說的如果不寫global,包含這句代碼的mel文件如果不被source,隻是執行了mel文件的同名函數,那麼$bb載入內存時將不被賦值,這時$bb的值為 0。

如果你隻是(在所有大括號外麵)聲明變量,在函數中給它賦值,就可以不寫global了。比如代碼改成這樣就沒問題了。

// 在Maya6.0中測試通過
float $bb;
global proc myTest()
{
global float $bb;
$bb = 5;
}


如果想在函數外麵聲明和使用變量,又不想讓Maya當作全局變量,可以加大括號,函數的生命在大括號結束時消亡。例如:

{
float $bb;
... ...
}


關於全局變量的用法,可以參考junesnow的說明,不過要注意我做的一點更正。


相關文章

感謝速聯科技、八度網絡、九九數據、億恩科技、群英網絡讚助部分帶寬!

關於本站 | 聯係方式 | 版權聲明 | 下載幫助(?) | 網站地圖

Copyright 2002-2020 95262.com 【數碼資源網】 版權所有 粵ICP備2020128507號-1

本站所有軟件來自互聯網,版權歸原著所有。如有侵權,敬請來信告知 ,我們將及時撤銷。