Proper way to draw 1000 billboards that always face the camera

I have up to 1000 visible GameObjects with trivial plane meshes, which are essentially sprites/billboards and which should always face in the relative direction -camera.forward.

There are so many ways to do this that I have trouble sorting the good ways from the bad ones.

1. The straightforward way is to use a geometry shader, but that isn't supported on most devices, so that's out.
2. Using a script is nice, easy, simple, and wasting performance.
3. Using a vertex shader and passing in center coordinate of the billboard through properties feels clean but is wasting even more performance because it breaks batching.
4. Doing it in a vertex shader and passing in center coordinate of the billboard through through uv2 feels brittle and wrong, but will be the most performant.

Ideally, someone has a better solution. If not, maybe someone can make a convincing argument for one of the approaches?

• #2 unless you notice performance issues. – Evorlor Nov 21 '15 at 3:32

Quite simply put, Evorlor is right. Use the script, only look at the shader if performance becomes an issue, not when it's simply a concern.

I implemented a scripted solution (option #2) with a default renderer first. It took about 10 ms per frame, with 1000 meshes with 10 triangles each. As it turns out, almost all of the performance cost in this case came from the Unity batching process. This cost will be exactly the same if using a shader.

Because the number of vertices rarely changes in my case, by batching the billboards on my own, in script, the time got down to 3 ms. Performance cost was down 70%, even though I rotated all vertices independently every frame in script just to make sure the load from the script stayed the same. Of course it's even more silly because I only need to do one single rotation and can replace the 999 remaining ones with vector additions - which then gets the time below 2 ms. So in the very best case a shader can save 2 ms of the original 10 ms, because that's all that remains.

In the end the performance cost came from an unexpected place, as usual, and a shader wouldn't have helped performance at all.