There are many, many ways to draw things in OpenGL, so this is naturally confusing sometimes. The first method you describe, setting the shader parameters and issuing one draw call per object is usually the most inefficient, due to the high API overhead. The second one, using instanced drawing is a much smarter approach for objects with the same parameters.
When it comes to particles, specifically, there are two other methods which I'm aware of and have tested:
The first one, more traditional and easier to implement, is to generate a unique quadrilateral for each particle in the application code. Then use one of the several optimized buffer streaming paths of OpenGL to upload this data and issue a single draw call. This is the most straightforward method and provides good results. It will involve very few API calls if you can map the vertex/index buffers (glMapBuffer/MapBufferRange
).
Another method is to move the whole thing to a shader program, using Transform Feedback. This method is a little more complicated to get up and running, but you can find a lot of references on the subject, such as this tutorial. This one should be the optimal path, since it moves the whole simulation to the GPU.
Those are some of the optimized ways of rendering particle effects. But OpenGL provides several other rendering paths that are better for different cases, one of such is indirect draw, which isn't available on ES at the moment, but is probably one of the fastest drawing paths available on modern PC OpenGL. Transform Feedback also requires a geometry shader, so it is not available for current OpenGL-ES.
For more on the optimized rendering paths of OpenGL, I recommend watching this very good presentation by NVidia: Approaching Zero Driver Overhead in OpenGL. At the end of the talk, they show a very interesting benchmark of several methods and how they compare with the Direct3D equivalents.