Notifications
Clear all

[Closed] Pflow — path follow script

OK its all working well although i am getting alot of bunching of particles at the start (bottom of vertical ) of the spline. Any ideas?

Hello jobwallis,

I see your file and after an hour of research, i see too that the arrow must be turn in his space object
to be align. I think is that you did. The Arrow was there but we see it’s thin side.

The fact you must close the script window to apply the script, it’s the way it works. Save deosn’t have any effect just close the windows to start the particles calculations.

I look at your file to see

1 Reply
 JHN
(@jhn)
Joined: 11 months ago

Posts: 0

Not behind max now, but I think hitting CTRL+e also evaluates/updates the script node.

-Johan

solution to my problems…
http://www.orbaz.com/forum/viewtopic.php?p=14597#14597
i found my machine slowing alot after including about 4 PF’s. I will need about 12 in the end.
Solution at the moment is to do away with the PF altogether and just animate along path (with out of range keys) and duplicate arrows. Much simpler. KISS keep it simple stupid. :wavey:
thanks all for you help. particularly BebeteLANUITE
:bowdown: :wavey:

Hello jobwallis,

I am happy if you find a good solution for your work.

In fact, i see your file and i made a test. The bunch of particles is the particles that appears after the time
they take to travel over the spline.

For example :
You want the particles travel the spline in 100 frames. (you type it in the script)
if you play it’s ok from the global time from 0 to 100 but after the particles don’t follow the spline anymore and stay on the pivot of the emitter.
So, it’s a problem of my script. I must modify it but i don’t have time by now to analyse what’s happens. But when i have time i will do it.

So here is the same script but to use as script test. I think it’s more interesting as a test.
When the particles leave the spline you can send them to an other event.
The “frame limit” problem still there but i will fix it soon.


   		  on ChannelsUsed pCont do
   	 (
   		  pCont.useTM = true
   		  pCont.useAge = true
   		  pCont.usePosition = true
   		  pCont.useVector = true
   		 pCont.useTime = true
   	 )
   	 
   	 on Init pCont do ()
   	 
   	 on Proceed pCont do 
   	 (
   		 count = pCont.NumParticles()
   		 
   		 splPath = $Line01 		   -- Path to follow. Put your path name here
   		 PartEmitter = $'PFlow Emitter 01' -- Emitter to get his position
   		 KnotPnt = (getKnotPoint splPath 1 1) -- First Knot position of the Path
   		 NumFrames = 100 	-- Number of frame that the particle take to travel over the Path
   		 sw_Banking = True	  -- True/False : If you want the particle follow the orientation of the Path.
   		 sw_AlignToPath = True	-- True/False : If you want the particles follow the path from emitter (False) or directly on the Spline Path (True).
   		 sw_ReorientParticles = True -- True/False : If you want the Transform Matrix of the particle be oriented to the Path. Useful for shape Orientation.
   		splEndPrcnt = 0.99999 --The percentage of the spline the script take to send particles in the following event.
   							  --Avoid a value of 1.0 with "sw_ReorientParticles = True" because the particle will reorient on the last spline knot. 
   							  --It will create a strange movement of the particle at this moment.   
   		
   		 if sw_Banking != True and sw_Banking != False do sw_Banking = True  -- If there is something different in sw_Banking than True or False, we put True in sw_Banking 
   		 
   		 for i in 1 to count do -- loop in the particles
   		 (
   			 pCont.particleID = i
   			 PathPartPos = (pCont.particleAge as float/ticksperframe)/NumFrames -- Get a percentage beetween 0.0 and 1.0 with the pCont.particleAge to calculate the travel position on the path (192 ticks per frame)
   			 
   			 if sw_Banking == False do -- if you don't want the Banking
   			 (
   				 if pCont.particleNew do pCont.particleVector = (pCont.particlePosition - KnotPnt) -- if it's a new particle. Store a vector from the particle position to the first PathKnot
   				 
   				 if PathPartPos <= splEndPrcnt do -- Set the new particle position if PathPartPos is smaller than 1.0 
   				 (
   					 if sw_AlignToPath == True do pCont.particlePosition = (lengthInterp splPath PathPartPos) -- with sw_AlignToPath
   					 if sw_AlignToPath == False do pCont.particlePosition = (lengthInterp splPath PathPartPos) + (pCont.particleVector) -- without sw_AlignToPath
   				 )--end if
   			 )--end if
   			 
   			 if sw_Banking == True do -- if you want the Banking
   			 (
   				 
   				 if pCont.particleNew do pCont.particleVector = (pCont.particlePosition - PartEmitter.pos) -- if it's a new particle. Store a vector from the particle position to the Emitter Position
   			 
   				 if PathPartPos <= splEndPrcnt do -- if PathPartPos is smaller than 1.0
   				 (
   					 -- Axis reconstruction - Thanks to Bobo for the explanation in the Max Help File ("How do I align the UVW_Modifier's Gizmo to a selected face?" section)
   					 ZNormal = (lengthTangent splPath 1 PathPartPos) -- get direction for the Position on the Path with LengthTangent function
   					 worldUpVector = [0,0,1] --Set up of the world
   					 rightVector = normalize (cross worldUpVector ZNormal) --set RightVector (X axe)
   					 upVector = normalize ( cross rightVector ZNormal ) --set upVector at 90° of the system
   					 
   					 Pos_RightVector = RightVector*pCont.particleVector.y --set length of x vector for particle position
   					 Pos_upVector = upVector*pCont.particleVector.z --set length of y vector for particle position
   					 
   					 if sw_AlignToPath == True do pCont.particlePosition = ((Pos_RightVector + Pos_upVector) + (lengthInterp splPath PathPartPos)) -- Calculate the Particle Position on the Path
   					 
   					 if sw_AlignToPath == False do 
   					 (
   						 PartPos_Vect = (lengthInterp splPath PathPartPos) - (getKnotPoint splPath 1 1) -- Vector from first pathKnot and current path coordinates.
   						 pCont.particlePosition = ((Pos_RightVector + Pos_upVector) + PartEmitter.pos) + PartPos_Vect -- Calculate the Particle Position and offset it from the center of the emitter
   					 )--end if
   					 
   					 if sw_ReorientParticles == True do pCont.particleTM = (matrix3 rightVector ZNormal upVector pCont.particlePosition) -- Create a Matrix for the particle shape Orientation
   					 
   				 )--end if
   
   			)--end if
   			
   			if PathPartPos >= splEndPrcnt do
   			(
   				pCont.particleTestStatus = true
   				pCont.particleTestTime = pCont.particleTime
   			)
   			
   		 )--end for
   		 
   	 )--end proceed
   	 
   	 on Release pCont do ()
   

