Modeling a wooden pier using MEL


Introduction

This tutorial is meant to be a practical example how you can harness the power of MEL scripting to aid in modeling. We will go through few primitive scripts line by line. We are also going to use the transformTypeIn.mel I've written. Only some minimal manual work is involved in this tutorial. I will not be explaining all the ins and outs of every command. I strongly suggest to open up the MEL Command Reference and at least take a glance what the options used in this tutorial means and what other options are available.

Let there be cubes

We will start by creating the basic geometry. Instead of doing it manually we're going to open up the script editor and execute the commands necessary to build the geometry. Each line has been commented (lines starting with //) here so you can easily follow what they do.
{
	// create a polygon cube with following parameters:
	// width = 20
	// height = 0.5
	// depth = 1
	// subdivisions x = 20
	// subdivisions y = 2
	// subdivisions z = 3
	// construction history off
	polyCube -w 20 -h 0.5 -d 1 -sx 20 -sy 2 -sz 3 -ch 0;
 
	// duplicate the cube 19 times and
// translate 1.2 units in z-axis
	int $i;
	for($i = 0; $i < 19; $i++)
	{
		// Duplicate and return only the
// root node of the new hierarchy
		string $sNewObj[] = `duplicate -rr`;
 
		// Select the new object (and de-select others)
		select -r $sNewObj[0];
 
		// Move the new object relatively in z-axis by 1.2 units
		move -r 0 0 1.2;
	}
}

The wear and tear

Nothing in real world is perfect so let's add some noise to these cubes. For this we are going to use the transformTypeIn.mel which you should now download and install. Select all cubes. Go into component mode and select all vertices. Execute the transformTypeIn.mel. Type in the following settings and hit the Muddle button.



The script went through all the selected vertices and moved them one by one with a random x y z value between -0.05 and 0.05. It may take a while to execute but imagine how long would it have taken to manually move all those 4280 verts.

Where's the saw?

Next we will make a handy shelf button. This is not a fool proof script and propably will not work in every situation but it will still speed up the manual work we're going to do next. Open up the script editor and paste the following code in it:
{
	// Get a list of selected vertices
	string $sSel[] = `filterExpand -sm 31`;

// Check if any vertices were selected.
// If none was selected throw an error and stop
	if(size($sSel) == 0)
		error("You must select some vertices first.\n");

// Select only the vertices and discard other possible selections
	select -r $sSel;

// Split the selected vertices
	polySplitVertex -ch 0;

// Get the object name which the vertices belongs to
	$sSel = `ls -sl -o`;

// Select all faces belonging to the object
	eval("select -r \"" + $sSel[0] + ".f[*]\"");

// Extract faces keeping the connected faces together.
// Duplication and construction history are also off
	polyChipOff -kft 1 -dup 0 -ch 0;

// Update the $sSel as it may have changed due to previous command
	$sSel = `ls -sl -o`;

// Re-select the object
	select -r $sSel;

// Separate the extracted halves into two objects
	polySeparate -ch 0;

// Update the $sSel as it may have changed due to previous command
	$sSel = `ls -sl -o`;

// Select all vertices of the other separated object and
// merge those which are closer than 0.001 units away
	eval("select -r \"" + $sSel[0] + ".vtx[*]\"");
	polyMergeVertex -d 0.001 -ch 0;

// Do the same for the other half
	eval("select -r \"" + $sSel[1] + ".vtx[*]\"");
	polyMergeVertex -d 0.001 -ch 0;

// Select both halves
	select -r $sSel[0] $sSel[1];

// Fill the ends
	FillHole;

// Re-select both halves
	select -r $sSel[0] $sSel[1];

// Delete the construction history of them
	DeleteHistory;

// Move the other half in x-axis by 0.1 units
	move -r .1 0 0 $sSel[1];
}
Select the code in the script editor and MMB drag-drop it to the shelf. A new shelf button is created. Now select a row of vertices as shown in the picture below and hit the newly created shelf button. The plank is "sawn" in to two. Repeat this for the other planks too as you see fit.



One more modeling step to do. We will bend the planks randomly just a bit to enhance the sense of realism. We will also apply automatic UV mapping to the planks here. Open up the script editor and paste the following code in it:
{
    // Get a list of selected objects
    string $sSel[] = `ls -sl -o`;

// Iterate through the list
    string $sObj;
    for($sObj in $sSel)
    {
        // Define a float variable and assign it a random
// number between -0.05 and 0.05
        float $fCrv = rand(-.05, .05);

// Select the next object in the list
        select -r $sObj;

// Create a bend deformer for it with a random curvature value
        nonLinear -type bend  -lowBound -1 -highBound 1 -curvature $fCrv;

// Rotate the bend handle 90 degrees in z-axis
        rotate -r -os 0 0 90;

// Select all faces of the object
        eval("select -r \"" + $sObj + ".f[*]\"");

// Apply automatic UV mapping
        polyAutoProjection -l 2 -sc 1 -o 0 -p 6 -ps 0.1;

// Select the object
        select -r $sObj;

// Delete the construction history
        DeleteHistory;
    }
}
Select all of the planks and execute the script above.

Phew... Finally done.

If all went well, here's what you should have:



I used this simple shader on the image above:



Can't remember all the settings I used but make sure you rotate the place3dTexture node 90 degs in y-axis. I also scaled it by a factor of 2 (scale -a 2 2 2;) and lowered the bump depth to about 0.25.

Conclusion

It should be obvious by now that MEL is a very powerful thing. Almost anything you do manually in the Maya GUI can be done via MEL. Especially in repetitive tasks, like in this example, MEL really shines. The code above may seem confusing and a big hassle to deal with. Once you start understanding what can be done with MEL it all becomes relatively simple.