Skip to content

daliife/IntroMaxScript

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 

Repository files navigation

Introduction to Maxscript

Description

This repository is based on the subject Tool scripting from the Salle Masters MVD. Its main purpose is to be used as a tutorial and guide for future projects. Hope it is useful.

You can also find all the maxscript documentation from 3ds Max here.

Syntax

  • function variable parameters
  • primitive parameter1:value1 parameter2:value2 ...
  • ...

Screenshots

1_basic_transformations 2_loops_and_iterations 4_user_interface_widgets_2 5_animations 6_splines 7_ray_intersections

Examples

1. Basic transformations

-- Information text
global names= #("creation","movement","scaling","rotation")
for i = 0 to 3 do (
	temp = -50 + i*50
	t = TextPlus Plane:0 name:("text_" + names[i+1] as string) size:10 pos:[temp,-50,0] wirecolor:(color 255 255 255)
	t.SetPlaintextString(names[i+1])
)

-- Primitive creation. We can use diferent type of primitives: box, sphere, plane,...
box name:"box_creation" wirecolor:(color 255 0 0) pos:[-50,0,0]

-- Primitive displacement. It's important to check the units setup, it will affect the results.
box name:"box_movement" wirecolor:(color 0 255 0) pos:[0,0,0]
move $box_movement [0,0,15]

-- Primitive scaling
box name:"box_scale" wirecolor:(color 0 0 255) pos:[50,0,0]
scale $box_scale [0.5,0.5,2]

-- Primitive rotation
box name:"box_rotation" wirecolor:(color 255 255 0) pos:[100,0,0]
rotate $box_rotation (eulerangles 0 15 45)

Maxscript file example: 1_basic_transformations

2. Loops and iterations

-- Information text
t = TextPlus Plane:0 name:"text_loops_and_iterations" size:10 pos:[0,-80,0] wirecolor:(color 255 255 255)
t.SetPlaintextString("Loops and iterations")

-- Example of double 'for loop' to create grid of objects
for i = 0 to 10 do (
	for j = 0 to 10 do (
		if mod i 2 == 0 and mod j 2 == 0 then (
			sphere name:("Red Sphere (x:" + i as string + " y:" + j as string + ")") pos:[-50 + 10*i,-50 + 10*j,6] radius: 5 wirecolor:(color 255 0 0)

		)else(
			sphere name:("Yellow Sphere (x:" + i as string + " y:" + j as string + ")") pos:[-50 + 10*i,-50 + 10*j,6] radius: 2 wirecolor:(color 255 255 0)
		)
	)
)

-- Example of 'for each' iterating all objects in the scene to modify some transform values.
for item in $objects do(
	if classOf item as string != "TextPlus" then (
		if item.wirecolor.r == 255 and item.wirecolor.g == 255 then(
			scale item [2,0.5,0.5]
			rotate item (eulerangles -45 0 0)
		)
	)
)

Maxscript file example: 2_loops_and_iterations

3. Functions

-- Information text
t = TextPlus Plane:0 name:"text_functions" size:6 pos:[0,-10,0] wirecolor:(color 255 255 255)
t.SetPlaintextString("Functions")

global max_depth = 5

-- Function implementation with recursive tree exercise.
function createChildren childAmount depth = (

	b = box name:(depth as string) width:1 height:1 length:1
	depth = depth + 1

	if depth > max_depth do
		return b

	initial = (b.pos.x - childAmount/2)

	for i = 1 to childAmount do (
		child = createChildren childAmount depth
		child.parent = b
		child.pos = [initial, depth, 0]
		initial += i*2
	)

	return b

)

-- Function being called
createChildren 2 0

Maxscript file example: 3_functions

4. User Interface Widgets

-- Function that replaces the 3Ds Max selection with the object previously picked
function replaceItems objs = (
	for item in objs do(
		print item
		maxOps.cloneNodes replace_object cloneType:#instance newNodes:&nnl #nodialog
		nnl.name = "clone_" + item.name
		nnl.position = item.position
		nnl.rotation = item.rotation
	)
	delete objs
)

