Category Archives: Particle System

Particle System Tutorial on Android Part 6

Pyro!!!

As an undergrad I did a special graphics project integrating ray tracing and particle rendering. The particle system I wanted to render was the classic concert pyrotechnics. This particle system is different from a fountain, the main difference being that there is an air resistance factor that needs to be taken into consideration. The new particles are emitted from the source at a random velocity vector as shown from the initialization code.

private void initParticle(int i)
{
    // loop through all the particles and create new instances of each one
    mParticles[i].x = 0f;
    mParticles[i].y = 0f;
    mParticles[i].z = 0f;

    float DOUBLESPEED = 20f;
    mParticles[i].dx = (gen.nextFloat()*DOUBLESPEED) - (DOUBLESPEED/2f);
    mParticles[i].dy = (gen.nextFloat()*DOUBLESPEED) - (DOUBLESPEED/2f);
    mParticles[i].dz = (gen.nextFloat()*DOUBLESPEED) - (DOUBLESPEED/2f);

    // completely random color
    mParticles[i].red = (gen.nextFloat()*.5f)+.5f;
    mParticles[i].green = (gen.nextFloat()*.5f)+.5f;
    mParticles[i].blue = (gen.nextFloat()*.5f)+.5f;
	
    // set time to live
    mParticles[i].timeToLive = (gen.nextFloat()*1.5f) + 0f;
}

In this system the initial speed is exponentially decreased. In this case, decreased by nearly 100% of the max particle speed per second (taking into account the framerate of course). Below is the code added to the update method to apply air resistance

// apply air resistance
mParticles[i].dx = mParticles[i].dx - (mParticles[i].dx*AIR_RESISTANCE*timeFrame);
mParticles[i].dy = mParticles[i].dy - (mParticles[i].dy*AIR_RESISTANCE*timeFrame);
mParticles[i].dz = mParticles[i].dz - (mParticles[i].dz*AIR_RESISTANCE*timeFrame);

There are two demos in this release. The first just cycles a pyro. In this one, not only did each particle have a time to live, but it needed a second respawn timer. In the second demo, you touch the screen to set off a particle system. The code for that one is limited to 40 touches, so there is a set array of 40 systems. A better approach is to use a collection, so you can add pyro systems as they are needed. The key here is to remove them when all particles in the system have expired.

Another future improvement is to change the initial velocity direction to be a random point on a sphere. You can notice that the random direction and velocity vector is a point within a cube, so the particle system looks square. What should be done is a random direction is calculated from the surface of a sphere, and then that vector is scaled by a random velocity.

The triangles are starting to lose their looks. Not bad at a distance but close up they stand out. It might be time to start texture mapping the triangles to something more realistic. If we add the right GL blending, we could give the impression that a high concentration of particles would also mean a brighter color if their colors are additive.

The first touch for the pyro appears small. This is because the time between the init and the first frame is large, so the particle velocity gets reduced significantly. What should be done here is there should be more updates done at smaller time frames. So if a large frame rate appears, break it up into smaller time slices and simulate those (so multiple updates per frame).

Maybe for the next release I’ll try and get those features added. As always, the code can be found on Google Code. The demo is also available on the Android Market, search for “Particle System” or scan the QR code below

Particle System Tutorial on Android Part 5

You can notice from the first couple of fountains that all the particles get generated at the start and then spawn after the time to live is up. This results in a massive blast at the start and then things start to get more evenly distributed. In this tutorial, the particles will get slowly released in to the system. This is actually fairly easy to do with only a new variable called activeParticles (set at zero) and few lines of code in the update method in ParticleSystem.java

// add the particles slowly
if (activeParticles < PARTICLECOUNT)
{
    // calculate how many particles per frame.  I have set
    // the particles per second at 100
    int addParticleCount = new Float(100f * timeFrame).intValue();
    // always be adding at least one particle
    if (addParticleCount < 1)
    {
    	addParticleCount = 1;
    }
    activeParticles = activeParticles + addParticleCount;
    if (activeParticles > PARTICLECOUNT)
    {
    	activeParticles = PARTICLECOUNT;
    }
}

The other feature added is a bounce when the particles hit the FLOOR. So instead of just stopping all speeds, we keep the x and y speeds intact and invert the Z speed. As well, cut the Z speed in half to have the particle not bounce as high as the previous height. The time to live can be extended to give that rolling look.

