One thing that is always fun to do in programming is to set up a basic particle system framework, and then experiment as wildly as you wish: spawn particles, add velocity, implement gravity. Finally, simply sit back and watch them fly.
This is where I began with ‘Gravitoids’, one of my earliest projects in Processing. I wanted to create a 2D particle system made up of planet-like circles that spin, attract, and collide. Ultimately, I hoped to initiate a Big Bang-esque situation at the program’s start-up that, through passive interaction, would lead to particle organisations similar to those of the planets in our universe.
In retrospect, the goal was rather lofty, especially for an experimental project. Nonetheless, I started small.
One of the key goals from the very beginning was to keep every single interaction organised and flexible. This allowed me to set up a control panel (using Andreas Schlegel‘s excellent controlP5 library) with which it is possible to change the system properties in real time. This feature enabled the testing of an incredibly broad range of results with only a single instance of the program. Furthermore, real-time feedback helped track bugs and discover interesting particle behaviour.
Another major goal of ‘Gravitoids’ was to create a closed system. I attempted to model the behaviour of the particles based on real-world phenomena, and, as such, had to account for every unit of energy and mass (according to the laws of conservation of mass and energy). Any leak would destabilise the system, making it unsustainable in the long run. So each individual particle has its own mass (which determines its actual render size), as well as internal energy (kinetic and potential). The mass and energy are constantly transfered within the system, but the overall total of each always remains the same (until new particles are spawned into the system by the user).
Reaching this type of stability with a few floating balls is not difficult. But for ‘Gravitoids,’ I was gunning for something more exciting. I wanted not only gravity, but also repulsion, friction, and collisions.
Friction was the simplest to implement; a simple dampening vector applied to the velocity vector of each particle did the trick. The user is able to toggle friction on and off, as well as change its magnitude on the fly. Kinetic energy lost due to friction is converted to thermal energy for the particle.
Repulsion was simple enough too. All I did was inverse the gravity function (Gravitational force = G * m1 * m2 / D^2). This increased repulsion as particles got closer, and decreased it as they went farther apart – which logically made perfect sense. Toggling repulsion on in the simulation creates an interesting lattice, as each particle attempts to stay away from others. However, size matters – bigger particles push more; this almost emulates the repulsion of like charges in electric systems.
Later, I considered adding an alternative mode to repulsion – springs. This function combines the gravity and repulsion functions : it attracts particles through gravity to a certain distance, then switches on the repel function. This clumps particles into groups, but still allows them to move freely. The interaction is similar to that of H2O molecules through hydrogen bonds, and the resulting movement is reminiscent of fluid motion. Furthermore, collisions between two or more of such clumps creates very elastic movement that could be applied for soft body dynamics (I’ll make that another project). As such, the spring toggle ended up being one of the more exciting modes to play around with.
Finally, the feature that cost me the most time and effort was collisions. My vision was that each particle would be able to crash into any other particle, spewing mass into system and breaking up into smaller pieces. In part, I have accomplished this goal.
Checking for collisions is basic (and, unfortunately, not very scalable) – each particle, during its update loop, checks its position vector and size against that of every other particle. If they overlap, flag the pair for collision.
The collision function is made up of multiple phases.
First comes the analysis phase. A nested loop checks the two particles against each other, comparing mass and energy. For the sake of simplicity, in the current incarnation of the simulation, the algorithm chooses the one with the bigger mass as superior. It then flags the smaller particle for destruction.
The destruction phase differs based on the size of the smaller particle. If the particle is below a certain mass, it is absorbed into the bigger one. Its instance is removed. If the smaller particle is still quite big, it cracks and splits instead. Its instance is removed.
The resolution phase enacts the rules of the system – it preserves energy and mass. If a particle is absorbed, its mass and energy are added to that of the greater particle. If a particle splits, its mass is divided amongst its children, and so is its energy along with that generated during the collision ( a large part of which is instantly converted into mechanical energy for the newly-born particles, flinging them away from the collision point ). If a big particle obtains too much energy in relation to its mass, it bursts and splits into many smaller particles, dividing its components equally.
Put together, all the features create an interesting sandbox for experimentation. Gravity and collisions lead to spinning structures with mega-particles in the center, ones that occasionally burst into a flurry of mass. Springs create bouncing and colliding soft-body objects. Toggling repulsion right after gravity spins the particles in all directions. Turning off all forces save friction while leaving collisions on is reminiscent of a billiard table or atomic reactions, with rolling balls hitting others, splitting, starting off chain reactions.
Beyond simply messing around with values in the control panel, the user can also spawn particles – either by spawning them in chunks, or launching a specific one of a defined velocity and mass. This allows the user to revive a system that has stalled, or make a wild one even wilder.
Of course, there is still a long way to go if I ever wish to accomplish my initial goal of simulating planetary motion and interaction. Right now, the program is merely a fun toy. I would like to eventually model it after actual, real-world data, and use it to test plausible scenarios. I plan to add more flexibility, open up more possible venues for interaction, and make the model more stable. I want to design atmospheric affects, simulating interactions based on fluid mechanics that create gas clouds, mass projections and nebulae. But for now, ‘Gravitoids’ can only run a few hundred particles at a reasonable fps. Optimisation is my next step.