-- Widget instantiation/definition and specification. You can create the base through "Tools > New Rollout"
rollout ReplaceObjectsWidget "Replacing Objects Widget" width:397 height:124
(
	pickbutton 'btn2' "Pick Object" pos:[39,39] width:127 height:56 align:#left
	button 'btn3' "Replace Objects" pos:[193,41] width:151 height:58 align:#left

	on btn2 picked obj do(
		if isValidNode obj do(
			btn2.text = obj.name
			replace_object = getnodebyname obj.name
		)
	)

	on btn3 pressed do(
		print "DONE - Replacing selected items"
		if replace_object != undefined then(
			replaceItems(selection as array)
		)else(
			messagebox "ERROR - No selected object, please select any object before replacing."
		)
	)

)

-- Widget creation
createDialog ReplaceObjectsWidget

Maxscript file example 1: 4_user_interface_widgets_1

-- Information text
t = TextPlus Plane:0 name:"User interface widgets 2" size:14 pos:[0,-150,0] wirecolor:(color 255 255 255)
t.SetPlaintextString("User interface widgets 2")

function createCircle rad step = (
	local amount = 360 / step
	for i = 0 to amount do (
		local out_angle = i * step
		x = rad * cos(out_angle)
		y = rad * sin(out_angle)
		sphere name:("circle_sphere_" + i as string) pos:[x,y,0] radius:3 wirecolor:(color 255 0 0)
	)
)

function createElipse rad1 rad2 step = (
	local amount = 360 / step
	for i = 0 to amount do (
		local out_angle = i * step
		x = rad1 * cos(out_angle)
		y = rad2 * sin(out_angle)
		sphere name:("elipse_sphere_" + i as string) pos:[x,y,0] radius:3 wirecolor:(color 0 255 0)
	)
)

function createSpiral a b amount step = (
	for i = 1 to amount do (
		local out_angle = i * step
		x = (a + b * out_angle) * cos(out_angle)
		y = (a + b * out_angle) * sin(out_angle)
		sphere name:(i as string) pos:[x,y,i] radius:2.5 wirecolor:(color 0 0 255)
	)
)

-- Widget instantiation and parameters
rollout ShapeCreationPanel "Shape Creation Panel" width:200 height:124
(
	button 'btn1' "Generate" pos:[23,70] width:150 height:38 align:#left
	dropDownList 'ddl1' "Type of shape:" pos:[23,16] width:150 height:40 align:#left items:#("Circle","Elipse","Spiral")

	on btn1 pressed do(
		case ddl1.selection of(
			1: createCircle 100 10
			2: createElipse 100 50 10
			3: createSpiral 0.1 0.1 100 10
		)
	)

)

-- Widget creation
createDialog ShapeCreationPanel

Maxscript file example 2: 4_user_interface_widgets_2

5. Animations

-- Information text
t1 = TextPlus Plane:0 name:"sequential_text" size:8 pos:[20,-40,0] wirecolor:(color 255 255 255)
t1.SetPlaintextString("sequential")
t2 = TextPlus Plane:0 name:"manual_text" size:8 pos:[-20,-40,0] wirecolor:(color 255 255 255)
t2.SetPlaintextString("manual")

-- Add keyframes manual
manual_box = teapot name:"manual_box" wirecolor:(color 255 255 0) pos:[-20,0,0] radius:15
rotate $manual_box (eulerangles 0 0 180)
with animate on(
	at time 0 manual_box.pos.z = 0
	at time 100 manual_box.pos.x = -100
)

-- Add keyframes sequentialy
sequential_box = teapot name:"sequential_box" wirecolor:(color 255 0 0) pos:[20,0,0] radius:15
animate on for t = 0 to 100 by 5
do at time t(
	sequential_box.position = sequential_box.position + [5,0,0]
)

Maxscript file example: 5_animations

6. Splines

-- Information text
t1 = TextPlus Plane:0 name:"spline_text" size:8 pos:[0,-50,0] wirecolor:(color 255 255 255)
t1.SetPlaintextString("Spline filled with objects")

-- Function that creates a two-point spline
fn drawLineBetweenTwoPoints pointA pointB =
(
  ss = SplineShape pos:pointA name:"spline_temporal"
  addNewSpline ss
  addKnot ss 1 #corner #line PointA
  addKnot ss 1 #corner #line PointB
  updateShape ss
  ss
)

