4
\$\begingroup\$

I'm developing a simple particle system that should be able to perform on mobile devices (iOS, Andorid). My plan was to use GL_POINT_SPRITE/GL_PROGRAM_POINT_SIZE method because of it's efficiency (GL_POINTS are enough), but after some experimenting, I found myself in a trouble. Sprite size is limited (to usually 64 pixels). I'm calculating size using this formula

gl_PointSize = in_point_size * some_factor / distance_to_camera

to make particle sizes proportional to distance to camera. But at some point, when camera is close enough, problem with size limitation emerges and whole system starts looking unrealistic. Is there a way to avoid this problem?

If no, what's alternative? I was thinking of manually generating billboard quad for each particle. Now, I have some questions about that approach.

I guess minimum geometry data would be four vertices per particle and index array to make quads from these vertices (with GL_TRIANGLE_STRIP). Additionally, for each vertex I need a color and texture coordinate. I would put all that in an interleaved vertex array. But as you can see, there is much redundancy. All vertices of same particle share same color value, and four texture coordinates are same for all particles. Because of how glDrawArrays/Elements works, I see no way to optimise this. Do you know of a better approach on how to organise per-particle data?

Should I use buffers or vertex arrays, or there is no difference because each time I have to update all particles' data.

About particles simulation... Where to do it? On CPU or on a vertex processors? Something tells me that mobile's CPU would do it faster than it's vertex unit (at least today in 2012 :).

So, any advice on how to make a simple and efficient particle system without particle size limitation, for mobile device, would be appreciated.

(animation of camera passing through particles should be realistic)

\$\endgroup\$

2 Answers 2

1
\$\begingroup\$

Instancing isn't available in ES2 but ultimately it would provide the best approach.

In the absence of instancing there are a few other ways you can optimize the data. You know that the index array data is not going to change even if the vertex array data does, so the index array can become a static array. The same can apply to texture coords (assuming that you don't have an atlas of particle textures) so they can be also shifted into a static VBO, which would - of course - need to be non-interleaved. That effectively leaves position and colour as being the only dynamic per-vertex data that needs updating, with colour being the only attribute that is duplicated (and if you're using 4 unsigned bytes for colour then the duplication isn't so onerous).

None of this is perfect and you've correctly identified reasons to be unsure of it. However, before you go ripping things apart it would pay to benchmark and see if using duplicate data actually is a problem. This can fly in the face of instinct, but it's often the case that pulling tricks to reduce memory usage ends up having overall negative consequences for performance. Accepting extra memory usage and accepting some duplication of data - even if it does seem instinctively "wrong" - can frequently turn out to be the most optimal approach.

\$\endgroup\$
3
  • \$\begingroup\$ In this case using index buffers is just additional overhead. Each of the 4 vertices is only visited exactly once in drawing the quad. The post I linked does describe how to do hardware instancing on an ES 2 GPU \$\endgroup\$
    – bobobobo
    Sep 30, 2012 at 0:00
  • \$\begingroup\$ Thank you for suggestions. I've implemented particle system this way and it looks it could be good enough for now. Unfortunately I am unable to test it on device for a few days, but I'll be back with results when I get them. \$\endgroup\$ Oct 2, 2012 at 11:10
  • \$\begingroup\$ That hardware instancing implementation passes a modelview matrix per-vertex - an index buffer is utterly trivial overhead by comparison. Using an index buffer will also let you join multiple sprites together in a single draw call, which you can't do without one. Proper instancing - using glVertexAttribDivisor - is the kind of instancing I refer to, and that will give the best combination of low overhead and high performance. \$\endgroup\$ Oct 2, 2012 at 15:10
5
\$\begingroup\$

Yeah, I would say go with a 4-vertex triangle stripped quad.

If you are drawing large numbers of these triangle strips using the same color, and the same set of texture coordinates, you could do 1 of 2 things:

1) Send the 4 vertices for each object and store the color and texcoords in uniforms

2) "Hardware instancing"

\$\endgroup\$
2
  • 1
    \$\begingroup\$ +1. OP should also be aware that point sprites have another problem -- each sprite clips out when its centre reaches the edge of the viewport, i.e. too soon. So useless for most applications. \$\endgroup\$
    – Engineer
    Sep 29, 2012 at 21:51
  • \$\begingroup\$ Thank you very much for this. That's what I actually needed in first place, but didn't know it is possible. For now I have system as described by mh01 bellow, but this is probably going to be an update. Thanks. \$\endgroup\$ Oct 2, 2012 at 11:14

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .