Particle System

General

A particle system in general is used to create all kinds of visual effects, like smoke, fire and explosions. It's aim is to make virtual environments more eye-catching and in case of many games more realistic. So what the system is doing to make this possible is basically controlling the movements and looks of many little graphical objects (particles), usually quads. In the system which is implemented now are 3 classes responsible for creating those visual effects.

  • The Particle class which forms one of those little graphical objects.
  • The ParticleEffect class which currently builds an array of particles and controls their movements and looks.
  • The Effect class contains a list of ParticleEffects because often there is more than one particle effect used to create visual effects like explosions e.g. for a simple explosion fire and smoke are needed.

Particle Class

Main Tasks

  1. Saving all the attributes that are needed to draw the particle and those who can vary between single particles.
  2. Drawing the particle.

Attributes

Needed attributes for drawing are:

protected Vector3D pos; //Position of the particle
protected float particle_size,rotation,alpha; //size,current rotation,transparency of the particle
protected static Texture materialTex,alphaTex; //material texture, transparency map texture of the particle

The other from particle to particle varying attributes are:

protected Vector3D v,initial_v; //current speed, speed at the beginning of the effect
protected float maxLife,life,vRotation; //Maximal life, current life, rotation speed
protected float timeStampIniV,timeStampIniLife,timeStampSize,timeStampVRot; /* Timestamps in which the last time an defined 
attribute was changed is saved. */

Drawing

Currently possible drawing modes are:

  • No texture drawing
  • One texture drawing
  • Two textures multi textured drawing

No texture drawing

It is just as the mode name says in this mode: There is no texture used to draw the particle quads. Instead of that they are just filled with a color.

One texture drawing

This mode draws the particles using one texture, the material texture.

Two textures multi textured drawing

Now it's getting interesting because in OpenGL you have the possibility to draw more than one texture over the same graphical object. OpenGL has different options which define how those textures are mixed together, the option which is used in here is GL_MODULATE. In this option the colors of each particle of the texture are added up to create the final texture on the graphical object. This makes it possible to use transparency maps which you can lay on a material texture in order to let the particle look like a quad or a star, despite of the fact that the graphical object is a quad. This makes it easier to create the desired particle effect.

Class development problems

The only problem which occurred while developing this class were problems with OpenGL in the multi textured drawing mode. The problem was when I drawed this mode everything except of the particle effect on the screen disappeared, regardless of the fact that the textures were bound properly to the quad. At that time the code looked like this:

             glEnable(GL_TEXTURE_2D);
                glActiveTextureARB(GL_TEXTURE0_ARB);
                materialTex.bind();
                glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
 
 
                glActiveTextureARB(GL_TEXTURE1_ARB);
                alphaTex.bind();
                glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND);
 
 
                glBegin(GL_QUADS);
                    glColor4f(1, 1, 1, alpha);
                    //glTexCoord2f(0, 0);
                    glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 0, 0);
                    glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 0, 0);
                    glVertex2f(-particle_size/2, -particle_size/2);
                    glMultiTexCoord2fARB(GL_TEXTURE0_ARB,1f, 0);
                    glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 1f, 0);
                    //glTexCoord2f(0.5f, 0);
                    glVertex2f(particle_size/2, -particle_size/2);
                    glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 1f, 1f);
                    glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 1f, 1f);
                    // glTexCoord2f(0.5f, 0.5f);
                    glVertex2f(particle_size/2, particle_size/2);
                    glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 0, 1f);
                    glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 0, 1f);
                    //glTexCoord2f(0, 0.5f);
                    glVertex2f(-particle_size/2, particle_size/2);
                glEnd();

The source of the problem was that graphics cards today usually have got 32 places where they can save textures (OpenGL refers to them as GL_TEXTURE0_ARB through GL_TEXTURE31_ARB), and the first of them is by default used to handle single texturing. But if you want to use multi-texturing you have to use multiple of these places and only the one currently used is activated. The last one I activated in the code above was GL_TEXTURE1_ARB and so all graphical objects using single texturing couldn't be drawn since GL_TEXTURE0_ARB was deactivated. The problem was solved by adding those lines:

                glActiveTextureARB(GL_TEXTURE1_ARB);
                glDisable(GL_TEXTURE_2D);
                glActiveTextureARB(GL_TEXTURE0_ARB);

