How To > Create Scripted Geometry Plug-in |
MAXScript lets you create scripted geometry plug-ins which can generate procedural mesh objects on the fly just like regular C++plug-ins.
We are going to use the simple mesh code from the How To ... Create Custom Mesh Object topic and extend it to a scripted plug-in.
Defining SimpleObject plug-ins
MAXSCRIPT |
plugin simpleObject AntiStar name:"AntiStar" category:"HowTo" classID:#(0xe855567c, 0xbcd73b8b) ( parameters main rollout:params ( num_faces type:#integer ui:num_faces default:10 radius1 type:#float ui:radius1 default:0 radius2 type:#float ui:radius2 default:0 width type:#float ui:width default:1 ) rollout params "AntiStar" ( spinner num_faces"# Faces"range:[2,100,10] type:#integer spinner radius1"Radius 1 "range:[0,10000,0] spinner radius2"Radius 2 "range:[0,10000,0] spinner width "Width "range:[0,90,1] ) on buildMesh do ( --Note: The code below has been taken from the --How To – Create Custom Mesh Object --topic and is identical. vert_array = #() face_array = #() vert_count = 0 for a = 0 to 360 by 360.0/num_faces do ( v1 = [radius1*cos(a+width),radius1*sin(a+width),0] v2 = [radius1*cos(a-width),radius1*sin(a-width),0] v3 = [radius2*cos(a),radius2*sin(a),0] append vert_array v1 append vert_array v2 append vert_array v3 append face_array [vert_count+1,vert_count+3,vert_count+2] vert_count += 3 ) setMesh mesh verts:vert_array faces:face_array )--end buildMesh tool create ( on mousePoint click do ( case click of ( 1: coordsys grid (nodeTM.translation = gridPoint) ) ) on mouseMove click do ( case click of ( 2: (radius1 = abs(gridDist.y)) 3: (radius2 = abs(gridDist.y)) 4: (width = abs(gridDist.x)) 5: (#stop) ) ) )--end create )--end plugin |
A scripted plug-in starts with the constructor plugin followed by the superclass of the scripted plug-in ( simpleObject ) and the new class name of the plug-in ( AntiStar ). In addition, we have to provide the name which will appear in the effects list, and a unique classID .
The classID is used by 3ds Max to recognize the plug-in class when loading the scene. To generate a new unique ID, you can use the GenclassID () method in the Listener and copy the result into the script.
To keep all versions of this plug-in compatible around the world, it is recommended to copy the above classID though.
Scripted SimpleObject Plug-ins
The scripted plug-in will store its parameters in a so-called Parameter Block. The ParamBlock2 format has been introduced in 3ds Max 3 and allows for easy properties and tracks management, automatic animation brackets in the UI and much more. In our case, we will store the same values used in the first mesh script (number of faces, the two radii and the width (offset) value in the ParamBlock.
All parameters in the block will have their counterparts in the plug-ins rollout in the UI. By providing the rollout name, we allow the ParamBlock to establish an automatic connection between the internal values and the UI elements.
Mid Topic ID: Parameter_block2
The num_faces object property will control the number of "rays" in the object, actually the number of faces. It will be an integer and will correspond to a spinner in the UI with the same name. The default number of faces will be 10.
The radius1 object property will control the outer radius of the object. It will be a floating point value and will correspond to a spinner in the UI with the same name. The default radius on creation will be 10. If you create an object via MAXScript by calling the constructor antiStar(), the object will use this value as the default outer radius.
The radius2 object property will control the inner radius of the object. It will be a floating point value and will correspond to a spinner in the UI with the same name. The default radius on creation will be 0.
The width object property will control the offset of the outer vertices and will define the width of the rays. It will be a floating point value and will correspond to a spinner in the UI with the same name. The default width on creation will be 1.
) rollout params "AntiStar" ( spinner num_faces "# Faces" range:[2,100,10] type:#integer spinner radius1 "Radius 1" range:[0,10000,0] spinner radius2 "Radius 2" range:[0,10000,0] spinner width "Width" range:[0,90,1] )
Now we provide the rollout with UI elements referenced by the Parameter Block. The UI elements can limit the input values using the optional range: parameter, but the default value will be taken from the ParamBlock2.
The buildMesh is the main handler of scripted simpleObject plug-ins. It is called each time the geometry needs to be updated. Inside the handler, we can use our existing mesh generation code from the other tutorial to generate the vertices and faces of the mesh.
vert_array = #() face_array = #() vert_count = 0 for a = 0 to 360 by 360.0/num_faces do ( v1 = [radius1*cos(a+width),radius1*sin(a+width),0] v2 = [radius1*cos(a-width),radius1*sin(a-width),0] v3 = [radius2*cos(a),radius2*sin(a),0] append vert_array v1 append vert_array v2 append vert_array v3 append face_array [vert_count+1,vert_count+3,vert_count+2] vert_count += 3 ) setMesh mesh verts:vert_array faces:face_array
The buildMesh handler accepts the setMesh method which feeds the mesh generation data into a fast routine which regenerates the object on the fly.
The tool create handles the mouse controls on object creation.
The on mousePoint handler is executed each time the user clicks with the mouse in the viewport. The variable click will count the number of clicks.
In case the user has clicked for the first time, we can set the translation part of the Node Transformation Matrix of the object to the grid point the user specified. This repositions the center of the object to the clicked point in the active grid.
The on mouseMove handler is executed each time the user moves the mouse in the viewport. The variable click will count the number of clicks so far.
The case expression allows the selection of options based on the value of the supplied variable. It is similar to using multiple if statements to compare the same variable with multiple values.
If the user has clicked twice so far, set the outer radius to the Y distance from the center of the object to the current mouse position.
If the user has clicked tree times, set the inner radius to the Y distance from the center of the object to the current mouse position.
If the user has clicked four times already, set the offset if the outer vertices by measuring the X distance from the center of the object to the current mouse position.
This is a scripted plug-in and it will be handled by 3ds Max as a real C++ plug-in.
To install it permanently on your system, just copy the file to the \plugins folder or to any folder listed in the plug-ins paths.
To try the plug-in without installing it permanently, just evaluate the code and look under Create panel>Geometry>HowTo category in the drop-down list. The plug-in will be only available for the single session and will not be there after restarting 3ds Max.
Any MAX files saved with the plug-in in the scene will require the script to be installed and evaluated in order to load correctly.
To use the plug-in, click the AntiStar button in the Create panel>Geometry>HowTo. Click in the viewport to define the center, drag to define the outer radius, click, drag again to define the inner radius, click, drag again to define the width. Click to finish or right-click to cancel.
Play with the controls in the UI under the Modify panel and note how quickly the mesh is updated by the script!