An Introduction to 3ds max 4’s Scripted Manipulators
Mark Young
Slide 1: Title
This is a brief introduction to Scripted Manipulators, a new feature in 3DS MAX 4 that opens up a huge realm of possibilities for creating custom 3D user-interface elements in MAX’s viewports. The Manipulator plug-in architecture and API is designed so that developers can easily build gizmo-style GUIs in the 3D viewports to directly manipulate the parameters of objects in the scene.
I’ll remind you of what’s involved in a direct manipulation interface so that I can point to the places where the new plug-in type helps out. A direct manipulation interface lets you edit geometric data with physical actions rather than typing text or adjusting some generic control. The interface includes three elements: (1) visual representation of the thing you are adjusting maybe with a gizmo, (2) user input by physical actions – dragging a mouse dragging is just one kind of action but it’s the most common one at this point in time, (3) immediate visual feedback for the input and its effect.
The MAXScript API for Manipulators provides hooks for building the visual part of the interface and listening to the user’s mouse input. The script author doesn’t have to do much besides (1) build gizmo geometry based upon the state of a scene object that is being manipulated, and (2) change the scene object’s state based upon mouse input – these two activities play off of each other and the rest of the flow of the interaction cycle is pretty much automatic.
Now why would you want to replace MAX’s Modify panels and spinners with gizmos in the viewports? As 3D graphics pros, I probably don’t have to sell you on the attractiveness of direct manipulation. A well-designed direct manipulation interface should be easier to learn because it’s more intuitive. I also think that a well designed manipulator will let the 3D user work faster, and more accurately because of the way our brain supports hand-eye coordination.
Putting the GUI into the viewport can also save the time its takes to switch your attention between your view of the model and the Command Panel – a switch that takes on the order of 2 seconds, not even counting the time to navigate through tabbed panels and rollouts. Besides direct manipulation, I will also show you how you can build gizmos that move a lot of other user interface control into the viewport so that you can customize and streamline various workflows with a more heads-up interface.
However, since MAX let’s you adjust so many things and includes so many tools – namely lots of spinners, buttons and selection lists, it would probably be too much to control everything with gizmos in the viewports – the viewports would get awfully cluttered – so Manipulators are a provided as a customization resource.
The new Manipulators are objects that can be implemented as DLL plug-ins with the MAX SDK or as scripted plug-ins with MAXScript. I am only going to discuss the MAXScript API – you can find out the details of C++ implementations in the SDK help documentation where it describes “New Plug-In Types” for Release 4.
Slide 2: Feature Summary
The new Manipulator framework has these main features:
- 1. There is a transparent global mode that activates only those Manipulators that are applicable to an object in the current selection set. Since you can toggle Manipulate mode on and off, and filter which Manipulators are activated for which objects, and do it in a transparent way – Manipulate mode does not affect MAX’s other modes - you can pop up context-sensitive gizmos in a very flexible way.
- 2. Manipulators have their own geometry that is of a distinguished type. A Manipulator’s gizmo geometry is displayed only when the Manipulator is activated. The gizmo geometry is not part of the scene so that it behaves transparently with respect to the rest of MAX’s processes. And the Scripted Manipulator API makes it relatively easy to build gizmo geometry.
- 3. Manipulators’ gizmo geometry can hear mouse events. Button events and drag events are passed to a Manipulator’s handlers when a mouse button is pressed when the cursor is over the Manipulator’s gizmos. Hit-testing is built into the gizmo architecture so that MAXScript developers don’t have to do anything fancy to support 3D picking other than specifying the gizmos’ geometry. Besides building the geometry, your work is largely concentrated on changing a scene object based upon whatever mouse input is passed to the event handlers.
- 4. There are new utilities in MAXScript to help with all of the above. There is a Function Publishing interface with methods for building 2D and 3D gizmos. There are also methods for interpreting 2D mouse data as 3D input.
All of these features in combination with the rest of MAXScript mean that you can put almost any kind of geometry you want in a viewport to give users things they can click or drag to change their scene or change states in MAX or launch other tools.
Demo 1: Parameter Manipulators
Let me show you some examples in action with some Manipulators that ship with 3DS MAX 4. I’ll make a sphere, cylinder and cone. Select any of them and nothing special happens. If I now turn on Manipulate mode and select either one, or a combination, additional elements are displayed – notice the green wires and knobs – Manipulators create that geometry. If I hover over the innermost circles, they turn red and a tooltip pops up, reporting the values of the radius property. Each of these objects is displaying a separate instance of the same Manipulator, one that provides a way of changing radius parameters by direct manipulation. In this case, Manipulator filtering is done on object property names – objects with a property whose name that include a “RADIUS” substring get a gizmo. A radius changes if I drag its gizmo – mouse events over the gizmo are passed to the Manipulator’s event handlers, interpreted with respect to the 3D layout of the gizmo to specify a new value for the radius. A cool thing about the plug-in type is that all of this requires very little scripting work.
Manipulators can operate on other types of scene objects. Look at what pops up if I apply a Bend modifier. There are handles to drag for the Bend direction and angle. This is actually two Manipulators – one for manipulating “direction” and another for manipulating “angle”. These are 2 out of a larger set that MAXScript guru Boris Petrov wrote to manipulate a comprehensive set of object parameters (see http://www.gfxcentral.com/bobo/mxs4/magmapulators). You might notice that there is a downside when Manipulators proliferate – the viewports get pretty busy with gizmos. Bobo did a great thing by including a macroscript ToggleManipulators that provides a user interface to turn particular Manipulators on and off. This scripted utility changes the values of global flags that are factors in the Manipulators’ filters – a very useful technique.
Now I’ll give you a quick tour of the API for scripted Manipulators and MAX’s framework for executing them: The global Manipulate mode is toggled on and off with the “Select and Manipulate” button which is just to the right of the Transform buttons in the Main Toolbar. Each Manipulator specifies a condition for when it will be activated. When MAX is in Manipulate mode, any Manipulator whose activation condition is satisfied will be displayed and may process mouse events.
An important characteristic of Manipulate mode is its transparency. It does not modify other modes except that it might grab mouse events. The transparency goes both ways too – other modes do not affect it. This provides some interaction possibilities that are not typically possible in MAX. For example, if you have a Manipulator that transforms nodes and you are in a subObject mode, you can alternate between transforming a subObject selection with MAX’s standard transform gizmo and transforming the entire object with the scripted gizmo, without changing your selection or changing modes.
Slide 2: Manipulator Plugin
What do I mean when I say that a Manipulator is “activated”? It depends. For those of you who are already familiar with MAXScript’s scripted plug-ins, note that the base Manipulator plug-in class simpleManipulator is similar to the scripted Geometry plugin. Instances of a Manipulator may be transient or persistent. Here is the skeleton of a Scripted Manipulator definition.
A persistent or standalone Manipulator plug-in specifies a classID and can be saved in a MAX file. You would probably set its invisible property to false so that there would be a button in the Command Panel that you could press to create instances of the Manipulator. Standalone Manipulators are useful for providing UI for wired parameters. When a standalone Manipulator is “activated” it will process mouse events – otherwise it doesn’t.
Transient Manipulators are created automatically for each selected node for which their filter condition is satisfied but are not part of the scene. They are deleted when their associated node is unselected or Manipulate mode is turned off. All of the examples I’ll show you involve transient Manipulators. When a transient manipulator is “activated”, it is instantiated and will update and process mouse events until it is deleted.
The filtering condition is handled by a plug-in’s canManipulate or canManipulateNode handler. Use only one or the other. Either one returns a boolean that determines if the Manipulator will be activated. CanManipulate occurs on the baseObject and every modifier and transform controller for each node in the selection set. CanManipulateNode occurs just for the node. The condition can depend upon any data that MAXScript can access. Most typically the condition depends on node properties but you saw in Bobo’s ToggleManipulators utility how a more powerful UI could be built if these conditions depend on global variables that are controlled by their own UI.
Visual Display
The second most important handler is for updateGizmo. This occurs when the Manipulator instance is created and when the node it is manipulating changes. When this handler is called, you delete previously specified gizmos and build a new visual representation based upon the current state of the object being manipulated. The Manipulator API and a companion function publishing interface manip provide a lot of support for building the gizmos.
Slide 3: Manipulator
Graphics
The Manipulator’s node or target properties are used to get information about the object’s position, size and shape. The Manipulator’s methods are used to remove stale gizmos (clearGizmos) and add new gizmo geometry. Any mesh that you can build with MAX can be used as a gizmo with the addMesh method. Wireframe gizmos can be added with addShape. The manip interface includes several methods for making the kinds of shapes that are most commonly used. AddMarker and addText display 2D objects with 3D positions but with fixed projected size and shape. By default, gizmo geometry is specified in the local coordinate frame of the object’s node.
Flags may be set for gizmos to specify that they are invisible, visible only in the active viewport, excluded from hit-testing, or that their geometry is in screen coordinates. Gizmos that are invisible but hit-tested can be used to make the actual scene object seem directly manipulatible. You can specify gizmo geometry in screen coordinates to make sure that it is not occluded. You may specify two colors for gizmos so that they highlight when the mouse rolls over them.
Slide 4: Manipulator
Event Handling
Event Handling
Finally, to actually manipulate scene objects we must trap mouse events and interpret them with respect to the geometry of the gizmos. The simpleManipulator plug-in has event handlers for button presses, drags and releases. These occur only when the mouse button is pressed when the mouse is over a hit-tested gizmo. The handlers include arguments that specify the mouse position in screen coordinates and an index that specifies which gizmo the mouse was pointing at. Each time you call an “Add” method you create a gizmo with a unique index. To support direct manipulation, you must interpret 2D mouse positions with respect to the 3D geometry of a gizmo. The Manipulator’s getLocalViewRay method helps with this problem, giving you the visual ray that passes through the mouse cursor, in the local coordinates of the object being manipulated.
Slide 5: Synthesizing Tools from Manipulators
Now I’ll show you some more examples of Manipulators. Earlier I showed you Manipulators that provided gizmos for changing numeric properties like the parameters of parametric surfaces and modifiers. The manipulators I’ll show you now go a bit further.
Demo 2: Brush Shape Gizmo for gMAX
Here is a Manipulator designed for a game pack for gMAX for a game engine that uses a Brush primitive. Brushes are surfaces that enclose volumes that are intersections of half-spaces – planar faces forming convex surfaces. Additionally, the vertices of Brushes snap to integer lattice points in a world coordinate frame.
I’ll make a Box, convert it to a Mesh and then turn it into a Brush. To make the vertex snapping more apparent I’ll crank up the lattice spacing. You see the effects of the snapping as I move the Brush. I want a tool for moving individual faces of the Brush. Because of the snapping, I’d like a Translation gizmo that constrains movements to the principal world axis directions. When I turn on Manipulate mode, notice the handles that pop up from the faces. I can drag any of them to move a face. Notice that I did not have to go to the Command panel and select a subObject mode.
This Manipulator has two modes: (1) A picking mode in which a handle is displayed for each face with mouse event handling that simply determines which face was picked, then switching to the other mode, (2) a translation mode in which an axis tripod gizmo is displayed with mouse event handling that reacts to drags projected onto an axis. The pick handles are just “buttons” for selecting faces. The axis tripods are the direct manipulation gizmos. There is a special case where if you start dragging in the picking mode, it turns into the translation mode with the active axis being the principal direction that is closest to the face’s surface normal.
Demo
3: 3D Wall Tool
Here’s another Manipulator that gives you a shortcut to subObject modifications with Lines. This Manipulator is geared towards a workflow in which you are building walls by first drawing the floorplan. I’ll draw a Line and turn on Manipulate mode. Notice the gizmos that show up at the vertices and segment midpoints. I can simply drag any of these gizmos to either move a single vertex or move pairs of adjacent vertices. Ordinarily, I would have to go into a subObject mode and select vertices and use the Transform gizmo. This manipulator provides a simpler and quicker way to perform a more limited transformation – I can only drag these gizmos along the ground plane but I don’t have to do as much work to select subObjects or select transform constraints.
This Manipulator also has multiple modes and uses the gizmos as buttons to switch modes. If I click on the gizmos I switch the Manipulator into an “Extension” mode. Now there is a gizmo I can drag to extrude a Wall. I can click on the gizmo to switch back to the “Translation” mode where I can now drag around the corners or segments of the wall. If I switch modes by clicking one of the Line’s endpoints I get two Extension gizmos – besides the Extrusion gizmo there is a gizmo that lets me add pieces. We can use gizmos as buttons to launch other tools, making them part of an integrated gizmo design to make the tools feel more like pieces of a whole. Contrast this with the panel of buttons in the Modify panel for Splines. If you’re building the interface for a gMAX game pack you might be able supply enough gizmos so that users don’t need to resort to the Command panel except for rarer, more advanced operations.
That’s a quick look at the new Scripted Manipulator plug-in. To recap: It’s a facility for putting customized context-sensitive GUI elements in the viewport. It is particularly useful for directly manipulating geometric properties. But I also showed you how Manipulator gizmos can serve as “buttons” to trigger more extensive series of actions in MAX. The strong point of the feature is that you don’t have to do much more than (1) build a visual representation of a gizmo based upon the state of the object being manipulated and (2) change the state the object in response to mouse input – the flow of the rest of the interaction cycle is otherwise pretty much automatic.
You can use Manipulators to provide more intuitive ways to adjust object parameters. You can also use them to put things in the viewport that provide shortcuts to various functions that can streamline particular workflows. For applications like gMAX game packs it provides an opportunity to build a user interface that relieves users of the need to use the Command Panel. It greatly expands what is possible for custom GUIs and allows for a lot more developer creativity.