maxscript_4

Upload: ux

Post on 30-Oct-2015

101 views

Category:

Documents


0 download

DESCRIPTION

MAXScript_4

TRANSCRIPT

  • MAXScript

  • MAXScript Listener The MAXScript Listener window is an interactive interpreter for the MAXScript language and works similar to a DOS command prompt window.

  • Macro RecorderThe Macro Recorder generates script code in a separate pane of the MAXScript listener based on the actions of the user. Several filtering options are available that control what types of user actions are recorded, whether the generated MAXScript commands contain explicit object references or are selection-relative, and whether the generated MAXScript commands contain explicit or relative transforms and coordinates. These options are set using the MacroRecorder menu in the Listener window. Absolute Transform Assignments/Relative Transform Operationsif Absolute Transform Assignments is enabled, $.position = [55.6739,23.5,0]If Relative Transform Operations is enabled, move $ [0,-47.8044,0]

  • Explicit Sub-object Sets/Selection-Relative Sub-object Setsif Explicit Sub-object Sets is enabled move $Sphere02.verts[#{20..32, 51..65}] [40.0986,10.3648,0]If Selection-Relative Sub-object Sets is enabledmove $Sphere02.selectedVerts [40.0986,10.3648,0]

    Learning MAXScript with the Macro Recorder

  • Customizing MacroScript Buttons Position your mouse over the text in the macro pane and press the left mouse button. Drag up to the main toolbar.As the cursor reaches the toolbar, you will see a small plus sign at the bottom of the cursor, indicating that you can drop the MacroScript there.

  • To edit the script, right-click the icon in the toolbar, and choose Edit Macro Script from the right-click menu.

  • Source Code Layout a + b * c / d - e + f * g / hThis line can be broken after any of the operators. MAXScript continues to read the next line, because an operator needs another argument. a + b * c / d - e +f * g / h

    You cannot break the example line as shown next a + b * c / d - e+ f * g / h The previous example of an invalid break can be made valid using the line continuation character (backslash \)a + b * c / d - e \+ f * g / h

  • MAXScript also lets you combine multiple statements and expressions in a single line. The statements or expressions are separated with a ; 1+2; 2^3; sin 0

  • The Mini-Listener

  • Using the '?' Symbol You can use the ? anywhere you normally use a variable name and MAXScript evaluates the ? as the last Listener result. x = ?

  • includeinclude :Inserts the specified files content into the Listener output pane. The inserted text is not evaluated. Examples:include "my_script.ms"

    scriptfile="c:\\my_scripts\\my_script.ms"include scriptfile

  • You can open a MAXScript Editor window from within the Listener by calling the edit() method. Examples:edit "my_script.ms

    You can create an empty MAXScript Editor window from within the Listener or from other running scripts by calling the newScript() method.

  • Running Scripts To run an existing script file, press "Run Script" . You can also run a script from Listener or from within other scripts using the fileIn() method Examples:fileIn "my_script.ms"

  • Variables and DataNumber Data TypesThere are two kinds of number data types: integers and floats.x = 5.0y = 6.0z = x * y

    String Data Typesmsg = "File not found."messagebox msg

    Boolean Data Typesready = trueready = off

  • Untyped Variables3dsMax automatically allows you to manipulate the variable according to the rules associated with that data type. For example, you can legally write the following:msg = "File not found."messagebox msgmsg = 5.6z = msg + 7.0When assigned a string, 3dsMax lets you manipulate msg as a string. Later, when msg is assigned a number, you can manipulate msg as a number.

  • Entering Arrays in MAXScript #() This is the most basic type of array: an empty one.

    #( , )Array1= #(5, pi, "String", 6+2^3)output#(5, 3.14159, "String",14)

    Array1[3]

    Append Array1 30

  • finditem Array1 144

    deleteitem Array1 4#(5, 3.14159, "String", 30)

    Array2 = #{2,4,10,20,30}array3 = for i in Array2 where i> 10 collect i#(20, 30)

  • Transformation matrixt = teapot()t.transform// output (matrix3 [1,0,0] [0,1,0] [0,0,1] [0,0,0])// the transformation matrix is like in the XNA ( the transpose of the transformation matrix in OpenGL)

    // translate by 10 units along the x-axist.transform = (matrix3 [1,0,0] [0,1,0] [0,0,1] [10,0,0])

  • // read only propertiest.transform.translation// output [10,0,0]

    t.transform.rotation// output (quat 0 0 0 1)

    t.transform.scale// output [1,1,1]

  • $.transform = rotateZMatrix 45

    $.transform = $.transform * rotateYMatrix 45

  • Scatter objects to vertex normalsdelete $*_Clone*theTarget = $Teapot01theSource = $Teapot02theMesh = snapshotAsMesh theTargetfor v = 1 to theMesh.numverts by 1 do(theNewObject = instance theSourcetheNewObject.name = uniquename (theSource.name + "_Clone")theNewObject.transform = matrixFromNormal (getNormal theMesh v)theNewObject.pos = getVert theMesh vtheNewObject.parent = theTarget)

  • Aligning nodes using the transformation matrixtheSource = $Teapot01theTarget = $Teapot02theTarget.transform = theSource.transform

    // copy the orientation and scale but do not copy the positiontheSource = $Teapot01theTarget = $Teapot02theTm = theSource.transformtheTm.row4= theTarget.transform.row4 theTarget.transform = theTm

  • $.bend.gizmo.transform = rotateXMatrix 90//change the transformation matrix of the gizmo

    $.uvw_mapping.gizmo.transform = rotateYMatrix 45

  • Align Slice Plane To Scene Plane(thePlane = $Plane01

    for theObj in selection where superclassof theObj == GeometryClass and classof theObj != TargetObject and theObj != thePlane do(theMod = theObj.modifiers[#slice]if theMod == undefined do(theMod = SliceModifier slice_type:2addModifier theObj theModaddModifier theObj (Cap_Holes()))theMod.slice_plane.transform = thePlane.transform * inverse theObj.transform))

  • AnimatingSlicePlaneWithScenePlane(thePlane = $Plane01for theObj in selection where superclassof theObj == GeometryClass and classof theObj != TargetObject and theObj != thePlane do(theMod = theObj.modifiers[#slice]if theMod == undefined do(theMod = SliceModifier slice_type:2addModifier theObj theMod) theMod.slice_plane.controller = transform_script()txt = "dependsOn $'" + thePlane.name + "'\n"txt += "$'" + thePlane.name+"'.transform * inverse $'"+ theObj.name +"'.transform\n"theMod.slice_plane.controller.script = txt))

  • Rotate one polygon in a plane (editable Poly) around the normal(theObj = $Plane01thePolyIndex = 6theVerts = polyop.getVertsUsingFace theObj thePolyIndex theTM = matrixFromNormal (polyop.getFaceNormal theObj thePolyIndex)theRotTM = (rotateZMatrix 1.0) * theTMfor t=1 to 360 do(for v in theVerts do( in coordsys theTM theVert = polyop.getVert theObj v theVert *= theRotTM polyop.setVert theObj v theVert )redrawViews()))

  • Camera// select all the geometry objects in front of the cameratheTM = inverse $camera01.transformselect ( for o in geometry where (o.pos * theTM).z < 0 collect o)

    // select all the geometry objects in front of the cameratheTM = $camera01.transformselect ( for o in geometry where in coordsys theTM o.pos.z < 0 collect o)

    // select all the geometry objects in front of the camera select ( for o in geometry where in coordsys $camera01 o.pos.z < 0 collect o)

  • Viewport transformation matrixFirst you have to create a camerainverse (viewport.getCamera()).transform

    You will get the same result if you get the transform matrix of the viewportviewport.getTM()

    //set the transformation matrix of the selected viewportviewport.setTM(inverse $Camera01.transform)

    //create a teapot in a position [0,0,-100] from the current viewport teapot pos:([0,0,-100] * inverse (viewport.getTM()))

  • Objectsfor o in objects do print o$Box:Box01 @ [-15.102085,1.018532,0.000000]$Sphere:Sphere01 @ [-13.588623,-53.728287,0.000000]$Cylinder:Cylinder01 @ [62.862854,-5.142868,0.000000]$Circle:Circle01 @ [-60.000847,-29.512146,0.000000]$Target_Light:TPhotometricLight01 @ [20.313614,-60.486160,0.000000]$Target:TPhotometricLight01.Target @ [30.839767,-52.193558,0.000000]$Free_Camera:Camera01 @ [54.398849,41.417953,0.000000]

  • for o in geometry do print o$Box:Box01 @ [-15.102085,1.018532,0.000000]$Sphere:Sphere01 @ [-13.588623,-53.728287,0.000000]$Cylinder:Cylinder01 @ [62.862854,-5.142868,0.000000]

  • for o in selection do print o$Free_Camera:Camera01 @ [54.398849,41.417953,0.000000]$Cylinder:Cylinder01 @ [62.862854,-5.142868,0.000000]

    for o in selection do print o.name"Camera01""Cylinder01"

  • Assigning Variables mystring = "This is my string."

    MAXScript doesnt distinguish between lowercase and uppercase variable names because MAXScript names are not case-sensitive.

  • If you need to locate the source of a scripted function, you can use the showSource() function. It displays a script Editor containing the source file in which the function was defined and positioned at the function's definition.

  • Mathematical Operations random 1 10078random 1.0 100 17.6577

    Incrementing x = x + 1 x += 1

  • Examples -- numbers test bedi=10 -- assign integers to variablesj=20i/j -- integer divide, result is integeri=i as float -- convert i to a floati/j -- float divide, result is floati += 1 -- increment i by 1if i < j do i=2.^3 -- if i is less than j, set i to 2 to the 3rd powermod j i -- return remainder of j divided by icos 30.0 -- return cosine of 30 degreessqrt j -- return square root of jseed 12345 -- seed the random number generatorfor k=1 to 5 do print (random i j) -- print out 5 random numbers

  • 10 -- result of line 220 -- result of line 30 -- result of line 4 (10/20)10.0 -- result of line 50.5 -- result of line 6 (10./20)11.0 -- result of line 78.0 -- result of line 8 (2.^3)4.0 -- result of line 90.866025 -- result of line 104.47214 -- result of line 11 (sqrt 20)OK -- result of line 1210.7775 -- output from line 13 (random 8. 20)15.018317.446716.102710.1344OK -- result of line 13

  • Color Examples magenta=color 255 255 0 255 -- create colors using constructorsaqua = [0, 255, 255] as coloraqua.v /= 2. -- reduce "strength" of aqua coloraquaaqua.alpha=128 -- set aqua to 50% opacityaqualightGray=white/4 -- create light gray color by dividing-- each component of white by 4composite aqua lightGray -- composite light gray over aquarandom black white -- generate a random color

  • (color 255 255 0) -- result of line 2. Note that if-- alpha=255 it is not displayed(color 0 255 255) -- result of line 3127.5 -- result of line 4 - value property of aqua(color 0 127.5 127.5) -- result of line 5 - color of aqua128 -- result of line 6 - alpha property of aqua(color 0 127.5 127.5,128) -- result of line 7 - color of aqua(color 63.75 63.75 63.75) -- result of line 8 - each component divided by 4(color 31.75 159.25 159.25 159.75) -- result of line 10(color 170.944 109.543 74.1957) -- result of line 11

  • RGB color box(step = 25for r = 0 to 255 by step dofor g = 0 to 255 by step dofor b = 0 to 255 by step dotheBox = box width:step height:step length:step pos:[r,g,b] wirecolor:(color r g b))

  • select $box*

    selectmore $sphere* //add to selection

    Orselect (join ($Box* as array) ($sphere* as array) )

    Hide $box*

    Unhide $box*

    unhide $* // unhide all

    deselect $*

    select helpers

  • Select by type instead of namethePoints = for o in helpers where classof o == Point collect oSelect thePoints

    select ( for o in geometry where o.radius < 20 and classof o == Teapot collect o)It will give an error. Why? It evaluates o.radius < 20 first which will give an error if the object does not have a radius properties

  • We need to select objects that has radius
  • select (for o in geometry where try (o.bend.angle > 90) catch(false) collect o)

    select (for o in geometry where ((for b in o.Modifiers where classof b == Bend collect b).count > 0) collect o)

  • select (for o in objects where o.material == undefined collect o)

    select (for o in objects where o.material != undefined collect o)$.material = standard()

    select ( for o in objects where o.material == medit.GetCurMtl() collect o)medit.GetCurMtl()This method returns the material currently selected in one of the sample slots of the Material Editor.

    if selection.count > 0 do select (for o in objects where o.material == selection[1].material collect o)

  • select (for o in objects where length o.pos < 100 collect o)Length: calculate the distance between the original of the world and the pivot

    select (for o in objects where length o.center < 100 collect o)Center: bounding box center Orselect (for o in objects where distance o.center [0,0,0] < 100 collect o)

  • select (for o in geometry where o.mesh.numfaces > 1024 collect o)o.mesh.numfaceso.mesh.numverts

  • (a="hello world" -- create a string value, put reference in ab=a -- put strings reference in bformat "a=%; b=%\n" a b -- and print their valuesb="thanks for the fish" -- create a string value, put reference in bformat "a=%; b=%\n" a b -- print values - they are differentb=a -- put strings reference from a in ba[1]="J" -- change a component valueformat "a=%; b=%\n" a b -- print values - they are the samea=b=[10,20,30] -- assign a point3 value reference to a and bformat "a=%; b=%\n" a b -- and print their valuesa.x=-100 -- change a component valueformat "a=%; b=%\n" a b -- print values - they are the same)

    Outputa=hello world; b=hello worlda=hello world; b=thanks for the fisha=Jello world; b=Jello worlda=[10,20,30]; b=[10,20,30]a=[-100,20,30]; b=[-100,20,30]OK

  • Drawing a Box with MAXScript box()This creates a box with the default parameters. mybox = box()It is generally better practice to assign an object to a variable, so you can later refer to it by name and manipulate it using that name mybox = box length:19 width:20 height:20mybox = box width:20 length:19 height:20 The order does not matter$Box:Box01 @ [0.000000, 0.000000, 0.000000]The first part of the statement is called a pathname. The second part of the statement is the object name: Box01 The values inside the brackets represent the x, y, and z coordinates of the center of the box.

  • Change the name property of the box mybox.name = "BlueBox" Change colormybox.wireColor = blue The color blue is a predefined color constant in MAXScript and its RGB value is defined as (0,0,255).The other predefined color variables are red, green, white, black, orange, yellow, and brown. Instead of using a predefined color, you can assign a color with different RGB values, such as:mybox.wireColor = (color 255 0 255)mybox.wireColor.r = 255newcolor = color 40 120 200mybox.wireColor = newcolornewcolor = color 40 120 200 128alphaNum = newcolor.a

  • Change Sizemybox.scale = [1.5,1.5,1.5] mybox.height = 40 mybox.width = 60

  • showclass "box.*" prints information about a specified 3ds Max class or classes. Box : GeometryClass {10,0} .height : float .length : float .lengthsegs : integer .width : float .widthsegs : integer .mapcoords : boolean .heightsegs : integerOK

  • mybox.lengthsegs = 10 mybox.widthsegs = 10 mybox.heightsegs = 10

  • showClass "box*" -- all 3ds max classes starting boxshowClass "box.*" -- all the accessible properties of the-- box classshowClass "*:mod*" -- all the modifier classesshowClass "*.*rad*" -- all the classes with a property name -- containing rad

  • The second inspector function is showProperties(). The showProperties() function is used to display the properties for a specific object that is an instance of one of the 3ds Max classes.It can be used in place of showClass() in situations where you have an actual object in hand. showProperties myBox

  • torus radius1:10 pos:[0, 0, 20] wirecolor:[225, 230, 100]s = sphere radius:100.0s = sphere()s.radius = 10.0for i = 1 to 3 do(sphere pos:[random -80 80, random -80 80, random -80 80]cone pos:[random -80 80, random -80 80, random -80 80]cylinder pos:[random -80 80, random -80 80, random -80 80])

  • rot_box = eulerangles 0 30 0rotate mybox rot_boxCreates an object called rot_box, which will rotate an object around the Y-axis by 30 degrees. Moving, scaling, or rotating objects, or setting transform-related properties operates in the World Coordinate System, by default. -- randomly jiggle each object in the selection around +/- 20 unitsin coordsys local selection.pos = random [-20,20,20] [20,20,20]

  • Change properties for a group of objectsfor i = 1 to 200 do sphere pos:(random [-300, -300, -300] [300,300,300]) radius:(random 2 40)

    for o in $Sphere* do o.radius = 10

    Or

    $sphere*.radius = 20 // faster

  • Assign instance of an animation controller to multiple objectsChange controller will affect multiple objectsExample:Select some boxes$.height.controller = bezier_float()Change the height parameter of any of the boxes will change the rest.Change any other parameter such as width will not affect the rest of the boxes

  • $.heightsegs.controller = bezier_float()

  • Select some boxes

    $.baseobject = $Cylinder01.baseobject

    You will note that the boxes change to cylinder

  • Creating and Assigning ModifiersaddModifier mybox (twist angle:30)

    Changing a Modifier mybox.twist.angle = 60

    for o in selection do addModifier o (bend())

    for o in selection do for x in o.modifiers where classof x == Bend do x.angle = 45

  • Add a modifier as an instance to some objectsChange the modifier will affect these objects

    theMod = bend angle:90for o in $ do addModifier o theMod

  • for o in objects do for m in o.modifiers do m.enabled = false

    for o in objects do for m in o.modifiers do m.enabledInViews = falseAffect Views only (not render)

  • for o in objects do for m in o.modifiers where classof a == Bend do m.enabled = not m.enabled

    for o in objects where classof o.baseobject == Box do for m in o.modifiers where classof a == Bend do m.enabled = not m.enabled

  • deleteModifier $ 11 = the top of the modifier stack

  • Animating the Box animate on(at time 0 (mybox.pos = [-100, 0, 0]; mybox.scale = [1, 1, 0.25])at time 100 (mybox.pos = [100, 0, 0]; mybox.scale = [1, 1, 3]))In this example, the time was given as a simple number. If no unit is specified, MAXScript interprets this as a frame number. You can also use one of the various time literals in the following manner:2.5s -- 2.5 seconds 20f -- 20 frames4800t -- 4800 ticks = 1 sec 1m3s5f -- 1 min, 3 seconds, 5 frames1:15.5 -- SMPTE: 1 min, 15 seconds, 5 framesNote: All times are automatically converted to frames.

  • theBox = box width:10 length:10 height:10animate on ( at time 20 theBox.height = 100; at time 30 theBox.height = 10 )for y=0 to 9 do for x=0 to 9 do (copy theBox).pos = [20*x, 20*y,0]delete theBoxfor o in $Box* do moveKeys o.height.controller (random 0 30)

    //moveKeys moves all keys

  • theBox = box width:10 length:10 height:10animate on ( at time 20 theBox.height = 100; at time 30 theBox.height = 10 )for y=0 to 9 do for x=0 to 9 do (copy theBox).pos = [20*x, 20*y,0]delete theBoxfor o in $Box* do moveKey o.height.controller 2 (random 0 10)

  • theBox = box width:10 length:10 height:10animate on ( at time 20 theBox.height = 100; at time 30 theBox.height = 10 )for y=0 to 9 do for x=0 to 9 do (copy theBox).pos = [20*x, 20*y,0]delete theBoxtheOffset = 0for o in $Box* do moveKeys o.height.controller (theOffset +=1)

  • Materials$.material = standard()$.material = standard diffuse:yellow$.material = standard diffuse:(random black white)$.material = undefined

  • $.material = standard shift = truefor z=0 to 9 do (shift = not shift; for x=0 to 9 do (copy $Box01).pos = if shift then [20*x,0,10*z] else [10+20*x,0,10*z])for m = 1 to 4 do meditmaterials[m] = standard diffuse:(#(red, blue, white, yellow)[m]) name:("L"+m as string)

    $.material = undefined

  • SavesaveNodes $ "temp/test1"// save the selected objects into test1.max

    select geometrysaveNodes $ "temp/test1

    select shapessaveNodes $ "temp/test1

    select helperssaveNodes $ "temp/test1

    select lights

  • saveNodes $Box* (GetDir #scene + "/ALLBoxes")// GetDir allows you to access the 3ds Max system directories

    loadMaxFile (GetDir #scene + "/ALLBoxes.max")// you have to put the extension

    maxFileName// output = ALLBoxes.max

    maxFilePath//output = "C:\Users\Dr. Khaled Fatehy\Documents\3dsmax\scenes\"

    thePath = maxFilePath + "Objects"makeDir thePath

    for o in objects do saveNodes o (thePath + "/"+o.name+".max")//save every single object in a separate max fileshellLaunch "Explorer.exe" thePath//run programs

  • makeDir (thePath = maxFilePath+"SingleObjectsExport")for o in geometry do (select o; exportFile (thePath +"/"+o.name+".3DS") #noPrompt selectedOnly:true )

    theFiles = getFiles (thePath + "/*.3ds")for f in theFiles do importFile f #noPrompt

  • RaystheRay = Ray [0,0,100] [0,0,-1]

    theIntersect = IntersectRay $Sphere01 theRay// theIntersect ray: // The start point = the point of intersect//the direction of that ray is the normal at the point of intersect

    if theIntersect != undefined do p = point pos:theIntersect.pos//create helper point at the point of intersect

  • IntersectRayfor o in $Box* do(o.height.controller = float_script()txt = "dependsOn $Sphere01.pos.controller\n"txt +="theInt = IntersectRay $Sphere01 (Ray $" + o.name +".pos [0,0,1])\n"txt +="if theInt != undefined then \n"txt +="if (theDist = length (theInt.pos - $" + o.name +".pos)) > 100 then 100 else theDist\n"txt +="else 100\n"o.height.controller.script = txt)

    // dependsOn was used with scripted controllers in versions prior to 3ds Max 8 to enable interactive update of scripted controllers when the code in them depends on other objects in the scene.

  • IntersectRayEx(Explore Mesh)(local theMeshfn filterMesh obj = classof obj == Editable_Meshrollout IntersectWithMesh "Intersect With Mesh"(timer timerControl interval:50 active:falsepickbutton pickMesh ">>Pick Mesh To Explore" width:380 filter:filterMeshedittext faceHit "Face:" edittext normalHit "Normal:" edittext worldHit "World:" edittext baryCoords "Barycentric:"

  • on pickMesh picked obj do(if obj != undefined do(theMesh = objpickMesh.caption = obj.nametimerControl.active = true))

  • on timerControl tick do(theRay = mapScreenToWorldRay mouse.postheInt = IntersectRayEx theMesh theRayif theInt != undefined then(faceHit.text = theInt[2] as stringnormalHit.text = theInt[1].dir as stringworldHit.text = theInt[1].pos as stringbaryCoords.text = theInt[3] as string)elsebaryCoords.text = faceHit.text = normalHit.text = worldHit.text = "???"))createDialog IntersectWithMesh width:400)

  • IntersectRayEx(Explore Texel)(local theMesh, theBitmap, theBitmapWidth, theBitmapHeight

    fn filterMesh obj = classof obj == Editable_Meshrollout IntersectWithMesh "Intersect With Mesh"(timer timerControl interval:50 active:falsepickbutton pickMesh ">>Pick Mesh To Explore" width:380 filter:filterMeshedittext faceHit "Face:" edittext normalHit "Normal:" edittext worldHit "World:" edittext baryCoords "Barycentric:" colorpicker pixelColor "Pixel Color"

  • on pickMesh picked obj do(if obj != undefined do(theMesh = objpickMesh.caption = obj.nametimerControl.active = trueif theMesh.material != undefined and classof theMesh.material.diffusemap == BitmapTexture do(theBitmap = openBitmap theMesh.material.diffusemap.filenametheBitmapWidth = theBitmap.width-1theBitmapHeight = theBitmap.height-1)))

  • on timerControl tick do(theRay = mapScreenToWorldRay mouse.postheInt = IntersectRayEx theMesh theRayif theInt != undefined then(faceHit.text = theInt[2] as stringnormalHit.text = theInt[1].dir as stringworldHit.text = theInt[1].pos as stringbaryCoords.text = theInt[3] as stringif theBitmap != undefined do(theMapFace = meshop.getMapFace theMesh 1 theInt[2]theMapVert1 = meshop.getMapVert theMesh 1 theMapFace.xtheMapVert2 = meshop.getMapVert theMesh 1 theMapFace.ytheMapVert3 = meshop.getMapVert theMesh 1 theMapFace.z

  • theUVCoords = theMapVert1* theInt[3].x + theMapVert2* theInt[3].y + theMapVert3* theInt[3].zthePixels = getPixels theBitmap [theUVCoords.x * theBitmapWidth , theBitmapHeight - theUVCoords.y * theBitmapHeight ] 1if thePixels[1] != undefined thenpixelColor.color = thePixels[1]elsepixelColor.color = red))elsebaryCoords.text = faceHit.text = normalHit.text = worldHit.text = "???"))createDialog IntersectWithMesh width:400)

  • Controlling Program FlowConditional StatementsIf-Then StatementsLogical Operators: Not, And, OrIf-Then-Else Statements

    Loop StructuresFor LoopLoops with Multiple StatementsWhile Loops

  • if mybox.height == 10 then mybox.width = 20 if mybox.height == 10 then mybox.width = 20 else mybox.width = 10 if b.height == 10then b.width = 20else b.width = 10for i = 1 to 5 do(box_copy = copy mybox box_copy.pos = [i * 50, 0, 0])

  • To make MAXScript increment the index by a value other than 1, insert by x for i = 1 to 5 by 2 do(box_copy = copy mybox box_copy.pos = [i * 50, 0, 0])

  • array1 = for i = 1 to 5 collect ioutput #(1, 2, 3, 4, 5)The collect statement in the for loop above tells MAXScript to collect the results of each iteration in an array, rather than just calculate them.In this case, you only asked MAXScript to collect the value of the index; however, you can collect iterations of any expression.

  • For loops can also perform iterations with the contents of an array for i in array1 do print iOutput 1 2345In this example you used in instead of =; they are both acceptable for i = 1 to array1.count do print array1[i]

  • x=10while x>0 do print (x-=1)Returns:98765432100MAXScript automatically returns the final value of the loop to the Listener. Therefore, the final value is returned twice.

  • x=10do print (x-=1) while x
  • Function Examplefn uppercase instring = -- beginning of function definition( local upper, lower, outstring -- declare variables as localupper="ABCDEFGHIJKLMNOPQRSTUVWXYZ" -- set variables to literalslower="abcdefghijklmnopqrstuvwxyz"-- create an unique copy of the string referenced by instring, and store-- reference to unique copy in outstringoutstring=copy instring---- increment from 1 to number of character in stringfor i=1 to outstring.count do( j=findString lower outstring[i]if (j != undefined) do outstring[i]=upper[j])outstring -- value of outstring will be returned as function result) -- end of fn uppercase

  • s1="AbCdEfGh" -- set variable to literals2=uppercase s1 -- call function uppercase, passing s1 as parameterif s1 == s2 do print "strings s2 and s3 are the same" -- compare stringsif s1 != s2 do print "strings s1 and s2 are different"--theObject="sphere" -- set variable to literaltheRadius= (random 10. 100.) as string -- convert number to string-- concatenate strings and execute stringmyObject=execute (theObject + " radius:" + theRadius)

  • Output:uppercase() -- result to function definition"AbCdEfGh" -- result of line 24"ABCDEFGH" -- result of line 25undefined -- result of line 26 - strings not equal,-- and no else expression in if expression"strings s1 and s2 are different" -- output from line 27"strings s1 and s2 are different" -- result of line 27"sphere" -- result of line 29"75.4091" -- result of line 30$Sphere:Sphere01 @ [0.0,0.0,0.0] -- result of line 32. Execute function-- created a sphere object

  • FunctionsFunction ParametersPositional Parameters (Function Parameters in Specific Order)Keyword Parameters (Function Parameters in Any Order)Function Parameters in Specific Order with Optional Keyword ParametersPassing ArgumentsPassing Arguments by ValuePassing Arguments by ReferenceExceptions to Pass by ValueReturning Values from Functions

  • Positional ParametersThe order of arguments is importantfunction SubNums x y =(z = (x - y))

    a = SubNums 1 3

  • Keyword ParametersFunction Parameters in Any Orderb1 = box length:20.5 width:15.0 height:5.6b2 = box height:5.6 length:20.5 width:15.0

    function putUpMessage text1:"File Not found." =(messageBox text1 title: Warning beep: true)

    s = sphere()msg1 = "The sphere's radius is "msg2 = s.radius as stringputUpMessage text1:(msg1 + msg2)

  • Function Parameters in Specific Order with Optional Keyword ParametersYou can also mix positional parameters with keyword parameters.

    The function definition in this case must use the positional parameters first, followed by the keyword parameters.

    function mysphere rad position:[0, 0, 0] =(sphere radius:rad pos:position)

  • Passing Arguments by Valuem = 30.4n = 23.0function addnums2 x y =(x = 10.0x + y)addnums2 m n

    The Listener returns a value of 33.0.Type m in the Listener and evaluateThe result for the value of m is 30.4.

  • Passing Arguments by Referencem = 30.4n = 23.0function addnums2 &x y =(x = 10.0x + y)addnums2 &m n

    The Listener returns a value of 33.0.Type m in the Listener and evaluate.The result is 10.0.

  • Exceptions to Pass by ValueWhen a variable that has sub-properties is passed to a function, the pointer or variable of the object is passed by value. However, the sub-properties of the object are passed by reference.

  • Exceptions to Pass by Value (Cont.)myPoint = point3 10 20 30function modifyPoints pnt =(pnt.x = 3pnt = point3 7 14 21)modifyPoints myPoint

    The Listener returns a point3 literal of [7, 14, 21],Type myPoint in the Listener and evaluate.The result is [3,20,30].

  • Returning Values from Functionsfunction foo =(g = 4h = 5g*h}Then if you type i = foo(), the Listener will return 20.

    function foo =(g = 4h = 5return g*h)Using the return keyword is a little slower to use. If the function is called many times, omit the keyword return, thereby reducing execution time.

  • function add a b = a + b

    fn factorial n = if n

  • fn starfield count extent:[200,200,200] pos:[0,0,0] =(local f = pos - extent / 2,t = pos + extent / 2for i = 1 to count dosphere name:"star" \radius:(random 0.1 2.0) \position:(random f t) \segs:4 smooth:false)

  • Local and Global Variables global rad = 10"rad" is a global variable, it can be used throughout the rest of the script. for i = 1 to 3 do(local rad = 10)Local variables can only exist within a block. For this reason, they must be created in a block. If you try to define a local variable from the top level of MAXScript, you will receive an error message.

  • It is not necessary to declare every variable with a "global" or "local" statement. You learned previously that you can implicitly create a variable by simply assigning a value to it. If you do not make the "global" or "local" distinction upon your variable, MAXScript will create the appropriate association, depending on where the variable is defined in the script. For example if you create a variable inside a block, MAXScript automatically treats it as a local variable. On the other hand, any variable created at the top level of MAXScript (outside of all blocks) is always a global variable.

  • for i = 1 to 5 do(global rad = 10cyl_height = 25c = cylinder()c.radius = radc.height = cyl_heightc.pos.x = i * 25)s = sphere radius:radc and cyl_height are both local variables. The other two variables are both global; s, because it was created outside of a block, and rad, because it was declared as a global variable.

  • function mycube side position:[0, 0, 0] =(box length:side width:side height:side pos:position)This function requires you to enter the size of the cube, but the position is optional.

  • Structure Definitions Create a new structure, called person:Struct person (name, height, age)

    Now create an instance of this structure using the person constructor:Bill = person name:"Bill" height:72 age:34

    Joe = person name:"Joseph" this person does not have initialized values for the height and age members. Since you did not provide these members with an optional default value in our structure definition, they will default to a value of undefined.

  • max Commands in MAXScript MAXScript scripts can invoke 3ds Max menu and toolbar commands. max file openmax unhide allmax quick render

    The available commands can be displayed by using the "?" character in a partial max command. max time ? -- shows all the time-related commandsmax sel ? -- shows all the commands with sel in them as a substringmax ? -- shows all the commands (there are a lot)

  • Diffuse Shading(st = timestamp()theObjects = for o in geometry where not o.isHidden and classof o != TargetObject collect omeshSel = mesh_select()for o in theObjects do addModifier o meshSel

    theLights = for o in lights where classof o != TargetObject and o.on collect o

    theView = getViewSize()theBitmap = bitmap theView.x theView.y color:backgroundColortheBitmap.filename = "RayScript - " + theView as string + " - "

  • fn fireRay theViewRay = (lastSurfaceColor = backgroundColorlastSurfaceColor.a = 0for o = 1 to theObjects.count do (theObj = theObjects[o]theDiffuseLighting = blacktheInt = intersectRayEx theObj theViewRay if theInt != undefined then (for aLight in theLights do(theLightRay = normalize (aLight.pos - theInt[1].pos )theLightAngle = dot theInt[1].dir theLightRayif theLightAngle > 0 do theDiffuseLighting += aLight.rgb * aLight.multiplier * theLightAngle )lastSurfaceColor = theObj.wirecolor * theDiffuseLighting ))lastSurfaceColor )

  • for y = 0 to theView.y-1 do (for x = 0 to theView.x-1 do (theSurfaceColor = fireRay (mapScreenToWorldRay [x,y]) if theSurfaceColor.r > 255 do theSurfaceColor.r = 255if theSurfaceColor.g > 255 do theSurfaceColor.g = 255if theSurfaceColor.b > 255 do theSurfaceColor.b = 255if theSurfaceColor.a > 0 do theSurfaceColor.a = 255setPixels theBitmap [x,y] #(theSurfaceColor))--end x loopdisplay theBitmap)--end y loop

    for o in theObjects do deleteModifier o meshSelpushprompt ("RayScript: " + ((timestamp() - st)/1000) as string + " sec."))--end script

  • Rollinrollout rollin "Rollin'"(group "Main settings"(pickbutton selobj "Select object"label lab_rotaxis "Rotation axis: " across:2radiobuttons rot_axis labels:#("X","Y","Z") default:3 align:#left across:1spinner obj_radius "Radius: " type:#float range:[1,1000,48] fieldwidth:45 align:#leftcheckbox detect "Detect radius" width:140 enabled:falsebutton center "Pivot to center of mass" width:140 enabled:falsecheckbox reverse "Reverse direction" align:#left

  • spinner calc_start "Calculation start: " type:#integer range:[1,1000,1] fieldwidth:47 align:#rightspinner calc_end "Calculation end: " type:#integer range:[2,1000,200] fieldwidth:47 align:#rightspinner step "Every Nth frame: " type:#integer range:[1,10,2] fieldwidth:47 align:#rightbutton go "GO!" enabled:false)

  • on rollin open do(global xvector, yvector,zvectorglobal xradius, yradius,zradiusxvector = [0,1,1]yvector = [1,0,1]zvector = [1,1,0])

  • on selobj picked obj do(if (superClassOf obj == geometryClass) then(global animated_objectanimated_object = objselobj.text = obj.namedetect.enabled = truedetect.state = falsecenter.enabled = truego.enabled = true))

  • on go pressed do(animate on(cont = animated_object.rotation.controllerfor frame in animationRange.start to animationRange.end do(key_index = getkeyindex cont frameif (key_index) != 0 and (key_index) != 1 then (deleteKey cont key_index))

  • for frame in calc_start.value to calc_end.value by step.value do(if frame < step.value then (at time 0 (prev_pos = animated_object.pos))else (at time (frame-step.value) (prev_pos = animated_object.pos))at time frame (current_pos = animated_object.pos)covered_distance = distance prev_pos current_posrotation = (180 * covered_distance)/(pi*obj_radius.value)in coordsys local at time frame(case rot_axis.state of(1: if reverse.checked == false then (rotate animated_object (eulerangles -rotation 0 0)) else (rotate animated_object (eulerangles rotation 0 0))2: if reverse.checked == false then (rotate animated_object (eulerangles 0 -rotation 0)) else (rotate animated_object (eulerangles 0 rotation 0))3: if reverse.checked == false then (rotate animated_object (eulerangles 0 0 -rotation)) else (rotate animated_object (eulerangles 0 0 rotation)))))))

  • on center pressed do(addModifier animated_object (edit_mesh())obj_center = [0,0,0]for i in 1 to animated_object.numVerts do(obj_center += getVert animated_object i)obj_center /= animated_object.numVertsanimated_object.pivot = obj_centerdeleteModifier animated_object 1)

  • on calc_start changed val do(if val > calc_end.value then calc_end.value = val)

    on calc_end changed val do(if val < calc_start.value then calc_start.value = val)

  • on rot_axis changed state do(if (state == 1) and (detect.state == true) then obj_radius.value = xradiusif (state == 2) and (detect.state == true) then obj_radius.value = yradiusif (state == 3) and (detect.state == true) then obj_radius.value = zradius)

    )

    Rollfloater = newRolloutFloater "Rollin'" 200 443addrollout rollin Rollfloater

  • Align objects to the PFlow particlestheTarget = $PF_Source_01theSource = Teapot radius:2theCount = 50theCopies = for o = 1 to theCount collect (instance theSource)

    for t = animationrange.start to animationrange.end by 5 do(sliderTime = tfor i = 1 to theCount do(theTarget.particleIndex = iwith animate on theCopies[i].transform = theTarget.particleTM)--end i loop)--end t loopdelete theSource

  • Slice into Chunksfn splitInTwo theObj theAngle =(local topObj = editable_mesh()local bottomObj = editable_mesh()centerPivot theObjresetXForm theObjconvertToMesh theObjtopObj.transform = theObj.transform bottomObj.transform = theObj.transform topObj.mesh = theObj.meshbottomObj.mesh = theObj.mesh

  • topSlice = SliceModifier Slice_Type:2bottomSlice = SliceModifier Slice_Type:3topSlice.slice_plane.rotation = EulerAngles (random -theAngle theAngle) (random -theAngle theAngle) (random -theAngle theAngle)bottomSlice.slice_plane.transform = topSlice.slice_plane.transform

    addModifier topObj topSliceaddModifier bottomObj bottomSlice

  • capMod = cap_holes()addModifier topObj capMod addModifier bottomObj capMod centerPivot topObjcenterPivot bottomObjresetXform topObjresetXform bottomObjconvertToMesh topObjconvertToMesh bottomObjdelete theObj#(topObj, bottomObj))

  • sel = selection as arrayfor i = 1 to 20 do(sel = for o in sel where isValidNode o collect onextObj = sel[random 1 sel.count]maxVolume = -1for o in sel do(bbox = o.max - o.minvol = bbox.x * bbox.y * bbox.zif vol > maxVolume do(maxVolume = volnextObj = o))join sel (splitInTwo nextObj 45.0))

  • Collision Flowcollision_objects = $Box* as arraycollision_pairs = #()collision_events = #()

    for i = 1 to collision_objects.count - 1 dofor j = i+1 to collision_objects.count doappend collision_pairs #(collision_objects[i],collision_objects[j],false,-10000)

  • for t = animationrange.start to animationrange.end do(undo off(at time t(for i = 1 to collision_pairs.count do(obj1 = collision_pairs[i][1]obj2 = collision_pairs[i][2]if intersects obj1 obj2 then(

  • if t-collision_pairs[i][4] >= 1 then(motionVector1= obj1.pos - (at time (t-1) obj1.pos)motionVector2= obj2.pos - (at time (t-1) obj2.pos)if length motionVector1 > 0 or length motionVector2 > 0 then(testmesh = (copy obj1) * obj2if testmesh.numfaces > 0 then(if not collision_pairs[i][3] then(collision_pairs[i][3] = true

  • collision_pairs[i][4] = tcenterPivot testmesh resetXform testmesh collision_mesh = Editable_Mesh()collision_mesh.transform = testmesh.transform collision_mesh.mesh = testmesh.meshappend collision_events #(t, obj1, obj2, collision_mesh, length(motionVector1-motionVector2))hide collision_mesh))elsecollision_pairs[i][3] = falsedelete testmesh)))elsecollision_pairs[i][3] = false))))

  • particleFlow.beginEdit()new_source = PF_Source()new_source.quantity_viewport = 100.0new_source.setPViewLocation 10 10

    new_action = DisplayParticles()new_source.appendAction new_action new_action.type = 4new_action.color = white

  • new_action = Force()new_source.appendAction new_action try(new_action.Force_Space_Warps = #($Gravity01))catch()

    new_action = renderParticles()new_source.appendAction new_action

    particleFlow.endEdit()

    cnt = 0particleFlow.beginEdit()

  • for i in collision_events do(new_event = event()new_event.setPViewLocation (10 + cnt*200) 400cnt += 1new_source.appendInitialActionList new_eventnew_action = Birth()new_event.appendAction new_action new_action.amount = (i[5]) * 10.0new_action.Emit_Start = i[1] * TicksPerFramenew_action.Emit_Stop = (i[1]+2) * TicksPerFrame

  • new_action = Position_Object()new_event.appendAction new_action new_action.variation = 50.0new_action.Emitter_Objects = #(i[4])new_action.location = 4

    new_action = speed()new_event.appendAction new_action new_action.speed = i[5] * 2.0new_action.variation = new_action.speed *10.0new_action.direction = 3new_action.divergence = 10)--end i loopparticleFlow.endEdit()holdmaxfile()fetchMaxFile quiet:true

    ***************************************************************************************************************************************