Thanks a lot for using my script

Hello folks !

This is the fixed “Script Test” for my spline follow script.
Now it works. Try it guys and report me if you have some bugs.

Jobwallis, i test the fixed script test in your scene and i work perfectly now.
I put a delete operator in as a next event from the script test.
The created particles follow the line from the beginning and be deleted when they
reach the “splEndPrcnt” value of the spline.
Test it and tell me if it works for you


	 on ChannelsUsed pCont do
	 (
		  pCont.useTM = true
		  pCont.useAge = true
		  pCont.usePosition = true
		  pCont.useVector = true
		 pCont.useTime = true
	 )
	 
	 on Init pCont do ()
	 
	 on Proceed pCont do 
	 (
		 count = pCont.NumParticles()
		 
		 splPath = $Line01 		  -- Path to follow. Put your path name here
		 PartEmitter = $'PFlow Emitter 01' -- Emitter to get his position
		 KnotPnt = (getKnotPoint splPath 1 1) -- First Knot position of the Path
		 NumFrames = 100 	-- Number of frame that the particle take to travel over the Path
		 sw_Banking = True	  -- True/False : If you want the particle follow the orientation of the Path.
		 sw_AlignToPath = True	-- True/False : If you want the particles follow the path from emitter (False) or directly on the Spline Path (True).
		 sw_ReorientParticles = True -- True/False : If you want the Transform Matrix of the particle be oriented to the Path. Useful for shape Orientation.
		splEndPrcnt = 0.99999 --The percentage of the spline the script take to send particles in the following event.
							  --Avoid a value of 1.0 with "sw_ReorientParticles = True" because the particle will reorient on the last spline knot. 
							  --It will create a strange movement of the particle at this moment.   
		
		 if sw_Banking != True and sw_Banking != False do sw_Banking = True  -- If there is something different in sw_Banking than True or False, we put True in sw_Banking 
		 
		 for i in 1 to count do -- loop in the particles
		 (
			 pCont.particleIndex = i
			 PathPartPos = (pCont.particleAge as float/ticksperframe)/NumFrames -- Get a percentage beetween 0.0 and 1.0 with the pCont.particleAge to calculate the travel position on the path (192 ticks per frame)
			 
			 if sw_Banking == False do -- if you don't want the Banking
			 (
				 if pCont.particleNew do	pCont.particleVector = (pCont.particlePosition - KnotPnt) -- if it's a new particle. Store a vector from the particle position to the first PathKnot
				 
				 if PathPartPos <= splEndPrcnt then -- Set the new particle position if PathPartPos is smaller than 1.0 
				 (
					 if sw_AlignToPath == True do pCont.particlePosition = (lengthInterp splPath PathPartPos) -- with sw_AlignToPath
					 if sw_AlignToPath == False do pCont.particlePosition = (lengthInterp splPath PathPartPos) + (pCont.particleVector) -- without sw_AlignToPath
				 )--end if
				else
				(
					pCont.particleTestStatus = true
					pCont.particleTestTime = pCont.particleTime
				)

			 )--end if
			 
			 if sw_Banking == True do -- if you want the Banking
			 (
				 if pCont.particleNew do	pCont.particleVector = (pCont.particlePosition - PartEmitter.pos) -- if it's a new particle. Store a vector from the particle position to the Emitter Position
			 
				 if PathPartPos <= splEndPrcnt then -- if PathPartPos is smaller than 1.0
				 (
					 -- Axis reconstruction - Thanks to Bobo for the explanation in the Max Help File ("How do I align the UVW_Modifier's Gizmo to a selected face?" section)
					 ZNormal = (lengthTangent splPath 1 PathPartPos) -- get direction for the Position on the Path with LengthTangent function
					 worldUpVector = [0,0,1] --Set up of the world
					 rightVector = normalize (cross worldUpVector ZNormal) --set RightVector (X axe)
					 upVector = normalize ( cross rightVector ZNormal ) --set upVector at 90° of the system
					 
					 Pos_RightVector = RightVector*pCont.particleVector.y --set length of x vector for particle position
					 Pos_upVector = upVector*pCont.particleVector.z --set length of y vector for particle position
					 
					 if sw_AlignToPath == True do pCont.particlePosition = ((Pos_RightVector + Pos_upVector) + (lengthInterp splPath PathPartPos)) -- Calculate the Particle Position on the Path
					 
					 if sw_AlignToPath == False do 
					 (
						 PartPos_Vect = (lengthInterp splPath PathPartPos) - (getKnotPoint splPath 1 1) -- Vector from first pathKnot and current path coordinates.
						 pCont.particlePosition = ((Pos_RightVector + Pos_upVector) + PartEmitter.pos) + PartPos_Vect -- Calculate the Particle Position and offset it from the center of the emitter
					 )--end if
					 
					 if sw_ReorientParticles == True do pCont.particleTM = (matrix3 rightVector ZNormal upVector pCont.particlePosition) -- Create a Matrix for the particle shape Orientation
				 )--end if
				else
				(
					pCont.particleTestStatus = true
					pCont.particleTestTime = pCont.particleTime
				)
			)--end if
		   
		 )--end for
	 )--end proceed
	 
	 on Release pCont do ()

