Blog of Rob Galanakis (@robgalanakis)

Shader-Driven Animation

DOWNLOAD SAMPLE FILES

Instructions: Folder should be extracted to C:\ . The .max file (3dsmax 9 and up) needs to find the .fx file when it loads (it will look for “C:\robg3d_shaderDrivenAnimation\robg3d_shaderDrivenAnimation.fx“, or all the parameters on the rig will be broken (they should be grayed out in the material editor). File may take a few moments to load.

Overview

Shader-driven animation (SDA) is essentially a stripped-down version of skeletal animation performed in the vertex shader. For skeletal animation, every bone needs to be transformed on the CPU, and a 4×3 transformation matrix is passed into the vertex shader. SDA was developed on the premise of two common performance realities: first, games are usually CPU bound. In this case, we want to off load as much as possible from the CPU on to the GPU. Second, vertex shaders usually have so much less to do than pixel shaders, and they sit idle much of the time. It makes sense, then, to offload as much work as possible from the CPU into the vertex shader. This was done very effectively with hardware skinning and morph targets, and also by geometry instancing, but even more CPU time can be saved by using SDA in applicable cases.

Shader-driven animation uses static shader constants to represent what would normally be more complex bone transform data. For our example, let us consider a bird. We would need a bone for the root, tail, head, shoulder, upper wing, and lower wing (the last three duplicated for each wing). This is a total of 108 constants, or 9 bones, for something as simple as an ambient bird that must maintain fidelity. By using SDA, we can reduce this down to just 17 constants, with the ability to use more or less (which corresponds to more or less animation fidelity), which is enough for almost any aerial situation, as the attached sample demonstrates.

SDA is more than a single algorithm, it is a methodology. The downside to using it stems from that truth, as well: It requires a bit of setup time with a specialized shader and a rig. However, this setup time is relatively short and once a user is familiar with SDA, should take no more than a couple hours for a complete setup.

In the Vertex Shader

So, how does SDA work? There are two components. First, is the ‘stripping down’ of the bone transform information. Instead of an XYZ position, we simply pass in whatever component of XYZ we need: for a snake, one only needs the front-back component (Z), and for the wings of a bird, only the side-to-side (X) component. Likewise, we do not need XYZ Euler or Quaternion rotation information for every bone: bones with one axis of rotation (elbow, knee) only need one rotation value. Also important to note is that all these transforms are in object, as opposed to parent, space. Once we have these components (the placement of the pivot and the amount to rotate), we transform the bones in the vertex shader using custom 2D or 3D rotation functions.

Finally, we have the issue of vertex weighting. Since we are not using skinning, we cannot use skin weighting- instead, we use vertex colors. This is very scalable, as we can include mutliple color channels, or even paint in ‘custom attributes’ per vertex in a DCC tool. The latter solution requires more setup work, but the gains may be worth it if SDA is used often or for complex skeletons, as it allows arbitrary complexity.

In the case of our bird, two facts create two shortcuts we can take. First, the skeleton and motion is symmetrical along an axis. This means we can mirror needed constants, and their motion (such as the wings). Second, no verts on the wings will cross the line of symmetry. This allows us to use the same vertex color/weighting but control which ‘side’ of the rig it responds to based on its -/+ position along the symmetrical axis.

In the DCC Tool

SDA’s implementation requires some sort of rig for practical use/animation. The controls of the rig are exactly what an animation would use for skeletal animation, but the parameters of the controls are piped directly into the shader, instead of controlling bones which then are passed into the shader (well not in the case of DCC tools that don’t support hardware skinning, but regardless).

Animation also requires a custom exporter, a sample of which is included in the SDA sample files. ‘Static’ constants are passed in and do not change, while a track is created for each animating parameter.

Ultimately, animation creation with SDA is identical as for skeletal animation, except for export is handled differently.

Advantages and Implementation

SDA is a unique solution and ultimately will see minor use. The special-casing required for effective SDA is prohibitive, but the future may see a much more flexible implementation perhaps handled through shader scripting.

That said, for those unique solutions that warrant it, SDA provides a few distinct advantages. First is speed: comprehensive tests need to be done for a better comparison, but the number of constants is directly controllable and not innately tied to the number of bones. For full XYZ rotation the advantages is negated, but for joints that rotate in just one or two axis, the transforms that otherwise wouldn’t be used are never taken into consideration. So instead of having to set up a 4×3 matrix for each bone, even if it only can rotate in one direction, we can just pass in between two and four floats (one to three for its position, and one for rotation amount along a pre-established axis).

Second advantage, and related to the above, is easier dynamic control of the animation. This, however, also requires some degree of special casing (though the potential does exist for flexibility with more research). Potentially, we could create entire cyclic animations, such as a bird flapping its wings or a snake slithering along the ground, entirely procedurally in the vertex shader. We can also easily modify the animation by controlling it with the application. It may control the position of the bird entity, and its speed of movement. For realistic motion, as our bird flies faster we want it to beat its wings more quickly. This is a CPU operation that requires adjusting animation. With SDA, we can do it directly in the vertex shader, by making the rotation of the bird wings a function of time with speed as a multiplier.

Conclusion

As mentioned above, the special-casing SDA requires makes it an interesting novelty at this time. It lacks the robustness and some of the fidelity of skeletal animation. At the very least, I hope the idea and the code has sparked some ideas of your own, and I look forward to seeing your scenes of a hundred thousand un-instanced birds flocking.

Leave a Reply