Ball Bi-Lerp
(bi-linear interpolation)

by
Duane Palyka
March 23, 2003

Starting with four spheres with modified cv's:
 
 
 
 
And applying the following MEL script:

 
 

SphereMatrix( "ball" );

 
global proc SphereMatrix( string $name ) {
/*
  SphereMatrix takes four spheres named <$name>1,
 <$name>8, <$name>41, <$name>48 (e.g.:
"ball1", "ball8", "ball41", and "ball48" and
 creates spheres inbetween to form a 8 x 6 matrix
 of spheres.  The spheres are linearly interpolated
 between the four defining spheres.  Their positions
 are interpolated first with "SphereFill()" and
 then their CV's are interpolated with "LerpSphere()".


  Duane Palyka, March 31, 2003
 */
 SphereLerp( $name, 1, 41, 8 );  // Lerps the left column.
 SphereLerp( $name, 8, 48, 8 );  // Lerps the right column.
 for ($i = 1, $j = 8;  $i <= 48;  $i += 8, $j += 8 ) {
  // Lerps each of the six rows.
  SphereLerp( $name, $i, $j, 1 );
 }
}
 

global proc SphereLerp( string $name, int $nbeg, int $nend, int $nstep ) {
 /*
  Calls the two procedures that do the lerping.
  Both leave the beginning and end spheres alone and just
  use them for reference.
 */
 SphereFill( $name, $nbeg, $nend, $nstep );  // Creates the spheres
            // and positions them.
 LerpSphere( $name, $nbeg, $nend, $nstep );  // Modifies the CV's.
}
 
 

global proc SphereFill( string $name, int $nbeg, int $nend, int $nstep ) {
 string $attr, $n;
 int $u, $v;
 int $i, $k;
 int $num;
 float $pos[3], $pos1[3], $pos2[3];  // Holds position information for
          // first, last and generated sphere.
 $num = ($nend - $nbeg) / $nstep;  // Calculates total number of spheres
           // in this row or column lerp.
 $n = $name + $nbeg;  // Calculate string containing name and number combined
       // (e.g.:  "ball41") for the beginning sphere.
 $attr= $n + ".spansU";  // Calculate string containing beginning object and
       //  its attribute (i.e. "ball.spansU").
 $u = `getAttr $attr`;  // Send the command to get the attribute and return
         // its value in variable $u.  Now we know how many
         // spans there are in the U direction of the
         // first sphere.
 $attr= $n + ".spansV";  // Do the same for V.
 $v = `getAttr $attr`;
 $attr = $n + ".translate";  // Get the position of the first sphere.
 $pos1 = `getAttr $attr`;
 print( $n + ": spansU=" + $u + ", spansV=" + $v);  // Print the info we gathered.
 print( ", pos= (" + $pos1[0] + "," + $pos1[1] + "," + $pos1[2] + ")\n" );
 $n = $name + $nend;  // Now calculate the string containing the name and
       // number for the ending sphere.
 $attr = $n + ".translate";  // Get the position of the ending sphere.
 $pos2 = `getAttr $attr`;
 for ($i=$nbeg + $nstep; $i<$nend; $i += $nstep) {
  // Step through all the spheres inbetween the first and last spheres
  // and create new spheres in lerped positions between them.
  $n = $name + $i;
  for($k=0; $k < 3; $k++)  // Lerp each x, y, and z separately.
   $pos[$k] = ylerp( (float) $i, $nbeg, $nend,
      $pos1[$k], $pos2[$k] );
  sphere -ax 0 1 0 -s $u -nsp $v -name $n;  // Send the command to create
              // the sphere.
  move -a $pos[0] $pos[1] $pos[2];    // Move it to the lerped position.
 }
}

global proc LerpSphere( string $name, int $nbeg, int $nend, int $nstep )
{
 string $attr, $n;
 int $u, $v;
 int $i, $j, $k, $m;
 int $num;
 string $attr, $attr1, $attr2;
 string $at;
 float $pt[3], $pt1[3], $pt2[3];
 $num = ($nend - $nbeg) / $nstep;
 $n = $name + $nbeg;
 $attr= $n + ".spansU";
 $u = `getAttr $attr`;
 $attr= $n + ".spansV";
 $v = `getAttr $attr`;
 $attr = $n + ".translate";
 $pos1 = `getAttr $attr`;
 print( $n + ": spansU=" + $u + ", spansV=" + $v + "\n");
 $n1 = $n;
 $n2 = $name + $nend;
 for ($i=$nbeg + $nstep; $i<$nend; $i += $nstep) {
  $n = $name + $i;
  for($j=0; $j <= $u; $j++){
   for($m=0; $m <= $v; $m++){
    $n = $name + $i;
    $at = ".cv[" + $j + "][" + $m + "]";
    $attr1 = $n1 + $at;
    $pt1 = `getAttr $attr1`;
    $attr2 = $n2 + $at;
    $pt2 = `getAttr $attr2`;
    for($k=0; $k < 3; $k++)
     $pt[$k] = ylerp( (float) $i, $nbeg, $nend,
      $pt1[$k], $pt2[$k] );
    $attr = $n + $at;
    setAttr $attr $pt[0] $pt[1] $pt[2];
   }
  }

 }
}
 
 

global proc float ylerp( float $x, float $x0, float $x1, float $y0, float $y1 )
{
    float $slope, $y;
    $slope = ($y1 - $y0) / ($x1 - $x0);
    $y = $slope * ($x - $x0) + $y0;
    return $y;
}
 
 
 

Using the above MEL script, we get the following result: