本部分假定了解 MEL 脚本和编程的知识。
有关 MEL 的详细信息,请参见面向程序员的 MEL。
“绘制脚本工具”(Paint Scripts Tool)的依据是在 NURBS 或多边形曲面上叠加的二维数值数组的概念。该数组由曲面的顶点位置定义或由均匀分布于曲面参数空间的任意 2D 栅格定义。将该数值数组想象成 2D 灰度图像,其中各像素对应一个数组位置,而灰度值对应与该数组位置相关联的数值。与“绘制脚本工具”(Paint Scripts Tool)相关联的脚本确定 Artisan 解释数值数组的方式。需要知道指定给如上所述其中之一数组位置的数值时,Artisan 调用脚本。更改指定给其中一个数组位置的数值时,Artisan 也可以调用脚本。
“绘制脚本工具”(Paint Scripts Tool)由一组 MEL 程序定义。MEL 程序的名称在“工具设置”(Tool Settings)编辑器的“设置”(Setup)区域显示。您还可以使用 MEL 命令 artUserPaintCtx 设置 MEL 程序。本章介绍了以下 Artisan MEL 程序:
在下列描述中,用于设置命令的 artUserPaintCtx 标志括在括号内。
如果已定义,一选定(通过使用修改 > 绘制脚本工具(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 命令的最终参数。
如果已定义,在即将退出“绘制脚本工具”(Paint Scripts Tool)之前,调用 ToolCleanupCommand。该程序定义如下:
global proc ToolCleanupCommand ( string $toolContextName ) { ... }
其中,$toolContextName 是已退出工具上下文的名称。
如果定义该命令,可忽略对初始化命令、完成命令、设置值命令以及获取值命令定义的任何命令。
如果已定义,一旦选定用于绘制的各个曲面,即调用 GetArrayAttributeCommand。该程序返回字符串,其解释为指称某些依存关系节点上双数组属性的名称列表。该程序定义如下:
global proc string GetArrayAttributeCommand ( string $surfaceName ) { string $arrayAttributes // determine array attributes that correspond to // $surfaceName ... return $arrayAttributes; }
其中,$surfacename 是曲面的名称,其与返回的数组属性相关联。如果返回多个数组属性,Artisan 需要一个值时将读取第一个属性,但是 Artisan 会将所有属性都写入。
如果已定义,开始每个笔划前会调用一次 InitializeCommand。该程序定义如下:
global proc string InitializeCommand( int $surfaceName ) { string $flags; // build up $flags // ... return $flags; }
其中,$surfacename 是曲面名称。有关示例,请参见以下目录中的 spherePaint.mel 和 geometryPaint.mel:
该程序应:
所有这类信息通过程序传递回的 $flags 变量传递回 Artisan。该字符串包含一系列标志和参数,这些标志和参数与能够传递到标准 MEL 程序中的标志和参数非常类似。下面介绍了“绘制脚本工具”(Paint Scripts Tool)能够识别的标志。每个标志都有一个短版本和一个长版本(按下面的方式即为:-短/长)以及一些参数:
该标志表示即将用于该曲面的整数曲面 ID。如果该标志未指定,该曲面的曲面 ID 为 -1。
该标志指示是否应该将 (U,V) 位置发送到 SetValueCommand。对于此标志,可能的值为 none、surface 或 normalized。默认值为 none。
该标志指示是否应该将 (x,y,z) 位置发送到 SetValueCommand。对于此标志,可能的值为 none、local 或 world。默认值为 none。
该标志指示是否应该将 (nx,ny,nz) 法线发送到 SetValueCommand。对于此标志,可能的值为 none、local 或 world。默认值为 none。
该标志指示应在曲面 U 方向大小为 int1 且曲面 V 方向大小为 int2 的参数空间内等间距分布的栅格上进行绘制。如果未指定该标志,将在曲面顶点定义的数组上进行绘制。
该标志仅与 -grid 标志配合使用时才有效。如果为 true,那么在将其传递到 SetValueCommand 之前,栅格位置发生抖动。默认值为 false。
该标志仅与 -grid 标志配合使用时才有效。如果为 true,Artisan 使用 16x16 抖动矩阵,以确定是否为其调用 SetValueCommand。
该标志指示 (U,V,W) 笔划方向是否应发送到 SetValueCommand。对于此标志,可能的值为 none、screenV(屏幕空间中的向量)或 worldV(世界空间中的向量)。默认值为 none。对于投影绘制,screenV 和 worldV 均返回屏幕空间中的向量。方向选项不支持反射绘制。如果请求的方向为屏幕向量,那么第三个值 (W) 将无效。
该标志指示 (spX,spY,spZ) 图章位置是否应发送到 SetValueCommand。对于此标志,可能的值为 none、local 或 world。默认值为 none。
此标志指示应将曲面路径发送到 SetValueCommand/GetValueCommand。默认值为 false。
如果已定义,每个笔划完成后,各可绘制曲面调用一次 FinalizeCommand。该程序定义如下:
global proc FinalizeCommand( int $surfaceID ) { ... }
其中,$surfaceID 是由该曲面相应的 InitializeCommand 指定给曲面的曲面标识符。
如果已定义,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 surface float $v, float $px, // ($px,$py,$pz) is position on surface float $py, float $pz, float $nx, // ($nx,$ny,$nz) is surface normal float $ny, float $nz, string $path // the full path to the associated surface ) { ... }
其中:
传递到该程序的附加参数取决于曲面 InitializeCommand 的返回。
如果已定义,Artisan 想要与曲面的特定“位置”相关联的值时,调用 GetValueCommand。该程序定义如下:
global proc float GetValueCommand( int $surfaceID, int $valueIndex, // // The following arguments are only passed if requested by // InitializeCommand. However, this is the order that they // will be passed in. // string $path ) { float $value // determine the value associated with $valueIndex location // on surface $surfaceID // ... return $value; }
其中:
很少对该命令进行定义。如果已定义,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 脚本,可见于:
布局在一个文件中保留所有 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 文件,提供位置如下:
该脚本仅适用于 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:
// 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] + "\n"); } 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; } }
以下是几个试验,可以尝试使用该脚本,以便要了解其工作方式。
更改第 89 行自:
+ " -grid 20 20"
为:
+ " -grid 40 30"
更改第 154 行自:
$sname=‘sphere -ch off -name $objname‘;
为:
$sname=‘cone -ch off -name $objname‘;
添加行:
+ " -jitter true"
于第 90 行之前。