MEL + PIXAR TONY DEROSE’S SPLIT AVERAGE METHOD *
*interpreted from guest lecture, Virginia Film Festival,11.9.2017
Note: This page contains MEL scripts that may be easier to copy & paste in to the Maya script editor rather than to type them in line by line more directly. However, the format of the Word Press site contains some text characters that do not paste correctly. Therefore, for a copy & paste friendly version please see the alternative web site for the same tutorial posted here: http://web.arch.virginia.edu/arch542/workshops/workshops2018/workshop15.html . We went to this alternative site during the tutorial itself.
- The Script Editor has two panels -> choose the script editor icon (see green arrow in image below).
- Create a polygon cube by using the Polygons menu and shelf icon and see the result.
CreatePolygonCube;
setToolTo CreatePolyCubeCtx;
polyCube -ch on -o on -w 3.739708 -h 2.49654 -d 3.577945 -cuv 4 ;
// Result: pCube1 polyCube1 //
Select and repaste the command editing the values, and hit the “enter” key
CreatePolygonCube;
polyCube -ch on -o on -w 1 -h 1 -d 1 ;
// Result: pCube2 polyCube2 //
- Select script and drag to shelf, or use the menu item File/Save select to shelf to generate a shelf command with the result above.
- Select shelf item and invoke cube. Note: Drag icon to “trash” symbol to upper right of shelf to remove it.
- Note three types of variables:
- float – decimals
- integer – whole numbers
- string – text character sequence. (Note Each variable type can be an array containing several values)
- Use random number to create a cube
//create a float variable $r using the rand() command by typing
float $r;
$r = rand(10);
//Edit the cube and use the random number for the cube size
//CreatePolygonCube;
polyCube -w $r -h $r -d $r -ax 0 1 0;
- Revisit the same command, but have the position be variable. (Note: cutting and pasting this next set of lines from this web page into the script editor could result in hidden characters being added to the expression editor. Therefore, it is best to retype this by hand.)
float $r, $Gx, $Gy, $Gz;
$r = rand(10);
string $Name[];
//CreatePolygonCube;
$Name = `polyCube -w $r -h $r -d $r -ax 0 1 0`;
$Gx = gauss(10);
$Gy = gauss(10);
$Gz = gauss(10);
move $Gx $Gy $Gz $Name;
Highlight in scrip editor and keep entering enter key and see results.
- Using a while loop to achieve the same result.
float $r, $Gx, $Gy, $Gz;
int $counter=1;
while ($counter++ < 10) {
$r = rand(10);
string $Name[];
//CreatePolygonCube;
$Name = `polyCube -w $r -h $r -d $r -sx 1 -sy 1 -sz 1 -ax 0 1 0 `;
$Gx = gauss(10);
$Gy = gauss(10);
$Gz = gauss(10);
move $Gx $Gy $Gz $Name;
}
- Using a for loop to move all the cubes in a selected group of them.
float $x, $y, $z;
for ($cube in `ls -sl`){
$x = gauss(1);
$y = gauss(1);
$z = gauss(1);
move $x $y $z $cube;
};
- Add “if” statement
float $x, $y, $z;
for ($cube in `ls -sl`){
$x = gauss(2);
$y = gauss(2);
$z = gauss(2);
move $x $y $z $cube;
if ($y > 1) { scale 2 2 2 $cube; }
};
- setAttr command
ctrl/ctrl-a on one of the cubes an open attribute editor
select pCubeShape (e.g., pCubeShape5) and the Render Stats section. Uncheck cast shadows yields
setAttr “pCubeShape5.castsShadows” 0;
try using the followwing code for a selected set of cubes:
for ($cube in `ls -sl`){
setAttr ($cube+”.castsShadows”) 0;
}
- Drag code to shelf/use shelf editor to add name and change icon. (32 x 32 pix)
- www.highend3d.com has a number of scripts.
**********************
14. Create a legacy particle emitter, and then use expressions editor under Translate Y attribute box to create the following expression: *
particle1.translateY = 10 * sin(deg_to_rad(sqrt(pow(particle1.translateX,2) + pow(particle1.translateZ,2)) + frame));
* Note: The same technique can be used with respect to an nParticle (e.g., nParticle1.translateY). In the case of an nParicle, the translations along the Y axis are smoother if the gravity attibute of the nucleus (e.g. nucleus1) is set to 0. The expression for an nParticle such as an “nParticle1” is:
nParticle1.translateY = 10 * sin(deg_to_rad(sqrt(pow(nParticle1.translateX,2) + pow(nParticle1.translateZ,2)) + frame));
*****************
15. Writing a procedure for a ball {WE WILL CONTINUE BY REVISITING THIS EXAMPLE]
global proc string moveball2(vector $pt){
float $px = $pt.x;
float $py = $pt.y;
float $pz = $pt.z;
string $balls[1] = `sphere -p $px $py $pz`;
string $myball = $balls[0];
expression -o $myball -s “tz = sin(deg_to_rad(frame)) * 10;”;
return $myball;
}
//test 1
vector $pt = <<4, 4, 0>>;
moveball2($pt);
//test 2
vector $pt = <<2, 2, 0>>;
moveball2($pt);
//Procedure to create array of moving spheres
global proc string makeballs(int $rows, int $cols) {
float $spaced = 4.0;
float $xpos = -1 * $cols * 0.5 * $spaced;
float $ypos = -1 * $rows * 0.5 * $spaced;
float $zpos = 0.0;
vector $pt = <<$xpos, $ypos, $zpos>>;
int $i = 0;
int $ii = 0;
while ($i < $rows) {
while ($ii < $cols) {
$pt = <<$xpos, $ypos, $zpos>>;
moveball2($pt);
$xpos = $xpos + $spaced;
$ii = $ii + 1;
print(“inner loop \n”);
print(“x val & y val ” + $xpos + ” ” + $ypos + “\n”);
}
print(“outer loop \n”);
$ii = 0;
$i = $i + 1;
$xpos = -1 * $cols * 0.5 * $spaced;
$ypos = $ypos + $spaced;
}
return “done”;
};
makeballs(2,2);
makeballs(20, 20);
***************************************************
VARIED HEIGHTS BY DISTANCE FROM ORIGIN
global proc string moveball3(vector $pt){
float $px = $pt.x;
float $py = $pt.y;
float $pz = $pt.z;
string $balls[1] = `sphere -p 0 0 0 -r 1`;
move -r $px $py $pz ;
string $myball = $balls[0];
expression -o $myball -s “ty = 10.0 * sin (deg_to_rad (15 * (sqrt (pow (tx, 2) + pow (tz, 2))) + frame));”;
return $myball;
}
global proc string makeballs(int $rows, int $cols) {
float $spaced = 4.0;
float $xpos = -1 * $cols * 0.5 * $spaced;
float $ypos = -1 * $rows * 0.5 * $spaced;
float $zpos = 0.0;
vector $pt = <<$xpos, $ypos, $zpos>>;
int $i = 0;
int $ii = 0;
while ($i < $rows) {
while ($ii < $cols) {
moveball3($pt); //change procedure in examples below … makeplanes
$xpos = $xpos + $spaced;
$pt = <<$xpos, $ypos, $zpos>>;
$ii = $ii + 1;
//print(“inner loop \n”);
}
$ii = 0;
$i = $i + 1;
$xpos = -1 * $cols * 0.5 * $spaced;
$zpos = $zpos + $spaced;
}
return “done”;
}
***************************************************
WITH PLANES
global proc string moveplane(vector $pt, float $spaced){
float $px = $pt.x;
float $py = $pt.y;
float $pz = $pt.z;
string $planes[1] = `nurbsPlane -p 0 0 0 -ax 0 1 0 -w $spaced -lr 1 -d 3 -u 1 -v 1 -ch 1`;
move -r $px $py $pz ;
string $myplane = $planes[0];
expression -o $myplane -s “ty = 10.0 * sin (deg_to_rad (15 * (sqrt (pow (tx, 2) + pow (tz, 2))) + frame));”;
return $myplane;
}
global proc string makeplanes(int $rows, int $cols) {
float $spaced = 4.0;
float $xpos = -1 * $cols * 0.5 * $spaced;
float $ypos = -1 * $rows * 0.5 * $spaced;
float $zpos = 0.0;
vector $pt = <<$xpos, $ypos, $zpos>>;
int $i = 0;
int $ii = 0;
while ($i < $rows) {
while ($ii < $cols) {
moveplane($pt, $spaced);//change procedure from example above … makeballs
$xpos = $xpos + $spaced;
$pt = <<$xpos, $ypos, $zpos>>;
$ii = $ii + 1;
//print(“inner loop \n”);
}
$ii = 0;
$i = $i + 1;
$xpos = -1 * $cols * 0.5 * $spaced;
$zpos = $zpos + $spaced;
}
return “done”;
};
makeplanes(20, 20);
16. Spiral
vector $pnts[];
string $spiral = “curve “;
float $radius = 4;
float $deltaRadius = 0.2;
float $deltaAngle = 10;
float $angleAccel = 0.0;
float $radAccel = 0.0; //try value of 0.01
float $curAngle = 0;
int $numSpirals = 10;
float $maxDeg = $numSpirals * 360;
for ($i = 0; $curAngle < $maxDeg; $i++) {
float $x = cos(deg_to_rad($curAngle)) * $radius;
float $z = sin(deg_to_rad($curAngle)) * $radius;
$pnts[$i] = <<$x, 0, $z>>;
$spiral += ” -p ” + $pnts[$i];
$radius += $deltaRadius;
$curAngle += $deltaAngle;
$deltaAngle += $angleAccel;
$deltaRadius += $radAccel;
}
eval($spiral)
17. Helix (add $deltaHeight)
vector $pnts[];
string $spiral = “curve “;
float $radius = 4;
float $deltaRadius = 0.2;
float $deltaAngle = 10;
float $deltaHeight = 0.1;
float $angleAccel = 0.0;
float $radAccel = 0.0;
float $curAngle = 0;
int $numSpirals = 10;
float $maxDeg = $numSpirals * 360;
for ($i = 0; $curAngle < $maxDeg; $i++) {
float $x = cos(deg_to_rad($curAngle)) * $radius;
float $z = sin(deg_to_rad($curAngle)) * $radius;
float $y = $i * $deltaHeight;
$pnts[$i] = <<$x, $y, $z>>;
$spiral += ” -p ” + $pnts[$i];
$radius += $deltaRadius;
$curAngle += $deltaAngle;
$deltaAngle += $angleAccel;
$deltaRadius += $radAccel;
}
eval($spiral)
18. Split Average Method (re: after Lecture by Pixar’s Tony DeRose)
Draw a closed one degree curve of four points:
global proc vector paramPt(vector $ptA, vector $ptB, float $param){
float $x = $ptA.x + $param * ($ptB.x – $ptA.x);
float $y = $ptA.y + $param * ($ptB.y – $ptA.y);
float $z = $ptA.z + $param * ($ptB.z – $ptA.z);
vector $curPt = <<$x, $y, $z>>;
return $curPt;
}
global proc vector[] split(vector $ptA, vector $ptB){
vector $ptS1 = paramPt($ptA, $ptB, 0.25);
vector $ptS2 = paramPt($ptA, $ptB, 0.75);
vector $splitPts[2];
$splitPts[0] = $ptS1;
$splitPts[1] = $ptS2;
return $splitPts;
}
global proc vector avg(vector $ptA, vector $ptB){
vector $avgPt = paramPt($ptA, $ptB, 0.5);
return $avgPt;
}
global proc vector[] splitPts(vector $ptList[]){
int $lenStart = size($ptList);
int $vecSize = 2 * $lenStart + 1;
vector $splitPoints[];
int $i = 0;
int $j = 0;
while($i < $lenStart){
vector $curPts[2];
vector $ptA = $ptList[$i];
vector $ptB = $ptList[$i + 1];
$curPts = split($ptA, $ptB);
$splitPoints[$j] = $curPts[0];
$splitPoints[$j + 1] =$curPts[1];
$i = $i + 1;
$j = $j + 2;
}
return $splitPoints;
}
global proc vector[] avgPts(vector $ptList[]){
int $lenStart = size($ptList);
vector $avgPts[];
vector $avgPt;
int $i = 0;
while($i < $lenStart – 1){
$avgPt = avg($ptList[$i], $ptList[$i + 1]);
$avgPts[$i] = $avgPt;
$i = $i + 1;
}
$avgPt = avg($ptList[$lenStart -1], $ptList[0]);
$avgPts[$i] = $avgPt;
return $avgPts;
}
global proc vector[] drawClosedPoly(vector $ptList[]){
string $polyLine = “curve -d 1 “;
int $numPts = size($ptList);
for($i = 0; $i < $numPts; $i++){
$polyLine += ” -p ” + $ptList[$i] ;
}
$polyLine += ” -p ” + $ptList[0];
eval($polyLine);
return $ptList;
}
global proc vector[] mergePts(vector $splitPoints[], vector $avgPts[]){
vector $mergedPts[];
int $j = 0;
for($i = 0; $i < size($avgPts); $i++){
$mergedPts[$j] = $splitPoints[$i];
$mergedPts[$j + 1] = $avgPts[$i];
$j += 2;
}
return $mergedPts;
}
global proc vector[] splitPts(vector $ptList[]){
int $lenStart = size($ptList);
vector $splitPoints[];
int $i = 0;
int $j = 0;
vector $curPts[];
while($i < $lenStart – 1){
vector $ptA = $ptList[$i];
vector $ptB = $ptList[$i + 1];
$curPts = split($ptA, $ptB);
$splitPoints[$j] = $curPts[0];
$splitPoints[$j + 1] = $curPts[1];
$i = $i + 1;
$j = $j + 2;
}
vector $ptA = $ptList[$i];
vector $ptB = $ptList[0];
$curPts = split($ptA, $ptB);
$splitPoints[$j] = $curPts[0];
$splitPoints[$j + 1] = $curPts[1];
return $splitPoints;
}
global proc int splitAvgPts(vector $ptList[], int $resolution){
vector $spltPts[];
vector $mergedPts[];
vector $tmpPtList[];
$tmpPtList = $ptList;
while ($resolution > 0) {
$spltPts = splitPts($tmpPtList);
$tmpPtList = avgPts($spltPts);
$resolution -= 1;
}
$mergedPts = mergePts($spltPts, $tmpPtList);
drawClosedPoly($mergedPts);
return 1;
}
vector $pt1 = `pointPosition curve1.cv[0]`;
vector $pt2 = `pointPosition curve1.cv[1]`;
vector $pt3 = `pointPosition curve1.cv[2]`;
vector $pt4 = `pointPosition curve1.cv[3]`;
vector $ptList[];
$ptList = {$pt1, $pt2, $pt3, $pt4};
int $resolution = 4;
splitAvgPts($ptList, $resolution);
//Result of split average: