Scripted SimpleMod Plug-ins

A SimpleMod plug-in is a deformation-type modifier that moves vertices around but does not change topology (adding or deleting vertices, faces, surfaces, lines, etc.) Examples of similar 3ds Max modifiers are Bend, Stretch, and Taper. These kinds of modifiers require only a single map handler to be provided for moving vertices around and they automatically supply 3D box deformation gizmo and center sub-objects. A scripted Modifier plug-in is declared by specifying the <superclass> as modifier.


plugin simpleMod saddle





parameters main rollout:params


amount type:#integer ui:amtSpin default:20


rollout params "Saddle Parameters"


spinner amtSpin "Amount: " type:#integer range:[0,1000,20]


on map i p do


p.z += amount * sin((p.x * 22.5/extent.x) * (p.y * 22.5/extent.y))




This script defines a new SimpleMod plug-in named SaddleDeform. It applies a saddle-type deformation to an object, curving up 2 opposite corners and curving down the other two opposite corners (try it on a plane object to see this best). There is a single parameter spinner, amount that specifies how much deformation to apply. The key component of a SimpleMod plug-in is the map handler.

Its form is:

on map <index> <point> do <expr>

This event handler is called once for every point in the object (or current point selection in the object) being modified. These points may be mesh vertices, spline vertices, NURBS CVs, and so on. The <index> argument gives the number of the point, but this index may not correspond to a vertex number in a mesh or a spline. The <point> argument supplied to the map handler gives the current object-space coordinates of the point as a Point3. The function should modify the supplied point value as appropriate and return it as the result of the map handler call. In the example above, the map handler applies a Z-coordinate deformation, using the equation z = sin(x * y), so that all the points retain their X and Y coordinates and the Z is moved up or down so as to follow the saddle function. Note that all coordinates are object-local.

The <index> value is 1-based, however the scripted plug-in is called with a <index> value of 0 to signal that this particular map call is being used by the gizmo bounding box drawing code to compute points in the gizmo box to draw. This occurs hit testing is performed on the object the SimpleMod modifier is applied to and the gizmo bounding box is displayed. This will be the case if the object is selected, the Modifier panel is active, and the SimpleMod modifier is selected in the object’s modifier stack.

It is basically up to the object being modified to decide what index value to pass. For meshes, for example, it is the actual mesh vertex index. For patches, it is the control points first all in one sequence, followed by the in and out vectors for each control point in control point order. For splines, it is control point, in vector, out vector in control point sequence within the curve sequence. This ordering may change in future versions of 3ds Max.

Since the map handler can be called many times, even on simple objects, it is highly recommended that you minimize the number of values that are created in the map handler. This will reduce the need for garbage collection to be run. If you need several local variables in the map handler, it is recommended that you declare one or more Point2 or Point3 values in the scripted plug-in definition, and then store values to the component values of the Point2 or Point3 values. This will prevent new local variables from being allocated in the map handler.

You should not try to access the object being modified from within the map handler as this will attempt to evaluate the scripted modifier again. This will result in an infinite loop and hang 3ds Max.

There are also three pre-defined plug-in locals you can access in the map handler, as follows:

min -- the modifier context's bounding box min coordinate

max -- the modifier context's bounding box max coordinate

center -- the modifier context's bounding box center coordinate

extent -- the modifier context's bounding box extent or size

In the example above, the map handler use the extent pre-defined local variable to compute a scaling for the saddle function, so that it gets a 1/8th cycle of the function (22.5 degrees) across the whole object. These bounding box locals relate to the modifier's context, either the whole object or group of objects if applied to a scene node selection, or sub-object selection if there is a sub-object selection modifier below it on the stack (such as a Mesh Select).

You can also use some other built-in capabilities of SimpleMod to implement modifier limits as in Bend and Taper. To do this, implement handlers for the following (you must implement all if you implement any):

on modLimitZMin do <expr>

on modLimitZMax do <expr>

on modLimitAxis do <expr>

If called, the on modLimitZMin and on modLimitZMax handler expressions must evaluate to float values corresponding to the minimum and maximum limits and the on modLimitAxis handler expression must return #x, #y or #z to specify the limit axis. The MAXScript global variable currentTime contains the time at which these values should be computed, although, normally, simple access to parameter values will yield the correct currentTime value automatically. The simplest way to implement these handlers is to maintain limit parameters and associated spinners and checkboxes, and simply pass these parameter values back.

The Modify panel actually creates a fresh instance of every modifier when it is to be shown in the More... list or the buttons in the Modifiers rollout. This will cause the create handler to be called for a scripted SimpleMod plug-in. No special handling in the create handler is required for this case.

See also

Updating Scripted Plug-ins

Scripted Plug-in Methods

Scripted Plug-in Clauses

Scripted Plug-ins

Scripted Mouse Tools