There are many cool applications out there that use particle system to display and animate 3D volumetric objects, which are very inspiring. Other than creating interesting visual effect, I’ve also seen a conceptual application that reconstructs 3D scene with live streaming vector data, which makes more sense because this technique is meant to reduce the large bandwidth required for live video streaming. On the other hand, 3D model assets are perfect resources for populating particle systems, as they are binary files that contain mainly vertex data.
For this sketch I used a space shuttle model which also appeared in my other posts. The model is a low polygon approximation which consists of about 5k vertices, most of which represents the very intricate parts of the model. As I imported the original model and rendered it in particles, I noticed there was a quite uneven distribution of vertices.
I subdivided the model for 3 folds and got a model with 500k vertices, which is dense enough for my laptop to render, but there is still more headroom.
I loaded the model with Cinder’s ObjLoader, and after quite a few steps converting back and forth I obtained a VboMesh, which I put into a batch associated with my particle shader.
// load obj file into TriMesh, convert to VboMesh
To render this mesh in a particle manner, I just need to implement a shader that outputs gl_Position and oColor, then call mBatch->draw().
However, there are a couple of problems with OpenGL’s default GL_POINTS primitive rendering. First is that the points are all 1 pixel dots, you won’t get good enough look even though you have 500k particles per screen size. Also, it is very confusing that the gl::pointSize() function doesn’t work, because it is actually deprecated, and this fact is not documented in Cinder.
After a lot of searching I found it’s possible through calling gl::enable(GL_VERTEX_PROGRAM_POINT_SIZE) and outputting gl_PointSize in vertex shader. Then I found that the particles became larger squares. And sadly GL_POINT_SMOOTH is not supported in Cinder. So I eventually went with point sprites.
To render the mesh in point sprites, you can still use a VboMesh with primitive type GL_POINTS, just enable GL_POINT_SPRITE_ARB. Then you can bind a texture to the shader. In the fragment shader, simply use a varying called gl_PointCoord to sample the texture. I disabled depth test and used additive blending in this sketch. I also associated the color with fragment depths.
Since it’s always good to harness the power of GPU to do particle system animations, I wrote a simple animation in the vertex shader using fake 3D perlin noise. Another way of doing complex computing is to use transform feedback buffers.
The final shader code is here: