Snakes alive!
A few years ago, probably around 2004/2005, I took advantage of some source code that Jared Tarbell posted on levitated.net. I was really impressed with the code because the magic was mostly limited to about a dozen lines. Very clean and surprisingly robust!
I didn’t end up doing much with it at the time but I would revisit it every now and then and give it a few tweaks. It was always a pleasure to see the little guys push themselves along but unfortunately, they existed on a 2D plane (see this example: flight404.com/p5). At the time, I just didn’t know nearly enough to make an interesting 3D version.
Then came The REV visualizer which we did for Relentless Energy drinks. That process was incredibly useful because I was taught (by fellow Barbarian Andrew Bell) how to use some OpenGL features to create more lush forms and also how to push the lighting and texture calculations to a shader. Bottom line, super fast, lit, and textured 3D forms.

Reenter the Tarbell flagellum code. While experimenting with some effects for a client, I decided to try making a decent 3D version. I had no specific look in mind, I just wanted to play around a bit. Fairly quickly, I had them swimming about in 3D. I ended up adding a floor plane to ground them in a space because it was rather uninteresting just letting them flop about, floating in thin air.
The first hurdle I faced was overlap and collision detection. When one snake encountered another snake, they would just pass through each other. This killed the illusion of them pretty quickly. No matter how solid they appeared in texture and form, they instantly became massless when you saw one pass right through another.
I had no interest in adding a complete 3D physics library because my needs at this time are fairly simple. I am not worried about environment… I just want the snakes to crawl over each other. I decided to try magnetic repulsion despite thinking it probably wouldn’t work well enough. The thinking is this: Take each segment of a snake (200 segments each), and check its distance to every single other segment of every other snake on screen. Stupid, right? Yeah, pretty much. But with some optimization and only checking the segment distances if the snakes in question are close enough for overlap to be possible, I got it to run at 60 fps with 10 snakes.

Now that I have those distances, I check to see if the distance is shorter than the sum of the widths of the snake’s body at those particular segments. If the distance is shorter, this means an overlap has occurred. I then apply a repulsive force to push the segments apart. Because the snakes very rarely have the exact same body radius at the point of interaction, one snake always gets pushed into the ground while the other gets pushed up. With some tweaking to mass/charge ratios and some guesswork, I ended up with a fairly believable rigid body collision which you can see pretty well in the following video.
The next thing to deal with was the look. I haven’t yet learned how to implement bump mapping properly so, like with the collision detection, I tried what I was already familiar with. I started with a simple texture that I made in Photoshop.

In the shader, I am using two light sources. One is where the camera is located and the other is directly above. To accentuate the implied scales in the texture, I apply specular and diffuse lighting only if the original texture’s frag color is above a certain threshold. I could just have easily done this on the original texture but by using it as a rudimentary heightmap, I can play around a bunch without needing to redo the texture each time. (Plus, I love GLSL… working with vectors is buttery smooth).
Lastly, there are the shadows. The ones I created are totally brute-force method. I am basically just redrawing the snake but making the y value always be 0.0f. Basically, each snake has an infinitely thin flat-shaded twin. Again, a totally ridiculous way to do it but it works well enough for now.
The problem here is simple. If I tried to do shadows ‘correctly’, I would need to take a couple weeks off from the project to research latest methodologies, check to see if my graphics card can support the newest executions, then probably learn a ton of matrix math and knowing my luck, evil QUATERNIONS too, before I can attempt to make it work with code which would most likely give me a migraine. If I take the time to learn how to do it the proper way, I lose motivation to work on it at all. If I stick with creating solutions using the knowledge I already have, I risk enforcing bad habits as well as creating code which runs far from optimally.
The eternal struggle.
7 comments
I'm a fraction of a decimal closer to understanding this amazing stuff you do.
Any chance you will let us peek under the covers and play with some of that source code ?