*************   MEL 语言初级教程(一)   Goomoo(古木) 2002/5/16*************** 
// 如需转载,请注明作者。如欲用于商业用途,请与我联系:zengjinsong@263.net // 
    首先,我们不讲枯燥的语法,来点实在的。 
    打开Maya的脚本编辑器(Window->General Editors->Script Editor),脚本编辑器分为上下两栏,上栏为历史栏,显示的是曾经操作的命令及其结果以及错误、警告等。下一栏是命令输入栏,我们可以在其中输入相关命令。请试着输入如下语句: 
window -vis true; 
然后按下Ctrl+Enter键,是不是立即弹出了一个标题为"window1"的窗口?那么这句话是什么意思呢?window是一个命令,表示我们要创建或修改一个窗口。vis是visible的缩写,即“可见”,-vis是window命令的一个开关,true则是该开关的参数,意为“是”。连起来说就是:创建一个窗口并使它可见。于是我们就得到了一个缺省的窗口,它的标题栏为"window1",名称也为"window1",但注意名称我们看不见,但从历史栏的最后一栏我们可以得知。下面我们更改该窗口的标题,在输入栏中输入: 
window -e -t "ChinaDV" window1; 
按下Ctrl+Enter键执行命令。我们看到,窗口的标题变成了"ChinaDV"。这句话又是什么意思呢?e是指edit,t是指title,表示我们要编辑名称为window1的窗口,把它的标题栏改为"ChinaDv"。当然,我们也可以用一条语句在生成窗口的同时指定窗口的标题、名称、长宽等属性。试着输入: 
window -w 450 -h 600 -vis true -t "Goomoo Studio" myFirstWindow; 
并执行之。这次我们得到了一个更大的窗口,它的宽度为450象素,高为600象素,标题为"Goomoo Studio",名称为"myFirstWindow"。 
    关闭标题为"ChinaDV"的那个窗口,将窗口"Goomoo Studio"调小些(怎么调?用鼠标呗!),使之不挡住主网格。再在命令栏中输入: 
sphere; 
并执行,看到了什么?视图的中间出现了一个nurbs球体。所以,sphere命令用来生成nurbs球体。 
下面我们要实现这样一个目的:在窗口Goomoo Studio上生成一个按钮,每单击一次该按钮,在视图的随机位置创建一个半径随机且小于1的nurbs球体。请输入以下两行: 
columnLayout; 
button -l "Create Random Sphere" -c " sphere -p (rand(-12.0,12.0)) (rand(-12.0,12.0)) (rand(-12.0,12.0)) -r (rand(1.0));"; 
输入时请注意大小写和括号、分号和引号,不要输错。执行完后,我们发现,窗口Goomoo Studio上出现了一个标题为"Create Random Sphere"的按钮。那么,这两句话又是什么意思呢? 
欲知详情,请听下回分解。 
下课! 
作业:单击"Create Random Sphere"按钮1000次,体会mel语言带来的乐趣!
*************   MEL 语言初级教程(二)   Goomoo(古木) 2002/5/15*************** 
//    如需转载,请注明作者。如欲用于商业用途,请与我联系:zengjinsong@263.net // 
    上节课的作业完成得怎样?要单击1000次才能生成1000个随机的球,太累!今天我们的目标是只单击一次就生成1000个随机的球,让我们为了此目标而奋斗吧! 
    先解决上节课悬而未决的问题。在上节课中,我们看到了一个很长的命令: 
button -l "Create Random Sphere" -c " sphere -p (rand(-12.0,12.0)) (rand(-12.0,12.0)) (rand(-12.0,12.0)) -r (rand(1.0));"; 
    这里,button表示要创建一个按钮,l即label,也就是要指定按钮上面的文字,而“Create Random Sphere”则是该开关的参数;c是command,表示单击该按钮后所要执行的命令。注意:这些命令要用双引号括起来。这里,我们要执行的命令是: 
sphere -p (rand(-12.0,12.0)) (rand(-12.0,12.0)) (rand(-12.0,12.0)) -r (rand(1.0)); 
    p即position,指定球的位置,用三个浮点数(即实数)分别表示它的x,y,z坐标,这里x,y,z的值全为rand(-12.0,12.0),这是什么意思呢?rand()是一个数学函数,它可以带一个或两个参数。当他带一个参数的时候,比如rand(10.0),表示从0到10.0中间随机取一个值,这个值可能是3.14159,也可能是2.71828,当然也可能是7.88414(吃点88试一试,:));当他带两个参数的时候,比如rand(-12.0,12.0),表示从-12到12之间取一个随机的实数,因此有可能是-9.600,3.245,12.0等。你可以在脚本编辑器中试着输入下列命令来体会rand()函数: 
print(rand(10)); 
print(rand(-10,10)); 
命令的结果将显示在命令历史栏中。 
r即radius,表示球的半径。 
    我们再在命令栏中输入下面一段: 
window -vis true;columnLayout; 
button -l "Create Random Sphere" -c "  int $i; 
for($i=0;$i<1000;$i++) 
sphere -p (rand(-12.0,12.0)) (rand(-12.0,12.0)) (rand(-12.0,12.0)) -r (rand(1.0)); " 
按数字键盘上的Enter键执行之,然后单击窗口上的“Create Random Sphere”按钮。****严正声明****:死机了可别怪我! 
哎呀!我要上班了,明天再写。 
下课! 
*************   MEL 语言初级教程(三)   Goomoo(古木) 2002/5/16*************** 
//    如需转载,请注明作者。如欲用于商业用途,请与我联系:zengjinsong@263.net // 
    执行完上次的命令后,你的机器死过去了吗?没有?那好,这样的机器才有做三维的资格啊。 
    在上节课的那个更长的命令中,我们看到了三个陌生的东西:“int”、“for(;;)”和“$i”。先从简单的讲起。 
$i是一个自定义的变量,它和物体的自定义属性差不多。变量名只能由字母、数字和下划线组成。那么如何理解变量呢?你可以把一个变量想像成一个盒子,这个盒子里可以存放各种数据,包括整数、实数、字符串、矢量等。“int”即“integer”是一个定义符,“int $i”指明了代号为$i这个盒子里只能存放整数,此外比较常用的有:float(实数),string(字符串)等。 
    注意:在mel中,所有的变量前都需要加一个“$”符号。为什么要这样呢?我想有两个方面的原因:一是与Maya系统所定义的变量区分开来,以免发生冲突;二是A|W公司可能缺钱花,这样规定之后呢,看着mel脚本上满眼的美元,心里那个爽啊!哈哈!! 
    for(;;)语法可就有点难了,大家要可要认真学罗。还是用实例来讲解吧,输入: 
int $i,$sum; 
$sum=0; 
for($i=1;$i<1001;$i++) 
$sum=$sum+$i; 
print($sum); 
    执行完后,我们看到了结果:500500。这就是从1加到1000的和(是否想起了高斯?)。第一句定义了两个整型变量:$i和$sum,$i用来控制循环,$sum用来存放相加的结果。第二句首先将结果置零。 
    下面就是for循环了,for循环首先执行第一条语句:$i=1,它将变量$i赋值为1;然后执行第二句:$i<1001,判断$i的值是否小于1001,如果是,就执行$sum=$sum+$i;显然,这条语句马上被执行了,所以,$sum=0+1=1;(否则,就跳出循环,执行print($sum);这条语句)然后才执行$i++,这是什么意思呢?这表示变量$i的值自加1,即$i=$i+1,所以$i=1+1=2,然后再次进行判断$i的值是否小于1001,如果是,则再次执行$sum=$sum+$i;显然,这次又执行了,$sum的值由1增为2...如此循环不已,直至$i的值大于1000为止,所以这个循环一共执行了1000次,$sum的值也就从1加到1000。说了这么多,不知大家听懂了没有,如果还没懂,看看附图吧。另外要注意,如果循环体有多条语句,这些语句要用花括号括起来,比如: 
float $i,$sum,$multi; 
$sum=0; 
$multi=1; 
for($i=1;$i<51;$i++) 
{ 
$sum+=$i; 
$multi*=$i; 
} 
print($sum); 
print("\n"); 
print($multi); 
显示结果: 
1275 
30414093201713376000000000000000000000000000000000000000000000000 
这段程序用来计算1加到50的和与1乘到50的积。Maya可真是厉害,这么大的数都算得出来,比微软的计算器可强多了! 
这里“$sum+=$i;”和“$multi*=$i;”是mel的简写法,它们分别等同于“$sum=$sum+$i;”和“$multi=$multi*$i;” 
    此外,for语句还有许多变异的写法,这里暂时就不涉及了。 
    以上全是枯燥的语法,下面来点实用的东西。请在脚本编辑器中输入: 
window myWindow; 
columnLayout; 
intSliderGrp -l "Number Of Spheres:" -field true -min 1 -max 1000 -v 50 slider; 
button -l "Create Random Sphere" -c " int $k=0; 
      int $n=`intSliderGrp -q -v slider`; 
for(;$k<$n;$k++) 
sphere -p (rand(-12.0,12.0)) (rand(-12.0,12.0)) (rand(-12.0,12.0)) -r (rand(1.0)); 
    "; 
showWindow myWindow; 
    执行完后,得到了一个有滑动条和按钮的窗口,这样我们就可以通过滑块来控制生成的球体的数目了。 
    今天埃了老板K,心情不太好,写出来的东西乱糟糟的,大家不要扔鸡蛋罗。 
    下课!
*************   MEL 语言初级教程(四)   Goomoo(古木) 2002/5/17*************** 
//    如需转载,请注明作者。如欲用于商业用途,请与我联系:zengjinsong@263.net // 
    执行上节课的最后一段后,我们的程序终于有了人机交互功能,可以由用户来控制生成的球体数目了。我先来逐句讲解上段程序的意思。 
    第一句,window myWindow;,创建一个名称为myWindow的窗口,但并不立即显示出来。 
    第二句,columnLayout;,设置窗口的控件布局为列布局。 
    第三句,intSliderGrp -l "Number Of Spheres:" -field true -min 1 -max 1000 -v 50 slider;,在该窗口上创建一个整数滑动条,其标题文字为"Number Of Spheres:";"-field true" 表示显示数值输入框,默认状态为不显示;"-min 1 -max 1000 -v 50"表示该控件的最小值为1,最大值为1000,默认值为50。连起来说就是:创建一个标题为"Number Of Spheres:",最小值为1,最大值为1000,默认值为50,名称为"slider"的整数滑条,并显示其数字输入框。 
    第四句,很长啊,我只讲解-c后面的命令序列。int $k=0;,定义一个整型变量$k,并将其值设为0;int $n=`intSliderGrp -q -v slider`;,这个命令有点难理解,定义一个整型变量$n,并将其值设为`intSliderGrp -q -v slider`,***注意***这句两端并不是单引号,而是“左手单引号”,也就是“Esc”键下、“Tab”键上、“1”键左的那个按键,用得很少的一个按键啦,A|W公司思想创新,令该键发挥奇效。该键用来括住一个命令,并捕获该命令执行的结果。有点难理解,还是举个例子来说吧,输入: 
string $mySphere[]=`sphere`; 
执行之,我们看到视图的中间生成了一个球体。这里,我们定义了一个字符串数组,字符串数组可以用来存放多个字符串。再输入: 
print($mySphere); 
执行之,得到结果: 
nurbsSphere1 
makeNurbSphere1 
这和历史栏中显示的//result:后显示的结果是一样的。更进一步,在视图的空白处单击,取消对球体的选取,然后输入: 
move -a 5 0 0 $mySphere[0]; 
执行之,该球被移到了世界坐标的(5,0,0)处,可以看到,我们既没有选择该球,也不知道该球的名字,但我们仍然能够通过程序控制它,怎么样,看到“左单引号”的威力了吧!这里,move是移动命令,a即absolute,表示绝对坐标。 
再把思路跳回去,那么intSliderGrp -q -v slider执行的结果是什么呢?q表示query,即“查询”,v表示value,即“值”,这句话表示我们要查询名称为“slider”的控件的值,并将查询的结果存入变量$n中。 剩下的就好理解了,for(;$k<$n+1;$k++),这是for循环的一个变种,它的括号中的第一条语句省略了,因为我们前面已将$k的值指定为0;for循环中的第二句把1001改为了$n,这样,这个循环就执行$n次,所以生成了$n个球,也就是用户输入的球体的数目。 
    第五句,showWindow myWindow;,这句话用来显示第一句创建的窗口。 
    至此,大功告成。不知我讲的你们是否都懂了。如有不懂,尽管发问,我有问必答。 
    几天没布置作业了,很高兴吧,今天出个难题。 
    今天的作业:在该窗体上再添加一个滑条,用以控制生成球体的最大半径。 
    下课!
*************   MEL 语言初级教程(五)   Goomoo(古木) 2002/5/19*************** 
// 如需转载,请注明作者。如欲用于商业用途,请与我联系:zengjinsong@263.net // 
    上节课布置的作业完成的怎么样啊?没完成的可是要打手心的哟! 
    以下是上节课练习的解答。 
window myWindow; 
columnLayout -adj true; 
floatSliderGrp -l "max Radius:" -field true -min 0.1 -max 10.0 -v 1.0 rSlider; 
intSliderGrp -l "Number of Spheres:" -field true -min 1 -max 1000 -v 50 nSlider; 
button -l "Create Ramdom Sphers" -c " int $n=`intSliderGrp -q -v nSlider`; 
float $r=`floatSliderGrp -q -v rSlider`; 
int $i=0; 
for(;$i<$n;$i++) 
{ sphere -p (rand(-12.0,12.0)) (rand(-12.0,12.0)) (rand(-12.0,12.0)) -r (rand($r)); 
} 
     "; 
showWindow myWindow; 
    在上面的程序中,我们看到了一个新的命令:floatSliderGrp,floatSliderGrp和intSliderGrp的用法基本上是一样的,只不过 intSliderGrp 表示的是整数,而 floatSliderGrp 表示的是浮点数,即实数,也就是带有小数部分的数。 
    另外,我们还发现了一个严重的问题:随着被用户所控制的参数的增多,button命令的-c参数后命令序列也会急剧增加,命令行也会更长,这将给我们阅读、修改和维护程序带来困难。 
    有没有办法解决这个问题呢?当然有,下面我们来讲讲“函数”(也称为过程)这个重要的东东。当然,函数不仅仅是为了阅读方便而引入的,它是结构化程序设计的一个重要的概念,它把一个长长的程序分成许多独立的模块,每个模块仅通过几个变量(函数的参数和返回值)与其他的模块进行沟通,这样极大地简化了程序的编写,提高了程序代码的可重用性。对于别人已经编好的函数,我们只用采取“拿来主义”,随手拿过来用就行了,不必考虑他是如何实现的。当然,我们也可编写自己的函数。这段话比较枯燥,不过暂时不理解也没关系,等我们把函数用熟了,自然就明白了。我们还是以事实来说话。 
    我们先来写一个简单的函数,该函数可以返回两个实数中较大的那一个。输入: 
proc float zjsMax(float $a,float $b) 
{ if($a>=$b) 
return $a; 
else 
return $b; 
} 
    执行之。咦?怎么一点反应都没有?反应是有的,只是我们看不见,我们已经定义了一个名为zjsMax的函数存到maya的内存中去了(不知这样说准不准确?),下面我们再输入: 
zjsMax(147.258,258.369); 
    执行之。咳!有反应了!历史栏中显示出:// Result: 258.369 //。这表示我们的第一个函数编写成功!下面我们来剖析这个函数。 
    proc即procedure,意为“函数”、“过程”,告诉Maya下面我们要定义一个函数了。 
    float,前面讲过,意为“浮点数”、“实数”,表示这个函数的返回值是一个实数。 
    zjsMax,这是函数名。函数名必须由字母、数字和下划线组成,第一个字符不能为数字,前不用加美元符号。 
    float $a,float $b,表示这个函数需要两个参数,而且都是浮点数。参数必须用圆括号括起来。最后不要加分号。 
    下面是函数体,函数体由多条语句组成,这些语句必须用花括号括起来。 
    if,意为“如果”,后面是条件。条件语句后不要带分号。 
    ($a>=$b),$a大于或等于$b。此外还有>(大于)、<(小于)、<=(小于或等于)、!=(不等于)、==(等于)。 
    return,返回;else,否则。 
    这段函数体翻译成中文就是:如果$a大于或等于$b,就返回$a ,否则,返回$b。所以,它返回的是较大的那个实数。 
    下面我们再编写一个函数,它需要两个参数,一个表示球体的最大半径,另一个表示球体的数目。请输入: 
