After Effects Expressions 

  

 

Focal Press After Effects Books
View all of our After Effects titles

Free Tutorials
Track mattes, grouping, layer control and more

Free Chapter Download
CS4 update for Creating Motion Graphics with After Effects, Vol.4

             







 

After Effects Expressions  

After Effects Expressions
By Marcus Geduld


USD: $49.95
GBP: £24.99
EUR: €36.95

Buy Now

Physical Simulations

from Chapter 9 of After Effects Expressions

By Marcus Geduld

With Expressions, you can easily animate bounces, jiggles, and bumps. In this chapter, that’s just what we’ll be doing. Most of the Expressions here build on concepts I’ve already explained, such as sine and cosine. I won’t repeat those explanations here. Rather, I’ll show you how to set up the Expressions, note key details, and suggest a few variations you can try.

In the following Expressions, I’ll list variables at the top, followed by a double space, followed by code that uses the variables. The top variables are for you to play with. Please have fun changing their values, previewing, and watching how your new values alter the way the Expressions work. 

Note: In some cases, I've converted the Expressions to keyframes. I've done this just to make the illustrations in this book clearer. With keyframes, you can see motion paths in the Comp window.

ORBITS

  • Example Comp: Chapter09.aep, Comp1.
  • Setup: Add two layers, Sun and Earth.
  • Expression on Earth’s Position:

var center  thisComp.layer("sun").transform.position;var distanceX 100; var distanceY 150; var orbitSpeed 2; center [Math.sin(orbitSpeed * time)*distanceX, �Math.cos(orbitSpeed * time)*distanceY];

http://i277.photobucket.com/albums/kk43/focalpress1986/StringMan_img1.jpg

http://i277.photobucket.com/albums/kk43/focalpress1986/StringMan_img1.jpg 

http://i277.photobucket.com/albums/kk43/focalpress1986/StringMan_img1.jpg 

http://i277.photobucket.com/albums/kk43/focalpress1986/StringMan_img1.jpg

Note: If you want Earth to rotate in a perfect circle (instead of an ellipse), set distanceX and distanceY to the same value.

Originally, I called one of the variables “speed”. That confused After Effects, because there’s a built-in property called “speed”. This means “speed” is a reserved word. You shouldn’t use it as a variable name. Same with “velocity ”. That’s why I used “orbitSpeed” instead.

 Variations:

1. [Chapter09.aep, Comp1a] For a “drunk” effect (maybe useful for a bee buzzing around a fl ower), add randomness to the orbit:

var centerX = thisComp.layer( " sun " ).transform.

position[0];

var centerY = thisComp.layer( " sun " ).transform.

position[1];

var distanceX = 100;

var distanceY = 150;

var orbitSpeed = 2;

var randomMax = 10;

[centerX , centerY] + [Math.sin(orbitSpeed * time)

*distanceX, Math.cos(orbitSpeed * time)*distanceY] +

random([randomMax, randomMax]);

http://i277.photobucket.com/albums/kk43/focalpress1986/StringMan_img1.jpg

2. [Chapter09.aep, Comp1b] Or, you can try a spiral:

var pivotX = thisComp.layer( " sun " ).transform.

position[0];

var pivotY = thisComp.layer( " sun" ).transform.

position[1];

var distanceX = 200;

var distanceY = 250;

var orbitSpeed = 2;

var spiralSpeed = 2;

distanceX distanceX - (time * spiralSpeed);

if (distanceX < 0) distanceX = 0;

distanceY = distanceY - (time * spiralSpeed);

if (distanceY 0) distanceY 0;

[pivotX , pivotY] + [Math.sin(orbitSpeed * time)

*distanceX, -Math.cos(orbitSpeed * time)*

distanceY]

http://i277.photobucket.com/albums/kk43/focalpress1986/StringMan_img1.jpg

http://i277.photobucket.com/albums/kk43/focalpress1986/StringMan_img1.jpg

http://i277.photobucket.com/albums/kk43/focalpress1986/StringMan_img1.jpg 

