I’ve been working on an installation project with Samsung for Milan design week for the past 2 month. It is for the first time I work so intensively with particle systems. The idea is simple : pushing particles to reveal / construct the image. This is like a dream project for all the developers, playing with particles for entire 2 month. And this is the first time for me to use cinder to build a project.
Convert to Cinder
The reason I choose cinder is because it is easy to setup. All the tool you need to work with opengl is pretty much there. Especially the framebuffer object is really useful, being able to render to multiple targets really saves my life.For the learning process, actually it doesn’t take really long for me to convert my code from WebGL/JS to cinder. Just few small things to watch out, i’ll point them out later in this post. The basic knowledge of 3D never change: vertex buffer, index buffer, textures and shaders, these are all re-usable from a WebGL/js project. The only thing i need to figure out is how to upload/bind them correctly, but this is really easy with the existing class in cinder such as VboMesh, GlslProg and Texture class. So this transition from WebGL/js to Cinder to me is quite painless, and now I’m really enjoy working in cinder for the performance i gain and also wider support for openGL.
The particle system
In this project we build a particle system. Like all other particle systems it’s based on the basic physics : the position of the particle is determined by its velocity, and the velocity of the particle is determined by its acceleration. You can find a really good tutorials from the book : “The nature of code” by Daniel Shiffman ( link ) or the tutorial from cinder ( link ) by Robert Hodgin.
Basically, the particle movements follow these rules :
new position = old position + velocity; new velocity = old velocity + acceleration;
In order to move the particles, you can either just change the position of the particles, or change the velocity of it, or the best is to change the acceleration of the particle to get the most natural movement. The acceleration of the particles might not very clear to what it does, there is another term : Force. This will make it easier to understand, when you want to move an object, you need to apply a force on it, so are our particles. We want to move it with our gestures, so we need to apply the force generated by the gesture to the particles. As for the force of your gesture, the leap motion already has the ability to find the velocity of the palms as a vector, we just need to multiply the right amount of force with this vector, than we got the acceleration we want. We’ve got couple of force more in this project, the first one is the constant wind force from left to right, the second one is the noise or we can see it as a turbulence force. Combine these 3 forces, we are able to create the particle behaviour we want.
The first prototype : The basic
There are different ways to build this particle system, the most straightforward way to build it is to create a particle class, with position, velocity and acceleration attributes. In my first attempt to build the system, I go with this way, the advantage of this method is that it’s easy to build and debug, therefore I can come up with a quick prototype so we know what’s achievable and we can start building visuals around it.
The particle movement looks nice, which says the way I generate the wind and turbulence is working, however the biggest problem about this version is : There is not enough particles. At maximum we can put about 5000 particles in the particle stream, it’s not enough to construct the images, we need more particles.
The second prototype : Trying to balance the calculation to GPU
The heaviest part of the particle system is the calculation of particles’ position and velocity, in every frame you need to go through all the particles and do the same calculation for all the particles. This actually sounds quite familiar to one thing : the Fragment shader, each frame the fragment shader will go through all the pixels and calculate the desired color. So in order to put more particles in our system, we need to balance this calculation on to GPU using fragment shader. But how ? in 3D space, a position of a particle need 3 values : x, y and z. So we just take one color channel for one axis : red for x, green for y and blue for z, by doing this we can save the position of a particle using color, and then each pixel on the texture represent one particle. In every frame we just looping through all these pixels and update the color, same as looping through all the particles and update the position. Just one thing to bear in mind, the color value in shader goes from 0 to 1, and the position of your particle should go from -1 to 1 then we can multiply by the range we want. So as a result, taking X ( red channel ) for example, if the red value is 0, it will be at the left border of the range, 0.5 will be the center of the screen and 1 will be at the right border. And this rule applies to not only position, but also velocity and acceleration as well.
The benefit of doing this is that we can push to a very good amount of particles, with my macbook pro i can push to 1024×1024 = 1,048,576 particles running with 60 fps without any optimisation. With more powerful machine like iMac or mac pro you can push to 4096×4096 particles which is insane and much more than we need.
The final prototype : Working entirely on GPU
The second prototype demonstrate it’s possible to balance the calculation of the particle movement to GPU, and we can get a really good amount of particles. The next step will be building the actual particle system on top of GPU. Idea is simple : I create 2 textures, one for velocity, another for position. Each frame i update the velocity texture first with perlin noise as turbulence and the wind force. Then I update the position texture with this new velocity by just adding them together. This fits our model of “Velocity += Acceleration, Position += Velocity”, however it doesn’t work as I expected. The problem is that the range of position if from 0 to 1 only, the velocity is much smaller like .001 and the acceleration is even much smaller, so when I multiply all these together it just disappear because it’s too small. This bugged me for couple days until i find out this :
gl::Fbo::Format format; format.setColorInternalFormat( GL_RGBA32F_ARB );
I need to set the color precision to a higher value ( in this case 32 bit ) instead of just the default 8 bit. After adding this new precision, all my particle movement is working now.
So now I can recreate the movement like the one i build only using CPU, and this time i can push to 256×256 = 65536 particles ( can go higher but it will make the particle stream feel too full , so we settle down with this value ). At this point we have a healthy particle system that we can start building our project.
The actual build
The first task come to hand is how to apply the gesture force to the particles. To do this we need to create another texture just to record the gesture force. Like this :
So when calculate the movement, i simply just add this force with other 2 forces together (wind/turbulence ).
Another thing i tried is to combine the texture for position and the texture for velocity into 1, as you can see the video above, on the left side is my position, on the right side is my velocity. This will save some framebuffer and 1 rendering call for me , as for performance i don’t know if it’s going to be better or worse, need to do more tests. The final shader code is quite complicated, combined with all the forces and also how to make particles go to their position form the image. In total I used 6 textures to store different informations and also output to 2 different target in order to track the completion rate of an image.
I’ve known this method of balance the calculation on to GPU for a long time, and there’s a lot of examples on the internet, just search for “GPU particles” you will get a lot. The basic idea of this technique is really easy to understand, but not until i really start building it I realise there’s a lot of details to be taken care of. Overall like i said the concept is not complicated, you will spend more effort on converting the color and values to vector in your head, and finding out which is the right uv coordinate to get the right color. It’s hard to debug, you can’t get too much info from the shader. But once you got it right it gives your a great reward : good performance with good amount of particles. I am really glad that i got this chance to work on this project, it’s a part of a big installation, i’ll share the b-reel making-of video later when it’s done. All the developers love particles, i am really lucky to have this chance to work on a particle system for full 2 month, which gives me a good opportunity for me to clear my thoughts about particle system and testing several different methods. I only list 3 prototypes in this post but actually there’s about 30 prototypes in total, just progress a bit by a bit. And I’m really happy about using Cinder as well, for a first cinder project this is a great challenge. I learned a lot during this project, and I really proud to be part of this big and beautiful installation.