HW 2: MEL Scripting and Procedural Terrain Generation

Goal Introduce you to MEL scripting and experiment with methods for automatic terrain generation.

In this project you will create a custom tool inside Maya for automatically generating a terrain.

  1. Fire up Maya and open the script editor window. Create a polySphere in the scene and move it using the manipulator. Observe the commands which stream by in the History window. Now experiment with copying and pasting those commands into the script window and executing them. You can use CTRL+ENTER to execute the commands (or the execute button in the toolbar at the top of the script window).

  2. Look through a couple online tutorials about MEL in order to get an idea of what a MEL script looks like. I suggest starting with this one: Intro by Lindsay Grace. While reading this, please use the script editor window to interactively test out the commands being discussed and see how they work.

    To test your comprehension, try writing a simple procedure which places a couple spheres in the scene.

    global proc drawMySpheres() {
    ...yourcodegoeshere...
    }

    Save the script as a text file in the Maya scripts directory as "drawMySpheres.mel". To run your procedure in the script window, you can first make Maya load your script by typing "source drawMySpheres.mel;". This loads your procedure into memory. You can then run your procedure by executing the line "drawMySpheres();".

    At some point you will probably find the need to refer to the documentation from Autodesk which you can find here: [MEL Command Reference]. You may also find this wiki a useful reference [MEL wiki].

    One thing to keep in mind when looking online for references for Maya scripting is that there are at least 3 different ways to interact with Maya: MEL (which we will use), Python scripting, and C++. Don't confuse yourself looking at a Python scripting example.

  3. Write a MEL procedure named createTerrain which creates a 3D terrain mesh in the current scene. Since Maya already has procedures for performing subdivision, we won't need to implement the square-diamond algorithm described in class. Instead, your procedure should work as follows:
    • Create a polyPlane
    • For some number of specified iterations...
      • Loop through all the vertices of the mesh and move each one up/down by a random amount in the range [-d,d]
      • Subdivide the mesh using the polySmooth command
      • Decrease the displacement range d by a factor of s

    Your procedure should take as input variables the number of iterations, the initial scale d and the scale factor s.


    HINTS:

    1. You should be able to implement this script using the following MEL basic commands and functions:
       polyPlane, for, select, polyEvaluate, rand(), move, polySmooth, print, if
      Look up these commands in the MEL reference as necessary to learn about their different parameters and flags. In particular, you will want to experiment with setting the continuity parameter for polySmooth.

    2. When calling polyPlane, it is convenient specify a name for the mesh (e.g. "terrain") so you can refer to it later. However, if the user runs your script multiple times, the name will conflict with that of the previous mesh. Maya's solution is to add a number to the end of the name (e.g. "terrain22") to make it unique. Thus, the best option is that whenever you create some new object, grab the return value so that you know the name. In our case, use string $names[] = `polyPlane -n terrain ....` and then later on when you need to refer to the name you can use the string stored in the variable $names[0].

    3. In your MEL script you will want to perform operations on nodes in the Maya scene. For example, suppose you have a mesh "terrain" and want to modify a vertex, whose name will be something like "terrain.vtx[19]". In your script you will have a string variable $names[0] which stores the name of the mesh and another integer variable $i which specifies the vertex number you want to work on. If you try to use $names[0].vtx[$i] you will get an error (why?). Instead you need to assemble the pieces into a string which is the name of the vertex. For example:

       $myvertexname = $names[0] + ".vtx[" + $i + "]"

    4. It is not hard to write a script which causes Maya to freeze up so make sure and save your script often. In this example, if we subdivide the mesh too many times, things will grind to a halt. Make sure your procedure checks the input parameters to see that the number of levels (iterations) is reasonable (e.g. a max of 5 or 6) to keep this from happening. Use the error command as appropriate.

  4. Make your terrain generator user friendly by creating a GUI. Write a MEL proceedure called terrainGUI which creates a window with textFields to enter the terrain parameters and a button labeled "generate" which calls your createTerrain proceedure with the parameters given in the textFields.

    Here is an example script with some commands to get you started:

    window -t "TerrainGenerator" -wh 250 250 "MyWindow";
    columnLayout;
    text -w 175 -al "left" -l "Terrain Parameters";
    separator -st "double" -w 200;
    textField -text "intialtext" -w 200 "field1";
    $whenclicked = "string $f1text = `textField -q -text field1`; print $f1text";
    button -l "print field1" -w 200 -c {$whenclicked};
    showWindow "MyWindow";

    Note how the button works. When it is clicked, Maya evaluates the string $whenclicked. In this case we are querying the contents of the text field (using textField -q) and the printing out the result.

  5. Add your terrain generator to the shelf. Once you have your proceedure saved to a file "terrainGUI.mel", the final step is to add a button to the Maya user interface. To do this, first enter commands necessary to load up your code and start your gui in the script window. For example:

    source generateTerrain.mel;
    source terrainGUI.mel;
    terrainGUI();

    Now, select the "custom" shelf in the Maya user interface, highlight the code and drag it to the shelf and indicate that it is a MEL script. This will create a shelf button that invokes your script any time you need it.

  6. Extend the simple terrain generation function to implement some more interesting features. Here are three possibilities:

    1. Implement plateaus and plains by allowing the user to specify a maximum and minimum displacement for the terrain map and modifying your code to enforce these constraints.

    2. Implement an option of producing sharp ridges discussed in class by generating the terrain and then changing the height of each vertex to be -abs(height).

    3. Implement terrain coloring by assigning colors to each vertex using polyColorPerVertex or by assigning UV-texture coordinates to each vertex based on the vertex height. If you use the per-vertex coloring technique, make sure to go to the menu (Color > Toggle Display Colors) in order to get them displayed in the scene view.

    Please implement at least one of these three. You will get up to 10% extra-credit for implementing all three or some other creative ideas of your own choosing. To distinguish this version from the basic version you already implemented, please call your new terrain generator scripts createTerrain2.mel and terrainGUI2.mel.

    Turn In Turn in a zip file lastname_firstname.zip containing the following:
    • The MEL scripts you wrote (text files)
    • A Maya scene file containing a terrain generated by your plugin (terrain_ex.ma or terrain_ex.mb)
    • A rendering of a terrain generated by your tool as a jpeg file (terrain_ex.jpg)