Object spreading methods using Maya.

Contrary to other classic 3d package, Maya has not dedicated tools to spread objects and it is often asked how to indeed. Placing each objects would be stupid and exhausting. In this article, I demonstrate five methods from my own experience/analysis and some talking boards threads. But their may exist many other methods that I did not list... for instance at rendering or at compositing. Feel free to contact me about this article or just to give your opinion about it. I really hope my article could help you.

I Paint objects on surface.
II Map driven spreading method.
III Using particle instancer.
IV Animation driven spreading.
V Melscripting issues.

 

I Paint objects on surface.

geometryPaint is a melscript coded tool bundled with maya (or with the free Bonus Tools pack). Geometry paint enables to use the artisan paint tools to paint objects on a surface. How does this tool work? It places some duplications of an object where you paint on the selected surface. It's a good spreading tool because that is you who choose where to spread objects.

To activate geometryPaint, go Modify>Script Paint Tool options. On the Setup panel, type "geometryPaint" into the "Tool Setup Cmd" text field. Then the other text fields will be entered, and the Geometry Paint Settings window will appear. Type the name of the gemometry you want to spread in the "Geometry" text field. Then select the surface and paint on. Lets tweak parameters! For instance, check the "Align" box to have the objects to be spreaded according to surface normals. Or to randomly scale the objects size, check all scale axis. To work easier, setup the paint tool before.

Geometry paint tool workflow.

A poor sheep brough to a isolated part of the cliff.

 

 

II Map driven spreading method.

I have coded a melScript called mapSpread that spread objects function to a texture map. So you have just to design 2D a black and white map or use another Maya 2d texture in order to spread objects randomly. Useful in numerous cases, for instance create a forest crossed by a river. How does it work? This script analyses the color of a random point of the map. Then if the color is brighter than the threshold you have given, an object is placed here. Then analyses another point color...
Download mapSpread melscript here (Read the header to learn how to use this script)

mapSpread melscript tool example of use (That is not blob particles but several spheres).

After placing, lets manage the object array/cloud via other melScript tools, such as the ones studied in last the part. (Note I think it is possible to use the geometryPaint tool this way after having applied this kind of alpha map on the object. Lets setup the paint tool so as to paint only on the white parts of the alpha maps. I have not already tested it.)

 

 

III Using particle instancer.

Particle instancing is a really fast method. The particle intancer replaces each particle with an object. Obviously, to use use the particle instancer, you have to create a range of particles. You can use a particle emitter or the particle paint tool (as easily as the paint geometry tool). Then select your particle shape and create an instancer (Dynamics mode, menu Particles>Instancer options).

Particle paint tool setuping.

