You are on page 1of 17



Simulating Swimming Creatures Using Mass-Spring Systems Bhavna Mahadevan, Chris Wojtan, and Greg Turk College of Computing Georgia Institute of Technology July 28, 2010

MASS-SPRING SWIMMING CREATURES Abstract This project uses angular springs in addition to linear springs to provide a large range of realistic


motion caused by the lifelike movement of a simple model of a swimming creature (for example, a swinging tail or contracting tentacles). This model is represented by several mass points, which are connected by linear springs, and advance via numerical integration. These linear springs are moved by angular springs, and this coupled with the application of a drag force combine to simulate independent motion of a simple swimming creature in a fluid. The simulation of swimming creatures using a mass-spring system such as the one in this project can be adapted for use in the film industry and in the video game industry. Plausible simulation has biological applications as far as study of animal behavior, as well as mechanical applications in the construction of robots able to move in an underwater environment. Keywords: mass-spring system, angular spring, swimming

MASS-SPRING SWIMMING CREATURES Simulating Swimming Creatures Using Mass-Spring Systems The motion of a swimming creature is different from the quadrupedal movement of a wolf or the two-legged locomotion of a human on land. Underwater motion involves the tensing and relaxing of muscles in order to swing the creature's appendages and propel it forward. The obvious benefits of this kind of simulation lie in computer graphics; specifically, in the entertainment industry—the portrayal of realistic, visually interesting creatures is key to the success of video games and films like Finding Nemo and Shark Tale. On a broader level, the simulation of swimming creatures teaches us about different swimming styles which can in turn Image 1: Disney Pixar, Finding Nemo give us more insight into the biology of swimming creatures (i.e. the creatures'


physiology, behavior, etc.). This simulation can also have mechanical Image 2: A Herzog, applications: for example, we might use the simulated swimming styles to Biologically Inspired Robotics Group, construct a robot capable of underwater locomotion. EPFL Thus, the problem here is the following: how to realistically simulate the motion of swimming creatures in an underwater environment? Previous research has achieved accurate simulation of the motion of swimming creatures using mass-springs systems with linear springs. In particular, work by Xiaoyuan Tu and Demetri Terzopoulos creates a fish model in three dimensions using 23 nodal point masses and 91 linear springs; the complex framework of this model maintains the structural stability of the fish while still allowing for the flexibility of the springs such that the springs may work as muscles (Tu & Terzopoulos, 1994). The goal of my project was to be able to create an interactive environment in which we could construct simple swimming creatures and simulate their motion in two dimensions.

MASS-SPRING SWIMMING CREATURES Methodology My contribution to the project was building an interactive environment in which a user could create simple swimming creatures that could move independently in the environment, and coding the equations that would allow the creature creation and motion. These equations were provided to me by my faculty advisor and graduate mentor, who also assisted in devising features for the user interface. The environment was built using Processing, an open-source, java-based programming language geared toward visual arts, because Processing is conducive to user interface design.


Figure 1

The first step after creating the environment was to implement the creation of masses ( a in Figure 1), whose positions would be advanced using numerical integration. I experimented

MASS-SPRING SWIMMING CREATURES with three different numerical integration methods which I translated from equations to code— Forward Euler Method, Midpoint Method, and Leapfrog Method. Each was tested against the others in a simple drop with the force of gravity, in order to determine which gave the most realistic result. Within the user interface, the user would need to left-click the mouse in order to add a mass. If the user clicked the “simulate” button, the mass would be affected by the force of gravity; otherwise, the user-created mass would stay in place. After I selected an integration method, the next step was to add linear springs ( b in Figure 1), which act as the limbs or muscles of the creature. Subsequent to translating the spring force equation to code, I experimented with different values of the stiffness coeffi cient, ks, and the damping coefficient,k d, to achieve a linear spring that remained stiff enough that a triangle created from springs would remain upright when affected by gravity, while also being fl exible enough that the springs would oscillate slightly as a result of impact with the fl oor of the environment. In order for the user to add a linear spring, the user would right-click on a mass, then drag to another mass and release the mouse button. While connecting masses with linear springs, represented by a black line with its midpoint marked by a red circle, the “connect” button would be highlighted in light blue. The third step, a crucial feature of this project, was to incorporate angular springs ( c in Figure 1), which change the angle between linear springs. The angular springs account for the oscillation of the limbs, which in turn gives the simulation a realistic, almost natural appearance. I first investigated different representations of angular springs in the user interface, as well as different methods of calculation of the angle between linear springs, which is used to calculate the angular spring force. Once the angular spring force calculation was implemented, I experimented with different values of k s and kd to attain an angular spring stiff enough that two


linear springs at a right angle would remain upright when affected by gravity, provided they were connected by an angular spring. To add an angular spring, the user would need to first left-click the “angular” button, the left-click and drag from the midpoint of one linear spring to another. The angular spring was represented by a red ring around the mass connecting the angular spring's endpoints. Once this goal was realized, I then added sinusoidal oscillation of the rest angle of the angular spring such that any linear springs connected by an angular spring would swing back and

MASS-SPRING SWIMMING CREATURES forth to produce forward motion. Newly-created angular springs have default values for the


amplitude, phase, and frequency of this oscillation; however, these values can be changed via the user interface, for each angular spring ( d in Figure 1). The fourth and final step was to render the drag force equation into Processing, simulating the effect of water and generating the forward motion of the creature. I experimented with different values of the drag coefficient to achieve realistic motion. This force was applied to all masses at all times. Once the drag force was in effect, gravity was removed from the simulation, as swimming creatures have natural buoyancy, which offsets the force of gravity and allows the creatures to float. Other features implemented in the user interface included a “C” button that clears the user's current mass-spring system and allows the user to start from scratch, and an “R” button that enables the user to reset the masses to their initial positions and velocities upon creation ( e in Figure 1). In addition, there are three buttons (not pictured above) used for demonstration purposes, that are pre-constructed examples of different swimming styles. Theory Numerical integration, used to advance the positions of each particle, is based on the equation F = ma, where particle i has mass m, and where the force F and the acceleration a are both vectors with x and y components. The forces on the particle are summed, and the above equation is used to find the acceleration. Then the chosen numerical integration method is used to find the new velocity, a vector as well, and from that, the new position, with x and y coordinates, of the particle, employing the previously-calculated acceleration. The numerical method I chose was the Leapfrog Method, which is as follows: vnew = vold + aΔt pnew = pold + vnewΔt (1) (2)

This method uses the previous velocity, vold, the acceleration, and the timestep, Δt, which is the time passed since the last calculation of the numerical method, to calculate the new velocity, vnew.



For this project, I used a set timestep of .1. Then vnew, Δt, and the previous position, pold , are used to calculate the new position, pnew. The theoretical equation for spring force, which is calculated for each particle connected to another particle by a spring, is Fspring = -kx, where k is the stiffness coefficient, which determines how stiff the spring is, and x is the displacement from the spring's rest length to the spring's current length. If the spring is stretched beyond the rest length, x is positive and Fspring is negative, pulling the spring back toward rest length. If the spring is compressed so that its current length is smaller than the rest length, then x is negative and F is positive, pushing the spring outward toward its rest length ( Figure 2).

Figure 2

In practice, the spring force equation requires some damping to the velocity, as the particle endpoints of the spring will have velocities of their own, and we do not want the simulation of the spring to explode (i.e. progress too fast for the program to follow). Thus, our damped equation is as follows: Fspring = -k(L – Lrest)D + kdU (3)

MASS-SPRING SWIMMING CREATURES where L is the current length, Lrest is the rest length, and D is a normalized vector connecting the endpoints of the spring, divided by its magnitude. The damping coefficient is kd, and U is the vector difference between the velocities of the endpoints of the spring.


