2019-06-01 22:22 - Technical
Shader: Elephants on Parade (Dumbo)
I got the idea for this shader while talking to colleagues about ShaderToy. I wanted to re-create the whole sequence but that’s too much work and very redundant (and it would probably require too much memory for a single ShaderToy entry). So I decided to create just this single shot.
A few technical details
The difficulty of this shader is to display the animated shape of the elephants. Moving the elephants and adding colors is quite easy once this is done. To display the shape, I used cubic Bézier curves. Deciding if a point belongs to the shape is hard to do efficiently (efficiently enough to calculate that for every pixel in less than 16ms), but I managed to do it in a reasonable time with the following technique: I choose a point outside the shape, and count the number of intersections between the line that links this point to a pixel and the polygon that approximates the shape. If this number is odd the point is inside the shape.
To animate these Bézier curves, I used Catmull-Rom splines to interpolate the control points of the Bézier curves in time. Adding a dimension to the Bézier curves is technically possible, but it’s not easy to create a good-looking animation with that technique. Using Catmull-Rom splines results in smooth curves without specifying explicitely control points. I created 4 frames and the interpolation does the rest of the work. The interpolation is always made on the same 4 points but in a rotating order. I must say I was positively surprised with the result.
The last step is the compression of this data. Storing naively each point with 2 32-bit floatin-point numbers costs 8 bytes per point. But by using bitwise operations I managed to store 2 points per 32-byte integer, which is 2 bytes per point (4 times less than the naive method). I could store the complete animation in an array of 216 integers.
If you want to check the code of this shader, the vector graphics or the script used to compress the svg files in an integer array, you can the repo that I created on GitHub.
Where to see the animation
It’s there if you have a recent enough GPU.
Conclusion
The shader would be quite easy to create with the traditional graphic pipeline but it’s quite an interesting challenge to do it in a single fragment shader.