Attaching Objects to Particles

In this lesson we shall look at attaching objects to particles. We shall then continue to look at the plethora of options available to us via scripting, and how we can make our own particle simulations.

Load moth_basic.scn

You’ll find all the scripts required inside the “scripts” folder of this project. There are also some extra scripts that that do differing effects – try experimenting with them.

You’ll also find the basic moths script at the bottom of this page.

We are going to attach the moth(like) creatures to particles. Later in the scene, we’ll use some the ultra violet light model to influence the direction of the particle travel.

Lets look at the scene.

There are 2 lights, we won’t use these.

There is a null called moths – this null is the parent of all the moth creatures. We have one model (called mothie) and then instances of him  - about 20. Why are we using instances instead of geometry? That’s right, to save memory and CPU time – we aren’t going to play with the actual geometry of the moths.

Under the UV_light null are stored all the geometry pieces that make up the (rather shakey) uv lamp.

Our particle emitter is next – it’s a disc. We also have a polygon model called “pot” – all the moths will come from a pot and so the particle emitter is positioned at the top of that.

There’s also our obligatory cloud for the particles.

Then there’s some groups for texturing purposes (not really the point of this exercise but I got carried away J )

The particles in this scene have already been set-up. There is a slow release rate, resulting in about 20 particles being released over 50 frames. Incidentally we have 20 instances of mothie (why make more particles than we have models?). I used a constant interpolation of the rate in the animation editor to achieve the savage cut off of particles (and thus a fairly accurate amount of particles produced). There’s also a nice spread to the emission to feather out the particles.

We can access particle information for scripting purposes in the properties of the particle cloud. Open up the particle cloud ppg.

One of the toggle options is the “pre collision script” operation. Toggle it on and notice that 3 data entry points become active, asking for text.

First of all we have the script file name: we create special scripts to utilize particle data and you specify them here. There’s also the browser icon to search for the script on your drive.

Pre-collision scripts are different from normal scripts. Pre-collision particle scripts require the actual algorithms used to be encased in a subroutine. This subroutine name must also be entered underneath the script name dialogue box. I am presuming that the script needs to run as an operator, thus requiring a subroutine callable by XSI. We’ll talk about this later too.

Lets leave the script procedure name for just a minute. The last option is the scripting language. By default its VBScript – which is our scripting language so lets leave it.

For now, lets open up moths.vbs in the scripting editor.

Lets take a look at the script.

First of all we notice that the script is in a subroutine called moths. Notice as well that particle scripts have information passed to them – shown by the input variable to the subroutine. Subroutines also facilitate this interaction process between XSI and VBScript. In this case, specific particle information is being passed into the script.

Next in our script is the dimensionalization of the variables for which we are going to use.

The next line copies properties from the cloud itself and stores them in a user-defined object called “cloud”. Now we can access parts of the particle cloud simply by using our “cloud” variable.

The next line is very similar in that it copies properties from the particles themselves into another user-defined object called “particles”.

In this basic example scene, we are going to translate objects (moths) to the same point in space as the individual particles. For this we need to access the position array inside XSI for the particles.

The line:

      posList      = particles.PositionArray

…does this by copying the position array into a user defined variable called “posList”.

The following line …

      idList       = particles.IDArray

…does a similar task, but copies the identification number array of the particles into a user defined variable called “idList”. More of why we need these later….

We now encounter a loop – it loops through each particle in the cloud.

      for i = 0 to particles.count - 1

In this case i loops from particle 0 to (particle.count –1 ) : remember that array dimension indexes start at 0, e.g. 70 particle would be stored in an array from index 0 to 69 – thus the subtraction of one from the total particle count.

We can now use the index of that loop to access specific particle data, as it loops through the current particles in the cloud.

      id=idList(i)

The next line takes the current identification number from the particle and stores it in a variable called “id”. Remember that we made the “idList” object earlier on, and we are referencing particle i in that list.

Id numbers are quite important in particles. There is always a stack of particles – we are actually looping through all the active particles in the stack in the above loop. When a particle dies however, what do you think happens to this stack?

Well, dead particles are removed from the stack. To eliminate the stack having void spaces (and thus getting very large) XSI shifts all the particles in that stack up to cover the empty space.

What happens if we reference our moths to the particle stack number – consider what happens if a particle dies?

We want to directly relate our individual moth object to specific particles. If we relate our objects to the stack position of the particle, then the moth object will flick from particle to particle, as the stack is updated and changed. As such, each particle has an individual id number, and we use that to make sure our moths “stick” to the correct particle.