proc zjsRandomSphere(float $r,int $n) 
{ int $i=0; 
for(;$i<$n;$i++) 
{ sphere -p (rand(-12.0,12.0)) (rand(-12.0,12.0)) (rand(-12.0,12.0)) -r $r; } 
} 
    执行之,照旧没反应。不过我们已有心理准备啦。再输入: 
zjsRandomSphere(1,100); 
    视图中立即出现了100个最大半径为1的球体。哈哈,连前面的界面都不用了。这个函数没有声明返回的数据类型,也没有任何返回值。 
    这样,我们上节课的练习答案可以改成: 
proc zjsRandomSphere(float $r,int $n) 
{ int $i=0; 
for(;$i<$n;$i++) 
{ sphere -p (rand(-12.0,12.0)) (rand(-12.0,12.0)) (rand(-12.0,12.0)) -r $r; 
} 
} 
window myWindow; 
columnLayout -adj true; 
floatSliderGrp -l "max Radius:" -field true -min 0.1 -max 10.0 -v 1.0 rSlider; 
intSliderGrp -l "Number of Spheres:" -field true -min 1 -max 1000 -v 50 nSlider; 
button -l "Create Ramdom Sphers" -c " int $n=`intSliderGrp -q -v nSlider`; 
float $r=`floatSliderGrp -q -v rSlider`; 
zjsRandomSphere($r,$n); 
     "; 
showWindow myWindow; 
    这段程序看上去比前面那段更长,但更易于阅读和修改。你有这样的感觉吗?如果没有,那是你还没有习惯,等习惯了就好了。 
    今天的作业:写一个函数,它需要3个参数,返回这三个数中最大的那一个。 
---------------------------------------------------------- 
*****附:为响应米侬朋友的要求,下面讲一下全局变量。***** 
----------------------------------------------------------      
    以下只是我个人对全局变量的理解,也许不够准确,但希望能够释疑。 
    全局变量可以认为是多个函数共同享用的变量。如何理解呢?请看例子: 
global float $gVar=12345; 
proc asignvalue(float $value) 
{ 
global float $gVar; //全局变量 
$gVar=$value; 
} 
proc outPut() 
{ 
global float $gVar; //全局变量 
print($gVar); 
} 
proc outPut1() 
{ 
float $gVar; //局部变量 
print($gVar); 
} 
执行之。这里定义了一个全局变量$gVar和三个函数asignvalue(float)、outPut()和outPut1()。按照书写约定,全局变量的前面要加一个g字母。任何一个函数在使用全局变量前都必须先声明该变量。在函数asignvalue和函数outPut中,使用的是全局变量$gVar,而在函数outPut1中,使用的是局部变量$gVar,他们的变量名相同,下面我们来看看他们有什么差别: 
输入outPut();并执行之,结果:12345;输入outPut1();并执行之,结果:0。 
再输入:asignvalue(-1000);并执行之。 
输入:outPut();并执行之,结果:-1000;输入outPut1();并执行之,结果:0,不变。 
*************   MEL 语言初级教程(六)   Goomoo(古木) 2002/5/21*************** 
// 如需转载,请注明作者。如欲用于商业用途,请与我联系:zengjinsong@263.net // 
    这是上节课的习题解答: 
proc float zjsMax(float $a,float $b,float $c) 
{ 
float $t; //定义一个临时变量$t 
if($a>=$b)  
$t=$a; 
else 
$t=$b; 
if($t>=$c) 
return $t; 
else 
return $c; 
} 
    如果熟悉了mel以后,这个函数还可以写成一句话: 
