-- BlowGrass.ms - version 1.5 - Michael B. Comet - comet@comet-cartoons.com - http://www.comet-cartoons.com/ -- http://www.comet-cartoons.com/ -- Copyright ©2001,2002,2003,2004 Michael B. Comet All Rights Reserved -- -- Takes any selected objects that have a "Bend" modifier on it...and causes the bend -- angle to be animated so it looks as if the objects are blowing. This is caused by -- a sin wave (speed) being propogated from the location of the "RootObj" node. -- The objects bend back and forth, and will periodically come to rest based on another -- sin type pattern. (speedr). There is also a slight direction variation sin wav speedd -- used to vary the direction, plus some randomness you can add. -- The values listed below can be changed in the interface. -- -- Version 1.5 changed variable speed to speedB so works in r6 since speed apparently -- became a reserved word. -- Version 1.6 is the original script adapted to Max9 by CHP (http://www.pixeltamer.net) global g_angle; -- amount of bend in degrees each way global speedB; -- speed of bending - it will bend back and forth over this period of frames global speedr; -- speed of rest period - It will come to rest once in this many frames global speedd ; -- speed of direction changes - frames that a complete sin wav bend will occur in for direction global dscale ; -- scale of wavelength based on distance - # is units in generic MAX units for how often sin wav peaks global direction; -- amount of random direction switch global startFrame = animationRange.start; global endFrame = animationRange.end ; global everyFrame ; -- Animate every N frames --global RootObj = $'DMY-BlowGrassRoot' -- Root object for center of Sin wave global RootObj = undefined; -- Root object for center of Sin wave global randomness; -- randomness in stuff global rand_angle=#(); -- random angle for each blade global rand_init_angle=#(); -- random init_angle for each blade global rand_dir = #(); -- random dir for each blade global init_angle ; -- initial bend angle global init_vary; -- how much to vary initial bend angle randomly, 0 would mean no variance -- Blows one grass node g with the addition of a random angle ra and random direction rd. fn blow g ra rd ria = ( animate on ( d = distance RootObj.pos g.pos -- figure the distance d = mod d dscale; -- Then do a mod so we have something between 0 and total dscale units d = 360.0 * d / dscale; -- Now figure out what percentage the distance is (d/dscale) of the -- user requested wavelength, this will be 0 to 1 and then mult by 360 -- so end result is 0 to 360. ct = currentTime as Integer / ticksPerFrame j = mod ct speedB; -- Do a mod on the current time with the speed/frames wanted for 1 cycle j = 360.0 * ct / speedB; -- Then figure what percentage 0 to 1 (currentTime / speed) it is and -- mult by 360 so end is in 0-360. j = j + d; -- then factor in offset for position k = mod ct speedr; -- Do a mod on the current time with the speed/frames wanted for 1 cycle k = 360.0 * ct / speedr; -- Then figure what percentage 0 to 1 (currentTime / speed) it is and -- mult by 360 so end is in 0-360. k = k + d; -- then factor in offset for position k = sin(k); -- now get sin for k, so 0 to 1 to 0 to -1 to 0 again. k = (k + 1) / 2.0; -- now normalize so instead it's in range of 0 to 1. -- i suppose i could have use 0.5*sin(k)+0.5 but this is easier to understand l = mod ct speedd; -- Do a mod on the current time with the speed/frames wanted for 1 cycle l = 360.0 * ct / speedd; -- Then figure what percentage 0 to 1 (currentTime / speed) it is and -- mult by 360 so end is in 0-360. l = l + d; -- then factor in offset for position try( g.bend.angle = ((sin(j)*g_angle)*k) + (ra*sin(j)) + ria -- calculate bend g.bend.direction = ((sin(l)*direction)*k) + (rd*sin(l)) -- calculate direction ) catch ( format "-- BlowGrass. WARNING: Object % does NOT have a Bend Modifier!\n" g.name; ) ) ) -- MAIN Start fn blowallgrass = ( if selection.count <= 0 then -- make sure something is selected ( format "--Blow Grass ERROR: You must select the grass objects to affect! --\n"; return 0; ) if RootObj == undefined then ( format "--Blow Grass ERROR: You must choose a WAV Center Object first! --\n"; return 0; ) setWaitCursor(); -- too lazy to make a progress bar...heh. for i = 1 to selection.count do ( -- pre-calc random angle/dir for each blade of grass rand_angle[i] = ((random 0.0 1.0)*randomness*g_angle) - (g_angle/2) rand_init_angle[i] = ((random 0.0 1.0)*(init_vary)) - (init_vary/2) + init_angle rand_dir[i] = ((random 0.0 1.0)*randomness*direction) - (direction/2) ) for f = startFrame to endFrame do ( -- do it for each frame if ( (mod f everyFrame) != 0) do ( -- do only every N frames the user specified continue; ) sliderTime = f -- go to that frame for i = 1 to selection.count do ( blow selection[i] rand_angle[i] rand_dir[i] rand_init_angle[i] -- and blow the grass ) ) setArrowCursor(); ) fn default_values = ( g_angle = 45 -- amount of bend in degrees each way speedB = 100 -- speed of bending - it will bend back and forth over this period of frames speedr = 300 -- speed of rest period - It will come to rest once in this many frames speedd = 100 -- speed of direction changes - frames that a complete sin wav bend will occur in for direction dscale = 1000.0 -- scale of wavelength based on distance - units in Generic max units for how often sin wav is direction = 10 -- amount of random direction switch startFrame = animationRange.start endFrame = animationRange.end everyFrame = 5 -- Animate every N frames randomness = 0.25 -- randomness in stuff rand_angle=#(); -- random angle for each blade rand_init_angle=#(); -- random init_angle for each blade rand_dir = #(); -- random dir for each blade init_angle = 45 -- initial bend angle init_vary = 10; -- how much to vary initial bend angle randomly, 0 would mean no variance ) fn getINIData = ( -- Set these by default in case it's an older ini...so they all get set. default_values(); if (f = openFile (scriptsPath + "BlowGrass.ini")) != undefined then ( execute f; close f ) ) getINIData() -- Do this first before making the rollout!!!!! rollout rolloutOptions "Options" ( button btn_default "Reset Default Values" tooltip:"Sets all values back to default" width:150 align:#left across:2 label lbl_default "Resets all values to default." offset:[-78,4] Spinner spn_initangle "Initial Angle: " range:[0,360,init_angle] type:#integer \ fieldWidth:30 align:#center offset:[-32,0] across:2 label lbl_initangle "degrees. Basic angle for grass to keep." offset:[-82,0] Spinner spn_initvary "Initial Variance: " range:[0,360,init_vary] type:#integer \ fieldWidth:30 align:#center offset:[-40,0] across:2 label lbl_initvary "degrees. Initial angle is randomized by this amount." offset:[-55,0] label lbl_b1 "" Spinner spn_angle "Bend Angle: " range:[0,360,g_angle] type:#integer \ fieldWidth:30 align:#center offset:[-33,0] across:2 label lbl_angle "degrees. It will bend +/- this amount." offset:[-89,0] Spinner spn_speed "Bend Speed: " range:[1,10000,speedB] type:#integer \ fieldWidth:40 align:#center offset:[-40,0] across:2 label lbl_speed "frames. It will bend back and forth once in this period." offset:[-47,0] Spinner spn_random "Randomness: " range:[0.0,1.0,randomness] type:#float \ fieldWidth:45 align:#center offset:[-44,0] across:2 label lbl_random "0 to 1. This % of blades bend more than others." offset:[-49,0] Spinner spn_speedr "Rest Speed: " range:[1,10000,speedr] type:#integer \ fieldWidth:40 align:#center offset:[-37,0] across:2 label lbl_speedr "frames. Grass will come to rest once in this period" offset:[-56,0] label lbl_b2 "" Spinner spn_direction "Direction: " range:[0,360,direction] type:#integer \ fieldWidth:30 align:#center offset:[-26,0] across:2 label lbl_direction "degrees. Direction will change this +/- this amount" offset:[-55,0] Spinner spn_speedd "Direct. Speed: " range:[1,10000,speedd] type:#integer \ fieldWidth:40 align:#center offset:[-42,0] across:2 label lbl_speedd "frames. Dir. will bend back and forth once in this period." offset:[-41,0] label lbl_b3 "" Spinner spn_dscale "Wavelength: " range:[0.001,10000,dscale] type:#float \ fieldWidth:45 align:#center offset:[-40,0] across:2 label lbl_dscale "generic MAX units. The sin wave is this many units long." offset:[-39,0] pickbutton btn_root "Pick Wav Center Obj" tooltip:"Node to specify center of Sin Wav" width:150 align:#left offset:[0,5] across:2 label lbl_root "Sin wave center is located at this objects pivot point." offset:[-20,8] on spn_angle changed val do ( g_angle = val ) on spn_speed changed val do ( speedB = val ) on spn_initangle changed val do ( init_angle = val ) on spn_initvary changed val do ( init_vary = val ) on spn_speedr changed val do ( speedr = val ) on spn_speedd changed val do ( speedd = val ) on spn_direction changed val do (direction = val ) on spn_dscale changed val do ( dscale = val ) on spn_random changed val do ( randomness = val ) on btn_root picked obj do ( RootObj = obj; btn_root.text = obj.name; rolloutAction.btn_blow.enabled = true;) on btn_default pressed do ( default_values(); -- first reset variables to default -- now update interface items.... spn_angle.value = g_angle; spn_speed.value = speedB; spn_speedr.value = speedr; spn_speedd.value = speedd; spn_initangle.value = init_angle; spn_initvary.value = init_vary; spn_direction.value = direction; spn_dscale.value = dscale; spn_random.value = randomness; rolloutAction.spn_every.value = everyFrame; ) ) rollout rolloutAction "Action" ( Spinner spn_start "Start: " range:[-10000,10000,startFrame] type:#integer \ fieldWidth:30 align:#left across:3 Spinner spn_end "End: " range:[0,10000,endFrame] type:#integer \ fieldWidth:30 offset:[-40,0] Spinner spn_every "Every N Frames: " range:[1,1000,everyFrame] type:#integer \ fieldWidth:30 align:#center button btn_blow "Animate Selected" tooltip:"Animates selected objects" width:100 align:#center offset:[0,5] enabled:false on spn_start changed val do ( startFrame = val ) on spn_end changed val do ( endFrame = val ) on spn_every changed val do ( everyFrame = val ) on btn_blow pressed do ( blowallgrass(); format "-- Blow Grass Done. --\n"; ) on rolloutAction open do ( startFrame = spn_start.value endFrame = spn_end.value ) on rolloutAction close do ( try ( f = createFile (scriptsPath + "BlowGrass.ini") format "g_angle = %\n" g_angle to:f format "speedB = %\n" speedB to:f format "speedr = %\n" speedr to:f format "speedd = %\n" speedd to:f format "dscale = %\n" dscale to:f format "direction = %\n" direction to:f format "everyFrame = %\n" everyFrame to:f format "randomness = %\n" randomness to:f format "init_angle = %\n" init_angle to:f format "init_vary = %\n" init_vary to:f close f ) catch ( local titleString = "File I/O Error" local messageString = "Please create a \"Scripts\" folder in your 3DSMAX directory. Default settings cannot be saved." messageBox messageString title:titleString ) ) ) rollout rolloutAbout "About" ( label abt_1 "Blow Grass v1.6" align:#center label abt_2 "By" align:#center label abt_3 "Michael B. Comet" align:#center label abt_4 "comet@comet-cartoons.com" align:#center label abt_5 "http://www.comet-cartoons.com/" align:#center label abt_6 "" label abt_7 "Thanks to: Michael Brumback Jr." label abt_8 " for all his suggestions." label abt_9 "" label abt_a "adapted to MAX9 by CHP (http://www.pixeltamer.net)" ) rolloutGFloater = newRolloutFloater "Comet - Blow Grass v1.5" 450 480 addRollout rolloutOptions rolloutGFloater addRollout rolloutAction rolloutGFloater addRollout rolloutAbout rolloutGFloater rolledUp:true