http://i277.photobucket.com/albums/kk43/focalpress1986/StringMan_img1.jpg 

BOUNCES

 Example Comp: Chapter09.aep, Comp2.

 Setup: Add two layers, ball and fl oor. Position the ball so that it’s resting on the floor.

 Expression on Ball’s Position:

var bouncesPerSecond = 1.5;

var bounceStrength = 200;

var decayRate = .5;

var floor = thisComp.layer( " floor " ).transform.

position[1];

var bounceOffset = Math.abs(Math.cos(bouncesPerSecond

* time * 2 * Math.PI));

var y = bounceStrength * bounceOffset/Math.exp(decay

Rate * time);

floor = floor - (height/2);

[position[0], floor] - [0,y]

http://i277.photobucket.com/albums/kk43/focalpress1986/StringMan_img1.jpg

http://i277.photobucket.com/albums/kk43/focalpress1986/StringMan_img1.jpg 

http://i277.photobucket.com/albums/kk43/focalpress1986/StringMan_img1.jpg  

http://i277.photobucket.com/albums/kk43/focalpress1986/StringMan_img1.jpg 

 

Note: As you may recall, Math.cos( ) generates values between 1 and negative -1. By wrapping a cosine inside Math.abs( ), we guarantee the resulting value will be positive. This means that instead of generating numbers between 1 and -1, we’ll be generating numbers between 1 and 0. So bounceStrength (the full height of the bounce) will either be multiplied by 1 (in which case the ball will be as far above the fl oor as it can get), 0 (in which case the ball will be on the fl oor) or somewhere in between.

 Variations:

1. [Chapter09.aep, Comp2a] Keyframe-animate the ball moving from left to right (or right to left) so it travels horizontally while it bounces up and down.

http://i277.photobucket.com/albums/kk43/focalpress1986/StringMan_img1.jpg

http://i277.photobucket.com/albums/kk43/focalpress1986/StringMan_img1.jpg

http://i277.photobucket.com/albums/kk43/focalpress1986/StringMan_img1.jpg 

http://i277.photobucket.com/albums/kk43/focalpress1986/StringMan_img1.jpg 

2. [Chapter09.aep, Comp2b] Animate the ball’s X position within the Expression, so that it naturally stops traveling horizontally when it stops bouncing:

var bouncesPerSecond = 1.5;

var bounceStrength = 200;

var decayRate = .5;

var floor = thisComp.layer( " floor " ).transform.

position[1];

var startX = 100;

var endX = 600;

var bounceOffset = Math.abs(Math.cos(bouncesPerSecond

* time * 2 * Math.PI));

var y = bounceStrength * bounceOffset/Math.

exp(decayRate * time);

var x = ((endX-startX) - (endX-startX)/Math.

exp(decayRate * time)) + startX;

floor floor - (height/2);

[x, floor] - [0,y]

http://i277.photobucket.com/albums/kk43/focalpress1986/StringMan_img1.jpg

3. [Chapter09.aep, Comp2c] Because bounce and decay calculations are based on time, they’ll get messed up if you start the ball layer later than 00;00;00;00. For instance, the decay will be too far advanced at the beginning. You can solve this problem by calculating time from the layer’s in-point, rather than from the beginning of the Comp. The Expressions language gives us the handy property inPoint, which holds the time when the layer starts:

var bouncesPerSecond = 1.5;

var bounceStrength = 200;

var decayRate = .5;

var floor = thisComp.layer( " floor " ).transform.

position[1];

var startX = 100;

var endX = 600;

var timeOffset = time - inPoint;

var bounceOffset = Math.abs(Math.cos(bouncesPerSecond *

timeOffset * 2 * Math.PI));

floor = floor - (height/2);

y = bounceStrength * bounceOffset/Math.exp(decayRate *

timeOffset);

x = ((endX-startX) (endX-startX)/Math.exp(decayRate *

timeOffset)) + startX;

[x, floor] - [0,y]

http://i277.photobucket.com/albums/kk43/focalpress1986/StringMan_img1.jpg