The angle between two linear springs is calculated using the Processing function, atan2, which calculates the angle from a certain position to the origin of the coordinate system. Subtracting atan2(endpoint 2) from atan2(endpoint1), where endpoints 1 and 2 are the two protruding endpoints of the angle, gives the angle between the linear springs. Angular spring force is calculated similarly to (3). Instead of using the current length and rest length, angular spring force calculation uses the current angle and rest angle ( Figure 3), and the force is calculated for the three different endpoints of the two linear springs that the angular spring connects (one endpoint is the same for both linear springs).

Figure 3

The angular springs oscillate due to a sinusoidal variation of the rest angle; specifically: θnr = θrest + A · sin(n/T + Φ) (4)

MASS-SPRING SWIMMING CREATURES where θnr is the new rest angle, θrest is the original rest angle, A is the amplitude of the sine


function, n is time and keeps track of the global clock, T is the period of the sine function, and Φ is the phase of the sine function. The fluid model I used was a simple drag force, which was calculated per linear spring and divided equally between the endpoints of the spring. The equation for this force is as follows: Fdrag = -d(N · V)LN (5)

where Fdrag is the drag force, d is the drag coefficient, V is the average velocity of the endpoints of the spring, N is the normal (the vector perpendicular to the spring), and L is the current length of the spring. Fdrag always acts in the opposite direction of the average velocity, V. As the drag force is dependent on the normal to the spring, the orientation of the spring determines the amount of drag ( Figure 4).

Figure 4

The drag force, angular spring force, and linear spring force are calculated per particle and used to find the total force. From this, we can find the acceleration, new velocity, and new position using numerical integration. Results & Discussion The end result of my project is pictured in Figure 1. I was able to implement flexible, spring-like behavior for the linear springs, as well as periodic oscillation of the angular springs in

MASS-SPRING SWIMMING CREATURES combination with the drag force, which worked together to allow creatures constructed within the user interface to move with independent, swimming-like motion ( Figure 5).



(b) Figure 5


The linear spring force, angular spring force, and numerical integration caused the particles to behave as expected, giving realistic spring-like motion as well as advancement of particle position. An unexpected result of the angular spring force was a slight forward displacement, as the force shifted the center of mass of the construction. With the addition of the drag force, simulated creatures were able to attain realistic swimming motion, and differently-constructed creatures were able to proceed by oscillating different appendages. See Appendices A through D for code for the calculations of numerical integration, linear spring force, angular sp ring force, and drag force. Conclusion In simulating swimming creatures using mass-spring systems, I was able to successfully implement numerical integration, linear springs, angular springs, and drag force, and create a user interface in which the user could construct a creature out of springs and masses and simulate different styles of swimming motion. This project illuminated a new path to mass-spring simulation of swimming creatures for my research group, in that angular springs can now be used as a simpler and more accurate method of reproducing natural motions of swimming creatures, rather than constructing the creature entirely from linear springs. In addition, my

MASS-SPRING SWIMMING CREATURES project provided a fast and computationally inexpensive way to create realistic simulation of different swimming styles. The next step I would take from this project would be to make the simulation more


realistic. There are several ways that this can be realized. One course of action would be to adapt the project from two dimensions to three dimensions, similar to the model constructed by Tu and Terzopoulos. Another option would be to improve the accuracy of the fluid by adopting a more realistic and thus more complex fluid model, as the drag force equation I used was quite simple. A third alternative would be to improve the accuracy of the solid by adding more detail to the simulated swimming creature, such as bone, muscle, or skin. A fourth direction to take would be to control the swimming motion such that the constructed creature would swim toward a predesignated goal.

MASS-SPRING SWIMMING CREATURES References Staedter, Tracy. (2007). Salamander robot shows how swimmers walk. Discovery News.


Retrieved July 25, 2010 from . htm Tu, Xiaoyuan, Terzopoulos, Demetri. (1994). Artificial Fishes: Physics, Locomotion, Perception, Behavior. ACM SIGGRAPH, SIGGRAPH '94, 43-50.