Hope this script will help you guys.

Thanks a lot JHN for your trick.
I didn’t know it.

Cheers.

Hi Guys,

Here is a new release of the script. Now you can set the "worldUpVector" which determine the direction of the top.

To use as a test Script:

    -- This is a script that can be used to check particles for a condition
  --
  -- Created:		  9-15-2010
  -- Last Updated:
  -- Author :  ISANA Bruno
  -- Version:  3ds max 9
  --********************************************************************
  -- MODIFY THIS AT YOUR OWN RISK
  
  	 on ChannelsUsed pCont do
  	 (
  		  pCont.useTM = true
  		  pCont.useAge = true
  		  pCont.usePosition = true
  		  pCont.useVector = true
  		 pCont.useTime = true
  		 pCont.useMatrix = true
  	 )
  	 
  	 on Init pCont do ()
  	 
  	 on Proceed pCont do 
  	 (
  		 count = pCont.NumParticles()
  		 
  		 splPath = $Line03			-- Path to follow. Put your path name here
  		 PartEmitter = $'Manif -> Pist LH' -- Emitter to get his position
  		 KnotPnt = (getKnotPoint splPath 1 1) -- First Knot position of the Path
  		 NumFrames = 200 -- Number of frame that the particle take to travel over the Path
  		 sw_Banking = True	  -- True/False : If you want the particle follow the orientation of the Path.
  		 sw_AlignToPath = True	-- True/False : If you want the particles follow the path from emitter (False) or directly on the Spline Path (True).
  		 sw_ReorientParticles = True -- True/False : If you want the Transform Matrix of the particle be oriented to the Path. Useful for shape Orientation.
  		worldUpVector = [0,0,1] --Set up of the world. If your particle is upside down try [0,0,-1] as worldUpVector.
  								--for a looping movement just put 1 to the rotation axis of the looping and rotate your shape in his object space by 90 degrees.
  		splEndPrcnt = 0.99999 --The percentage of the spline the script take to send particles in the following event.
  							  --Avoid a value of 1.0 with "sw_ReorientParticles = True" because the particle will reorient on the last spline knot. 
  							  --It will create a strange movement of the particle at this moment.   
  		
  		
  		 if sw_Banking != True and sw_Banking != False do sw_Banking = True  -- If there is something different in sw_Banking than True or False, we put True in sw_Banking 
  		
  		 for i in 1 to count do -- loop in the particles
  		 (
  			 pCont.particleIndex = i
  			 PathPartPos = (pCont.particleAge as float/ticksperframe)/NumFrames -- Get a percentage beetween 0.0 and 1.0 with the pCont.particleAge to calculate the travel position on the path (192 ticks per frame)
  			 
 			 if sw_Banking == False do -- if you don't want the Banking
  			 (
  				 if pCont.particleNew do pCont.particleVector = (pCont.particlePosition - KnotPnt) -- if it's a new particle. Store a vector from the particle position to the first PathKnot
  				
  				 if PathPartPos <= splEndPrcnt then -- Set the new particle position if PathPartPos is smaller than 1.0 
  				 (
  					 if sw_AlignToPath == True do pCont.particlePosition = (lengthInterp splPath PathPartPos) -- with sw_AlignToPath
  					 if sw_AlignToPath == False do pCont.particlePosition = (lengthInterp splPath PathPartPos) + (pCont.particleVector) -- without sw_AlignToPath
  				 )--end if
  			 )--end if
  			 
  			 if sw_Banking == True do -- if you want the Banking
  			 (
  				 if pCont.particleNew do pCont.particleVector = (pCont.particlePosition - PartEmitter.pos) -- if it's a new particle. Store a vector from the particle position to the Emitter Position
  				
  				 if PathPartPos <= splEndPrcnt then -- if PathPartPos is smaller than 1.0
  				 (
  					 -- Axis reconstruction - Thanks to Bobo for the explanation in the Max Help File ("How do I align the UVW_Modifier's Gizmo to a selected face?" section)
  					ZNormal = (lengthTangent splPath 1 PathPartPos) -- get direction for the Position on the Path with LengthTangent function
  					--worldUpVector = [0,0,-1] --Set up of the world
  					rightVector = normalize (cross worldUpVector ZNormal)--set RightVector (X axis)
  					 upVector = normalize ( cross rightVector ZNormal ) --set upVector at 90° of the system
  					
  					 Pos_RightVector = RightVector*pCont.particleVector.y --set length of x vector for particle position
  					 Pos_upVector = upVector*pCont.particleVector.z --set length of y vector for particle position
  					 
  					 if sw_AlignToPath == True do pCont.particlePosition = ((Pos_RightVector + Pos_upVector) + (lengthInterp splPath PathPartPos)) -- Calculate the Particle Position on the Path
  					 
  					 if sw_AlignToPath == False do 
  					 (
  						 PartPos_Vect = (lengthInterp splPath PathPartPos) - (getKnotPoint splPath 1 1) -- Vector from first pathKnot and current path coordinates.
  						 pCont.particlePosition = ((Pos_RightVector + Pos_upVector) + PartEmitter.pos) + PartPos_Vect -- Calculate the Particle Position and offset it from the center of the emitter
  					 )--end if
  					 
  					 if sw_ReorientParticles == True do pCont.particleTM = (matrix3 rightVector ZNormal upVector pCont.particlePosition) -- Create a Matrix for the particle shape Orientation
  				)--end if
  			)--end if
  			
  			if PathPartPos >= splEndPrcnt do
  			(
  				pCont.particleTestStatus = true
  				pCont.particleTestTime = pCont.particleTime
  			)--end if
  			
  		 )--end for
  	 )--end proceed
  	 
  	 on Release pCont do ()
    
Enjoy !

Nice script very useful. But how to use it ? ok i put in pflow script operator, evaluate it. There is spline in scene, and pflow, nothing happens. how does the script know what spline to use?

1 Reply
(@bebetelanuite)
Joined: 11 months ago

Posts: 0

Hello Dodgeas,

There is two variable in the script (“splPath” and “PartEmitter”).
Just put the name of your spline in splPath like this


 splPath = $name_of_spline 
-- replace name_of_spline by the name of your spline. If you have space in the name, just replace them by an underscore _.
 

Do the same thing for the emitter name in PartEmitter.

Enjoy !

Thanks! great stuff. keep up!

Page 3 / 4