http://i277.photobucket.com/albums/kk43/focalpress1986/StringMan_img1.jpg

http://i277.photobucket.com/albums/kk43/focalpress1986/StringMan_img1.jpg 

http://i277.photobucket.com/albums/kk43/focalpress1986/StringMan_img1.jpg

http://i277.photobucket.com/albums/kk43/focalpress1986/StringMan_img1.jpg

JIGGLES

Here’s a simple “squash and stretch ” jiggle you can add to any layer:

 Example Comp: Chapter09.aep, Comp3.

 Setup: Create a single Jello layer. Move its anchor point to its bottom edge.

 Expression on Scale:

var maxJiggleAmount= 20;

var jiggleSpeed = 15;

var decayRate = 1.2;

var x = transform.scale[0] maxJiggleAmount * Math.

sin(jiggleSpeed * time)/Math.exp(decayRate * time);

var y = transform.scale[0] * scale[1]/x;

[x,y] 

http://i277.photobucket.com/albums/kk43/focalpress1986/StringMan_img1.jpg

http://i277.photobucket.com/albums/kk43/focalpress1986/StringMan_img1.jpg

http://i277.photobucket.com/albums/kk43/focalpress1986/StringMan_img1.jpg

 Variation:

[Chapter09.aep, Comp3a] As with bouncing, you may want to replace all timebased calculations with ones based on the layer’s in-point:

var maxJiggleAmount = 20;

var jiggleSpeed = 15;

var decayRate = 1.2;

var timeOffset = time - inPoint;

var x = transform.scale[0] + maxJiggleAmount * Math.

sin(jiggleSpeed * timeOffset)/Math.exp(decayRate * timeOffset);

var y = transform.scale[0] * scale[1]/x;

[x,y]

BOUNCE AND JIGGLE

When balls bounce, they squash as they hit the fl oor. The amount they squash depends on the hardness of the ball and the fl oor and how fast the ball is traveling. It’s a bit tricky to forge a bounce/jiggle Expression, because you don’t want the ball to jiggle until it hits the fl oor. If you just add the jiggle Expression (shown earlier), the ball will jiggle as it’s falling, before it hits the fl oor, and that will look odd. Here’s a bounce-jiggle Expression I stole from Dan Ebberts’s endlessly useful site, www.motionscript.com . Combine it with the bounce Expression from earlier in this chapter, and you’ll get a highly realistic simulation:

 Example Comp: Chapter09.aep, Comp4.

 Setup: Once again, a ball and a fl oor—the ball resting on the fl oor.

 Expression on Ball’s Position:

var bouncesPerSecond = 1.5;

var bounceStrength = 200;

var decayRate = .5;

var floor = thisComp.layer( " floor " ).transform.position[1];

var startX = 100;

var endX = 600;

var bounceOffset = Math.abs(Math.cos(bouncesPerSecond *

time * 2 * Math.PI));

var y = bounceStrength * bounceOffset/Math.exp(decayRate *

time);

var x = ((endX-startX) + (endX-startX)/Math.exp(decay

Rate * time)) + startX;

floor floor - (height/2);

[x, floor] - [0,y]

 Expression on Ball’s Scale:

var freq = 1.5; // make sure this matches

bouncesPerSecond, above

var squashFreq = 4.0;

var decay = 5.0;

var masterDecay = 0.4;

var amplitude = 25;

delay = 1/(freq*4);

if (time > delay)

{

bounce = Math.sin(squashFreq*time*2*Math.PI);

bounceDecay = Math.exp(decay*((time

delay)%(freq/2)));

overallDecay = Math.exp(masterDecay*(time delay));

x scale = [0] + amplitude*bounce/bounceDecay/

overallDecay;

y = scale[0]*scale[1]/x;

[x,y]

}

else

{

scale

}

http://i277.photobucket.com/albums/kk43/focalpress1986/StringMan_img1.jpg

http://i277.photobucket.com/albums/kk43/focalpress1986/StringMan_img1.jpg

http://i277.photobucket.com/albums/kk43/focalpress1986/StringMan_img1.jpg

