You are on page 1of 42

INTRODUCTORY MAXSCRIPT TUTORIALS 1-5

As seen on www.maxforums.org
created by: Dub (Rhys2@xtra.co.nz) and Nick Clark (http://wwwnickclark.com)
Introductory max
script tutorials
Volume
1


D U B M A X S C R I P T T U T O R I A L S

Part 1 The basics t he
very basics
Thistutorial shouldtakearound5 minutestocomplete
will hopefully do a few of these over the next while. I'll start off really really basic
for those who have always wanted to learn maxscript but haven't been able to get
started. (That was me for a long time)

The best way to learn maxscript is to learn a few basic tricks that you can use in your
everyday work. You can then extend your knowledge as you come across tasks that
you can *almost do with your current knowledge.

Int ro
Ok, first of all I'll go over a few basics.
To follow along with these tuts, open the maxscript listener by
hitting F11.

The pink area up the top is the listener where if you enable the macrorecorder, it will
tell you what max is doing in maxscript terms as you do regular tasks in max. We won't
pay attention to this area in this tut.

The white area is where everything will be happening. Delete the "Welcome to
maxscript" message so we have a blank slate to start with.
.


Chapter
1
I

D U B M A X S C R I P T T U T O R I A L S

The basics
Create a sphere in the scene so we have an object to talk to.

There are two simple ways to refer to an existing scene object in max. You can select it and refer to
the selection or you can refer to it by name. The way maxscript refers to objects is by their name
with a $ in front. So to refer to the sphere you just created, type:

$Sphere01

Now, with the cursor at the end of that, hit the enter on the numeric keypad. That will execute the
current line. If you want to execute more than one line, select them all and hit numeric enter.

once you hit enter, maxscript will return the following in blue:
$Sphere:Sphere01@ [10,-5,0]

The last numbers will vary depending on where you created the sphere in the scene.
This is confirmation that you are talking about the sphere and that your syntax is correct.

Object Attributes

Now lets try something slightly more useful. Type:

$Sphere01.radius

and hit numeric enter to execute. maxscript will return the radius of the sphere!
Notice how there is a hierarchy to the command. You started with the object itself then a period (.)
then the parameter belonging to the object. You can refer to other parameters the same way. ie;

$Sphere01.segments will return the segments value.

Setting attribute values

Now what we want to do is change the values not just look at them.

Simply type:

$Sphere01.segments = 35

You'll notice as soon as you execute the line, the sphere changes it's segments to 35!
Well you could have done that faster with the GUI right? What if you have 25 spheres all with
different radii and you want to just change their segment count? (a common problem)

D U B M A X S C R I P T T U T O R I A L S

Working on selections of many objects

I referred earlier to the fact we can refer to objects by referring to the current selection. In
maxscript the shortcut to this is to simply select an object (select your sphere) and type:

$

When you execute this, you'll get the same result as if you had typed $Sphere01
Now we are going to exploit the power of "mapped functions"

Create 10 spheres of random radii and position. Select them all. Now type the following and
execute it:

$.segments = 10

All the spheres will retain all their setting except the segments on all of them will be set to 10.

Thats it for now!

Conclusion

Play around with other objects and other attributes.
if you want to know what parameters are availiable to you on a given object, type:

showproperties $

For the sphere, that will return the following list:

.smooth : boolean
.radius : float
.segs : integer
.mapcoords : boolean
.slice : boolean
.hemisphere : float
.sliceFrom : angle
.sliceTo : angle
.chop : integer
.recenter : boolean
.realWorldMapSize : boolean
false


D U B S M A X S C R I P T T U T O R I A L S

Part 2 St ill t he basics
Thistutorial shouldtakearound10 minutestocomplete
e're going to step it up a level in this tutorial




Int ro
We will be covering four main areas.
1: Variables and data types
2: Loops
3: Comparison Operators
4: If statements
.







Chapter
1
W

D U B S M A X S C R I P T T U T O R I A L S

Variables
You can think of variables in MXS (maxscript) as a temporary named storage place for an "object"
of some sort. think of them like lockers at the swimming pool. there are a huge number of them
available (unlimited) and they all have nothing in them and are unnamed. Once you put something
in a locker (variable) - it might be a number, a piece of text or even a modifier - and give it a name it
will always be in there until you replace it with something else.

To set a variable in maxscript you simply type the following:

variableName = variableValue

The variable name can be anything you like and the value can be almost anything as well. For now
we will use a float which is a number with a decimal place

ourVariable = 34.5

if you enter that into the listener and execute it, it will return 34.5
now if you type an expression such as:

2 * ourVariable

Maxscript will return 69.0

The main data types in maxscript are the following:

Float - these are numbers will a decimal component to them ie 234.643
Integer - These numbers are whole numbers only ie 5 or 200
Boolean - true or false
String - this is a piece of text. To set a string you need to enclose it in quote marks ie:

myStringVariable = "Maxscript sure is handy"

One last thing. You can convert different data types from one to another like this:

"35" as integer

the 35 is a string (because it has quote marks around it) but the "as integer" after it, turns it into an
integer. Obviously "as string" and "as float" do as you would expect.


D U B S M A X S C R I P T T U T O R I A L S

Loops
Loops are where maxscript becomes really powerful and useful. They enable maxscript to do
repetitive tasks rather than you and the mouse.

Imagine you have built a scene with many objects. You have added a turbosmooth modifier to
all the objects with an iteration value of 2. This is now causing you problems because the scene
is too slow to navigate and you wish you had set the iterations to 1 with a rendertime setting of
2.

Here is the code:

for obj in $ do
(
obj.modifiers[#turbosmooth].iterations = 1
obj.modifiers[#turbosmooth].useRenderIterations = true
obj.modifiers[#turbosmooth].renderIterations = 2
)

We will now look at it line by line.

for obj in $ do - Our for loop is saying in plain English: "For the objects in our current
selection, do the commands inside the following brackets."

( - We open the brackets
obj.modifiers[#turbosmooth].iterations = 1 - we set the iterations to 1

obj.modifiers[#turbosmooth].useRenderIterations = true
obj.modifiers[#turbosmooth].renderIterations = 2 - these lines should be obvious to you by
now.

) - We close the brackets to end the for loop.

Max will keep looping through the code on every object in the selection until it has done them
all.

You can test the code by making a bunch of objects all with turbosmooth on them. THEY
MUST ALL HAVE A TURBOSMOOTH MODIFIER. if one object doesn't have a
turbosmooth modifier, when MXS tries to talk to it, it won't find it and your script will fail with
an error. This obviously isn't very satisfactory.


D U B S M A X S C R I P T U T O R I A L S


Comparison operators

We can solve this problem by adding an "If" statement to the code

But first of all we'll look at some comparison operators. if we have two items such as the
numbers 5 and 2, we can compare them in different ways try typing the following into the
listener:

5 == 2
-Is 5 equal to 2? -This returns False

5 != 2
-Is 5 NOT equal to 2? -This returns True

5 < 2
-Is 5 less than 2 -This returns False

5 > 2
-Is 5 greater than 2 -This returns True

There are more as well which you'll find useful in due course.

If St at ement s

The way if works is like this:

if (expression resulting in true or false) do
(
code goes here
)

Here is a sample which you should be able to read easily by now:

if (obj.modifiers[#turbosmooth] != undefined) do
(
obj.modifiers[#turbosmooth].iterations = 1
obj.modifiers[#turbosmooth].useRenderIterations = true
obj.modifiers[#turbosmooth].renderIterations = 2
)

That will check an object to make sure it has a turbosmooth modifier and then if it does, run
through the code in the following brackets

D U B S M A X S C R I P T U T O R I A L S

Conclusion

Now when we put it all together, we get the following script:

for obj in $ do
(
if (obj.modifiers[#turbosmooth] != undefined) do
(
obj.modifiers[#turbosmooth].iterations = 1
obj.modifiers[#turbosmooth].useRenderIterations = true
obj.modifiers[#turbosmooth].renderIterations = 2
)
)

It should happily run through every object in your current selection and if it has a turbosmooth
modifier, set it to the values we specified..












D U B S M A X S C R I P T U T O R I A L S

Part 3 Making st uff
random
Thistutorial shouldtakearound10 minutestocomplete
or this tut, we'll have a look at the random function, object positioning and also
do some more loops for practice.




Int ro
Here is our hypothetical scenario. We want to build a fence across a
field. We have made an array of tall boxes - 20 of them - for fence
posts unfortunately they look really uniform and CG like. What to
do? Maxscript to the rescue.
.






Chapter
1
F

D U B S M A X S C R I P T U T O R I A L S

The Random Funct ion
Open the listener and type in the following command:

random 1.0 35.0

Maxscript will return a float number between 1 and 35. Notice how putting .0 after the number
made maxscript realise that we wanted it to generate floats and not integers.

Now we'll make a variable with a random integer between 1 and 6

diceThrow = random 16

Now whenever we access the diceThrow variable we made, it will contain the number that it
randomly chose when we first created the variable.
Randomizing post heights
Create an array of about 20 boxes. They should have their pivot on the ground and be 10 x 10 by
100 high. Make the spacing about 150 units.

I'm sure that you have a rough idea in your head by now of how we will go about this. Here is the
code:

for obj in $ do
(
randHeight = random 90.0 110.0
obj.height = randHeight
)

We have the same loop as last time. For all the objects in the selection, execute the following code:

randHeight = random 90.0 110.0 - Make a variable with a random float between 90 and 110 in it.
obj.height = randHeight - Assign that variable to the objects height.

Select all your fencepost boxes and run the code. Now all the posts should have slightly different
heights!




D U B S M A X S C R I P T T U T O R I A L S

Position
Create a sphere in the scene and select it.

The way Maxscript accesses the position of objects is with the .position (or .pos) property.

If you type:

$.pos

Maxscript should return: [12.3434,34.6446,0] or similar. You exact results will depend on where
you made the sphere in your scene.
Point 3 Dat a t ype
This result is a special type of data type called a Point3 data type. It contains X Y and Z values
always in that order. If we assign one to a variable:

ourPoint3variable = [5,4,1]

and then type this:

ourPoint3variable.y

Max will return 4 which is the Y component of our Point3. If we just type:

ourPoint3variable

Maxscript will return all the values - [5,4,1]
Position (and many other things) in 3D often needs 3 values, X, Y and Z so a Point3 is a very
useful data type.

Moving Object s
Back to setting an objects position.
We could type the following:

$.pos = [0,0,0]

that will move our selected sphere to the center of the world. We are giving the sphere explicit co-
ordinates to go to. What if we want to move it relative to where it is now?
maxscript provides a move function to do just that.


D U B S M A X S C R I P T T U T O R I A L S

move $ [3,2,0]

That is simply saying "Move the selected object +3 units in X, +2 units in Y and 0 units in Z"
type:

$.pos

Now maxscript will return the position as [3,2,0]
Execute the move line again:

move $ [3,2,0]

Then ask the position:

$.pos

You'll see that it is now at [6,4,0]
Delete the sphere. (if you want to be fancy, type: delete $)

Now we want to randomise the position of all the posts slightly.

Randomizing Position

Select all the posts again.

Here is the code we are going to use.

for obj in $ do
(
randX = random -5.0 5.0
randY = random -5.0 5.0
move obj [randX,randY,0]
)

Lets step through it.
For each object in our current selection do:
Create a random float between -5 and 5 and assign it to the variable randX
Create a random float between -5 and 5 and assign it to the variable randY
move the current object according to the following Point3. Where it says randX in the point3,
maxscript will substitute in the random number it generated earlier. The same goes for the randY.
we don't want the posts to move vertically so we have just put in a 0.

Highlight the code and run it.

D U B S M A X S C R I P T T U T O R I A L S

Conclusion
We now have fence posts that vary randomly in height and x,y position. In the next tut, we'll also
randomize their rotation so they all lean in slightly different directions.
Save the max file as we'll use the same one next time.

















D U B S M A X S C R I P T T U T O R I A L S

Part 4 More complex
basics
Thistutorial shouldtakearound10 minutestocomplete




Int ro
In this tut we'll be covering 4 things. Rotations,
Comments, Saving and running scripts
and making macroscripts. Hopefully you still have your
max file with the randomized fence posts from tut 3. Open
it up.







Chapter
1

D U B S M A X S C R I P T T U T O R I A L S


Maxscript Edit or
From now on, we won't be running our main scripts from the listener. The listener is still useful
for testing snippets of code before you incorporate it into your main script. Also you'll need to
look at the listener to see stuff returned from the maxscript parser.
Click Maxscript>New Maxscript

Hopefully a blank page should present itself. We will work in here from now on.

Save your script. I suggest making two folders in your scripts folder. One for your random
snippets of code that you've written for one-off tasks and the other for finished release quality
scripts with proper error checking, documentation and interfaces etc.

Last time we finished with a script to randomly set the positions of the fencepost. Now we want to
modify the script so that we can randomly set their rotations.
Rot at ions
Rotations are slightly odd in Max in that we need to first create a "rotation object" that we will
store as a variable. Then we apply our rotation object to our object (a fencepost in this case!)

As you possibly already know, in Max, there are 3 different types of rotations that you can use.
Euler angles, Quaternions and Angleaxis. As you get more advanced, you will want to work with
the different types in different scenarios but for now, we will use euler angles.

Eulerangles are defined in the following way: rot_obj = eulerangles x y z

create a cube somewhere in your scene and type the following into the listener:

cubeRotationObject = eulerangles 0 20 0

Maxscript should return: (eulerAngles 0 20 0)

Now we have our rotation object stored in our variable; cubeRotationObject.

All we need to do now is apply the rotation object to our object. Select the cube and type the
following:

rotate $ cubeRotationObject

The cube should rotate 20 degrees around the Y axis.

D U B S M A X S C R I P T T U T O R I A L S

Back to our script. Hopefully you should be ahead of me now with a clear idea how to modify the
script to randomly rotate the posts. In case you're lost, here is the code: (this time, type it into our
blank new maxscript file)

for obj in $ do
(
randXrot = random -3.0 3.0
randYrot = random -3.0 3.0
randZrot = random -3.0 3.0
rot_obj = eulerangles randXrot randYrot randZrot
rotate obj rot_obj
)

Select all the fence posts (or if you don't have the file from tut3, create an array of fence posts and
select them all) and run the maxscript by hitting CTRL+E (evaluate) All the posts should now
have random heights, positions and rotations giving a much more organic look than what we
started with.

Comment s

Once your scripts grow beyond a few lines long, comments start to get really important so that you
don't forget what parts of your code do what. Also if you need to give your code to anyone else,
good comments will make things much easier for them. A comment is text notes inside your script
that the Maxscript parser knows to ignore. You can make a comment by typing "--" Anything after
the -- will be interpreted as a comment and is not executed. If you need to write more than one
line, you'll need to put -- at the beginning of each line. Now go through and comment your
random rotation script. You'll notice that the comments show as green.

for obj in $ do -- Loop over currently selected objects
(
randXrot = random -3.0 3.0 -- create a random X rotation value and store as a variable
randYrot = random -3.0 3.0 -- create a random Y rotation value and store as a variable
randZrot = random -3.0 3.0 -- create a random Z rotation value and store as a variable
rot_obj = eulerangles randXrot randYrot randZrot -- Build our rotation object and store
rotate obj rot_obj -- Apply the rotation to the current obj
)





D U B S M A X S C R I P T T U T O R I A L S

Macroscript s

I'm now going to show you how to make your script into a macroscript that you can bind to a
shortcut key or set as a menu option or button inside max.

There is a function that we will be using strangely enough called macroscript. Here is a template:

MacroScript Script_Name category:"Category Name" buttonText:"Name of Button or
Menu Item" tooltip:"Tooltip Name"
(
your script code goes here
)

Obviously you will need to substitute names of your choosing into it.
Here is what my final script looks like:

MacroScript Random_Rotate category:"Rhys Tools" buttonText:"Random Rotate"
tooltip:"Random Rotate"
(
for obj in $ do -- Loop over currently selected objects
(
randXrot = random -3.0 3.0 -- create a random X rotation value and store as a variable
randYrot = random -3.0 3.0 -- create a random Y rotation value and store as a variable
randZrot = random -3.0 3.0 -- create a random Z rotation value and store as a variable
rot_obj = eulerangles randXrot randYrot randZrot -- Build our rotation object and store
rotate obj rot_obj -- Apply the rotation to the current obj
)
)

Save it and evaluate it (CTRL+E)

Maxscript will appear to do nothing and a number will be returned in the listener. This is good.

Now open Customize>Customize User Interface and under the category dropdown, there should
be one labeled "Rhys Tools" (or whatever you decided to call yours) You can now make this a
button or as I usually do, create a "Rhys Tools" menu bar item and add it there.


now whenever you click the item, it will randomise the rotations of whatever objects you have
selected within +/ - 3 degrees.
D U B S M A X S C R I P T T U T O R I A L S

Conclusion

You may have realised that there are two fatal flaws. The first is that the script will crash if you
have nothing selected as $ will be undefined. Secondly what if you want different values than the
+/ - 3 degrees hard coded into the script? We will deal with these things in the next tut.































D U B S M A X S C R I P T T U T O R I A L S

Part 5 More basics
Thistutorial shouldtakearound10 minutestocomplete




Int ro
In this tut we will be covering 4 things. Arrays, Error Checking,
Messagebox prompts, and user interfaces.
This is the longest tut yet and will take about 1/ 2 hour to complete.
We left our random rotate script last time with two fatal flaws. 1, It
crashes if there is no object selected and 2, there is also no way to
specify the range of random rotation.









Chapter
1

D U B S M A X S C R I P T T U T O R I A L S


Arrays
First of all, I'd like to introduce a new concept - Arrays. If you're new to programming in general
this will be a relatively meaningless term.
Put most simply, an array is just a list of "things". Almost anything that can be saved as a variable
can be saved into an array. Lets make a quick array to get an idea about how they work.
First of all, we need to create an empty array with a name. Fire up the listener and input and execute
the following:

ourFirstArray = #()

ourFirstArray is our arbitrary name we have chosen, # is the symbol for arrays in maxscript, and the
() encloses the contents of our array which is nothing in this case. Thus we have just created an
empty array.
Now we want to put something in our array. Maxscript has a useful little function called "append"
which does just that. Usage is as follows:

append ourFirstArray 1

now type:

append ourFirstArray 3

now, type:

ourFirstArray

Maxscript will show us the contents of our array: #(1,3)

We can keep adding to the array as much as we like. But how do we retrieve a certain value from it?
Each item in the list is numbered from 1 upwards. So to retrieve the second item in our array we
need to ask for item 2 from ourFirstArray we do this by typing:

ourFirstArray[2]

Maxscript will return the integer 3 that we saved into the array earlier.

One last thing that you will find very useful with arrays is the property .count - if we type the
following:

ourFirstArray.count

Maxscript will return 2 being the number of items in the array.
D U B S M A X S C R I P T T U T O R I A L S

Error Checking
Open up the script we finished with last tut. it should look like this:

MacroScript Random_Rotate category:"Rhys Tools" buttonText:"Random Rotate"
tooltip:"Random Rotate"
(
for obj in $ do -- Loop over currently selected objects
(
randXrot = random -3.0 3.0 -- create a random X rotation value and store as a variable
randYrot = random -3.0 3.0 -- create a random Y rotation value and store as a variable
randZrot = random -3.0 3.0 -- create a random Z rotation value and store as a variable
rot_obj = eulerangles randXrot randYrot randZrot -- Build our rotation object and store
rotate obj rot_obj -- Apply the rotation to the current obj
)
)

Now we have been referring to the current selection by typing $.
Another way we can refer to the current selection is by typing the word "selection" This is actually
an array of objects. Create a bunch of random objects in a scene. A bunch of teapots will do fine.
Select them all. Now type:

selection.count

Maxscript will return the number of teapots that are selected! Try typing:

selection[1]

Maxscript will return the first teapot in the selection list. Now deselect the teapots so that nothing is
selected and type:

selection.count

Maxscript returns 0. This is obviously useful to us. Lets now add an if clause to our script so that it
will only run the script if more than 0 items are currently selected. Add the following code:

MacroScript Random_Rotate category:"Rhys Tools" buttonText:"Random Rotate"
tooltip:"Random Rotate"
(
for obj in $ do -- Loop over currently selected objects
(
if (selection.count > 0) then -- if the current selection has more than 0 items, then do...
(
randXrot = random -3.0 3.0 -- create a random X rotation value and store as a variable
randYrot = random -3.0 3.0 -- create a random Y rotation value and store as a variable
D U B S M A X S C R I P T T U T O R I A L S

randZrot = random -3.0 3.0 -- create a random Z rotation value and store as a variable
rot_obj = eulerangles randXrot randYrot randZrot -- Build our rotation object and store
rotate obj rot_obj -- Apply the rotation to the current obj
)
)
)

Before we run it, lets add a warning to the user so that if they have no items selected, they will
realise why nothing is happening when they run the script.

Message boxes
We will use an else after our if/ then statement. Also we'll invoke the messagebox function to
display an error message to the user. Add the following lines:

MacroScript Random_Rotate category:"Rhys Tools" buttonText:"Random Rotate"
tooltip:"Random Rotate"
(
for obj in $ do -- Loop over currently selected objects
(
if (selection.count > 0) then -- if the current selection has more than 0 items, then do...
(
randXrot = random -3.0 3.0 -- create a random X rotation value and store as a variable
randYrot = random -3.0 3.0 -- create a random Y rotation value and store as a variable
randZrot = random -3.0 3.0 -- create a random Z rotation value and store as a variable
rot_obj = eulerangles randXrot randYrot randZrot -- Build our rotation object and store
rotate obj rot_obj -- Apply the rotation to the current obj
)
else
(
messagebox "You must have at least one object selected!"
)
)
)

Now run the script. As it has the same macroscript name as last time, it should overwrite the
previous version of the script and you can immediately use the menu item or button you made to
kick off the new script. Make sure nothing is selected in the viewport and run it. Hopefully an error
prompt should appear telling you that you need to have at least one item selected!
Good work. We have solved the first flaw with the script.

D U B S M A X S C R I P T T U T O R I A L S

User Int erfaces
Obviously to solve the second problem, we're going to have to give the user some way to enter in the
range of values that he/ she wants the random rotations to fall between.

Open the Visual Maxscript Editor - Maxscript>visual Maxscript editor...
It's very simple to use the editor to create an interface. Add elements from down the bottom and
position them in the workspace to your liking. Here is the results of my interface:


Now, save your interface as a .ms file (make sure you don't save it as a .vms file which is the
default.)
Open the file in max as a maxscript and lets take a look. This is what mine looks like.

rollout RandomRotateRollout "Random Rotate" width:162 height:122
(
groupBox grp1"Random Rotation Range" pos:[10,12] width:142 height:99
button btn1"Randomly Rotate!" pos:[19,81] width:125 height:22
spinner spn1"Minimum value " pos:[22,34] width:122 height:16 range:[-360.0,360.0,0.0]
spinner spn2 "Maximum value" pos:[23,56] width:122 height:16 range:[-360.0,360.0,0.0]
)

It contains 4 elements. A groupbox to keep things tidy, A button to run the script and two spinners
to select the random constraints.
D U B S M A X S C R I P T T U T O R I A L S

So how do we get the interface to run our script when we push the button?

Inside the rollout function, we can add the following code:

rollout RandomRotateRollout "Random Rotate" width:162 height:122
(
groupBox grp1"Random Rotation Range" pos:[10,12] width:142 height:99
button btn1"Randomly Rotate!" pos:[19,81] width:125 height:22
spinner spn1"Minimum value " pos:[22,34] width:122 height:16 range:[-360.0,360.0,0.0]
spinner spn2 "Maximum value" pos:[23,56] width:122 height:16 range:[-360.0,360.0,0.0]

on btn1pressed do -- when btn1is pressed do...
(
for obj in $ do -- Loop over currently selected objects
(
if (selection.count > 0) then -- if the current selection has more than 0 items, then do...
(
randXrot = random -3.0 3.0 -- create a random X rotation value and store as a variable
randYrot = random -3.0 3.0 -- create a random Y rotation value and store as a variable
randZrot = random -3.0 3.0 -- create a random Z rotation value and store as a variable
rot_obj = eulerangles randXrot randYrot randZrot -- Build our rotation object and store
rotate obj rot_obj -- Apply the rotation to the current obj
)
else
(
messagebox "You must have at least one object selected!"
)
)
)
)

You'll see that I have just taken the contents of our macroscript and pasted it inside the "on btn1
pressed do" brackets.
That takes care of the button press! Now we just have to set things up so that the values of the two
spinners are used as the random values instead of the hard coded +/ - 3.
We can do this by switching the hard coded values with: spn1.value and spn2.value
make the changes.

Now we have two more little things we need to do. We need to tell max to display the rollout when
our script starts running. we do this by adding the following after the rollout code:

createDialog RandomRotateRollout 162 166

And we also need to wrap the whole thing with our macroscript function. Our final script should
look like this:
D U B S M A X S C R I P T T U T O R I A L S


MacroScript Random_Rotate category:"Rhys Tools" buttonText:"Random Rotate"
tooltip:"Random Rotate"
(
rollout RandomRotateRollout "Random Rotate" width:162 height:122
(
groupBox grp1"Random Rotation Range" pos:[10,12] width:142 height:99
button btn1"Randomly Rotate!" pos:[19,81] width:125 height:22
spinner spn1"Minimum value " pos:[22,34] width:122 height:16 range:[-360.0,360.0,0.0]
spinner spn2 "Maximum value" pos:[23,56] width:122 height:16 range:[-360.0,360.0,0.0]

on btn1pressed do -- when btn1is pressed do...
(
for obj in $ do -- Loop over currently selected objects
(
if (selection.count > 0) then -- if the current selection has more than 0 items, then do...
(
randXrot = random spn1.value spn2.value -- create a random X rotation value and store as a
variable
randYrot = random spn1.value spn2.value -- create a random Y rotation value and store as a
variable
randZrot = random spn1.value spn2.value -- create a random Z rotation value and store as a
variable
rot_obj = eulerangles randXrot randYrot randZrot -- Build our rotation object and store
rotate obj rot_obj -- Apply the rotation to the current obj
)
else
(
messagebox "You must have at least one object selected!"
)
)
)
)
createDialog RandomRotateRollout 162 166
)

Run the script. If you have no errors, it should just return a number in the listener. Now test it out
on a bunch of objects!



D U B S M A X S C R I P T T U T O R I A L S

Conclusion and Homework

Hopefully by now, you should be able to create basic interfaces to interact with your scripts.
As an exercise, try adding separate range controls for X rotation, Y rotation and Z Rotation. Post
your solution in this thread if you can!







Max script fun: a couple of examples
A selection of examplescriptsprovidedbyNick Clark




Int ro
In this section youll find a selection of example scripts for you to
analyze and deconstruct. Each scripts purpose is explained to give
you a better understanding of how it works.












Chapter
2



Int roduct ion:

Maxscript provides two main things for a max user. The ability to create new features in max, and
a way to perform repetitive, or difficult tasks. Even if some of this makes no sense to you, I hope
some of it teaches you something new
Take the example of a light which flickers. This would be tedious to animate by hand, but a
parametric light flickering tool can be made quickly in maxscript, which can be used over and over
again.
Here's a couple of examples of using of maxscript to reduce repetitive or difficult tasks. The more
you see of maxscript, the more you can imagine what you can do with it. This is less of a tutorial
than the Dub's excellent work, but I hope the experience of this will help you write maxscripts in
the future.




This picture illustrates the use of maxscript to alter the color of a group of objects. As you can see,
the colors blend nicely. Coloring the objects this way manually would be possible, but would be
time consuming.









Here is the complete script:

color_01= color 0 0 80
color_02 = color 255 255 255
stepsize_r = (color_02.r - color_01.r)/ $.count
stepsize_g = (color_02.g - color_01.g)/ $.count
stepsize_b = (color_02.b - color_01.b)/ $.count

for i = 1to $.count do
(
newColor = (color ((i*stepsize_r)+ color_01.r-stepsize_r) ((i*stepsize_g)+color_01.g-
stepsize_g) ((i*stepsize_b)+color_01.b-stepsize_b))
$[i].wirecolor = newColor
)

To use it, select a row of objects, and run the script. If there are no errors, your objects will be
given a new wire color. There is supposed to be 2 lines of code between the brackets above, but
the forum is making it wrap. I hope this doesn't confuse people.

Explanation:
color_01= color 0 0 80
color_02 = color 255 255 255
color_01 and color_02 are the start and end colors to use for the color fade
This is how you would define pure white in maxscript

color 255 255 255
Pretty obvious, right?
stepsize_r = (color_02.r - color_01.r)/ $.count
stepsize_g = (color_02.g - color_01.g)/ $.count
stepsize_b = (color_02.b - color_01.b)/ $.count
This bit divides the difference between the start and end color divided by the number of objects.
One for red, green and blue. This gives us the amount of change of color in each step for use later
in the script. Don't worry if this makes no sense, it's the technique rather than the math I want
you to experience.


A "for" loop repeats a number of times, and gives an incrementing value for each cycle in the
loop
For i = 1to 10 do (print i) would print all the numbers from one to ten in the listener. Using
Print is a great way of having feedback from your calculations, like a debugger would be used by a
programmer (if you are doing this tutorial, you are a programmer!)
In the code
for i = 1to $.count do
(
blah blah blah
)
Any code in the brackets (blah blah blah) will be executed a number of times. In this case, the
number ($.count) equals the number of selected objects. "i" will be incremented every time the
loop repeats, until it reaches the ($.count) last number.
$in max means "the selected object"
$.count gives a number of how many selected objects you have.
When working on a selection of objects, FOR and $ are really useful.
The next lines of code do the actual work of coloring the objects. First, I calculate the new color
of the object.
newColor = (color ((i*stepsize_r)+ color_01.r-stepsize_r) ((i*stepsize_g)+color_01.g-
stepsize_g) ((i*stepsize_b)+color_01.b-stepsize_b))
This defines a new color I have called newColor. The code here calculates the new color based on
i (the step in the loop) and the step sizes calculated above. Don't worry if this bit is gibberish to
you right now, all experience is good.
$[i].wirecolor = newColor
This line applies the "newColor" to the objects.
$[1] would be the first object in the selection
$[2] would be the second object in the selection
$[3] would be the third object in the selection
When we use $[i], we can use i to define which object in the selection we are referring to. This is
where the i in the "FOR loop" comes in.
You might want to use something other than the wire color. You can create a material and apply
the color to the diffuse channel with script instead. To find out what code to use. Manually make
a material in the material editor, and watch the code that appears in the listener window. Use this
code to create your material


This method can be used to do almost anything to a group of selected objects. You could
randomly scale objects, rotate them, adjust the material, apply modifiers. The possibilities are
almost endless.

Here's a slightly more advanced example of something I could not do without maxscript:


The full script can be found at the end of this tutorial in appendix 1



This is one I made years ago, so please ignore the horrible, awful formatting, and lengthy
calculations in the code. Select your grid of objects (has to be an even square), select the four
colors by clicking on them and using the color picker, then click on the button.
I don't expect you to understand this script, but there may be something of use to you in it. Part
of the problem with maxscript is not knowing what it can do, and the more exposure to various
scripts, the better. Steal ideas (even code) from other scripts, use the listener and the help to work
out what you need to do. Select a word in the Maxscript editor, and press F1. The help will go
straight to the relevent article (mostly).
Happy scripting


Appendix 1
Nick Clarks color teapot gridscript
Just copy and past the below into the max script listener to run the script

rollout DialogExample "ColorGrid" width:200 height:200
(
colorPicker cp1"" pos:[4,4] width:50 height:50 color:[255,0,0]
colorPicker cp2 "" pos:[55,4] width:50 height:50 color:[0,255,0]
colorPicker cp3 "" pos:[4,59] width:50 height:50 color:[0,0,255]
colorPicker cp4 "" pos:[55,59] width:50 height:50 color:[255,128,0]
button btn1"Colorize" pos:[8,113] width:97 height:18


function theunction =
(

fn multiDimArr r c =
(
local arr, arrTMP
arr=
for i=1to r collect
Appendix
1


(
arrTMP=#()
for j=1to c do
(
append arrTMP (0)
)
arrTMP
)
arr
)
root

numCol = sqrt ($.count)
numrow = sqrt ($.count)
print (numCol as string + " x " + numRow as string)

topLeftColor = #(cp1.color.red,cp1.color.green,cp1.color.blue)
TopRightColor = #(cp2.color.red,cp2.color.green,cp2.color.blue)
BottomLeftColor = #(cp3.color.red,cp3.color.green,cp3.color.blue)
BottomRightColor = #(cp4.color.red,cp4.color.green,cp4.color.blue)

-- Red

myRedArray=multiDimArr numRow numCol
myGreenArray=multiDimArr numRow numCol


myBlueArray=multiDimArr numRow numCol

myRedArray[1][1] = topLeftColor[1]
myRedArray[1][numCol] = TopRightColor[1]
myRedArray[numRow][1] = BottomLeftColor[1]
myRedArray[numRow][numCol] = BottomRightColor[1]
myNewRedArray = #(1,2,3)


j = 1

for i = 1to numRow do
(
myRedArray[i][j] = (((myRedArray[numRow][1]) - (myRedArray[1][1])) * (i-
1)/ (NumRow-1)) + (myRedArray[1][1])
)


j = numCol

for i = 1to numRow do
(
myRedArray[i][j] = (((myRedArray[numRow][numCol]) - (myRedArray[1][NumCol])) *
(i-1)/ (NumRow-1)) + (myRedArray[1][NumCol])
)



for i = 1to NumCol do
(
for j = 1to NumRow do
(
myRedArray[i][j] = (((myRedArray[i][NumRow]) - (myRedArray[i][1])) * (j-
1)/ (numCol-1)) + (myRedArray[i][1])
)
)


for x = 1to numCol do
(
for y = 1to numRow do
(
myNewRedArray[(y+(numCol*(x-1)))] = myRedArray[x][y]
)
)


-- Green

myGreenArray[1][1] = topLeftColor[2]
myGreenArray[1][numCol] = TopRightColor[2]
myGreenArray[numRow][1] = BottomLeftColor[2]
myGreenArray[numRow][numCol] = BottomRightColor[2]
myNewGreenArray = #(1,2,3)




j = 1

for i = 1to numRow do
(
myGreenArray[i][j] = (((myGreenArray[numRow][1]) - (myGreenArray[1][1])) * (i-
1)/ (NumRow-1)) + (myGreenArray[1][1])
)


j = numCol

for i = 1to numRow do
(
myGreenArray[i][j] = (((myGreenArray[numRow][numCol]) -
(myGreenArray[1][NumCol])) * (i-1)/ (NumRow-1)) + (myGreenArray[1][NumCol])
)

for i = 1to NumCol do
(
for j = 1to NumRow do
(
myGreenArray[i][j] = (((myGreenArray[i][NumRow]) - (myGreenArray[i][1])) *
(j-1)/ (numCol-1)) + (myGreenArray[i][1])
)
)




for x = 1to numCol do
(
for y = 1to numRow do
(
myNewGreenArray[(y+(numCol*(x-1)))] = myGreenArray[x][y]
)
)


-- Blue

myBlueArray[1][1] = topLeftColor[3]
myBlueArray[1][numCol] = TopRightColor[3]
myBlueArray[numRow][1] = BottomLeftColor[3]
myBlueArray[numRow][numCol] = BottomRightColor[3]
myNewBlueArray = #(1,2,3)


j = 1

for i = 1to numRow do
(
myBlueArray[i][j] = (((myBlueArray[numRow][1]) - (myBlueArray[1][1])) * (i-
1)/ (NumRow-1)) + (myBlueArray[1][1])


)


j = numCol

for i = 1to numRow do
(
myBlueArray[i][j] = (((myBlueArray[numRow][numCol]) - (myBlueArray[1][NumCol]))
* (i-1)/ (NumRow-1)) + (myBlueArray[1][NumCol])
)

for i = 1to NumCol do
(
for j = 1to NumRow do
(
myBlueArray[i][j] = (((myBlueArray[i][NumRow]) - (myBlueArray[i][1])) * (j-
1)/ (numCol-1)) + (myBlueArray[i][1])
)
)


for x = 1to numCol do
(
for y = 1to numRow do
(
myNewBlueArray[(y+(numCol*(x-1)))] = myBlueArray[x][y]


)
)


--

mySelection = $ as array
for x = 1to numCol do
(
for y = 1to numRow do
(
myRedColor = (myNewRedArray[y+((x-1)*numRow)])
myGreenColor = (myNewGreenArray[y+((x-1)*numRow)])
myBlueColor = (myNewBlueArray[y+((x-1)*numRow)])
mySelection[y+((x-1)*numRow)].wirecolor = (color myRedColor myGreenColor
myBlueColor)
)
)

)


on btn1pressed do theunction()


)




-- create the rollout window and add the rollout
if DialogExampleFloater != undefined do
(
closerolloutfloater DialogExampleFloater
)
CreateDialog DialogExample width:114 height:140

You might also like