Creating Floating Tool Windows in 3ds Max

Technical art is one of the few areas in the Computer Games industry where the supply does not meet the demand. At the same time, the amount of literature available on how to develop the skills is tiny compared to the other disciplines, such as character art or level design. So many artists are put off venturing down this street simply because the basics are not well laid out. Not many university courses cater for the specialisation, and there is no dedicated book concentrating on the role. Hopefully, some of these tutorials will help to get the willing learner off the ground.

Creating a Simple Tool

We are going to have a look at writing a script that creates a basic tool. By tool, we mean a floating window that helps another user achieve a task within 3ds Max. Our tool will be a tool to help control the position of an object’s pivot. First, we have to create the interface.

Creating the UI

In 3ds Max, open the MAXScript window with the following command:

Menubar > MAXScript > New Script

In this window, type the following code:


rollout pivotControls "Pivot Controls"
(
button btnCenter "Center Pivot" width:150
button btnBase "Base Pivot" width:150
button btnOrigin "Origin Pivot" width:150
)

if theNewFloater != undefined then
closeRolloutFloater theNewFloater
theNewFloater = newRolloutFloater "Pivot Tool" 180 120
addRollout pivotControls theNewFloater

This is the basic code that creates the floating tool.

In the MAXScript editor, click: Menubar > Tools > Evaluate All

You should see something like the following:

PivotTool

The first thing we are doing is defining a rollout with a rollout clause:

rollout [rolloutName] [rolloutText]
(
--content goes here
)

Then within the rollout clause, we create three button objects. Each button object has a name, a text value which goes onto the button, and we assign each button a width value.

Then the code at the foot of the script creates a ‘RolloutFloater’. This is a floating window that gives us an object into which to put our rollout.

Adding The Functionality

Within the rollout clause, we add our functionality so that the buttons are hooked up to actions. Change the code to the following:


rollout pivotControls "Pivot Controls"
(
button btnCenter "Center Pivot" width:150
button btnBase "Base Pivot" width:150
button btnOrigin "Origin Pivot" width:150
on btnCenter pressed do
messagebox "Center Pivot"
on btnBase pressed do
messagebox "Base Pivot"
on btnOrigin pressed do
messagebox "Origin Pivot"
)
if theNewFloater != undefined then
closeRolloutFloater theNewFloater
theNewFloater = newRolloutFloater "Pivot Tool" 180 120
addRollout pivotControls theNewFloater

When you run the script this time, you will notice that pressing the buttons now makes dialog boxes pop up.
We use ‘event handlers’ to detect when the user has interacted with our tool:


on btnCenter pressed do
messagebox "Center Pivot"

The first line detects the ‘pressed’ event, then we add a command to carry out when the event gets triggered. In this case we are creating a dialog box with the message “Center pivot” in it.
The next stage is to replace these basic statements with our real code; the code that will handle the object pivots.

Commands

The next thing we are going to do is to add a command. Commands are processes that we can trigger using MAXScript. The command we are going to use is ‘CenterPivot’. This command centers the pivot of a target object. To add it to our tool, we just replace line 8 of our script with the command: ‘CenterPivot $’.
The dollar sign is what Max uses to denote the current selection. So you should have the following:


rollout pivotControls "Pivot Controls"
(
button btnCenter "Center Pivot" width:150
button btnBase "Base Pivot" width:150
button btnOrigin "Origin Pivot" width:150

on btnCenter pressed do
CenterPivot $
on btnBase pressed do
messagebox “Base Pivot”
on btnOrigin pressed do
messagebox “Origin Pivot”
)

if theNewFloater != undefined then
closeRolloutFloater theNewFloater
theNewFloater = newRolloutFloater “Pivot Controls”

Clicking the ‘Center Pivot’ button now will carry out that command.

Functions

The other two buttons require us to create our own commands. Custom commands are known as ‘functions’. Functions take the following form:


fn FunctionName [optional_parameters] =
(
--function code goes here
)

The name is important, as every time we call a function we will use its name. The optional parameters can be put in to give the function settings or to tell the function what objects to act on.
In our first function, we need to send an object’s pivot to it’s base, which is it’s minimum point in the Z-axis. So here is our function:


fn BasePivot =
(
for item in selection do
item.pivot = [item.center.x, item.center.y, item.min.z]
)

In the first line of our function code, we use a ‘for loop’. That piece of code steps through all the items that we have in our selection so that each item can be processed.
The next line tells the code what to do with each of the items in the for loop. The item’s pivot is sent to a location in space. A location in space, also known as a point3 value takes the form, [x, y, z]. In our case, we want the x and y values for the pivot to be at the object centre, and the z value to be at the minimum z location, so we send the pivot to: [item.center.x, item.center.y, item.min.z]
To carry out this code, we have to insert the function into our rollout code and then add a ‘function call’ to the button:


rollout pivotControls "Pivot Controls"
(
button btnCenter "Center Pivot" width:150
button btnBase "Base Pivot" width:150
button btnOrigin "Origin Pivot" width:150

fn BasePivot =
(
for item in selection do
item.pivot = [item.center.x, item.center.y, item.min.z]
)
on btnCenter pressed do
CenterPivot $
on btnBase pressed do
BasePivot()
on btnOrigin pressed do
messagebox “Origin Pivot”
)
if theNewFloater != undefined then
closeRolloutFloater theNewFloater
theNewFloater = newRolloutFloater “Pivot Tool” 180 120
addRollout pivotControls theNewFloater

Note that when we call the function, we use the following notation:


BasePivot()

When we call a function without sending a parameter, we have to add the open and closed brackets after the function name to tell Max that it is a function call. This is unnecessary when we make a function call with a parameter.

Mapped Functions

For the final button, we are going to use a special form of a function called a mapped function. Mapped functions allow us to carry out a set of operations on a collection of similar objects, but without the use of a ‘for loop’. For complicated operations, Max handles mapped functions more efficiently than it does for loops. This is a simple case, but it demonstrates the principle.
The function is as follows:


mapped fn OriginPivot obj =
(
obj.pivot = [0,0,0]
)

This time, we make use of a parameter (obj) so that the function knows what it is operating on. obj can be passed either a single item, or a collection of items. When we call the function this time, we need to send the function which objects to operate on. So here is what our final code looks like:


rollout pivotControls "Pivot Controls"
(
button btnCenter "Center Pivot" width:150
button btnBase "Base Pivot" width:150
button btnOrigin "Origin Pivot" width:150

fn BasePivot =
(
for item in selection do
item.pivot = [item.center.x, item.center.y, item.min.z]
)

mapped fn OriginPivot obj =
(
obj.pivot = [0,0,0]
)

on btnCenter pressed do
CenterPivot $

on btnBase pressed do
BasePivot()

on btnOrigin pressed do
OriginPivot $
)

if theNewFloater != undefined then
closeRolloutFloater theNewFloater

theNewFloater = newRolloutFloater "Pivot Tool" 180 120
addRollout pivotControls theNewFloater

As you can see, we send the current selection ($) to the OriginPivot function.

OriginPivot $

Summary

So there we have our final script. We create a rollout out. Add it to a rollout floater. Create three buttons. Then map the buttons to a series of commands and functions.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s