Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
MAXScript Listener
The MAXScript Listener window is an interactive interpreter for the MAXScript language and works similar to a DOS command prompt window.
Macro Recorder
The 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.
To edit the script, right-click the icon in the toolbar, and choose Edit Macro Script from the right-click menu.
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
include
include <filename_string> :Inserts the specified files content into the Listener output pane. The inserted text is not evaluated. Examples:
include "my_script.ms"
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"
Untyped Variables 3dsMax 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 msg msg = 5.6 z = msg + 7.0 When 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.
Array1[3]
Append Array1 30
Transformation matrix
t = 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-axis t.transform = (matrix3 [1,0,0] [0,1,0] [0,0,1] [10,0,0])
$.bend.gizmo.transform = rotateXMatrix 90 //change the transformation matrix of the gizmo $.uvw_mapping.gizmo.transform = rotateYMatrix 45
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:2 addModifier theObj theMod addModifier theObj (Cap_Holes()) ) theMod.slice_plane.transform = thePlane.transform * inverse theObj.transform )
)
AnimatingSlicePlaneWithScenePlane
( 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:2 addModifier 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 )
( theObj = $Plane01 thePolyIndex = 6 theVerts = polyop.getVertsUsingFace theObj thePolyIndex theTM = matrixFromNormal (polyop.getFaceNormal theObj thePolyIndex) theRotTM = (rotateZMatrix 1.0) * theTM for 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 camera theTM = inverse $camera01.transform select ( for o in geometry where (o.pos * theTM).z < 0 collect o)
// select all the geometry objects in front of the camera theTM = $camera01.transform select ( 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)
Objects
for 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]
Assigning Variables
mystring = "This is my string." MAXScript doesnt distinguish between lowercase and uppercase variable names
because MAXScript names are not casesensitive.
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 100
78
Incrementing
x=x+1 x += 1
Examples
-- numbers test bed i=10 -- assign integers to variables j=20 i/j -- integer divide, result is integer i=i as float -- convert i to a float i/j -- float divide, result is float i += 1 -- increment i by 1 if i < j do i=2.^3 -- if i is less than j, set i to 2 to the 3rd power mod j i -- return remainder of j divided by i cos 30.0 -- return cosine of 30 degrees sqrt j -- return square root of j seed 12345 -- seed the random number generator for k=1 to 5 do print (random i j) -- print out 5 random numbers
10 -- result of line 2 20 -- result of line 3 0 -- result of line 4 (10/20) 10.0 -- result of line 5 0.5 -- result of line 6 (10./20) 11.0 -- result of line 7 8.0 -- result of line 8 (2.^3) 4.0 -- result of line 9 0.866025 -- result of line 10 4.47214 -- result of line 11 (sqrt 20) OK -- result of line 12 10.7775 -- output from line 13 (random 8. 20) 15.0183 17.4467 16.1027 10.1344 OK -- result of line 13
Color
Examples
magenta=color 255 255 0 255 -- create colors using constructors aqua = [0, 255, 255] as color aqua.v /= 2. -- reduce "strength" of aqua color aqua aqua.alpha=128 -- set aqua to 50% opacity aqua lightGray=white/4 -- create light gray color by dividing -- each component of white by 4 composite aqua lightGray -- composite light gray over aqua random 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 3 127.5 -- result of line 4 - value property of aqua (color 0 127.5 127.5) -- result of line 5 - color of aqua 128 -- 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
Or select (join ($Box* as array) ($sphere* as array) ) Hide $box* Unhide $box* unhide $* // unhide all deselect $* select helpers
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 <20 select ( for o in geometry where (classof o == Teapot or classof o == Sphere or classof o == Geosphere or classof o == Cylinder) and o.radius < 20 collect o)
Too long and we did not include all types
select ( for o in geometry where hasProperty o "radius" and o.radius < 20 collect o) Or select ( for o in geometry where try (o.radius < 20) catch (false) collect o)
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.
Or
select (for o in objects where distance o.center [0,0,0] < 100 collect o)
( a="hello world" -- create a string value, put reference in a b=a -- put strings reference in b format "a=%; b=%\n" a b -- and print their values b="thanks for the fish" -- create a string value, put reference in b format "a=%; b=%\n" a b -- print values - they are different b=a -- put strings reference from a in b a[1]="J" -- change a component value format "a=%; b=%\n" a b -- print values - they are the same a=b=[10,20,30] -- assign a point3 value reference to a and b format "a=%; b=%\n" a b -- and print their values a.x=-100 -- change a component value format "a=%; b=%\n" a b -- print values - they are the same )
Output a=hello world; b=hello world a=hello world; b=thanks for the fish a=Jello world; b=Jello world a=[10,20,30]; b=[10,20,30] a=[-100,20,30]; b=[-100,20,30] OK
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:20 mybox = 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 color
mybox.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 = 255 newcolor = color 40 120 200 mybox.wireColor = newcolor newcolor = color 40 120 200 128 alphaNum = newcolor.a
Change Size
mybox.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 : integer OK
showClass "box*" -- all 3ds max classes starting box showClass "box.*" -- all the accessible properties of the -- box class showClass "*:mod*" -- all the modifier classes showClass "*.*rad*" -- all the classes with a property name -- containing rad
torus radius1:10 pos:[0, 0, 20] wirecolor:[225, 230, 100] s = sphere radius:100.0 s = sphere() s.radius = 10.0 for 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]
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 units in coordsys local selection.pos = random [-20,20,20] [20,20,20]
$.heightsegs.controller = bezier_float()
$.baseobject = $Cylinder01.baseobject You will note that the boxes change to cylinder
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 = false
Affect 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 $ 1
1 = the top of the modifier stack
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 frames 4800t -- 4800 ticks = 1 sec 1m3s5f -- 1 min, 3 seconds, 5 frames 1:15.5 -- SMPTE: 1 min, 15 seconds, 5 frames
Note:
All times are automatically converted to frames.
theBox = box width:10 length:10 height:10 animate 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 theBox for o in $Box* do moveKeys o.height.controller (random 0 30) //moveKeys moves all keys
theBox = box width:10 length:10 height:10 animate 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 theBox for o in $Box* do moveKey o.height.controller 2 (random 0 10)
theBox = box width:10 length:10 height:10 animate 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 theBox theOffset = 0 for 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 = true for 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
Save
saveNodes $ "temp/test1" // save the selected objects into test1.max select geometry saveNodes $ "temp/test1 select shapes saveNodes $ "temp/test1 select helpers saveNodes $ "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 file shellLaunch "Explorer.exe" thePath //run programs
makeDir (thePath = maxFilePath+"SingleObjectsExport") for o in geometry do (select o; exportFile (thePath +"/"+o.name+".3DS") #noPrompt selectedOnly:true )
Rays
theRay = 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
IntersectRay
for 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.
on pickMesh picked obj do ( if obj != undefined do ( theMesh = obj pickMesh.caption = obj.name timerControl.active = true ) )
on timerControl tick do ( theRay = mapScreenToWorldRay mouse.pos theInt = IntersectRayEx theMesh theRay if theInt != undefined then ( faceHit.text = theInt[2] as string normalHit.text = theInt[1].dir as string worldHit.text = theInt[1].pos as string baryCoords.text = theInt[3] as string ) else baryCoords.text = faceHit.text = normalHit.text = worldHit.text = "???" ) ) createDialog IntersectWithMesh width:400 )
on pickMesh picked obj do ( if obj != undefined do ( theMesh = obj pickMesh.caption = obj.name timerControl.active = true if theMesh.material != undefined and classof theMesh.material.diffusemap == BitmapTexture do ( theBitmap = openBitmap theMesh.material.diffusemap.filename theBitmapWidth = theBitmap.width-1 theBitmapHeight = theBitmap.height-1 ) ) )
on timerControl tick do ( theRay = mapScreenToWorldRay mouse.pos theInt = IntersectRayEx theMesh theRay if theInt != undefined then ( faceHit.text = theInt[2] as string normalHit.text = theInt[1].dir as string worldHit.text = theInt[1].pos as string baryCoords.text = theInt[3] as string if theBitmap != undefined do ( theMapFace = meshop.getMapFace theMesh 1 theInt[2] theMapVert1 = meshop.getMapVert theMesh 1 theMapFace.x theMapVert2 = meshop.getMapVert theMesh 1 theMapFace.y theMapVert3 = meshop.getMapVert theMesh 1 theMapFace.z
theUVCoords = theMapVert1* theInt[3].x + theMapVert2* theInt[3].y + theMapVert3* theInt[3].z thePixels = getPixels theBitmap [theUVCoords.x * theBitmapWidth , theBitmapHeight - theUVCoords.y * theBitmapHeight ] 1 if thePixels[1] != undefined then pixelColor.color = thePixels[1] else pixelColor.color = red ) ) else baryCoords.text = faceHit.text = normalHit.text = worldHit.text = "???" ) ) createDialog IntersectWithMesh width:400 )
Loop Structures
For Loop
Loops with Multiple Statements
While Loops
if mybox.height == 10 then mybox.width = 20 if mybox.height == 10 then mybox.width = 20 else mybox.width = 10 if b.height == 10 then b.width = 20 else b.width = 10 for 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 i output #(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 i
Output
1 2 3 4 5
In this example you used in instead of =; they are both acceptable for i = 1 to array1.count do print array1[i]
MAXScript automatically returns the final value of the loop to the Listener. Therefore, the final value is returned twice.
Function Example
fn uppercase instring = -- beginning of function definition ( local upper, lower, outstring -- declare variables as local upper="ABCDEFGHIJKLMNOPQRSTUVWXYZ" -- set variables to literals lower="abcdefghijklmnopqrstuvwxyz" -- create an unique copy of the string referenced by instring, and store -- reference to unique copy in outstring outstring=copy instring --- increment from 1 to number of character in string for 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 literal s2=uppercase s1 -- call function uppercase, passing s1 as parameter if s1 == s2 do print "strings s2 and s3 are the same" -- compare strings if s1 != s2 do print "strings s1 and s2 are different" -theObject="sphere" -- set variable to literal theRadius= (random 10. 100.) as string -- convert number to string -- concatenate strings and execute string myObject=execute (theObject + " radius:" + theRadius)
Output: uppercase() -- result to function definition "AbCdEfGh" -- result of line 24 "ABCDEFGH" -- result of line 25 undefined -- 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
Functions
Function Parameters Positional Parameters (Function Parameters in Specific Order) Keyword Parameters (Function Parameters in Any Order) Function Parameters in Specific Order with Optional Keyword Parameters Passing Arguments
Passing Arguments by Value Passing Arguments by Reference Exceptions to Pass by Value
Positional Parameters
The order of arguments is important function SubNums x y = ( z = (x - y) ) a = SubNums 1 3
Keyword Parameters
Function Parameters in Any Order b1 = box length:20.5 width:15.0 height:5.6 b2 = 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 string putUpMessage text1:(msg1 + msg2)
The Listener returns a value of 33.0. Type m in the Listener and evaluate
The result for the value of m is 30.4.
The Listener returns a value of 33.0. Type m in the Listener and evaluate.
The result is 10.0.
The Listener returns a point3 literal of [7, 14, 21], Type myPoint in the Listener and evaluate.
The result is [3,20,30].
function foo = ( g=4 h=5 return 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 <= 0 then 1 else n * factorial(n - 1) function rand_color x = x.wireColor = random (color 0 0 0) (color 255 255 255)
fn starfield count extent:[200,200,200] pos:[0,0,0] = ( local f = pos - extent / 2, t = pos + extent / 2 for i = 1 to count do sphere name:"star" \ radius:(random 0.1 2.0) \ position:(random f t) \ segs:4 smooth:false )
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 = 10 cyl_height = 25 c = cylinder() c.radius = rad c.height = cyl_height c.pos.x = i * 25 ) s = sphere radius:rad c 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)
The available commands can be displayed by using the "?" character in a partial max command.
max time ? -- shows all the time-related commands max sel ? -- shows all the commands with sel in them as a substring max ? -- 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 o meshSel = 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:backgroundColor theBitmap.filename = "RayScript - " + theView as string + " - "
fn fireRay theViewRay = ( lastSurfaceColor = backgroundColor lastSurfaceColor.a = 0 for o = 1 to theObjects.count do ( theObj = theObjects[o] theDiffuseLighting = black theInt = intersectRayEx theObj theViewRay if theInt != undefined then ( for aLight in theLights do ( theLightRay = normalize (aLight.pos - theInt[1].pos ) theLightAngle = dot theInt[1].dir theLightRay if 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 = 255 if theSurfaceColor.g > 255 do theSurfaceColor.g = 255 if theSurfaceColor.b > 255 do theSurfaceColor.b = 255 if theSurfaceColor.a > 0 do theSurfaceColor.a = 255 setPixels theBitmap [x,y] #(theSurfaceColor) )--end x loop display theBitmap )--end y loop for o in theObjects do deleteModifier o meshSel pushprompt ("RayScript: " + ((timestamp() - st)/1000) as string + " sec.") )--end script
Rollin
rollout rollin "Rollin'" ( group "Main settings" ( pickbutton selobj "Select object" label lab_rotaxis "Rotation axis: " across:2 radiobuttons rot_axis labels:#("X","Y","Z") default:3 align:#left across:1 spinner obj_radius "Radius: " type:#float range:[1,1000,48] fieldwidth:45 align:#left checkbox detect "Detect radius" width:140 enabled:false button center "Pivot to center of mass" width:140 enabled:false checkbox reverse "Reverse direction" align:#left
spinner calc_start "Calculation start: " type:#integer range:[1,1000,1] fieldwidth:47 align:#right spinner calc_end "Calculation end: " type:#integer range:[2,1000,200] fieldwidth:47 align:#right spinner step "Every Nth frame: " type:#integer range:[1,10,2] fieldwidth:47 align:#right button go "GO!" enabled:false )
on rollin open do ( global xvector, yvector,zvector global xradius, yradius,zradius xvector = [0,1,1] yvector = [1,0,1] zvector = [1,1,0] )
on selobj picked obj do ( if (superClassOf obj == geometryClass) then ( global animated_object animated_object = obj selobj.text = obj.name detect.enabled = true detect.state = false center.enabled = true go.enabled = true ) )
on go pressed do ( animate on ( cont = animated_object.rotation.controller for frame in animationRange.start to animationRange.end do ( key_index = getkeyindex cont frame if (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_pos rotation = (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.numVerts animated_object.pivot = obj_center deleteModifier 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 = xradius if (state == 2) and (detect.state == true) then obj_radius.value = yradius if (state == 3) and (detect.state == true) then obj_radius.value = zradius ) )
topSlice = SliceModifier Slice_Type:2 bottomSlice = SliceModifier Slice_Type:3 topSlice.slice_plane.rotation = EulerAngles (random -theAngle theAngle) (random -theAngle theAngle) (random -theAngle theAngle) bottomSlice.slice_plane.transform = topSlice.slice_plane.transform addModifier topObj topSlice addModifier bottomObj bottomSlice
capMod = cap_holes() addModifier topObj capMod addModifier bottomObj capMod centerPivot topObj centerPivot bottomObj resetXform topObj resetXform bottomObj convertToMesh topObj convertToMesh bottomObj delete theObj #(topObj, bottomObj) )
sel = selection as array for i = 1 to 20 do ( sel = for o in sel where isValidNode o collect o nextObj = sel[random 1 sel.count] maxVolume = -1 for o in sel do ( bbox = o.max - o.min vol = bbox.x * bbox.y * bbox.z if vol > maxVolume do ( maxVolume = vol nextObj = o ) ) join sel (splitInTwo nextObj 45.0) )
Collision Flow
collision_objects = $Box* as array collision_pairs = #() collision_events = #() for i = 1 to collision_objects.count - 1 do for j = i+1 to collision_objects.count do append 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) * obj2 if testmesh.numfaces > 0 then ( if not collision_pairs[i][3] then ( collision_pairs[i][3] = true
collision_pairs[i][4] = t centerPivot testmesh resetXform testmesh collision_mesh = Editable_Mesh() collision_mesh.transform = testmesh.transform collision_mesh.mesh = testmesh.mesh append collision_events #(t, obj1, obj2, collision_mesh, length(motionVector1-motionVector2)) hide collision_mesh ) ) else collision_pairs[i][3] = false delete testmesh ) ) ) else collision_pairs[i][3] = false )
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 = 0 particleFlow.beginEdit()
for i in collision_events do ( new_event = event() new_event.setPViewLocation (10 + cnt*200) 400 cnt += 1 new_source.appendInitialActionList new_event new_action = Birth() new_event.appendAction new_action new_action.amount = (i[5]) * 10.0 new_action.Emit_Start = i[1] * TicksPerFrame new_action.Emit_Stop = (i[1]+2) * TicksPerFrame
new_action = Position_Object() new_event.appendAction new_action new_action.variation = 50.0 new_action.Emitter_Objects = #(i[4]) new_action.location = 4 new_action = speed() new_event.appendAction new_action new_action.speed = i[5] * 2.0 new_action.variation = new_action.speed *10.0 new_action.direction = 3 new_action.divergence = 10 )--end i loop particleFlow.endEdit() holdmaxfile() fetchMaxFile quiet:true