/*#################################### Script by Martin Geupel http://www.racoon-artworks.de v0.45 8/12 ####################################*/ macroScript PflowToSplines category: "RacoonScripts" ( try(destroydialog ::ParticleSplinesRoll)catch() SplineGen_iso_x = getinisetting "$plugcfg\\RacoonScripts.ini" "SplineGen" "pos_x" as integer SplineGen_iso_y = getinisetting "$plugcfg\\RacoonScripts.ini" "SplineGen" "pos_y" as integer global GeneratedSplines fn CreateSpline startFrame endFrame PositionArray knottype swFade FadeFrames byX optim steps =( srcPos = 1 -- loop position in positionarray lifeSpan = ( -- count total amount of positions which are not undefined tmpCounter = 0 for cnt in PositionArray where cnt != undefined do tmpCounter +=1 tmpCounter ) while PositionArray[srcPos] == undefined AND srcPos <= (endFrame-startFrame) do( -- if current pos in positionArray is undefined step 1 forward srcPos += 1 ) firstFrameSv = srcPos if PositionArray[srcPos] != undefined do( -- if cached particle is not in supplied range it would fail otherwise anSpl = SplineShape pos:PositionArray[srcPos] anSpl.wirecolor = green anSpl.optimize = optim anSpl.steps = steps addNewSpline anSpl for iter = 1 to lifeSpan do( -- create either corner or smooth knots case knottype of( 1: (addKnot anSpl 1 #corner #line PositionArray[srcPos]) 2: (addKnot anSpl 1 #smooth #curve PositionArray[srcPos]) ) ) if numKnots anSpl < 2 then(try(delete anSpl)catch()) -- important: if particles are born on the last frame in range, spline wouldn't have more than 1 knot --> error! else( append GeneratedSplines anSpl -- collect generated splines in an array updateShape anSpl -- update shape after knot creation animateVertex anSpl #all -- set spline to animate mode for iter = 1 to lifespan do( -- for precalculated "lifespan" do... tempArray = (for p = (iter) to lifespan collect p) -- collect all knot indexes starting from current active setKnotSelection anSpl 1 tempArray -- select those indexes for knot in tempArray do( -- for each of the collected knots... theKnotIndex = knot theTrackIndex = 3*(theKnotIndex-1)+2 -- some fancy stuff from bobo theKey = addNewKey anSpl[4][8][theTrackIndex].controller (startFrame+((srcPos-1)*byX) ) -- some other fancy stuff from bobo for key generation theKey.value = PositionArray[srcPos] - anSpl.pos -- value is the cached position minus the spline position (important to reset offset) ) updateShape anSpl -- update shape srcPos += 1 -- step to next iteration ) if swFade then( -- fading function for currKnot = 1 to ((numKnots anSpl)-1) do( -- for each but the last knot do... setKnotSelection anSpl 1 #(currKnot) -- set the selection to current know theKnotIndex = currKnot theTrackIndex = 3*(theKnotIndex-1)+2 -- fancy bobo stuff theKey = addNewKey anSpl[4][8][theTrackIndex].controller (startFrame+((firstFrameSv+((FadeFrames-1)/byX) as integer -1+currKnot-1)*byX)) -- Basicly a second key with the same value as orginal is added to the frame before starting to fade (no sliding points then) theKey.value = PositionArray[firstFrameSv+currKnot-1] - anSpl.pos frSwitch = 0 while PositionArray[(firstFrameSv+currKnot+frSwitch)] != undefined AND frSwitch < 10000 do( -- loops through all positions, stepping 1 frame forward (per knot) frSwitch += 1 -- stepping one frame try( theKey = addNewKey anSpl[4][8][theTrackIndex].controller (startFrame+((firstFrameSv+frSwitch+((FadeFrames-1)/byX) as integer-1+currKnot-1)*byX)) -- adds a key x "FadeFrames" after the first original key theKey.value = PositionArray[firstFrameSv+currKnot+frSwitch-1] - anSpl.pos -- the value is the position of the next know at the same time )catch(print "ERROR") ) ) ) -- end of fading ) ) ) rollout ParticleSplinesRoll "Particles to Splines" width:184 height:380 ( fn Pf_filt obj = classof obj == PF_Source GroupBox grp3 "Particle Source" pos:[8,4] width:168 height:52 pickButton btnPickPF "Pick PF Source" pos:[16,20] width:152 height:28 filter:Pf_filt radioButtons rdoFrameTime "" pos:[16,80] width:124 height:32 labels:#("Active Time Segment", "Range\t\t\t\t\t\t") default:1 groupBox grp1 "Frame Range" pos:[8,60] width:168 height:104 spinner spnStart "" pos:[16,116] width:68 height:16 range:[-9999,9999,0] type:#integer enabled:false label lblTo "To" pos:[86,116] width:12 height:16 enabled:false spinner spnend "" pos:[100,116] width:68 height:16 range:[-9999,9999,100] type:#integer enabled:false label lblPrec "Precision: 1/" pos:[20,141] width:80 height:16 spinner spnPrec "" pos:[100,140] width:68 height:16 range:[1,10,2] type:#integer GroupBox grp2 "Spline behavior" pos:[8,168] width:168 height:132 checkbox chkFadeSplines "Fade after" pos:[16,188] width:72 height:16 spinner spnfadeAmnt "" pos:[88,188] width:60 height:16 range:[-9999,9999,10] type:#integer enabled:false label lbl2 "f" pos:[152,188] width:8 height:16 enabled:false radiobuttons rdknottpe "Knot Type" pos:[16,208] width:90 height:46 labels:#("corner+line", "smooth+curve") default:2 checkbox chkOptimize "Optimize" pos:[17,258] width:72 height:16 checked:true label lblSteps "Steps:" pos:[19,278] width:30 height:16 spinner spnSteps "" pos:[55,278] width:40 height:16 range:[1,100,6] type:#integer GroupBox grp4 "Generate" pos:[8,304] width:168 height:68 button btnGEN "Generate Splines" pos:[16,320] width:92 height:28 button btnDel "Delete" pos:[108,320] width:60 height:28 progressBar pb1Gen "ProgressBar" pos:[16,352] width:152 height:12 color:(color 0 255 0) on btnPickPF picked obj do( if obj != undefined then( btnPickPF.text = (">> " + obj.name + " <<") )else() ) on chkFadeSplines changed state do( spnfadeAmnt.enabled = state lbl2.enabled = state ) on btnDEL pressed do( pb1Gen.value = 0. try(delete GeneratedSplines)catch() ) on btnDEL rightclick do( try(select GeneratedSplines)catch() ) on rdoFrameTime changed state do( case state of( 1:(spnStart.enabled = spnend.enabled = lblTo.enabled = false) 2:(spnStart.enabled = spnend.enabled = lblTo.enabled = true) ) ) on btnGEN pressed do( -- when generate button pressed... pb1Gen.value = 0. PCache = #() case rdoFrameTime.state of( -- get cacheRange 1: (startFr = (animationrange.start.frame as integer); endFr = (animationrange.end.frame as integer)) 2: (startFr = spnStart.value; endFr = spnend.value) ) if btnPickPF.object != undefined then( -- if picked particle system is not undefined... undo off( byX = spnPrec.value maxOps.getDefaultTangentType &inTangent &outTangent maxops.setDefaultTangentType #linear #linear -- linear interpolation between keys, important for steps grp4.text = "... caching data ..." GeneratedSplines = #() start = timeStamp() PContainer = btnPickPF.object slidertime = endFr -- set slidertime to endframe to.. totalParticleNum = PContainer.numParticlesGenerated() -- ... get the total amount of generated particles for pCnt = 1 to totalParticleNum do( -- fill PCache array with empty Array for each generated particle append PCache #() PCache[pCnt][(endFr-startFr)+1] = undefined ) counterN = -1 for cTime = startFr to endFr by byX while keyboard.escPressed == false do( -- loop through each frame and collect positions counterN += 1 slidertime = cTime pb1Gen.color = (color 18 187 223) if mod (cTime as integer) 5 == 0.0 then ( -- on each 5th frame do: (dotnetClass "Application").doEvents() -- force max to update ui elements pb1Gen.value = 100.*(cTime-startFr)/(endFr-startFr) -- update Progressbar )else() for pCnt = 1 to totalParticleNum do( -- for each particle... thIndex = 0 -- variable to store the ORIGINAL particle birth ID (ids will reset when particles die!) PContainer.hasParticleID pCnt &thIndex -- get the birth particle ID for correct position in cachearray SubCache = PCache[pCnt] if PContainer.getParticleID thIndex != 0 then( -- if particle is still alive.. SubCache[(counterN)+1] = (PContainer.getParticlePosition thIndex) -- ... append the position in PCache array at the index of current particle ) else( SubCache[(counterN)+1] = undefined -- if dead: append undefined ) ) ) pb1Gen.value = 0.0 grp4.text = "... generating shapes ..." for cCount = 1 to PCache.count while keyboard.escPressed == false do( -- for each array in PCache (means: for each particle) do... while esc not holding... CreateSpline startFr (endFr/*/byX*/) PCache[cCount] rdknottpe.state chkFadeSplines.checked spnfadeAmnt.value byX chkOptimize.checked spnSteps.value-- call spline generation function and supply StartFrame, EndFrame, cached Positions of the particle, knottype, fadeSwtich, fadeFrames, Steps pb1Gen.color = green if mod cCount 5 == 0.0 then ( -- on each fifth particle do: (dotnetClass "Application").doEvents() -- force max to update ui elements pb1Gen.value = 100.*cCount/PCache.count -- update Progressbar )else() ) pb1Gen.value = 100. -- set to 100 when finished end = timeStamp() grp4.text = if ((end - start) / 1000.0) < 60.0 then( "proc. took: " + ((((end - start) / 100.0)as integer)/10.) as string + " secs" ) else( "proc. took: " + (((((end - start) / 100.0)as integer)/10.)/60) as string + " mins" ) gc() maxops.setDefaultTangentType inTangent outTangent ) -- end of undo ) ) on ParticleSplinesRoll close do( setinisetting "$plugcfg\\RacoonScripts.ini" "SplineGen" "pos_x" ((GetDialogPos ParticleSplinesRoll).x as string) setinisetting "$plugcfg\\RacoonScripts.ini" "SplineGen" "pos_y" ((GetDialogPos ParticleSplinesRoll).y as string) ) ) createDialog ParticleSplinesRoll 184 380 SplineGen_iso_x SplineGen_iso_y )