That’s right, space bees! One of the new customers we are developing features a space bee as its buzzing, bumbling companion. The bee was sort of an afterthought and wasn’t even drawn in the character’s original concept, but after modeling the grumpy cactus person, I felt like he needed an adorable counterpart to offset his prickly temperament. However, since we already have a slew of unique skeletally-animated characters running around the scene at any given time, adding a bunch of bone-driven bees on top of that would start getting computationally expensive. So we went with a unique and rather unorthodox approach: animate the bee with a shader.
Shaders are cheap because they have to be. They tell the game how to draw a mesh based on accompanying images and computations that must be executed every frame, so ideally about 60 times per second. There are many attributes at a shader’s disposal, one of them being vertex offset, which tells the game where to draw each point on a model’s surface. By manipulating the positions of these points, a mesh can be animated without using a traditional skeleton or blend shape
In order to do this, I need to select the vertices I want to move and multiply their positions by a vector. Vectors consist of a direction and magnitude. Direction being some combination of X,Y, and Z and magnitude basically being the speed at which it travels in that direction. To select the vertices I use an image whose color channels correspond to a part of the mesh. The magnitude of the vector corresponds to how much of each color there is. For example, red areas of the image move the wings. The redder the area, the more the wing moves. I use green for the antennas and legs and I use blue for the eyes.
A secondary UV set is used with this image so I can define how the vertices interact without affecting the bee’s yellow and black striped texture, which lies in the primary UV set. I then move this image along the UVs, which distributes waves of magnitude across the mesh over time. The wings and especially the eyes are super tiny on the UV chart so the waves will pass over those parts of the mesh very quickly. The UV islands are separated quite a bit so even a low resolution offset image will work.
Since I want different timing and behavior in different parts of the mesh, the different colored waves are also different sizes and frequencies. For example, a bunch of little red waves close together moves the wings quickly, while longer green waves move the limbs in a lazier fashion. In addition, I use the alpha channel of this image to mask off areas of the mesh that I don’t want to move. This allows the ends of the wings to move while the base of them stays attached to the bee’s body.
So that handles the magnitude of the vectors, but what about direction? By getting the object’s position, I can create vectors that are relative to the mesh so it won’t matter how it’s rotated — the vertices will always move the same way. I get the object’s Y axis to make the wings move up and down and I combine the Y and Z axes to move the limbs up and down plus forward and back.
The eye blinking is handled a little differently. Instead of getting the object’s axis for direction, I get the direction of each point on the mesh, also known as the normal direction. Moving points along the normal direction scales the mesh to be larger or smaller. By combining the normal direction with small dispersed waves of magnitude, I quickly make the eyes shrink to mimic a blink. Finally, I grab the entire object’s Y position and multiply it by a sine wave which lets the bee bob up and down.
There are limitations though. Using 2D images to manipulate 3D objects gets more difficult and convoluted as you add more complex movement behavior. This makes rotation impossible or at least way more complicated than it’s worth. This method of animation works well if you want simple movement for a low cost. All the magnitude data is stored in a single tiny 256 x 256 image and the direction information is already available in the model itself. No skeleton, no skinning, no keyframes. And because it’s all just mesh and texture data, I can hook the bee up to a particle system and spawn a swarm of them. It’s the bee’s knees!