The goal of my technical piece was to dynamically generate realistic snake or worm-like motion. My implementation was based on Gavin Miller's 1988 SIGGRAPH paper, "The Motion Dynamics of Snakes and Worms". At the center of the simulation is a mass-spring system driven by a travelling sine-wave and directional friction (described below). Since the goal is to reproduce the behavior of a living organism and not a rigid object, a spring constant of 0.5 - 3.5 is used and equations are non-stiff.
The Lattice
In this paper, a series of connected cubes was used as an abstraction to a snake. Each cube is a segment of the snake, with masses at each corner and springs along each edge and face-diagonal. There are no springs internal to any cube, and neighboring cube share a face (the back of one is the front of the next). This results in three types of springs:
Generating Motion - The traveling sine-wave
To simulate muscle contractions along the length of the snake's body, the natural spring length of axial springs is varied via a traveling sine-wave. The length of a given spring is determined by 1. the spring's position along the length of the body and 2. the current time of the simulation. In my implementation, I varied spring lengths by 70% (30% - 170%), had 4*pi for a position-based period along the length of the snake's body, and a time-based period of 2*pi for every 14 seconds.
If the traveling sine-wave was the only source of friction, the snake would oscillate in-place but never actually move anywhere. To rectify this, friction between the snake's lower scales and the ground is simulated. For every mass in the snake a "spinal vector" is the unit vector between the two masses in front of and behind the current mass. If the dot product of the spinal and velocity vectors is less than zero, the new velocity is V = V - S*s. V is the velocity vector, S is the unit spinal vector, and s is the dot product between the velocity and unit spinal vector. This modifies any motion which would move the snake backwards in a direction orthogonal to the unit spinal vector.
Varieties of MotionThere are four basic types of motion, two of which my implementation can do. The first is trivial, "Rectilinear Progression". Following the travelling sine-wave, parts of the snake/worm's body are contracting axially while others are expanding. A more interesting motion, and my focus, is "Horizontal Undulatory Progression". This is the familiar wave-like motion associated with snakes, and it is produced by placing a 180-degree phase difference between the axial springs on the left and right side of the snake's body. When expanding the simulation to generate this motion, the sine-wave's period over time and the snake's body is important. High-frequencies will result in little motion, while low-frequencies can shear the snake apart.
ProblemsThe greatest hiderance to implementing this paper is the lack of numerical data. The spring constants and dampening forces are given for catepillars, worms, and snakes (0.5 and 3.5, respectively for snakes); however, the mass and segment-length for the lattice is not given, nor are the amplitude and frequency for the sine-wave. I chose 0.2 for the mass and 1.0 for the default segment-lengths, which resulting in good motion, but roughly equates to a 40lbs, 20 meter snake. Since masses are not allowed to penetrate the ground, and axial compression generates an upward force from the diagonal springs, gravity is necessary to keep the snake from floating or rolling along the ground. However, gravitational force is mass-dependent, while spring forces are not. I was unable to find an adequate mass to balance these forces to prevent the snake from floating or collapsing while still moving.
Integrating the generated motion into Maya was done by placing a joint at the midpoint of every front-face of every segment. This results in (n+1) nodes for each frame of animation, where 'n' is the number of segments. Below is a screenshot of the generated skeleton.
Make a plugin! The simulation will need to be restarted if any of the parameters is changed, and this would seem to favor a plugin over regenerating and running MEL scripts (although I've never made a plugin so it's hard to say for sure). This may also allow for surface generation using the mass-spring lattice as opposed to skeletal data.
Be prepared to run a fair number of simulations. Getting a good motion means getting the right number/parameters, and varying the mass and wave-frequency can produce very different results, from no motion to the snake twisting itself apart.
A trivial point, but this paper only deals with motion of the snake's body, not the head. It isn't noticable until the skeletal data is attached to a snake model, but a snakes head remains fairly motionless while the snake is moving.