为“绘制脚本工具”(Paint Scripts Tool)写入 MEL 脚本
注意
本部分假定了解 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) Drive:\Program Files\Autodesk\Maya2012\scripts\others
(Linux) mayapath/scripts/others
(Mac OS X) /Applications/Autodesk/maya2012/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 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
)
{
...
}
其中:
$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) Drive:\Program Files\Autodesk\Maya2012\scripts\others
(Linux) mayapath/scripts/others
(Mac OS X) /Applications/Autodesk/maya2012/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) Drive:\Program Files\Autodesk\Maya2012\scripts\others
(Linux) mayapath/scripts/others
(Mac OS X) /Applications/Autodesk/maya2012/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] + "\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;
}
}
以下是几个试验,可以尝试使用该脚本,以便要了解其工作方式。
更改“栅格大小”(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 行之前。
请将您关于此页内容的评论发送给我们