-- Spline creation calling function
input_spline = drawLineBetweenTwoPoints [-50,0,0] [50,0,0]

-- Filling spline surroundings with props
density = 200 as float
for i = 0 to density do (
	road_point = lengthInterp input_spline (i/density)
	road_tangent = lengthtangent input_spline 1 (i/density)
	road_off_dir = cross road_tangent  [0,0,1]

	new_pos1 = road_point + (random 5 22) * road_off_dir
	new_pos2 = road_point - (random 5 22) * road_off_dir
	b1 = box name:("prop_" + i as string) pos:new_pos1 scale:[0.1,0.1,0.1]
	b2 = box name:("prop_" + i as string) pos:new_pos2 scale:[0.1,0.1,0.1]
	local amount = random 0 4
)

Maxscript file example: 6_splines

7. Ray intersections

-- Information text
t = TextPlus Plane:0 name:"raytrace_text" size:14 pos:[0,-60,0] wirecolor:(color 255 255 255)
t.SetPlaintextString("Ray intersections")

-- Primitive object example to cast ray and place object on
cone pos:[0,0,0] name:("raytrace_sphere") wirecolor:green scale:[2,2,3]

-- Raytracer function
rayPicker_primitive = box
tool rayPicker
(
	on mousePoint clickno do
	(
		ry = mapScreenToWorldRay mouse.pos
		myray = ray ry.pos ry.dir
		local intersect = intersectRayScene myray

		if intersect.count > 0 do
		(
			rayPicker_primitive name:"raytracer_primitive" pos:intersect[1][2].pos scale:[0.1,0.1,0.1] wirecolor:(color (random 0 255) 0 0)
		)
	)
)

-- Widget instantiation and parameters
rollout RaytracerWidget "Raytracer Widget tool" width:245 height:106
(
	button 'btn1' "Apply" pos:[11,63] width:220 height:29 align:#left
	dropDownList 'ddl1' "Spawn primitive type" pos:[11,11] width:219 height:40 align:#left items:#("sphere","box","teapot")

	on btn1 pressed do (
		case ddl1.selection of
		(
			1: rayPicker_primitive = sphere
			2: rayPicker_primitive = box
			3: rayPicker_primitive = teapot
			default: box
		)

		stopTool rayPicker
		startTool rayPicker

	)

)

-- Widget creation
createDialog RaytracerWidget

Maxscript file example: 7_ray_intersections

8. Macros

-- Remove macro function to avoid stacking up macros on toolbar
function removeMenu m_name = (
	del_menu = menuMan.findMenu m_name
	if del_menu != undefined do
		menuMan.unregistermenu del_menu
)

-- Test function to be called from macro in toolbar
function create_object_test =
(
	delete $objects

	-- Information text
	t1 = TextPlus Plane:0 name:"macro_text" size:8 pos:[0,-40,0] wirecolor:(color 255 255 255)
	t1.SetPlaintextString("Macros")

	-- Sphere object
	sphere name:"macro_sphere" wirecolor:(color (random 0 255) (random 0 255) (random 0 255))

	print "Object created successfully!"
)

macroScript LaunchMenu category:"MVD" --macroscript menu
(
	create_object_test()
)

--Adding menu macro process with menuMan
removeMenu "MVD Tools"
theMainMenu = menuMan.getMainMenuBar() --get the main menu bar
theMenu = menuMan.createMenu "MVD Tools" --create a menu called Forum Help
theSubMenu = menuMan.createSubMenuItem "Launch tool" theMenu --create a SubMenuItem
theMainMenu.addItem theSubMenu (theMainMenu.numItems()+1) --add the SubMenu to the Main Menu
theAction = menuMan.createActionItem "LaunchMenu" "MVD" --create an ActionItem from the MacroScript
theMenu.addItem theAction (theMenu.numItems()+1) --add the ActionItem to the menu
menuMan.updateMenuBar() --update the menu bar

Maxscript file example: 8_macros

About

Documentation for 3DS Max scripting language

Topics

Resources

Stars

Watchers

Forks