The particle instancer options will window appear. Select an object and add it to the list. Lets tweak parameters (don't touch "cycle" related parameters). I advise you to turn the "Level Of Detail" to "BoundingBoxes" for a better workflow.

Lets take advantage of using particles... You could apply to the instanced objects complexes particle motion/effects such as using fields and collisions rigid solver (to reach the floor for example). Note that on creating a particle instancer you can set many connection with particles attributes which affect the instanced objects.


How to bake particle instancer? To do so, open the hypergraph, select your instancer node, press Input and Output connections button. Then break the connection between the time node and the particle shape. Your spreaded instanced objects would keep this position in time.




IV Animation driven spreading.

We are going to "bake" animation. A kind of solid ghosting effect. First, animate one object the way you want (using any animation helpers you need, such as motion path). Then we will bake animation by simply duplicating the object at its position on the frames required. Also you would have non animated objects correctly placed. ! Last minute note : If you are using Maya 4.5 or higher, use the tool called Create Animation Snapshot.

Animation baked so as to spread the animated object. Example using motion path animation.

You can do it by hand by sliding the time slider and duplicate (CTRL+D) the object at this position in time. Or using this simple script (opent the script editor and execute this script bellow to load this function). Select the the animated object(s) you want to bake animation, then is the command line (or in the script editor) type launch the function giving the arguments you want : bakeAnimation(3, 0, 25) for instance. This script does automatically what you would have done by hand... great!

global proc bakeAnimation(int $step, int $startFrame, int $endFrame) {

    if(
$step < 1)  { error("bakeAnimation : the step argument must be at least higher than 1.\n"); }

    
string $selection[] = `ls -sl`;

    for(
$object in $selection) {

        for(
$n = $startFrame; $n <= $endFrame; $n+=$step) {

            
currentTime -e $n;
            
duplicate $object;
        }

        print(
$object + " animation baked.\n");
    }
}




V Melscripting issue.

Here is maybe one of the more interesting way to spread. You need simple melscripting knowledges (or other c-like scripting languages) . You must know some basics of melscripting... and especially the random function, duplicate function, transformations (move, rotate, scale) and the loop. Read the comments to understand the scripts steps.

Lets start code a simple object spreader. Simply duplicate several times the chosen object and place it randomly. The loop repeats several times this same action : returns random value for each axis, duplicate the object, place it with the random values. That is all!

global proc spreadObjects(
    
string $object,
    
int $duplicateNb,
    
float $Xmin,
    
float $Xmax,
    
float $Ymin,
    
float $Ymax,
    
float $Zmin,
    
float $Zmax
    ){

    for(
$n = 0; $n < $duplicateNb; $n++) {

        
// Get location random values
        
float $randomX = `rand $Xmin $Xmax`;
        
float $randomY = `rand $Ymin $Ymax`;
        
float $randomZ = `rand $Zmin $Zmax`;

        
// Duplicate and place it randomly
        
string $duplicatedObject[] = `duplicate $object`;
        
move $randomX $randomY $randomZ $duplicatedObject;
    }
    print(
$object + " duplicated and randomly placed " + $duplicateNb + " times.\n");
}

To use this procedure/function, first execute it in the script editor or source the melscript file, then call the function from the command line. For instance, you can use this function by typing spreadObjects("myObject", 30, -10, 10, -10, 10, -10, 10). This tool we've just coded is very useful and easy to use.

spreadObjects() function used to place randomly 60 sheeps.

Next, you might want to randomize the scale of this range of objects just created. Lets use a such as melScript one more time. This script applys a loop on selected objects to random their scales.

global proc randomizeSelectedObjectsScale(float $minScale, float $maxScale) {

    
// Build the selected objects list
    
string $objectsList[] = `ls -sl`;

    
// Random scale of each object of the list
    
for ($object in $objectsList) {

        
// Get random value and scale object
        
float $randomScale = `rand $minScale $maxScale`;
        
scale $randomScale $randomScale $randomScale $object;
    }
    print(
"Random scale on " + size($objectsList) + " selected objects done.\n");
}

For instance, type randomizeSelectedObjectsScale(1, 5)

Sheeps sizes have been a bit changed thank to the randomizeSelectedObjectsScale function.

You should be able to code a such script to random rotation (replace scale by rotate), move or even other object attributes! Programming note : Do not create a procedure that do all in one. Work step by step, such as with passes/filters.

Result of another similar function to randomize rotations. Is not it more realistic?

The spreading method of the spreadObject() function is not based on a surface, but on objects location. Lets code a script to spread objects on a surface, that is really more interesting (for instance, spread trees on a mountain). First, we will search for a method in Maya to have an object to be right placed on a surface. Second we will "translate" this method into melscript. Then we will merge this method in a such as loop in spreadObjects() function.

To place an object on a surface we are not going to code it, but simply use two constraint nodes (the same you use for rigging). Geometry constraint restricts an object to a surface. And normal constraint aligns an object with the normal vectors of a surface. Let try it by yourself. The combination of those two constraint nodes places an object exactly as we want (and with ease).

Places an object with a combination of a geometry and a normal constraint nodes.

To translate this method into melscript, let check the melscript commands F1 doc to learn more about flags and attributes. Study those two functions. Note you can see every actions made by Maya in the upper part of the script editor.

Now we will apply this method on several objects into a loop. Taht is the way you should work : first search for a method on an object, second apply it to a range of objects thanks to a loop. The script we are going to code is based on the spreadObjects() function. In this case, we are not going to give a random area thanks to a method based on the surface dimensions (by getting its bounding box size). So the duplicated object is randomly placed on the surface area. Then geometry and normal constraint nodes are applied to the object to place it right on the surface. As easily as it's said.

global proc spreadObjectsOnSurface(string $object, string $surface, int $duplicateNb) {

    
// Get surface size
    
float $surfaceMinX = `getAttr ($surface+".boundingBoxMinX")`;
    
float $surfaceMaxX = `getAttr ($surface+".boundingBoxMaxX")`;
    
float $surfaceMinY = `getAttr ($surface+".boundingBoxMinY")`;
    
float $surfaceMaxY = `getAttr ($surface+".boundingBoxMaxY")`;
    
float $surfaceMinZ = `getAttr ($surface+".boundingBoxMinZ")`;
    
float $surfaceMaxZ = `getAttr ($surface+".boundingBoxMaxZ")`;

    for (
$n = 0; $n < $duplicateNb; $n++) {

        
string $duplicatedObject[] = `duplicate $object`;

        
// Set random value and place the duplicated object
        
float $randomX = `floor(rand($surfaceMinX, $surfaceMaxX))`;
        
float $randomY = `floor(rand($surfaceMinY, $surfaceMaxY))`;
        
float $randomZ = `floor(rand($surfaceMinZ, $surfaceMaxZ))`;
        
move $randomX $randomY $randomZ $duplicatedObject;

        
// Could add random rotation and scale task here (apply it to $duplicatedObject)

        // Aim the object to the surface
        
string $geometryConstraintNode[] = `geometryConstraint $surface $duplicatedObject`;
        
string $normalConstraintNode[] = `normalConstraint -aim 0 1 0 -wut "object" $surface $duplicatedObject`;

        
// Activate this line if you want to delete the constraints nodes keeping the object pose. So as too manipulate it easier after placing. Note normal constraint node prevent to rotate objects.
        // delete $geometryConstraintNode $normalConstraintNode;
    
}
}

 

Objects right spreaded on a surface thank to spreadObjectsOnSurface() function.

MelScript enables to code particular ways to spread objects. At this point, the procedures we have coded are based on the random function... Let change it by linear maths functions and logic. What is important is to have your algorithm to return the coordinates for each axis and then place the object (Maths, trigo circle, cosinus and sinus to axis coordinates...) Just a good start of computer generated arts... I mean, from a math abstract, you could get amazing results.

// Spread cubes on a virtual spiral

string $object= "pCube1";
int $objectsNb = 30;
float $step = .8;
float $amplitudeFactor = 3;

float $var, $x, $y, $sin, $amplitude;
$var = $x = $y = $sin = $amplitude = 0;

for(
$n=0; $n < $objectsNb; $n++) {

    
$cos = `cos($var)`;
    
$x = $cos*$amplitude;

    
$sin = `sin($var)`;
    
$y = $sin*$amplitude;

    
$z = $var;

    
$var += $step;
    
$amplitude = $var/$amplitudeFactor;

    
string $duplicatedObject[] = `duplicate $object`;
    
move $x $y $z $duplicatedObject;
}

Cubes placed from a spiral function.

Note you can merge your scripts to make several in one. But I think better to work step by step, and it's easier to code some little scripts with their own actions. Let code your own melscript tools library!

 

© Nicolas d'Haussy Februar 2004 - http://ndhaussy.free.fr