There is a particle system for an explosion, similar to fireworks:
Code of vertex shader:
#version 300 es
uniform float u_lastTimeExplosion; // time elapsed since the explosion
// explosion center (particle coordinates are set relative to this center
uniform vec3 u_centerPosition;
uniform float u_sizeSprite;
// particle lifetime in seconds
layout(location = 0) in float a_lifeTime;
// initial position of the particle at the time of the explosion
layout(location = 1) in vec3 a_startPosition;
layout(location = 2) in vec3 a_endPosition; // final position of the particle
out float v_lifeTime; // remaining particle lifetime
void main()
{
// calculate particle position (algorithm from the book of D.Ginsburg, B.Purnomo)
gl_Position.xyz = a_startPosition + (u_lastTimeExplosion * a_endPosition);
gl_Position.xyz += u_centerPosition;
gl_Position.w = 1.0;
// calculate the remaining particle lifetime
v_lifeTime = 1.0 - (u_lastTimeExplosion / a_lifeTime);
v_lifeTime = clamp(v_lifeTime, 0.0, 1.0);
// calculate sprite size based on remaining life time
gl_PointSize = pow(v_lifeTime, 5.0) * u_sizeSprite;
}
Code of fragment shader:
#version 300 es
precision lowp float;
in float v_lifeTime;
uniform vec4 u_color;
out vec4 fragColor;
uniform sampler2D s_texture;
void main()
{
vec4 texColor = texture(s_texture, gl_PointCoord);
fragColor = u_color * texColor;
// increase sprite transparency
fragColor.a *= v_lifeTime;
}
Three vertex buffers are used: for an array with particle lifetime; array of initial coordinates of particles; array of final particle coordinates:
lifeTimeAsFloatBuffer.position(0);
GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, VBO[0]);
GLES30.glBufferData(GLES30.GL_ARRAY_BUFFER,
FLOAT_SIZE * numberParticles, lifeTimeAsFloatBuffer,
GLES30.GL_STATIC_DRAW);
startPositionAsFloatBuffer.position(0);
GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, VBO[1]);
GLES30.glBufferData(GLES30.GL_ARRAY_BUFFER,
FLOAT_SIZE * NUM_COORDINATES * numberParticles,
startPositionAsFloatBuffer, GLES30.GL_STATIC_DRAW);
endPositionAsFloatBuffer.position(0);
GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, VBO[2]);
GLES30.glBufferData(GLES30.GL_ARRAY_BUFFER,
FLOAT_SIZE * NUM_COORDINATES * numberParticles,
endPositionAsFloatBuffer, GLES30.GL_STATIC_DRAW);
Generate Vertex data:
private final float[] lifeTimeData; // life time of particles
private final float[] startPositionData; // start coordinates of particles
private final float[] endPositionData; // end coordinates of particles
...
public void createDataVertex() {
float maxLifeTime = 3.0f;
for (int i = 0; i < numberParticles; i ++) {
// life time of particle, random value 0-3 second
lifeTimeData[i] = random.nextFloat() * maxLifeTime;
}
float[] xyz;
for (int i = 0; i < numberParticles * NUM_COORDINATES; i += NUM_COORDINATES) {
xyz = getPointForSphere(startRadius); // start position particle
startPositionData[i] = xyz[0] * aspect;
startPositionData[i + 1] = xyz[1];
startPositionData[i + 2] = xyz[2];
xyz = getPointForSphere(endRadius); // end position particle
endPositionData[i] = xyz[0] * aspect;
endPositionData[i + 1] = xyz[1];
endPositionData[i + 2] = xyz[2];
}
lifeTimeAsFloatBuffer = floatBuffer(lifeTimeData);
startPositionAsFloatBuffer = floatBuffer(startPositionData);
endPositionAsFloatBuffer = floatBuffer(endPositionData);
}
Pass data to shader:
public void onDrawFrame(GL10 glUnused) {
...
GLES30.glEnableVertexAttribArray(startPositionLink);
GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, VBO[1]);
GLES30.glVertexAttribPointer(startPositionLink, NUM_COORDINATES,
GLES30.GL_FLOAT, false, FLOAT_SIZE * NUM_COORDINATES, 0);
GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, 0);
...
}
Problem: on some physical devices there is a slowdown in rendering (FPS reduction). Even if there are several hundred particles. Watched a post: Improve Particle system OpenGL. But here the problem seems to be different.
Question: Is there a way to further optimize this particle system? Any answer/comment would be very valuable.