proc float zjsMax(float $a,float $b,float $c) 
{ 
return $a>($b>$c?$b:$c)?$a:($b>$c?$b:$c); 
} 
    嘿嘿,看不懂吧。这是mel中的一个独特的语句:a>z?a:z,它表示:a大于z吗?如果a大于z,则值为a,否则,值为z。上面那句只是把z换为了“b>c?b:c”,所以返回的是三个数中的最大值。 
    在看别人写的脚本的时候,我们经常会看到这样的符号“//”、“/* …… */”这样的符号,这是什么意思呢?这是mel的注释符号。在“//”后面的语句和“/* …… */”之间的语句是给人看的,maya在执行脚本时是不理会这些语句的。“//”一次只能注释它后面的一行语句,而“/* …… */”则能注释包含在其中的多行语句。注释语句有什么作用呢?当我们写一个很长很复杂的脚本的时候,当时看起来也许很简单,但经过很长一段时间后再转回来看时,也许连自己也看不懂了;另一方面,当多人合作开发一个程序时,注释能使别人更容易理解你的程序和思路,从而提高程序开发的效率。 
    我们的创建随机球的程序基本上已经完成了,现在我们要提供给其他人实用。当然,我们不能指望别人在每次执行这个程序时都将代码重输或复制粘贴一遍,所以我们还需要继续完善。Let's go! 
    首先,我们要把我们创建随机球的函数zjsRandomSphere改成全局函数,这样,我们就能在maya的任何地方调用它了,与你一起合作的其他人也可方便地调用它。如下: 
global proc zjsRandomSphere(float $r,int $n) 
{ int $i=0; 
for(;$i<$n;$i++) 
{ sphere -p (rand(-12.0,12.0)) (rand(-12.0,12.0)) (rand(-12.0,12.0)) -r $r; 
} 
} 
    只用在函数名前加上单词“global”即可。“global”是“全局的”、“全球的”之意。另外,我们还需把创建窗口的代码放入另一个全局函数中,如下: 
global proc createRandomSphere() 
{ 
window myWindow; 
columnLayout -adj true; 
floatSliderGrp -l "max Radius:" -field true -min 0.1 -max 10.0 -v 1.0 rSlider; 
intSliderGrp -l "Number of Spheres:" -field true -min 1 -max 1000 -v 50 nSlider; 
button -l "Create Ramdom Sphers" -c " int $n=`intSliderGrp -q -v nSlider`; 
float $r=`floatSliderGrp -q -v rSlider`; 
zjsRandomSphere($r,$n); 
     "; 
showWindow myWindow; 
} 
    将以上两个函数复制粘贴到一个文本文件中,将文件存盘。**注意**:存盘后必须将文件名改为“createRandomSphere.mel”,也就是文件名必须与创建用户界面的函数名相同,还要注意大小写。然后把createRandomSphere.mel文件拷贝到以下地方,就可以方便的使用它了: 
1.Windows 2000 或 WindowsXP 
<我的文档>\maya\scripts 
2.Windows NT  
C:/WINNT/Profiles/my-login-name/maya/scripts" 
3.UNIX  
~username/maya/scripts 
    拷贝完毕后,请重新启动maya,按一下“左手单引号”(也就是A|W公司令其发挥奇效的那个键),将焦点跳到maya的命令行中,输入“createRandomSphere;”,然后回车。瞧!我们编的窗口出现了,Enjoy it!为省去每次输入的麻烦,你可以打开脚本编辑器,在历史栏中,选中“createRandomSphere;”这一行,将其拖到maya的工具架上,形成一个按钮,以后只用单击该按钮就行啦,maya真是方便呀!如果你记得创建随机球的那个函数,你还可以直接在命令行中输入:zjsRandomSphere(0.5,500);来创建最大半径为0.5的500个随机球,这就是在函数前加上“global”所起的作用。 
    今天讲的东西很简单,就不布置作业了。 
    下课!
*************   MEL 语言初级教程(六)   Goomoo(古木) 2002/5/24*************** 
// 如需转载,请注明作者。如欲用于商业用途,请与我联系:zengjinsong@263.net // 
    作为本初级教程的最后一课,我们讲一下经典实用的弹簧曲线的生成方法。这里要涉及到一点三角函数的知识,高中学的,大家应该还没忘吧。 
    先看看如何生成曲线。输入: 
