How To > Draw a Freehand Spline |
3ds Max does not provide a built-in function for drawing splines freely with the mouse. Surprisingly enough, the old Autodesk 3D Studio DOS had such a feature.
Using the power of MAXScript, we can implement this feature as a simple MacroScript. It will let us draw a spline in the ground plane using the mouse.
Spline Shape Common Properties, Operators, and Methods
Picking Points in the Viewports
MAXScript Message and Query Dialogs
The macroScript will be called FreeSpline . To use the script, you can go to Customize... and drag the script from the category "HowTo" to a toolbar, a menu, a quad menu or assign to a keyboard shortcut.
We will need some local variables to store the last knot position and the new object created by the script. The third variable will be used as a flag to tell us whether we just started creation of the spline.
These variables will exist only inside the macroScript’s context as we declare them as local.
We create our own function to handle the drawing of new knots in the splineShape. This function receives two parameters – the current position of the mouse, and the result of the first click captured by the pickPoint function (see below).
If we don’t know of an existing Knot (creation just started!), we set the value of the old_pos local variable to the first clicked point provided by the old_pen_pos parameter.
Next we check the distance between the last known knot’s position and the current mouse position. If the distance is longer than 10 units...
The flag variable we defined will contrain either true or false. When the variable contains false, spline creation has just started. Because a spline must have at least two knots (vertices), we will create the first knot twice and then set this flag to false. When the next knot position is to be set, instead of creating a new one, we will reposition the existing second knot to the new coordinates and then set the flag to true.
When the flag is set to true, we will just create the next new knot - see next line...
...we go on and place a new knot, thus adding a new segment to the spline shape. The addKnot function requires a splineShape object, the index of the spline (we have just 1), the type of the knot (we use #smooth in our case), and the position to put the knot at.
When the flag is set to false, we have to move the existing second knot instead of creating a new one...
Then we set the flag to true. Next time, a new knot will be created instead...
Then we remember the new knot’s position to use by the next mouse movement check.
To see the changes made to the spline, we update the splineShape object.
We create another function to handle the capturing of the mouse motion.
Our function calls only the built-in pickPoint function which provides an optional callback which calls the function we just defined (get_mouse_point) and passes the current mouse position and any user parameters supplied (in our case, old_pen_pos).
As long as the mouse is moving and no clicks are encountered, the pickPoint’s mouseMoveCallback will constantly call our function and thus create new knots at distance of 10 units...
Picking Points in the Viewports
We will put the complete code in an undo context to be able to undo the whole drawing result.
When starting the script, we first construct an empty splineShape object.
Then we go into pickPoint mode (but this time without a mouse callback). The function will wait for a click in the viewport and return the position of the picked point, or #RightClick if the Right Mouse Button has been pressed.
Picking Points in the Viewports
If the Right Mouse Button has been actually pressed, we just delete the newly created splineShape and finish the script.
If the pickButton has returned a position value and not #RightClick, we can select the splineShape...
Set the position of the splineShape to the clicked point...
...add a new spline to the empty splineShape...
...and add two new knots to the newly create spline in the splineShape. As mentioned above, a spline should have at least two knots, so we create the first two with the same position and will then move the second knot instead of creating a new one.
We "lower the flag" by setting it to false. This way, the script will know that we just created the first two knots and the second one has to be set to the next mouse position captured by the script. When this is done in the get_mouse_pos function, we will "raise the flag" again by setting it to true and thus know that the initial spline creation steps are over...
Now we can call our draw_new_line function and pass the first clicked point as parameter. That function will start monitoring the mouse movements until a new click occurs.
If a new click has been captured by the pickPoint function, the draw_new_line function will return to this point. Now we can ask the user whether he wants to close the newly drawn spline.
MAXScript Message and Query Dialogs
If the answer to the query is Yes, we close the first and only spline in the splineShape and update the internal data structures to reflect the changes.
Finally, we select the newly-created splineShape in the scene before exiting.
Evaluate the script. To use it, you can use Customize... to drag the script from the category "HowTo" to a toolbar, a menu, a quad menu or to assign to a keyboard shortcut.
Execute the FreeSpline script and left-click in the top or perspective viewport. Drag the mouse freely to draw a spline. Left-click again to finish drawing. Answer the prompt with Yes to close or No to leave the spline open.