fish link
Figure 2: The final movie clip is provided here to give you an impression of what we want to achieve. Note that this is a pre-rendered animation, though the entire system actually runs in real time within Maya.

The following table shows an example of a few control parameters that are desired for the system:

Group Behavioral Control System

Parameter Name

Functions

Group

Start Position

Random starting position

Number

User input's number of fish

Individual

Height

Individual fish's jump height

Speed

Individual fish's speed

Direction

Individual fish's direction

Tweaking

Individual fish's body twisting when in air

Advanced Control

Collision Avoidance

Collision avoidance of individual fish

Splashing

Splashes of water as a fish enters and leaves the water surface

 

The Tools

Alias Wavefront's Maya is one of the most complete tools available, capable of providing users and developers with the power to do animation and game productions, from prototyping to the final delivery. The strength of Maya lies in its innovative workflow and user interface as well as its custom scripting capability. The scripting language MEL provides a good basement for users to quickly test out their ideas and methods. The ability to implement custom codes is a crucial flexibility, a fact that, unfortunately, many other software and tool vendors failed to see, instead electing to bury the flexibility deep in their program codes.

In addition to MEL, Maya also provides a good API library that allows you to implement your system as a plug-in using C++ codes. A plug-in implementation runs at least several times faster than the MEL script implementation. Best of all, the API comes with standard Maya software, and does not cost the user an extra cent.

Mathematics for the movement

The main part of this system lies in the jumping motion of the fish. To recall, a typical trajectory path can be described using a simple mathematical equation:

S = ut + ½ at2

where

S is the displacement of the object

u is the initial velocity of the object

t is the time of flight

and a is the acceleration, which in this case is the force of gravity.

Assuming that the air resistance is negligible, this equation is appropriate to model the movement of the fish in the air, with S and u being vector quantities. Since MEL provides a complete set of vector functions, you will be able to implement this equation easily.

Looking at the above trajectory function, however, you may realize that it could turn out to be quite complex and troublesome when you need to build in all the controls for the motion of the fish. What determines whether a function is useful or appropriate in modeling a system is not merely its accuracy in producing real-world results, but also the ease of implementation and its flexibility. In the entertainment production environment, realistic simulation is something that is great to have, but flexibility and extensibility of the functions always take precedence.

An alternative to the trajectory functions is the very simple and versatile trigonometry functions, sine and cosine. Some of you may realize that sine and cosine functions are some of the easiest to use and most versatile building blocks of many wonderful algorithms. In this case, using the frequency, amplitude, and the phase components of the sine and cosine functions, along with some modification and appropriate changes in values, you are able to create variable control for the speed and height control of the animation. And with the help of some random functions and simple vector manipulation, a rather convincing and simple control system is created.

The MEL codes shown in Listing 1 illustrate an example of the result that you could attain by expanding on the above discussion.

Listing 1: Sample MEL codes to implement a group behavioral control system.

float $t = time;
float $speed_ctrl;

int $num; // number of fish

vector $position_start;

float $current_t;
string $object = "fish";
$num = 6;

for ($i = 1; $i <= $num; $i++)
{
// Initial position
//

if (frame == 1)
{
$position_start= abs (sphrand (<<float ($num),0.0,float ($num)>>));
$speed_ctrl= rand(3.0,4.0);
$height_ctrl= rand(1.5,1.5);
$current_t= <<locator1.translateX, 0.0, locator1.translateZ>>;
}

// Direction control
//

int $lowest_point = 141.37167/$speed_ctrl;
int $cycle = 188.49556/$speed_ctrl;

if (((frame + $cycle)%($cycle)) == $lowest_point)
{
$heading= <<locator1.translateX, 0.0, locator1.translateZ>>;
float $temp3x;
float $temp3z;
vector $temp_heading;

$temp3x = getAttr ($object + $i + ".translateX");
$temp3z = getAttr ($object + $i + ".translateZ");
$current_t= time;
$temp_heading = $heading- <<$temp3x, 0.0, $temp3z>>;
$heading= $temp_heading;
$position_start= <<$temp3x,0.0,$temp3z>>;
}

// Position control
//

vector $temp;
float $posx, $posy, $posz;
$temp = $position_start;
$posx = $temp.x + ($t-$current_t)*$temp2.x*0.15;

$posy = $temp.y + ($height_ctrl*time));
$posz = $temp.z + ($t-$current_t)*$temp2.z*0.15;

setAttr ($object + $i + ".translateX") $posx;
setAttr ($object + $i + ".translateY") $posy;
setAttr ($object + $i + ".translateZ") $posz;

// Rotation control
//

float $rotz;
$rotz = -90+50*cos($speed_ctrl*time);
setAttr ($object + $i + ".rotateZ") $rotz;

// Further Rotation control
//

float $roty;
float $RTOD = 57.29578;
float $theta;

$theta = $RTOD*angle(<<1.0,0.0,0.0>>,$temp2);
$normal = cross(<<1.0,0.0,0.0>>,$temp2);

if ($normal.y > 0.0)
$roty = $theta;

else
$roty = (360-$theta);

setAttr ($object + $i + ".rotateY") $roty;

}


The Individual Model