ParticleEffect class

Main Tasks

  1. Build the particles which are used for this effect.
  2. Control the particle movements and visuals though the effect.

Particle building

The particle building is a crucial thing for the particle effect and it's visuals. Because you want all the particles to vary in their attributes to make effects like smoke look more realistically. But you also don't want them to be too random because then you will be unable to design the effect you want. The methods that can be used to generate those different start attributes are:

protected float setRichtung(float Angle, float spannweite){...}
 
//Methods for calculating a random speed value
protected Vector3D setSpeed(float generalSpeed,float angle){...}
 
protected Vector3D setSpeed(float maxSpeed,float minSpeed, float angle){...}
 
//Generates random life-values of the particles
protected float setLife(float maxLife,float minLife){...}
protected float setLife(float maxLifep){...}
 
//creates the rotation speed and direction
protected float setRotation(){...}
protected float setVRotation(float vRotationGeneral){...}
 
protected float setVRotation(int richtung,float vRotationMax,float vRotationMin){...}
 
 
//Method for calculating the speed vector of a particle
private Vector3D setSpeedVect(float speed, float angle){...}

Controling particle movements and visuals (Tick Function)

Only by doing that the particle effect really looks like one. If it wouldn't be done, no particle would move, fade over time, rotate, change it's size and so on. The problem in doing this was to create a construct of methods which is easy to understand, well arranged, and easily adaptable. My current solution is a construct of methods that begins with this tick function:

public void tick(){
for(int i=0;i<particles.size();i++){
    timepassed = (System.nanoTime()-lastTick)/(float)Math.pow(10, 9);
    Particle tempParticle = (Particle) particles.get(i);
    if(tempParticle.getLife()>=tempParticle.getmaxLife()){
         dieTick(tempParticle);
    }
    else if(tempParticle.getLife()>=0){
         alifeTick(tempParticle);
    }
 
    }
    lastTick=System.nanoTime();
}

It basically divides the tick in two types: The tick of a particle when its “alive” and the tick when it “dies” (when its current life would be grater than its maximal life) which leads to the next two functions:

The aliveTick:

protected void 
        alifeTick(Particle tempParticle){
 
         tempParticle.setPos(positionTick(tempParticle));
         tempParticle.setV(VTick(tempParticle));
         tempParticle.setLife(lifeTick(tempParticle));
         rotationTickManager(tempParticle);
         if(change_Particle_Size){
            tempParticle.setParticle_size(particleSizeTick(tempParticle));
         }
}

This function only calls up all functions that are changing values when the particle is still alive. So if you got a new variable for the particle that also has to be changed through the life of the particle, the only thing you have to do is write the changing method and add it here. The dieTick() function follows the same idea in which all functions are called up which changes particle attributes and in case of its “death” most of them are reset methods:

protected void dieTick(Particle tempParticle){
    if(!fadeOut){
         tempParticle.setPos(positionResetTick(tempParticle));
         tempParticle.setV(VResetTick(tempParticle));
         tempParticle.setLife(lifeResetTick(tempParticle));
        if(change_Particle_Size){
            tempParticle.setParticle_size(particleSizeResetTick(tempParticle));
         }
         if(editMode){
             changeTick(tempParticle);
         }
    }
    else{
 
    }
}

Class development problems

The most difficult thing to write in this class were the functions that control the attribute changes in each Tick(). That is because some of them have got some difficult algorithms in them. For example this one:

        Vector3D newV= new Vector3D(tempParticle.getInitial_v().getX()*(1-(speed_decay*tempParticle.getLife())),
                                    tempParticle.getInitial_v().getY()*(1-(speed_decay*tempParticle.getLife())),0f);
        return newV;

The first algorithm was about 4 times as long as this one and didn't work. Though there weren't many functions which did the thing I wanted them to do after the first try of writing them.

Effect Class

I will keep the description short for this class because the only thing it does is managing as many ParticleEffects as you want.

 
 documentation/particlesystem.txt · Last modified: 2011/05/09 08:24 by armageddon
 
Except where otherwise noted, content on this wiki is licensed under the following license:CC Attribution-Noncommercial-Share Alike 3.0 Unported
Recent changes RSS feed Driven by DokuWiki