注意
本部分假定了解 MEL 脚本和编程的知识。有关 MEL 的详细信息,请参见面向程序员的 MEL。
“绘制脚本工具”(Paint Scripts Tool)的依据是在 NURBS 或多边形曲面上叠加的二维数值数组的概念。该数组由曲面的顶点位置定义或由均匀分布于曲面参数空间的任意 2D 栅格定义。将该数值数组想象成 2D 灰度图像,其中各像素对应一个数组位置,而灰度值对应与该数组位置相关联的数值。与“绘制脚本工具”(Paint Scripts Tool)相关联的脚本确定 Artisan 解释数值数组的方式。需要知道指定给如上所述其中之一数组位置的数值时,Artisan 调用脚本。更改指定给其中一个数组位置的数值时,Artisan 也可以调用脚本。
脚本绘制 MEL 程序
“绘制脚本工具”(Paint Scripts Tool)由一组 MEL 程序定义。MEL 程序的名称在“工具设置”(Tool Settings)编辑器的“设置”(Setup)区域显示。也可以使用 artUserPaintCtx MEL 命令设置 MEL 程序。本章介绍了以下 Artisan MEL 程序:
工具设置命令(-tsc "ToolSetupCommand")
工具清理命令(-tcc "ToolCleanupCommand")
获取数组属性命令(-gac "GetArrayAttributeCommand")
初始化命令(-ic "InitializeCommand")
完成命令(-fc "FinalizeCommand")
设定值命令(-svc "SetValueCommand")
获取值命令(-gvc "GetValueCommand")
获取曲面命令(-gsc "GetSurfaceCommand")
更改栅格大小
绘制圆锥体而不是球体
抖动栅格
在下列描述中,用于设定命令的 artUserPaintCtx 标志括在括号内。
“工具设置命令”(Tool Setup Command) (-tsc "ToolSetupCommand")
如果已定义,一选定(通过使用修改 > 绘制脚本工具(Modify > Paint Scripts Tool)菜单项或从“工具箱”(Tool Box)或工具架中选择)“绘制脚本工具”(Paint Scripts Tool)之后,即调用 ToolSetupCommand。该程序常用于设置所有其他的 Artisan MEL 程序。该程序定义如下:
global proc ToolSetupCommand (string $toolContextName){// This is an example artUserPaintCtx command that would setup// the following Artisan procedures. This is not a realistic// example because you would never have all the procedures// defined.//artUserPaintCtx -e-tcc "ToolCleanupCommand"-gac "GetArrayAttributeCommand"-ic "InitializeCommand" -fc "FinalizeCommand"-svc "SetValueCommand" -gvc "GetValueCommand"-gsc "GetSurfaceCommand"$toolContextName;}
其中,$toolContextName 是选定工具上下文的名称。旨在将其用作 artUserPaintCtx 命令的最终参数。
“工具清理命令”(Tool Cleanup Command) (-tcc "ToolCleanupCommand")
如果已定义,在即将退出“绘制脚本工具”(Paint Scripts Tool)之前,调用 ToolCleanupCommand。该程序定义如下:
global proc ToolCleanupCommand (string $toolContextName){...}
其中,$toolContextName 是已退出工具上下文的名称。
“获取数组属性命令”(Get Array Attribute Command) (-gac "GetArrayAttributeCommand")
如果定义该命令,可忽略对初始化命令、完成命令、设定值命令以及获取值命令定义的任何命令。
如果已定义,一旦选定用于绘制的各个曲面,即调用 GetArrayAttributeCommand。该程序返回字符串,其解释为指称某些依存关系节点上双数组属性的名称列表。该程序定义如下:
global proc string GetArrayAttributeCommand (string $surfaceName){string $arrayAttributes// determine array attributes that correspond to// $surfaceName...return $arrayAttributes;}
其中,$surfacename 是曲面的名称,其与返回的数组属性相关联。如果返回多个数组属性,Artisan 需要一个值时将读取第一个属性,但是 Artisan 会将所有属性都写入。
“初始化命令”(Initialize Command) (-ic "InitializeCommand")
如果已定义,开始每个笔划前,各可绘制曲面调用一次 InitializeCommand。该程序定义如下:
global proc string InitializeCommand(int $surfaceName){string $flags;// build up $flags//...return $flags;}
其中,$surfacename 是曲面名称。有关示例,请参见以下目录中的 spherePaint.mel 和 geometryPaint.mel:
(Windows) 驱动器:Program FilesAutodeskMaya2014scriptsothers
(Linux) mayapath/scripts/others
(Mac OS X) /Applications/Autodesk/maya2014/Maya.app/Contents/scripts/others
该程序应:
为该曲面确定唯一的整数 曲面 ID。该 ID 将被传递到与该曲面相关联的 SetValueCommand、GetValueCommand 和 FinalizeCommand 的未来调用。如果脚本保持每个曲面的信息,将该 ID 变成数组索引是极容易的,索引可用于轻松访问每个曲面的信息。
确定未来调用与该曲面相关联的 SetValueCommand 哪种类型的信息。
确定是在曲面顶点绘制,还是在曲面参数空间中等间距分布的栅格上绘制。
所有这类信息通过程序传递回的 $flags 变量传递回 Artisan。该字符串包含一系列标志和参数,这些标志和参数与能够传递到标准 MEL 程序中的标志和参数非常类似。下面介绍了“绘制脚本工具”(Paint Scripts Tool)能够识别的标志。每个标志都有一个短版本和一个长版本(按下面的方式即为:-短/长)以及一些参数:
-id/identifier int
该标志表示即将用于该曲面的整数曲面 ID。如果该标志未指定,该曲面的曲面 ID 为 -1。
-uv/uvlong string
该标志指示是否应该将 (U,V) 位置发送到 SetValueCommand。对于此,可能的值为无、曲面或规格化。默认值为无。
-p/position string
该标志指示是否应该将 (x,y,z) 位置发送到 SetValueCommand。对于这一点,可能的值为 none、local 或 world。默认值为无。
-n/normal string
该标志指示是否应该将 (nx,ny,nz) 法线发送到 SetValueCommand。对于这一点,可能的值为 none、local 或 world。默认值为无。
-g/grid int1 int2
该标志指示应在曲面 U 方向大小为 int1 且曲面 V 方向大小为 int2 的参数空间内等间距分布的栅格上进行绘制。如果未指定该标志,将在曲面顶点定义的数组上进行绘制。
-j/jitter boolean
该标志仅与 -grid 标志配合使用时才有效。如果为 true,那么在将其传递到 SetValueCommand 之前,栅格位置发生抖动。默认值为 false。
-d/dither boolean
该标志仅与 -grid 标志配合使用时才有效。如果为 true,Artisan 使用 16x16 抖动矩阵,以确定是否为其调用 SetValueCommand。
-dt/directionType string
该标志指示 (U,V,W) 笔划方向是否应发送到 SetValueCommand。对于此,可能的值为无、screenV(屏幕空间中的向量)或 worldV(世界空间中的向量)。默认值为无。对于投影绘制,screenV 和 worldV 均返回屏幕空间中的向量。方向选项不支持反射绘制。如果请求的方向为屏幕向量,那么第三个值(W) 将无效。
-sp/stampPosition string
该标志指示 (spX,spY,spZ) 图章位置是否应发送到 SetValueCommand。对于这一点,可能的值为 none、local 或 world。默认值为无。
“完成命令”(Finalize Command) (-fc "FinalizeCommand")
如果已定义,每个笔划完成后,各可绘制曲面调用一次 FinalizeCommand。该程序定义如下:
global proc FinalizeCommand(int $surfaceID){...}
其中,$surfaceID 是由该曲面相应的 InitializeCommand 指定给曲面的曲面标识符。
“设定值命令”(Set Value Command) (-svc "SetValueCommand")
如果已定义,Artisan 设定了与曲面的特定“位置”相关联的值后,调用 SetValueCommand。每个位置调用该程序一次。因此,如果某个 Artisan 绘制操作在曲面上的 10 处位置更改值,那么调用 SetArrayAttributeCommand 10 次。该程序定义如下:
global proc SetValueCommand(int $surfaceID,int $index,float $value,//// The following arguments are only passed if requested by// InitializeCommand. However this is the order that they// will be passed in.//float $u,// ($u,$v) is UV location on surfacefloat $v,float $px,// ($px,$py,$pz) is position on surfacefloat $py,float $pz,float $nx,// ($nx,$ny,$nz) is surface normalfloat $ny,float $nz){...}
其中:
$surfaceID 是由该曲面相应的 InitializeCommand 指定给曲面的曲面标识符
$index 是顶点或栅格索引
$value 是即将指定给传递索引的值
传递到该程序的附加参数取决于曲面 InitializeCommand 的返回。
“获取值命令”(Get Value Command) (-gvc "GetValueCommand")
如果已定义,Artisan 想要与曲面的特定“位置”相关联的值时,调用 GetValueCommand。该程序定义如下:
global proc float GetValueCommand(int $surfaceID,int $valueIndex){float $value// determine the value associated with $valueIndex location// on surface $surfaceID//...return $value;}
其中:
$surfaceID 是由该曲面相应的 InitializeCommand 指定给曲面的曲面标识符
$valueIndex 是 Artisan 请求其值的某“位置”的索引
“获取曲面命令”(Get Surface Command) (-gsc "GetSurfaceCommand")
很少对该命令进行定义。如果已定义,Artisan 每次处理选择列表时,选择列表上各依存关系节点调用一次 GetSurfaceCommand。任何时候选定“绘制脚本工具”(Paint Scripts Tool),通常都会出现这种情况。该程序定义如下:
global proc string GetSurfaceCommand (string $selectedDependencyNode){string $surface;// Set $surface based on $selectedDependencyNode.// Set $surface to NULL string (""), if no surface // is to be painted because of $selectedDependencyNode.//...return $surface;}
该程序覆盖 Artisan 对选择列表的默认处理。
示例脚本绘制脚本
本部分介绍总体脚本布局并给出注释脚本示例。
总体脚本布局
用于“绘制脚本工具”(Paint Scripts Tool)的脚本可以以多种方式排列。该示例脚本布局用于采样 Artisan 脚本,可见于:
(Windows) 驱动器:Program FilesAutodeskMaya2014scriptsothers
(Linux) mayapath/scripts/others
(Mac OS X) /Applications/Autodesk/maya2014/Maya.app/Contents/scripts/others
布局在一个文件中保留所有 MEL 程序,所有的脚本,并仅允许填充“工具设置”(Tool Settings)窗口“设置”(Setup)区域中的“工具设置命令”(Tool Setup Cmd)框的方式定义所有脚本。该程序通过使用 artUserPaintCtx 命令设置所有其他 MEL 程序。对此的详细介绍如下:
// Define global variables used throughout the script//global ...;// Define the Tool Setup Cmd procedure. This procedure will// setup all the other MEL procedures used by the Paint //Scripts tool.//// "spherePaint" would be entered into the Tool Setup Cmd field in// the Setup section of the tool settings window.//global proc spherePaint( string $context ){artUserPaintCtx -e-ic "initSpherePaint"-fc "finishSpherePaint"-svc "setSpherePaintValue"-gvc "getSpherePaintValue"-gsc ""-gac ""-tcc ""$context;}// Define various procedures that were mentioned in the Tool//Setup Cmd procedure above. All the procedures defined by//the artUserPaintCtx command have to be global.//global proc string initSpherePaint( string $surfaceName ){...}...
spherePaint.mel
这是一个注释版本的 spherePaint.mel 文件,提供位置如下:
(Windows) 驱动器:Program FilesAutodeskMaya2014scriptsothers
(Linux) mayapath/scripts/others
(Mac OS X) /Applications/Autodesk/maya2014/Maya.app/Contents/scripts/others
该脚本仅适用于 NURBS 曲面。
//// This is a simple example script for the Artisan Paint //Scripts tool. It will paint spheres onto the selected//surfaces. The size of the spheres are controlled by the//painted values.//// Usage:// 1) Place this script into your scripts directory (usually//the maya/scripts directory in your home directory// 2) Select the Paint Scripts Tool (Modify > Paint Scripts// Tool) and bring up the Tool Settings window// 3) Go to the Setup section and enter "spherePaint" into // the "Tool Setup Cmd" field and hit enter// 4) Paint Geometry//// Tips:// Once you have the Geometry Paint Tool setup you may want// to it from the toolbar to the shelf so that it is always// accessible//
这些全局变量用于确定正在绘制的曲面数量并确定曲面 ID。$sphereNamePrefix 是一个字符串数组,每个活动曲面一个字符串。如果条目为空字符串,则表示可获取其数组索引,并将其用作曲面 ID。如果该条目非空,那么创建球体时将该字符串用作前缀。$spherePaintFreeSlot 是 $sphereNamePrefix 的第一个可用条目,$spherePaintSlots 是 $sphereNamePrefix 的当前大小。曲面 ID 使用数组索引来存储每个曲面信息,这种方法经常在一些其他的采样 Artisan 脚本中频繁使用。
// These are global variables used to keep track of multiple// surfaces and the name prefixes used for the spheres on each// surface//global string $sphereNamePrefix[];global int $spherePaintFreeSlot = 0;global int $spherePaintSlots = 0;
spherePaint 是初始化“绘制脚本工具”(Paint Scripts Tool)的程序,方法是告知其在各种情况下应调用哪些程序。
// This procedure should be set as the "Tool Setup Cmd" in the // Setup section of the Maya Artisan Paint Scripts Tool’s tool settings// window. The tool context is supplied as an argument.//global proc spherePaint( string $context ){// initialize all the other commands in this scriptable // paint tool context.// artUserPaintCtx -e-ic "initSpherePaint"-fc "finishSpherePaint"-svc "setSpherePaintValue"-gvc "getSpherePaintValue"-gsc ""-cc ""-tcc ""-gac ""$context;}// This is the "Initialize Cmd". This procedure is called once// for every selected surface when an initial click is received// on any surface. The argument is the name of the surface. This// procedure returns a string which indicates to the scriptable// tool how to behave for the duration of the stroke. //global proc string initSpherePaint( string $name ){global string $sphereNamePrefix[];global int $spherePaintFreeSlot;global int $spherePaintSlots;int $slot;
首先要确定与该曲面相关联的曲面 ID。这可以通过查阅 $sphereNamePrefix 数组,查找第一个可用条目完成。一旦找到条目,该条目索引将被用作曲面 ID ($slot)。
// find a free slot for this surface in the global arrays//for ( $slot = $spherePaintFreeSlot; $slot < $spherePaintSlots; $slot++ ){if ( $sphereNamePrefix[$slot] == "" ) {break;}} if ( $slot == $spherePaintSlots ) {$spherePaintSlots++;$spherePaintFreeSlot = $spherePaintSlots;}
下一步是确定传入的 $name 是否对应于 NURBS 曲面。如果对应,那么生成已绘制球体的前缀,并将其存储到 $sphereNamePrefix 数组中相应的条目。
if ( ‘nodeType $name‘ == "nurbsSurface" ) {// save the name of the parent of this shape as well// as a prefix to use when creating the spheres//string $parent[] = `listRelatives -p $name`;$sphereNamePrefix[$slot] = $parent[0] + "Sphere";}
初始化程序的最终功能是返回一个字符串,该字符串指示 Artisan 如何处理该曲面。该字符串是特殊标志及其参数组成的一个序列,上文已有描述。在本例中,字符串包含的标志可指示 Artisan:
应为该曲面使用哪个曲面 ID
绘制应在曲面的参数空间上均匀分布的 20x20 栅格上进行
任何时候一旦调用,即将世界空间的位置传递到 setSpherePaintValue。
// Return an argument string which:// - tells the tool what surface ID to use for this surface// - indicates that values should be distributed on a 20x20// grid on the surface// - indicate that the associated world space position// should also be passed to the "Set Value Cmd".//return ( "-id " + $slot + " -grid 20 20" + " -position world");}// This is the "Finalize Cmd". This procedure is called at the// end of the stroke. It is passed the surface ID, that was// generated by the "Initialize Cmd".//global proc finishSpherePaint( int $slot ){
在笔划结束时调用。使用 $slot 清除该曲面在 $sphereNamePrefix 中的相应条目。如果数组中已有 $slot,也可以用 $slot 更新 $spherePaintFreeSlot。
global string $sphereNamePrefix[];global int $spherePaintFreeSlot;// clear out the slot that was used for this surface//$sphereNamePrefix[$slot] = "";if ( $slot < $spherePaintFreeSlot ) {$spherePaintFreeSlot = $slot;}}// This is the "Set Value Cmd". It is called everytime a value// on the surface is changed. A surface ID, a grid index// on the surface and the value associated with that grid index// is passed. There can be additional arguments depending on the// options generated by the return value of the "Initialize Cmd".// In this case the (x,y,z) surface position for this grid point// is also passed.// global proc setSpherePaintValue(int $slot,int $index,float $val,float $x,float $y,float $z){global string $sphereNamePrefix[];
确定 $slot 是否是有效的曲面 ID,方法是检查 $sphereNamePrefix 中的相应条目是否并非空字符串。
if ( $sphereNamePrefix[$slot] != "" ) {
已绘制的所有球体都具有唯一的名称,该名称是曲面的 $sphereNamePrefix 和栅格索引的组合。这正是该脚本确定在此位置是否已进行绘制的方式。该方法的一个缺点是它对 initSpherePaint 中指定的栅格大小较为敏感。例如,索引 44 将对应于 10x10 栅格上的栅格位置 (4,4)。但是,如果栅格大小已更改为 20x20,索引 44 现在将对应于栅格位置 (2,4)。
// determine the name of the sphere associated with this// grid location //string $objname = $sphereNamePrefix[$slot] + $index;if ( ‘objExists $objname‘ ) {
在本例中,球体已经存在。因此,传递的值 $val 将用作球体的总体比例因子。作为一种特殊情况,如果值小于或等于 0,应移除对应的球体。
// if the sphere already exists, use the value to// adjust the size of the sphere. If the value is// 0, the sphere is deleted//if ( $val > 0 ) {scale $val $val $val $objname;} else {delete $objname;}} else if ( $val > 0 ) {
在本例中,对应于该栅格位置没有已绘制的球体。使用球体 MEL 命令创建一个球体,并使用 -name 选项为新创建的球体给出所需名称。球体创建之后,均匀地更改球体的比例因子,直至达到传入的值 ($val)。此时球体也将定位,通过将球体从原点(默认情况下在此处创建球体)移动到传入该程序的世界空间位置($x,$y,$z),可以使球体出现在正确的位置。
// the sphere doesn’t exist//string $sname[];// create a sphere with the proper name, scale it by// the passed value and parent the sphere to the same// parent as the surface we are painting on//$sname=‘sphere -ch off -name $objname‘;if ( $sname[0] != $objname ) {print ("SPHERE NAME FAILED: wanted "+ $objname + " got " + $sname[0] + "");}scale $val $val $val;move $x $y $z;}}}// This is the "Get Value Cmd". It is called everytime a value// on the surface is needed by the scriptable paint tool. A// surface ID and a grid index is passed in. This procedure should// return the value for this grid location on the specified surface.// global proc float getSpherePaintValue( int $slot, int $index ){global string $sphereNamePrefix[];if ( $sphereNamePrefix[$slot] != "" ) {// if this slot is valid, generate the name for the// sphere at this grid index//string $objname = $sphereNamePrefix[$slot] + $index;
任何时候 Artisan 需要一个对应于特定栅格位置的值时,便会调用该程序。在该脚本中,值是球体的比例因子。
if ( ‘objExists $objname‘ ) {
如果在 $index 引用的位置上绘制了球体,将返回球体的 X 轴比例因子。X 轴比例因子也没有什么神奇奥妙之处。可能很容易拥有 Y 轴或 Z 轴比例因子,或者是所有与此相关的比例因子的平均值。这完全取决于脚本。
// if the sphere exists, return the X scale factor// as the value for this grid location//return ‘getAttr ($objname + ".sx")‘;} else {
如果在该位置没有球体,那么仅返回 0.0 作为该位置的值。
// the sphere doesn’t exist, therefore return 0 as// the value for this grid location//return 0.0;}} else {return 0.0;}}
以下是几个试验,可以尝试使用该脚本,以便要了解其工作方式。
更改“栅格大小”(Grid Size)
更改第 89 行自:
+ " -grid 20 20"
为:
+ " -grid 40 30"
绘制圆锥体而不是球体
更改第 154 行自:
$sname=‘sphere -ch off -name $objname‘;
为:
$sname=‘cone -ch off -name $objname‘;
抖动栅格
添加行:
+ " -jitter true"
于第 90 行之前。
,