SWAYS AND UNDULATIONS

Let’s say you want to simulate a boat riding on a wave or a rubber ducky bobbing up and down in a tub. The following Expressions are great for gentle swaying motions:

 Example Comp: Chapter09.aep, Comp5.

 Setup: One layer, a boat.

 Expression on Position:

var waveHeight = 30;

var wavesPerSecond = .3;

var waveSpeed = 150;

var wavelength = waveSpeed/wavesPerSecond;

var xOffset = ((transform.position[0] % wavelength)/

wavelength) * 2 *

Math.PI;

var y = waveHeight * Math.sin(2 * Math.PI * wavesPer

Second * time + xOffset);

transform.position + [0,y]

 Expression on Rotation:

var wavesPerSecond = .3;

var waveSpeed = 150;

var damping = 15;

var wavelength = waveSpeed/wavesPerSecond;

var xOffset = ((transform.position[0] % wavelength)/

wavelength) * 2 * Math.PI;

var rotationAmount = Math.atan(Math.cos(2 * Math.PI *

wavesPerSecond * time + xOffset));

radiansToDegrees(rotationAmount)/damping;

http://i277.photobucket.com/albums/kk43/focalpress1986/StringMan_img1.jpg http://i277.photobucket.com/albums/kk43/focalpress1986/StringMan_img1.jpg 

 http://i277.photobucket.com/albums/kk43/focalpress1986/StringMan_img1.jpg http://i277.photobucket.com/albums/kk43/focalpress1986/StringMan_img1.jpg 

http://i277.photobucket.com/albums/kk43/focalpress1986/StringMan_img1.jpg http://i277.photobucket.com/albums/kk43/focalpress1986/StringMan_img1.jpg 

Note the variable xOffset in both Expressions. It’s calculated using the layer’s original x-position value. This allows variations, as follows:

 Variations:

1. [Chapter09.aep, Comp5a] Duplicate the boat three times, dragging each duplicate to a different horizontal position. Because the xOffset calculation takes each layer’s x position into account, each layer will realistically ride a different part of the wave.

http://i277.photobucket.com/albums/kk43/focalpress1986/StringMan_img1.jpg

http://i277.photobucket.com/albums/kk43/focalpress1986/StringMan_img1.jpg 

http://i277.photobucket.com/albums/kk43/focalpress1986/StringMan_img1.jpg 

2. [Chapter09.aep, Comp5b] It would be nice to see the wave, wouldn’t it? You can create three wave layers, positioning each one below a different boat. Make sure the waves slightly overlap their boats’ bottoms, covering just a bit of each boat, so it looks like the boats are in the water. Finally, parent each wave to its boat, so the boat is the parent and the wave is the child.

http://i277.photobucket.com/albums/kk43/focalpress1986/StringMan_img1.jpg

http://i277.photobucket.com/albums/kk43/focalpress1986/StringMan_img1.jpg

http://i277.photobucket.com/albums/kk43/focalpress1986/StringMan_img1.jpg

http://i277.photobucket.com/albums/kk43/focalpress1986/StringMan_img1.jpg 

3. [Chapter09.aep, Comp5c] The same technique works equally well with a sea monster. Instead of boats, you can use upside-down, U-shaped, neck segments. In the example, the head is an embedded Comp [Chapter09.aep, MonsterHead]. The eyes and mouth are randomized via Expressions you’ve seen in earlier chapters.

http://i277.photobucket.com/albums/kk43/focalpress1986/StringMan_img1.jpg http://i277.photobucket.com/albums/kk43/focalpress1986/StringMan_img1.jpg

http://i277.photobucket.com/albums/kk43/focalpress1986/StringMan_img1.jpg http://i277.photobucket.com/albums/kk43/focalpress1986/StringMan_img1.jpg

COLLISION DETECTION

If you want to know if two circular layers are colliding, you need to fi rst calculate how close they can get to one another without touching. This is actually pretty simple: You fi nd the widths of both circles, add them together, and divide by 2.

Here’s a little function that does just that, returning true if the circles are colliding and false if they’re not:

