/*********************************************************************************** Daniel Loran 12-07-2007 Lab 5 Grass Generator (tested with Maya 8.5) To run this script with GUI: - create new project in Maya - put Lab5.mel file into the /mel directory in your project - copy Lab5.mb scene into the /scenes directory in your project - check that the project is set correctly in Maya - open Lab5.mb scene - open Window > Rendering Editors > Hypershade, check if GrassShader is present - open Script Editor and execute: source Lab5; main; To run this script without GUI call: generateGrass(100, -1.0, 1.0, -1.0, 1.0); ************************************************************************************/ /*--------------------------------------------------------------------------------- Select given object by replacing the active list -----------------------------------------------------------------------------------*/ proc selectObject(string $objName){ eval("select -replace " + $objName); // select given object } /*--------------------------------------------------------------------------------- Harden cone edges to produce more realistic shading -----------------------------------------------------------------------------------*/ proc hardenConeEdges(string $objName){ // harden cone edges polySoftEdge -angle 30 -constructionHistory off ( $objName + ".e[0:59]" ); changeSelectMode -object; // switch to object mode selectObject($objName); } /*--------------------------------------------------------------------------------- Apply Bend deformation to the blade of grass -----------------------------------------------------------------------------------*/ proc deformBend( string $objName, float $bend_curvature, float $bend_envelope ){ // apply Bend deformer string $bend[] = `nonLinear -type bend -lowBound 0 -highBound 2 -curvature ($bend_curvature) `; // set bend1Handle.translateY to 0, so deformation will start from the base of the blade setAttr( $bend[1] + ".ty" ) 0 ; setAttr( $bend[0] + ".envelope" ) $bend_envelope ; // set bend1.envelope selectObject($objName); // select cone delete -all -constructionHistory; } /*--------------------------------------------------------------------------------- Reset transformations and pivot point -----------------------------------------------------------------------------------*/ proc resetTransformationAndPivots(string $objName){ // step 1 with apply true makeIdentity -apply true -translate true -rotate true -scale true $objName; // step 2 with apply false makeIdentity -apply false -translate true -rotate true -scale true $objName; } /*--------------------------------------------------------------------------------- Generate 1 blade of grass -----------------------------------------------------------------------------------*/ proc string generateBlade() { // randomly determine variable values float $blade_radius = `rand 0.02 0.06`; float $blade_height = `rand 0.7 1.2`; float $bend_curvature = `rand (-0.25) (-1.25)`; float $bend_envelope = `rand 0.6 1.0`; // Create polyCone = grass blade and capture the name in blades string $blade[] = `polyCone -radius $blade_radius -height $blade_height -subdivisionsX 3 -subdivisionsY 10 -subdivisionsZ 0 -axis 0 1 0 -constructionHistory off `; // Reset transformations and pivot point resetTransformationAndPivots($blade[0]); // Move blade so it will grow from the origin (height was 1) setAttr( $blade[0] + ".translateY" ) ( $blade_height * 0.5); // scale it too look more like a grass setAttr( $blade[0] + ".scaleX" ) 0.25 ; hardenConeEdges($blade[0]); // this is necessary to obtain a realistic grass shader deformBend($blade[0], $bend_curvature, $bend_envelope); // apply Bend deformation return $blade[0]; } /*--------------------------------------------------------------------------------- Generate multiple blades of grass -----------------------------------------------------------------------------------*/ global proc generateGrass ( int $density, // e.g.: 100 float $minX, // e.g.: -1.0 float $maxX, // e.g.: 1.0 float $minZ, // e.g.: -1.0 float $maxZ // e.g.: 1.0 ){ string $grass[]; // calculate number of blades to generate based on area size and density float $grass_area = ( ($maxX - $minX) * ($maxZ - $minZ) ); int $number_of_blades = ( $grass_area * $density ) ; // for loop to create multiple blades of grass for( $i = 0; $i < $number_of_blades; $i++ ){ $grass[$i] = `generateBlade`; // Randomly set blade position float $translateX = `rand $minX $maxX`; float $translateZ = `rand $minZ $maxZ`; float $rotateY = `rand 0 360`; setAttr( $grass[$i] + ".translateX" ) $translateX; setAttr( $grass[$i] + ".translateZ" ) $translateZ; setAttr( $grass[$i] + ".rotateY" ) $rotateY; } // select all blades string $bladeNames = ""; for( $i = 0; $i < $number_of_blades; $i++ ){ $bladeNames += $grass[$i] + " "; // store blade names so we could select them all at once later } selectObject($bladeNames); } /*--------------------------------------------------------------------------------- show GUI window for Grass Generator -----------------------------------------------------------------------------------*/ global proc showMyWindow(){ // Set default values int $density = 100; // min 10, max 100, step 1 float $minX = -1.0; // min -5.0, max 5.0, step 0.5 float $maxX = 1.0; // min -5.0, max 5.0, step 0.5 float $minZ = -1.0; // min -5.0, max 5.0, step 0.5 float $maxZ = 1.0; // min -5.0, max 5.0, step 0.5 int $developing = true; if($developing && `window -exists myWindow`){ deleteUI myWindow; } if(!`window -exists myWindow`){ window -title "Grass Generator by D. Loran (2007)" - resizeToFitChildren true myWindow; columnLayout -adjustableColumn true; // main window layout //-------------------------------------------------------------------------------------------- rowLayout -numberOfColumns 3 -columnWidth3 120 50 250 //-adjustableColumn -columnAlign 1 "right" -columnAttach 1 "both" 0 -columnAttach 2 "both" 0 -columnAttach 3 "both" 0 rowDensity; // grass density controls text -label "Grass Density: " labelDensity; intField -editable false -minValue 10 -maxValue 100 -step 1 -value $density fieldDensity; intSlider -min 10 -max 100 -step 1 -value $density -changeCommand ("$density = #1; intField -edit -value $density fieldDensity; ") sliderDensity; //-------------------------------------------------------------------------------------------- setParent ..; // so the next row will be added to the columnLayout and not previous rowLayout rowLayout -numberOfColumns 3 -columnWidth3 120 50 250 //-adjustableColumn -columnAlign 1 "right" -columnAttach 1 "both" 0 -columnAttach 2 "both" 0 -columnAttach 3 "both" 0 rowMinX; // grass area minX controls text -label "Grass area min X: " labelMinX; floatField -editable false -minValue -5.0 -maxValue 5.0 -precision 2 -value $minX fieldMinX; floatSlider -min -5.0 -max 5.0 -value $minX -changeCommand ("$minX = #1; floatField -edit -value $minX fieldMinX;") sliderMinX; //-------------------------------------------------------------------------------------------- setParent ..; // so the next row will be added to the columnLayout and not previous rowLayout rowLayout -numberOfColumns 3 -columnWidth3 120 50 250 //-adjustableColumn -columnAlign 1 "right" -columnAttach 1 "both" 0 -columnAttach 2 "both" 0 -columnAttach 3 "both" 0 rowMaxX; // grass area maxX controls text -label "Grass area max X: " labelMaxX; floatField -editable false -minValue -5.0 -maxValue 5.0 -precision 2 -value $maxX fieldMaxX; floatSlider -min -5.0 -max 5.0 -value $maxX -changeCommand ("$maxX = #1; floatField -edit -value $maxX fieldMaxX;") sliderMaxX; //-------------------------------------------------------------------------------------------- setParent ..; // so the next row will be added to the columnLayout and not previous rowLayout rowLayout -numberOfColumns 3 -columnWidth3 120 50 250 //-adjustableColumn -columnAlign 1 "right" -columnAttach 1 "both" 0 -columnAttach 2 "both" 0 -columnAttach 3 "both" 0 rowMinZ; // grass area minZ controls text -label "Grass area min Z: " labelMinZ; floatField -editable false -minValue -5.0 -maxValue 5.0 -precision 2 -value $minZ fieldMinZ; floatSlider -min -5.0 -max 5.0 -value $minZ -changeCommand ("$minZ = #1; floatField -edit -value $minZ fieldMinZ;") sliderMinZ; //-------------------------------------------------------------------------------------------- setParent ..; // so the next row will be added to the columnLayout and not previous rowLayout rowLayout -numberOfColumns 3 -columnWidth3 120 50 250 //-adjustableColumn -columnAlign 1 "right" -columnAttach 1 "both" 0 -columnAttach 2 "both" 0 -columnAttach 3 "both" 0 rowMaxZ; // grass area minZ controls text -label "Grass area max Z: " labelMaxZ; floatField -editable false -minValue -5.0 -maxValue 5.0 -precision 2 -value $maxZ fieldMaxZ; floatSlider -min -5.0 -max 5.0 -value $maxZ -changeCommand ("$maxZ = #1; floatField -edit -value $maxZ fieldMaxZ;") sliderMaxZ; //-------------------------------------------------------------------------------------------- setParent ..; // so the next row will be added to the columnLayout and not previous rowLayout // Button Generate Grass string $button = `button -label "Generate Grass"`; button -edit -command ( " onClick_btnGenerateGrass(); " ) $button; showWindow myWindow; } else{ error "myWindow already exists!"; } } /*--------------------------------------------------------------------------------- When btnGenerateGrass is pressed by user, query GUI fields and call generateGrass() -----------------------------------------------------------------------------------*/ global proc onClick_btnGenerateGrass(){ string $result = ""; int $density = `intField -query -value fieldDensity`; float $minX = `floatField -query -value fieldMinX`; float $maxX = `floatField -query -value fieldMaxX`; float $minZ = `floatField -query -value fieldMinZ`; float $maxZ = `floatField -query -value fieldMaxZ`; if($minX >= $maxX || $minZ >= $maxZ){ error "max value must be larger than min value."; return; } deleteUI myWindow; // close the Grass Generator window /* print ("\ntest: $density = " + $density); print ("\ntest: $minX = " + $minX); print ("\ntest: $maxX = " + $maxX); print ("\ntest: $minZ = " + $minZ); print ("\ntest: $maxZ = " + $maxZ); */ generateGrass($density, $minX, $maxX, $minZ, $maxZ); } /*--------------------------------------------------------------------------------- Provide GUI to the Grass Generator. Call main() to graphicaly edit the parameters or call generateGrass() directly if you don't want GUI. -----------------------------------------------------------------------------------*/ global proc main(){ showMyWindow(); }