Particle Speed By Age

The following tutorial shows how to speed up and slow down particles based on their Age and LifeSpan.

 Particle View Setup

• Particle Flow particles are like The Highlander - they are born to live forever.
A Delete Operator is needed to "cut their heads off" and give them a finite life expectation.

• The Script Operator contains the code explained below.
It should be placed AFTER the Delete Operator in order to have valid LifeSpan when the script is first evaluated.

 Natural Language - Script
• Enable the Age, Speed, Lifespan Vector channels

• In the Proceed handler, get the number of particles, the max. desired velocity and the particle system transformation matrix.

• For each particle, first check whether the particle is new born. If it is, store the orientation vector in the particleVector channel.

• Get the age of the particle and calculate a velocity factor based on age and lifespan.

• Assign the vector stored in the particleVector channel multiplied by the velocity factor to the particle speed.

 Final Result

Watch the Preview AVI ( 310K, DivX 5.2)

 Complete Script

on ChannelsUsed pCont do
(
pCont.useAge = true
pCont.useSpeed = true
pCont.useLifespan = true
pCont.useVector = true
)

on Init pCont do
(
)

on Proceed pCont do
(
count = pCont.NumParticles()
maxSpeed = 0.1
pSystemTM = (pCont.getParticleSystemNode()).transform

pSystemTM.row4 = [0,0,0]
for i in 1 to count do
(

pCont.particleIndex = i
if pCont.particleAge.frame == 0.0 then pCont.particleVector = ([0.0,0.0,-1.0] * pSystemTM)
life = pCont.particleLifespan.frame
vel = maxSpeed * (1.0 - Abs (2* (Mod pCont.particleAge.frame life)/life - 1.0))
pCont.particleSpeed = vel * pCont.particleVector
)
)

on Release pCont do
(
)

on ChannelsUsed pCont do
(

The ChannelsUsed handler defines the channels to be used by the Script Operator - you cannot get or set particle related values from the particle container without specifying which properties you need access to. This way, Particle Flow does not have to provide the Script Operator with all possible channels (and there can be an arbitrary number of channels in Particle Flow) but only with those that are actually needed. This conserves memory!
The parameter pCont contains  the Particle Container.

pCont.useAge = true
pCont.useSpeed = true
pCont.useLifespan = true

As we want to change the speed based on the Age and Lifespan of the particles, we need to activate the respective channels. .

pCont.useVector = true

We will also need the particleVector channel which can be used to store user values. We will store the initial orientation of the particles there.

)

on Init pCont do
(

The Init handler is called on initialization. Not used this time though.

)

on Proceed pCont do
(

The Proceed  handler is called every time the Script Operator is evaluated by Particle Flow.
It contains the actual body of the script.
The parameter pCont contains  the Particle Container which contains all particles the Operator is applied to.

count = pCont.NumParticles()

Here we read the current number of particles in the particle container.
We will access every one of them in the following loop.
The reason we assign the value to a variable is that in the for loop that follows, the to limit is evaluated after each cycle of the loop to decide whether the i variable is greater than the limit.
Using the pCont.NumParticles() method call inside the for loop would call the method n times where n is the number of particles.
With the current code though, the method will be called just once and this will make the script faster!

maxSpeed = 0.1

This variable contains the max.  speed in units per tick a particle can reach. Change this to get faster or slower top velocity at age of 50%

pSystemTM = (pCont.getParticleSystemNode()).transform

In order to respect the orientation of the Source icon, we need to get the transformation matrix of the Source. We call the .getParticleSystemNode() method to access the actual scene particle system node and assign its matrix to the user variable.

pSystemTM.row4 = [0,0,0]

We only need the rotation part of the transformation matrix. This will zero out the position information...

for i in 1 to count do
(

Now we repeat the following code block for every single particle by using a for loop which counts from 1 to the number of particles.
The variable i will contain the current particle index.

pCont.particleIndex = i

In order to work with multiple particles, we have to specify the current particle to access.
Setting the .particleIndex property of the Particle Container to the i variable will make the i-th particle the current one.
Any subsequent particle property access calls will be directed to that particle!

if pCont.particleAge.frame == 0.0 then pCont.particleVector = ([0.0,0.0,-1.0] * pSystemTM)

When a particle is first born in the scene, (its Age is 0.0), we will get the actual transformation matrix of the source at that time, multiply a -Z vector by this matrix and store the value in the particleVector channel for later access.

life = pCont.particleLifespan.frame

Now we take the lifespan of the the particle as a Float value (by default it returns a time value like 10f, .frame returns 10.0 in that case) and assign to a variable.

vel = maxSpeed * (1.0 - Abs (2* (Mod pCont.particleAge.frame life)/life - 1.0))

Now we multiply the max. speed value defined in a user variable by a Triangle function  which starts at 0.0, goes up to 1.0 in half the life time value and then falls down to 0.0 again. The resulting variable vel contains the velocity factor of the current particle based on its age relatively to its life span...

pCont.particleSpeed = vel * pCont.particleVector

Finally, we multiply the velocity factor by the direction vector stored in the particleVector channel and assign to the particleSpeed channel of the current particle.

)
)

on Release pCont do
(
)