// leapfrog numerical integration method void leapfrog(){ PVector v0 = new PVector(vel.x,vel.y); // p.vel = v0 PVector vnew = new PVector(vel.x,vel.y); PVector newacc = PVector.mult(acc,dt); //a*dt vnew.add(newacc); //vnew = v0 + a*dt float xnew = x + vnew.x*dt; //xnew = x0 + dt*v0 float ynew = y + vnew.y*dt; //ynew = y0 + dt*v0 vel=vnew; y=ynew; x=xnew; }


//spring force PVector spring_force(spring spr){ int i1=spr.index1; int i2=spr.index2; particle p1= (particle) parts.get(i1); //endpoints of spring particle p2= (particle) parts.get(i2); float distance = p1.distance(p2); //distance between endpoints //U = v2-v1 PVector U = PVector.sub(p1.vel,p2.vel); //D = (p2 - p1)/ ||p2-p1|| PVector par1 = new PVector(p1.x,p1.y); PVector par2 = new PVector(p2.x,p2.y); PVector D = PVector.sub(par2,par1); D.div(D.mag()); //F=-K(l-r)*D+kd*U, U=v2-v1 PVector spf = D; spf.mult((-1*spr.ks)*(distance-spr.len)); U.mult(spr.kd); spf.add(U); return spf; }


//angular spring force void ang_force(angular_spring ang){ // vary the temporary rest angle sinusoidally // but don't change the original rest angle float rest_angle = ang.r_ang; rest_angle+=ang.amp*sin((n/ang.per)+ang.phase); particle p1= (particle) parts.get(ang.i1); //central mass of angular spring particle p0= (particle) parts.get(ang.i0); particle p2= (particle) parts.get(ang.i2); // create vectors pointing from central mass to the other masses float dx1 = p1.x - p0.x; float dy1 = p1.y - p0.y; float dx2 = p2.x - p0.x; float dy2 = p2.y - p0.y; float len1 = sqrt (dx1*dx1 + dy1*dy1); float len2 = sqrt (dx2*dx2 + dy2*dy2); if (len1 > 0) { dx1 /= len1; dy1 /= len2; } if (len2 > 0) { dx2 /= len2; dy2 /= len2; } // calculate angle between these vectors float angle = atan2(dy1, dx1) - atan2(dy2, dx2); // find displacement angle in range [-pi,pi] float diff = angle - rest_angle; while (diff < -PI) diff += 2 * PI; while (diff > PI) diff -= 2 * PI; // calculate angular velocity float dt1 = dx1 * ((p1.vel).x - (p0.vel).x) + dy1 * ((p1.vel).y (p0.vel).y); float dt2 = dx2 * ((p2.vel).x - (p0.vel).x) + dy2 * ((p2.vel).y (p0.vel).y); float angular_velocity = dt2 - dt1; //torque is proportional to angular difference, plus damping float torque = ang.ks * diff - ang.kd * angular_velocity; // apply (p1.f).x (p1.f).y (p2.f).x (p2.f).y forces to point masses; multiply by m to get force += m*(dy1 * torque / len1); += m*(-dx1 * torque / len1); += m*(-dy2 * torque / len2); += m*(dx2 * torque / len2);


(p0.f).x += m*((-dy1/len1 + dy2/len2) * torque); (p0.f).y += m*(( dx1/len1 - dx2/len2) * torque); }


//drag force calculated per spring void dragForce(spring sp){ int i1=sp.index1; int i2=sp.index2; if (i1==i2) return; particle p1= (particle) parts.get(i1); //endpoints of spring particle p2= (particle) parts.get(i2); float l=p1.distance(p2); //l=length of spring float xd=p2.x-p1.x; float yd=p2.y-p1.y; //calculate average velocity V & normal N PVector v1=p1.vel; PVector v2=p2.vel; PVector V=PVector.add(v1,v2); V.div(2); //average velocity PVector SV=new PVector(xd,yd); //vector between endpoints of spring PVector N=new PVector(-SV.y,SV.x); //normal vector //calculate drag force: D= -d(N . V)l N float; fd*=-d*l; PVector D=PVector.mult(N,fd); //split D between 2 endpoint particles of spring and apply force D.div(2); (p1.f).add(D); (p2.f).add(D); }