Ride The Flow!

This tutorial shows how to create a Camera Ride on a Particle Flow system.
A Script Operator assigns the transformation of a particle to a scene camera which then travels with the particles in the middle of the stream.

Final Result

Download the Sample Scene

Watch the Ride Preview AVI (2.9MB, DivX 5.2)

Particle View Setup

Natural Language - Script
Complete Script

on ChannelsUsed pCont do
(
  pCont.useTM = true
)

on Init pCont do
(
  global pflow_travel_camera_170268 = $pflow_travel_camera_170268
  if pflow_travel_camera_170268 == undefuned then
  
  pflow_travel_camera_170268 = FreeCamera name:"pflow_travel_camera_170268"
)

on Proceed pCont do
(
  index = 0
  rideParticleId = 400
  if pCont.hasParticleId rideParticleId &index then
  (
    pCont.particleIndex = index
    pflow_travel_camera_170268.transform = pCont.particleTM
  )
)

on Release pCont do
(

)

Step-By-Step Comments

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.useTM = true

Since we want to read the Transformation Matrix of the particles in order to orient the Camera, we will need access to the TM channel.

)

on Init pCont do
(

The Init handler is executed when the Operator is being initialized.
We will use it to get an existing scene Camera, check its validity and create a new one if no Camera existed.

global pflow_travel_camera_170268 = $pflow_travel_camera_170268

Create a global variable with a unique name and get the scene camera by its unique name.
The Camera must have a unique name to make sure the correct object is referenced by the script.

if pflow_travel_camera_170268 == undefuned then
pflow_travel_camera_170268 = FreeCamera name:"pflow_travel_camera_170268"

In the variable is undefined, there was no Camera with this name in the scene.
In this case, we create a new Free Camera with the unique name and assign it to the variable.

)

on Proceed pCont do
(

The Proceed handler contains the main code of the script.
It will be evaluated every time the Operator is proceeded.
The pCont parameter references the Particle Container of the Event the Operator is located in.

index = 0

We will need a user-defined local variable to store the index of the particle to ride on. 
We initialize to 0.


rideParticleId = 400

This variable contains the Particle ID we want to ride on.


if pCont.hasParticleId rideParticleId &index then
(

Now we call the .hasParticleId method in the Particle Container.
We pass the Particle ID as parameter, and the index variable by reference.
The method returns true when a particle with the specified ID exists in the container.

What is the difference between ParticleID and ParticleIndex?

The ParticleID is a sequential number given to every new born particle in a Particle System. 
This ID identifies the particle throughout its whole life and stays the same when a particle changes from Event to Event.

Every Particle Container of every Event contains a pool of particles. 
These particles are always numbered from 1 to the number of particles in the pool without gaps.  
When particles change between Events, the ParticleIndex will change, and the pools will be renumbered to avoid gaps. 

Since we want to stick to the same particle no matter which Event it is in, we want to access it by the Particle ID.
But we also want to access the corresponding ParticleIndex in every Event the script is evaluated in.
Using the .hasParticleId method, we get true or false depending on whether the particle is in the current Event or not.
If it is in the Event, we also get the actual ParticleIndex of this particle inside the variable index.

pCont.particleIndex = index

Now we can set the current particle in the current Event to access its Transformation Matrix.

pflow_travel_camera_170268.transform = pCont.particleTM

Finally, we get the Transformation Matrix of the current particle and assign it to the transformation of the Camera.

)

The If context ends here. If the particle ID does not exist in the current Event, the script will do nothing.
Since the particle with ID 400 can be only in one Event at a time, but the script is instanced in 3 different Events, the Camera will be affected by just one Script Operator a time.

)

on Release pCont do
(

)

Copyright 2003 by Borislav 'Bobo' Petrov.