function circleCollisionTest(circle1,circle2)

{

var minDistance - (circle1.width + circle2.width)/2;

if (length(circle1.position, circle2.position)

minDistance)

{

return true;

}

else

{

return false;

}

}

I decided to use this function in a Comp with fi ve circles all milling about at

random. If any two circles touch, I want their opacity to dim to 50%. Here’s

the solution:

 Example Comp: Chapter09.aep, Comp6.

 Setup: Create one circular layer, adding a wiggle() Expression to its Position property. I used wiggle(1,400).

After adding the following Expression to the layer’s Opacity property, duplicate the layer four times. (Make sure you duplicate the layer after typing the Expression so that all the duplicates have copies of it on their Opacity properties.)

 Expression on Opacity:

var myOpacity - transform.opacity;

var totalLayers - thisComp.numLayers;

var otherLayer;

function circleCollisionTest(circle1,circle2)

{

var minDistance - (circle1.width + circle2.width)/2;

if (length(circle1.position, circle2.position) <-

minDistance)

{

return true;

}

else

{

return false;

}

}

for (var i - 1; i totalLayers; i + + )

{

if (i !- index)

{

otherLayer - thisComp.layer(i);

if (circleCollisionTest(thisLayer, otherLayer) - -

true)

{

myOpacity - 50;

break;

}

}

}

myOpacity

http://i277.photobucket.com/albums/kk43/focalpress1986/StringMan_img1.jpg http://i277.photobucket.com/albums/kk43/focalpress1986/StringMan_img1.jpg

http://i277.photobucket.com/albums/kk43/focalpress1986/StringMan_img1.jpg http://i277.photobucket.com/albums/kk43/focalpress1986/StringMan_img1.jpg 

Note: The Expression loops through all layers, doing nothing when the loop hits the current layer. (It would be stupid to test if a layer is colliding with itself.)

The loop potentially calls the circleCollisionTest() function once for each other layer. But the “break” statement stops the loop after circleCollisionTest() detects a collision. After all, if circle A is colliding with circle B, who cares whether or not it’s also colliding with circle C. If it’s colliding with any other circle, I want to dim its opacity.

By the way, the word “thisLayer ” in circleCollisionTest (thisLayer, otherLayer) is a special property that’s built into the Expressions language. It means “this layer ”— the layer that the Expression is on. So each time through the loop, I’m testing to see if the layer with the Expression is colliding with one of the other layers.

Actually, all layers have a copy of the Expression. Each layer thinks of “thisLayer ” as itself, the same way that you and I can both say “me” and mean ourselves. Each layer tests to see if itself (thisLayer) is colliding with the other layers:

 Variation:

Of course, not all layers are circular. Testing collisions between irregularly shaped layers is possible but not easy. Luckily, Dan Ebberts comes to the rescue again. This time, I won’t give you his code here. Part of becoming an Expressions master involves venturing out onto the wild, wild Web and finding other people’s Expressions. But I’ll give you a hint: www.motionscript.com/ design-guide/collision.html.

Dan’s site will get you started as you stretch your imagination and skill set beyond what I’ve shown you in this book. But if you’re interested in physical simulations, the sky is the limit. You can get as involved as you want. At some point, should you want to go beyond the basics, you’ll need to learn some trigonometry and physics.

I recommend Keith Peters’s book, Actionscript Animation. It was written for Flash developers, but Flash’s language (Actionscript) is an offshoot of JavaScript. You’ll feel a bit like an American reading a British novel—sometimes you’ll have to  translate pounds to dollars, but the basic concepts are the same. And maybe Peters will suck you into the world of Flash. If you enjoy making animations with code, After Effects is a good launching pad, but Flash is your home planet. But no matter what planet you’re from, JavaScript is the universal language.

For more Expressions, check out these sites:

http://forums.creativecow.net/forum/adobe_after_effects_expressions

http://www.mographwiki.net/After_Effects_expressions_library

http://aenhancers.com /

http://www.colinbraley.com/tutorials.html

Lightroom_bottom