if (mParticles[i].z <= FLOOR)
{
    mParticles[i].z = FLOOR;
    // invert the Z speed and cut it in half so the bounce is not as high
    mParticles[i].dz = mParticles[i].dz * -.5f;
}

Again the code can be found on Google Code. The demo is also available on the Android Market, search for "Particle System" or scan the QR code below

Particle System Tutorial on Android Part 4

Adding physics and creating a fountain makes the particle systems come to life. There are many more features that can be added. In this one, I am going to add color, a time to live for the particles and sideways motion.

First, the sideways is simply making the X velocity larger than the others and easy to do

mParticles[i].dx = (gen.nextFloat()*2f) + 2f;
mParticles[i].dy = (gen.nextFloat()*2f) - 1f;

Now the X velocity will be in a range of 2 – 4. I also had to make some adjustments to the camera / perspective

GLU.gluPerspective(gl, 15.0f, 80.0f/48.0f, 1, 100);
GLU.gluLookAt(gl, 0f, -17f, 5f, 0.0f, 0.0f, 1f, 0.0f, 1.0f, 0.0f);

Sadly, I’m still tied to the Nexus One resolution of 800 by 480. I’m going to have to change that to be dependent on the resolution of the device. Not to mention change the SDK level to Android 1.5. Next the color and time to live. Simply add the color and time to live to the particle class

        // color
        public float red, green, blue;

        // time to live
        public float timeToLive;

Then add the initialization in the ParticleSystem class

    // set color (mostly blue, for water)
    mParticles[i].blue = (gen.nextFloat()+1f)/2f;
    mParticles[i].red = mParticles[i].blue * .8f;
    mParticles[i].green = mParticles[i].blue * .8f;
		
    // set time to live
    mParticles[i].timeToLive = gen.nextFloat()*1f+0.6f;

When updating the particles, rather than re-initializing after hitting the floor, they need to be stopped and also decrement the time to live. If the particle has died, then respawn it.

    // third if the particle hits the 'floor' stop it
    if (mParticles[i].z <= FLOOR)
    {
        mParticles[i].z = FLOOR;
        mParticles[i].dx = 0f;
        mParticles[i].dy = 0f;
        mParticles[i].dz = 0f;
    }
			
    // fourth decrement the time to live for the particle,
    // if it gets below zero, respawn it
    mParticles[i].timeToLive = mParticles[i].timeToLive - timeFrame;
    if (mParticles[i].timeToLive < 0f)
    {
        initParticle(i);
    }

That's it. Again the code can be found on Google Code. The demo is also available on the Android Market, search for "Particle System"

Particle System Tutorial on Android Part 3

Basic Fountain Particle System

First, no screenshot this time. I took a couple using ddms but found that it really didn’t represent what the application looks like. This looks way better in motion than in a single screen capture. I’ve changed the whole application to have all the particle system demos in the one app, selectable from a menu. The code is quite a bit different so I’ll only mention the highlights for the fountain particle system in this post. If anyone wants more information email me at bayninestudios@gmail.com

To simulate a fountain, we’ll need to add to the particle class itself. Each particle now has an individual velocity.

// velocity
public float dx, dy, dz;

Some changes need to be made to the particle system. Those massive triangles need to be made smaller, which is done from a simple PARTICLESIZE constant and changes to the vertex array

float[] coords = {
            -PARTICLESIZE,0.0f,0.0f,
            PARTICLESIZE,0.0f,0.0f,
            0.0f,0.0f,PARTICLESIZE};

Another addition to the code is a framerate modifier. Each time the particle system is updated we need to check how much time has passed. This is because on slower machines a particle system would appear to be moving slower. If we know how much time has passed between updates, we can make the particles move at the same apparent speed between different devices. I put this in the update routine but I’m undecided if the main ParticleSystemDemo class should handle framerate calculations or if the ParticleSystem class.

Each particle in the fountain has two forces moving them each update. Their own velocity, and gravity. What is done in the update method is to adjust the particle z velocity by gravity, update the particle’s location given it’s x,y,z velocities. Last, check if the particle hits a FLOOR value, and if so re-initialize it.

    // update the particle system, move everything
    public void update()
    {
        // calculate time between frames in seconds
        long currentTime = System.currentTimeMillis();
        float timeFrame = (currentTime - lastTime)/1000f;
        // replace the last time with the current time.
        lastTime = currentTime;

        // move the particles
        // first apply gravity to the z speed
        // second move the particle according to its speed and time frame
        // third re-init a particle if it has gone below the 'floor'
        for (int i = 0; i < PARTICLECOUNT; i++) {
	    // apply a gravity to the z speed, in this case 
            mParticles[i].dz = mParticles[i].dz - (GRAVITY*timeFrame);

            // move the particle according to it's speed
            mParticles[i].x = mParticles[i].x + (mParticles[i].dx*timeFrame);
            mParticles[i].y = mParticles[i].y + (mParticles[i].dy*timeFrame);
            mParticles[i].z = mParticles[i].z + (mParticles[i].dz*timeFrame);

            // if the particle hits the 'floor' respawn it
            if (mParticles[i].z < FLOOR) {
                 initParticle(i);
            }
        }
    }

Improvements on this?

  • Simulating partial steps between framerates. If the time between frames is large, I should update in some small timestep the particle system, so that the entire time does not move the particle in the one velocity.
  • Add time to live to the particles so that they can die in mid-air or stop them on the floor
  • The particles spawn all at the same time. It would be better to have them be spawned slowly or simulate the particle system for a few seconds before drawing

That's it. Again the code can be found on Google Code. The demo is also available on the Android Market, search for "Particle System"

Particle System Tutorial on Android Part 2

Movement

Adding animation to the existing project is fairly easy. Particle System will need a new method, update()

    // simply have the particles fall at a hard coded gravity rate
    // and when they hit zero, bump them back up to a z of 1.0f
    public void update() {
        for (int i = 0; i < PARTICLECOUNT; i++) {
	    mParticles[i].z = mParticles[i].z - 0.01f;
            if (mParticles[i].z < 0.0f) {
                mParticles[i].z = 1.0f;
            }
        }
    }

All this method does is loop through each particle, and subtract 0.01 from it. If the z position gets lower than zero, simply put the particle back up at a z of 1.0. Now in the main ParticleSystemDemo class, we need to call this method on each onDrawFrame

    public void onDrawFrame(GL10 gl) {
        gl.glClearColor(0, 0, .5f, 1.0f);
        gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
        mParticleSystem.update();
        mParticleSystem.draw(gl);
    }

The update and the draw routines can be in separate threads. In one of the Android talks I watched, the user input, rendering and world simulation are all separate threads. This just keeps the tutorial simple. Another thing to note is that all the particles fall at the same rate, and the rate is based on each frame draw. So on slower machines the particles will fall slower, and fast on faster devices. In a future tutorial I'll add using the framerate to determine how much to move the particles.

I've also refactored some code. After giving it some though, I don't like having to pass in the Random generator to the particle. The particle system should be responsible for creating the particle and assigning it's location. So instead, I created a new constructor which takes in the x,y,z coordinates.

public class Particle {

    // location
    public float x;
    public float y;
    public float z;
	
    public Particle() {	
    }

    // the constructor which also assigns location
    public Particle(float newx, float newy, float newz) {
        super();
        this.x = newx;
        this.y = newy;
        this.z = newz;
    }
}

The source and apk can be found here. The apk is only compiled for Android version 2.1. The most recent code can be found at Bay Nine Studios on Google Code. That's it for now, stay tuned for Part 3

Particle System Tutorial on Android


Particle systems are a way to add effects to a game, like an explosion, fire, or water fountain. They usually don’t interact with each other or the world around them, to improve performance. Even a simple system can have 50 particles which are a lot of polygons to do for an effect. First, you’ll want to start a new Android project and paste in the simplest GLSurfaceView application from the Google Android Blog. This is a great starting point for any OpenGL app on Android, I use it all the time when starting a new OpenGL project. It really helped me get up and running quickly so I could start learning more about OpenGL rather than struggle with learning Android and OpenGL at the same time.

First, we need to make a particle object.

package com.bayninestudios.particlesystemdemo;

import java.util.Random;

public class Particle {

    // location
    public float x;
    public float y;
    public float z;

    public Particle(Random gen)
    {
        this.x = gen.nextFloat();
        this.y = gen.nextFloat();
        this.z = gen.nextFloat();
    }
}

Simple particle with an x,y,z coordinate and assigned a random value between 0 and 1. The local variables are public, rather than using getters and setters for performance reasons. Now this particle needs to belong in a system.

package com.bayninestudios.particlesystemdemo;

import com.bayninestudios.particlesystemdemo.Particle;

public class ParticleSystem {
    private Particle[] mParticles;
    private int PARTICLECOUNT = 20;
	
    public ParticleSystem() {
        mParticles = new Particle[PARTICLECOUNT];

        Random gen = new Random(System.currentTimeMillis());
        for (int i=0; i < PARTICLECOUNT; i++) {
            mParticles[i] = new Particle(gen);
        }
    }
}

Simple. Now we have to draw everything. Rather than have a draw routine for each particle, with an assigned texture and vertexes, I have one object that gets allocated by the system and drawn. For each draw, you'll need to do the appropriate translates for the position of the particle. The ParticleSystem class will need a vertex buffer and index buffer to define the triangle to draw. I've also added two helper methods to convert float or short arrays to native order buffers. In previous Android versions I just used FloatBuffer.wrap(float[]) but newer versions require the native order buffers.

    // for use to draw the particle
    private FloatBuffer mVertexBuffer;
    private ShortBuffer mIndexBuffer;
	
    public ParticleSystem() {
        mParticles = new Particle[PARTICLECOUNT];

        Random gen = new Random(System.currentTimeMillis());
        for (int i=0; i < PARTICLECOUNT; i++) {
            mParticles[i] = new Particle(gen);
        }

        float[] coords = {
                -0.1f,0.0f,0.0f,
                0.1f,0.0f,0.0f,
                0.0f,0.0f,0.1f};
        short[] icoords = {0,1,2};

        mVertexBuffer = makeFloatBuffer(coords);
        mIndexBuffer = makeShortBuffer(icoords);
    }

    // use to make native order buffers
    private FloatBuffer makeFloatBuffer(float[] arr) {
        ByteBuffer bb = ByteBuffer.allocateDirect(arr.length*4);
        bb.order(ByteOrder.nativeOrder());
        FloatBuffer fb = bb.asFloatBuffer();
        fb.put(arr);
        fb.position(0);
        return fb;
    }

    // use to make native order buffers
    private ShortBuffer makeShortBuffer(short[] arr) {
        ByteBuffer bb = ByteBuffer.allocateDirect(arr.length*4);
        bb.order(ByteOrder.nativeOrder());
        ShortBuffer ib = bb.asShortBuffer();
        ib.put(arr);
        ib.position(0);
        return ib;
    }

Also ParticleSystem will need a draw routine. This routine setups the vertex buffer to use, the color, translates the draw to the location of the particle, and draws it.

    public void draw(GL10 gl) {
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mVertexBuffer);
        gl.glColor4f(1f, 1f, 1f, 1f);
        for (int i = 0; i < PARTICLECOUNT; i++) {
            gl.glPushMatrix();
            gl.glTranslatef(mParticles[i].x, mParticles[i].y, mParticles[i].z);
            gl.glDrawElements(GL10.GL_TRIANGLES, 3, GL10.GL_UNSIGNED_SHORT, mIndexBuffer);
            gl.glPopMatrix();
        }
    }

Finally, in the main ParticleSystemDemo class, create a new ParticleSystem, initialize the GL perspective and call the draw routine.

class ClearRenderer implements GLSurfaceView.Renderer {
    private ParticleSystem mParticleSystem;
	
    public ClearRenderer() {
        mParticleSystem = new ParticleSystem();
    }

    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        GLU.gluPerspective(gl, 15.0f, 80.0f/48.0f, 1, 100);
        GLU.gluLookAt(gl, 0f, -10f, 15f, 0.5f, 0.0f, 0f, 0.0f, 1.0f, 1.0f);
    }

    public void onSurfaceChanged(GL10 gl, int w, int h) {
        gl.glViewport(0, 0, w, h);
    }

    public void onDrawFrame(GL10 gl) {
    	gl.glClearColor(0, 0, .5f, 1.0f);
        gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
        mParticleSystem.draw(gl);
    }
}

After all of this you should have a blue background with a bunch of triangle particles in the middle of the screen. They don't move yet but that will be for part two of this. There are other improvements to make, possibly having the system assign the initial location of the particle. Randomizing the color. The particle size is hardcoded, and could be dynamic if needed. Texture mapping the particles. Moving the particle drawing to a different class, that way there can be multiple particle models for the same system.

The most recent code can be found at Bay Nine Studios on Google Code.