curve -d 3 -p 1 0 0 -p 0.707 0.2 -0.707 -p 0 0.4 -1 -p -0.707 0.6 -0.707 -p -1 0.8 0;  
    执行之,视图中出现了一个圆弧,这是一个半圈的螺旋线。打开它的CV点,可以看到,一共有5个CV。在上面的这行命令中,curve表示要创建一条曲线;-d 3,指定曲线的度数(degree)为3;-p x y z,指定CV的位置。在以上的命令中,我们一共指定了5个CV。 
    下面我们用循环语句生成一个半径为3的圆。生成一个圆需要8个CV。 
int $i=0;float $deg=0.0,$rad=0.0; //$deg:角度数,$rad:弧度数 
string $curve=`curve -p 3 0 0`; //定义第一点,同时捕捉生成的曲线的名称,以便追加CV 
for(;$i<7;$i++) //进入循环 
{ $deg+=45; //即:$deg=$deg+45;旋转45度 
$rad=deg_to_rad($deg); //deg_to_rad()用来将度数转为弧度 
curve -a -p (3*cos($rad)) 0 (3*sin($rad)) $curve; //三角函数的参数必须使用弧度数 
} 
closeCurve -ps 0 -rpo 1; 
    在这段语句中,curve命令的-a开关表示追加CV(append),最后要指定追加的曲线名,这里为$curve。closeCurve为关闭曲线命令,-ps 0,表示保护形状(preserve shape)为否,即不保护形状;-rpo 1,表示替换原有曲线(replace orignal)。 
    我们先考虑生成一个弹簧曲线需要哪些参数。首先,应该是弹簧曲线的圈数;其次,如果弹簧曲线的上下底半径不同,还要考虑它的上下底半径;再次,就是弹簧的旋转方向。这里,弹簧的高度是可以不予考虑的,因为我们通过简单的缩放就可以调整。假设上半径为r1,下半径为r2,圈数为n,则该曲线所需的CV数为(8*n+1),每次半径的递增量为(r2-r1)/(8*n+1)当然,这个值可能为正数,也可能为负数。于是,生成弹簧曲线的函数可以写成: 
global proc string spiral(float $r1,float $r2,int $turns,int $direction) 
{ string $curve=`curve -p $r2 0 0`; 
float $r=$r2; float $y=0; float $deg=0.0,$rad=0.0; 
int $numOfCVs=8*$turns+1; 
float $r_inc=($r2-$r1)/$numOfCVs; 
int $i=0; 
for(;$i<$numOfCVs-1;$i++) 
{ $y+=0.1; //y坐标递增 
$r-=$r_inc; 
if($direction==1) 
$deg+=45; //顺时针 
else 
$deg-=45; //逆时针 
$rad=deg_to_rad($deg); 
curve -a -p ($r*cos($rad)) $y ($r*sin($rad)) $curve; 
} 
return $curve; 
} 
spiral(1,3,8,1); 
    执行之,视图中出现了一个上半径为1,下半径为3,圈数为8,方向为顺时针的弹簧线。再执行 
spiral(2,2,10,2); 
    视图中出现了一个上下半径均为2、圈数为10、方向为逆时针的弹簧线。 
    一切就这么简单! 
    至于其他类型的曲线,只需要动一点点脑筋,再加上一点点数学知识,就可以全部写出来啦。有兴趣的朋友可以试试看。 
    我们的mel初级教程到这里就要结束了,以后我的水平提高了,再给大家写中级、高级教程吧。但愿我写的这些东西能给大家一点帮助,至少不辜负我瞒着老板偷偷打这些文字!大家如果以后在mel方面有什么问题,可以发EMail(zengjinsong@263.net)给我,我将尽我所能帮你解答。 
    今天的作业,为弹簧曲线编写图形界面。 
    解散!
goomoo.diy.163.com/zjsCurves.zipgoomoo.diy.163.com/zjsCurves02.zipgoomoo.diy.163.com/03cn.zipgoomoo.diy.163.com/gu03bcn/gu03bcn.zipgoomoo.diy.163.com/gu03bcn/gu033bcn.zip