If I tried to move mothie21 to particle 21, I would generate an error – mothie21 does not exist! It’s not a cataclysmic error but it is sloppy programming.

            if(id < 20) then

What this condition does is check to see if the current particle id falls within the current amount of moths available to use. Why?

We want to move mothie1 to particle1, mothie2 to particle2, mothie3 to particle3, etc. We only have 20 mothies so we need ensure that we don’t try and use model that do not exist.

Inside this condition we have 3 simple lines that translate the x, y and z position of the moth to the current particle position.

We use simple setvalue commands and use the posList made earlier in the script to access each particle position – based on the id number.

Okay – so lets run this script.

Go back to the particle cloud ppg. In the pre-collision script, browse through and select moths.vbs from the moth project.

Now enter the subroutine name in the box – moths.

Press play and watch the moths fly up from the pot.

This first script is just a simple example.

Lets consider more advanced features.

Part 2 : Making the moths fly towards the uv light.

Now open up script again.

What we want to do is to perturb the velocity of the particles. Remember that velocity is a vector- its speed in a given direction. So by adjusting the velocity we not only change how fast the particles are traveling, but also direction in which they are traveling.

We can access the velocity of the particles by using the line:

      velocityList = particles.VelocityArray

In this case we are copying the velocity array into a user-defined array called velocityList.

To access the array we use the same notion that we use on most XSI arrays:

          X amount is equal to velocityList(0, particle number)

          Y amount is equal to velocityList(1, particle number)

          Z amount is equal to velocityList(2, particle number)

If we want our moths to fly towards a target, then we need the coordinates of a target.

If we consider the lines :

targetx=getvalue("uv_light.kine.global.posx")

targety=getvalue("uv_light.kine.global.posy")

targetz=getvalue("uv_light.kine.global.posz")

     

… this will get the x, y and z value of the uvlight global position.

To consider the ray vector between the target position and the particle we need to generate new variables.

aimx = targetx - posList(0,i)

aimy = targety - posList(1,i)

aimz = targetz - posList(2,i)

This subtracts the particle position from the target position – i.e. the distance from the particle to the target.

What we need to do is work out the direction from this vector – we can normalize it. Remember that a normalized vector is a vector divided by its magnitude. A normalized vector represents a direction.

We could use a line to calculate magnitude – using 3d pythag.

mag=sqr((aimx * aimx)+(aimy * aimy)+(aimz * aimz))

therefore the unit vectors of aimx could be expressed in new variables as:

aimxunit = aimx / mag

aimyunit = aimy / mag

aimzunit = aimz / mag

           

To consider a speed we could implement another variable(for example):

speed = 5

To actually replace the velocity we could write back to the velocityList array from earlier:

e.g.

velocityList(0,i) = aimxunit * speed

Remember that velocity is speed in a given direction. We also need to calculate the other two axis components…

Finally, the process involves putting the values “back” into XSI.

Before when we took the particle velocity array from XSI, we used the following command:

velocityList = particles.VelocityArray

To actually put the velocity list back into XSI, we reverse the process:

particles.VelocityArray = velocityList

That’s it. Now the moths flock towards the uv light. They do not however face the direction of travel.

See if you can implement a rotation to mimic the basic direction of rotation.

You’ll find all the scripts required inside the “scripts” folder of this project. There are also some extra scripts that that do differing effects – try experimenting with them.

You’ll find the basic moths script at the bottom of this page.

Sub Moths(input)

Dim cloud, particles, posList, idList, i, id

    

‘GET THE PARTICLE CLOUD PROPERTIES AND STORE THEM IN AN OBJECT VARIABLE CALLED 'CLOUD'

Set cloud = input.Parent

 

'ACCESS THE PARTICLES THEMSELVES AND COPY THEIR PROPERTIES INTO AN OBJECT VARIABLE CALLED PARTICLES

Set particles = cloud.Particles

 

'This gets all the information we need - a position list and an idlist

posList      = particles.PositionArray

idList      = particles.IDArray

    

'Loop for each particle 

for i = 0 to particles.count - 1

    

' Get ID of current p art and store it in a variable called "id"

id=idList(i)

    

'SEE IF THE CURRENT ID IS LESS THAN THE NUMBER OF MOTHS IN THE SCENE

if(id < 20) then

                               

'SET THE POSITION OF THE CORRESPONDING MOTH WITH THE CURRENT ID

setvalue "mothie" & id&".kine.global.posx",posList(0,i )

setvalue "mothie" & id&".kine.global.posy",posList(1,i )  

setvalue "mothie" & id&".kine.global.posz",posList(2,i )  

end if

next

    

End Sub