Accessing Particles

Emitters represent a special case, because they are actually nothing more than a container or source for particles. Since there is normally more than one particle, a list is required to store them. Scalar variables are not able to catch all the different values. A particle can be seen as an element of an emitter and the idea is to gather all particles first. With an adequate method it is possible to go through the particles and access  their attributes. Such a method is called a loop:

emitter  = scene.get_PB_Emitter("Circle01")
particle = emitter.getFirstParticle()
 
while (particle):
    do something here, e.g. read out the current particle's position
    particle = particle.getNextParticle()

 

So what is happening here? First, the emitter is picked from the scene, then the script starts with the first particle. As long as there are particles in the scene, RealFlow loops through them. After the calculation of the current particle is completed, the script goes on with the next particle and the while-loop starts again. 

The particles themselves also have certain attributes – each particle has a particular velocity, mass or position, for example. These properties are very special and that is the reason why they have their own methods to access them. If you remember the position query of an emitter object, then you will see that you had to write this:

position = emitter.getParameter("Position")

 

With particles it is different:

emitter  = scene.get_PB_Emitter("Circle01")
particle = emitter.getFirstParticle()

while (particle):
    position = particle.getPosition()
    particle = particle.getNextParticle()

 

You could now, for example, print out the position of each particle with the scene.message command. In this case, you have to type the script’s code to an simulation events' script window, for example under the "FramesPost" function:

emitter  = scene.get_PB_Emitter("Circle01")
particle = emitter.getFirstParticle()

while (particle):
    position = particle.getPosition()
    scene.message(str(position))
    particle = particle.getNextParticle()

 

The result is a little bit strange, because we have to deal with a vector. In the messages window you can see something like this:

<RealFlow Vector object at 0xf74218>

<RealFlow Vector object at 0xf74140>

<RealFlow Vector object at 0xf74218>

 

Vectors are coded within RealFlow and if you want to print out the scalars you have to determine the values individually:

emitter = scene.get_PB_Emitter("Circle01")
particle = emitter.getFirstParticle()

while (particle):
 position   = particle.getPosition()
 position_x = position.getX() 
 position_y = position.getY()
 position_z = position.getZ()

 scene.message(str(position_x)+" / "+str(position_y)+" / "+str(position_z))

 particle = particle.getNextParticle()

 

Now the output is clearly readable:

  • 0.320292592049 / 0.439999759197 / 0.239609465003
  • 0.250641554594 / 0.439999759197 / 0.311735242605

 

The position of the particle.getNextParticle() statement is of special importance. If it is not inserted correctly, the loop will not stop and will RealFlow freeze.

Another concept of accessing and looping through an emitter’s particles is the for ... in“ method. In this case the currently existing particles are written to a list. With a continuous stream of particles this list grows larger with every frame and allocates more memory. Because of the higher memory demand the “for … in” method is often restricted to a certain number of particles. One of the most common approaches is to detect particles colliding with objects. A loop with “for … in” with an events script may look like this:

emitter       = scene.getEmitter("Circle01")
all_particles = emitter.getParticles() 
 
for single_particle in all_particles:
    do something here

 

The all_particles list contains a 1:1 copy of all currently existing particles in your scene and you can loop through them. But sometimes you will only want to restrict operations to a certain amount of particles, maybe the first 1,000 particles. For this purpose, it is possible to set a certain range with a start, stop and step value:

emitter       = scene.get_PB_Emitter("Circle01")
all_particles = emitter.getParticles()

for single_particle in range(0,999,1):
    current_particle = all_particles[single_particle]
    do something here

 

This structure reads out the first 1,000 particle (0-999) from the all_particles list. As you have learned before, particles in a list always have an index. Each entry has its own number assigned and these numbers can be accessed. The loop goes through numbers from 0 to 999 successively in steps of 1. This number is then used to create an index addressing the list, e.g.

current_particle = all_particles[7] or

current_particle = all_particles[749]

 

The “for … in” and “for … in range” methods are not limited to particles. A list object does not care whether there are particles, objects or vertices stored inside. So these loops can be used with any node, polygon, result and anything else you have inside a list.

Loops are one of the most important methods with RealFlow scripts, especially when you have to deal with particles. There is always a situation where you have to go through all of, or a certain amount of, the particles or objects. For this reason it is highly recommended to become familiar with all different kinds of loops.