Sunday, May 29, 2011

Particle System with Point Sprites–Part II

After struggle for a day (though it’s a simple logic), i got the desired particle effect…

Effect i was looking for is “Particles continuously flow from the centre”, this effect i could achieve without Shaders, but i wanted to do the same with Shaders.

code changes from the previous post are as below…

Changes in Draw function of ParticleManger class are highlighted below.

public void draw(int iPosition, int iMove, int iTimes, int iColor, int iLife, int iAge)
  {
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
  
    vertexBuffer.position(0);
    GLES20.glVertexAttribPointer(iPosition, 3, GLES20.GL_FLOAT, false, PARTICLE_SIZE * 4, vertexBuffer);
    GLES20.glEnableVertexAttribArray(iPosition);
  
    vertexBuffer.position(3);
    GLES20.glVertexAttribPointer(iColor, 3, GLES20.GL_FLOAT, false, PARTICLE_SIZE * 4, vertexBuffer);
    GLES20.glEnableVertexAttribArray(iColor);
  
    vertexBuffer.position(6);
    GLES20.glVertexAttribPointer(iMove, 3, GLES20.GL_FLOAT, false, PARTICLE_SIZE * 4, vertexBuffer);
    GLES20.glEnableVertexAttribArray(iMove);
  
    vertexBuffer.position(9);
    GLES20.glVertexAttribPointer(iLife, 1, GLES20.GL_FLOAT, false, PARTICLE_SIZE * 4, vertexBuffer);
    GLES20.glEnableVertexAttribArray(iLife);
  
    vertexBuffer.position(10);
    GLES20.glVertexAttribPointer(iAge, 1, GLES20.GL_FLOAT, false, PARTICLE_SIZE * 4, vertexBuffer);
    GLES20.glEnableVertexAttribArray(iAge);
  
    GLES20.glUniform1f(iTimes, nTimeCounter);
  
    GLES20.glDrawArrays(GLES20.GL_POINTS, 0, NUM_PARTICLES);
  }

I'm passing life and age attribute values for each particle to Vertex Shader.

Changes in Vertex Shader are highlighted below (need to optimize interms of operation steps though).

String strVShader =
            "precision mediump float;" +
            "attribute vec4 a_Position;" +
            "attribute vec4 a_move;" +
            "uniform float a_time;" +
            "attribute vec4 a_color;" +
            "varying vec4 v_color;" +
            "attribute float a_life;" +
            "attribute float a_age;" +
            "varying float alpha;" +
            "float time;" +
            "void main()" +
            "{" +
                "alpha = a_life - (a_time * 10.0 * a_age);" +
                "time = a_time;" +
                "if (alpha < 0.0)" +
                "{" +
                    "float td = a_life/a_age;" +
                    "td /= 10.0;" +
                    "float df = a_time/td;" +
                    "int div = int(df);" +
                    "df = float(div);" +
                    "td *= df;" +
                    "time = a_time - td;" +
                    "alpha = a_life - (time * 10.0 * a_age);" +
                "}" +
                "gl_PointSize = 5.0;" +
                "v_color = a_color;" +
                "gl_Position = a_Position;" +              
                "gl_Position += (time * a_move * 0.5);" +
                "gl_Position.w = 1.0;" +
            "}";

here calculation logic is as follows:

  1. if particle run out of life (i.e., alpha calculated is less than zero), then
  2. Calculate the time (td), when particle has possibly died.
  3. find the modulo of current time and the calculated time in above step. thats is stored in time variable.
  4. calculate the alpha value based on the new calculated time.
  5. use calculated time to set the vertex position.

Fragment Shader do not have any changes.

Code for this post can be found at Google Code