Beruflich Dokumente
Kultur Dokumente
http://www.jjgifford.com/expressions/basics/index.html
What Is an Expression?
An expression is a statement that produces values for a specific parameter. The simplest
expression would be just a number:
6;
Obviously, this kind of expression isnt very useful youd be much better off just setting the
parameter to 6 directly. A slightly more useful expression would be something like:
rotation;
When evaluated, this statement will return the value of rotation for the current layer at the
current time. This return value, or result, will then be used for whatever parameter the
expression is attached to. If applied to a layers opacity parameter, this expression would
make the layers opacity change in sync with its rotation: when the rotation was 30 degrees,
the opacity would be set to 30%, etc..
Expressions use the JavaScript language and syntax (an industry-standard language
commonly used for web development, and for which there are many helpful books).
Javascript includes a rich set of tools for creating more complex expressions, including, of
course, the basic math operations:
opacity*10;
This expression is slightly more sophisticated, but still very simple. Its result is the value of
opacity for the current layer at the current time, multiplied by ten. Since opacity has a range
of zero to 100, the results of this expression will range from zero to 1,000. These results will
be used for whatever parameter to which you've applied the expression.
Multi-line Expressions
Expressions can be more than one line. In fact, they could run to several hundred lines. Its a
good idea to keep them short, however, as that will make them easier to follow, and probably
quicker to execute as well.
When an expression contains more than one line, its result will be the value of the last line
evaluated. For instance, the value of the following expression:
offset=30;
ralph=rotation+offset;
ralph;
will be the value of ralph, which would be the layers current rotation plus 30 degrees, viz:
By the way, notice that each line of these expressions ends in a semicolon. You must end
every line with a semicolon, so that After Effects knows where one line ends and the next
begins. Consider it the equivalent of a period in English. Technically, the last line doesnt
need a semicolon, but because it doesnt hurt, I always put a semicolon there as well.
Youll notice that you now have a few new elements in the Timeline:
First, there is a button with an equals sign (=) to the left of the parameter name click this
to temporarily disable or re-enable this expression.
Second, the parameters value has turned red, indicating that it is driven by an expression
and can no longer be directly edited.
Third, there is a short row of three icons to the right of the parameter name, which we
discuss below.
Finally, there is the expressions text-edit field, where your expression lives and can be
edited. Notice that you can pull down the bottom of this area if you need more room for
multi-line expressions.
The first button will twirl down a graph of your expressions results in the Timeline. If your
expression affects an elements motion path, this will also change the way the path is
displayed in the Comp window, to display the post-expression results.
The second button is the Pick Whip, a tool that can help you write basic expressions. Simply
drag the whip to another parameter, and After Effects will create a live link, driving the
current parameter with values from the whip's target. I discuss the Pick Whip in greater detail
in the next section.
The third is the Expressions language pop up menu. This menu is a handy reference to all of
the After Effects-specific features in the Expression language. You can use this menu to
quickly see what objects and attributes are available to you.
NEXT
Page 1
Introduction to Expressions
Before we really focus on Expressions, we should talk a little about relationships in After
Effects in general. As far as I know, there are five main ways to establish relationships
between elements in After Effects:
Brute Force: you simply keyframe things in a way that makes them look like theyre related,
even though theres no essential connection between them. This is perhaps the most
common kind of relationship, and is extremely flexible, but can be tedious to set up and to
modify later.
Pre-composing: You can place a number of layers together in one comp, and then use that
comp as a layer in a second comp. This really acts like grouping in other programs, a way to
treat several elements as a single unit.
Parenting: New to After Effects 5.0, Parenting lets you establish hierarchical relationships
without pre-composing. In a parent-child relationship, any transformations applied to the
parent immediately cascade to the child; changes to the child do not flow upstream to the
parent, however.
Motion Math: Like Expressions, Motion Math is a simple programming environment within
After Effects. Motion Math scripts can create keyframes for your layer based on values from
another layer or property. For instance, you could use Motion Math to have one layer mimic
anothers position changes. Unfortunately, relationships created via Motion Math are
temporary, and only reflect the conditions at the time the script is executed. Afterwards,
changes to one layer will not be reflected in the other layer, unless the script is re-applied.
Expressions: Expressions are similar to Motion Math, but maintain live relationships. While
Motion Math scripts simply leave behind a set of keyframes, Expressions remain attached to
your parameter, and work alongside any existing keyframes. With Expressions, changes to
one layer may be reflected in another, long after the Expression was initially applied.
Of these types of relationships, Expressions may be the most powerful, but also can be the
toughest to create, with the least assistance from After Effects.
rotation of the green layer, while the expression-controlled layer follows only the position. It
doesnt rotate because we did not apply an expression to its rotation parameter.
This creates a live link that will drive the current parameter with values from the target
parameter. For instance, dragging the whip from opacity to rotation will create an expression
that copies values from rotation to opacity. Thereafter, animating your layers rotation will
also animate its opacity:
If you drag the pick whip to a property of another layer in the same comp, the whip will
create a slightly more complex expression, identifying which layer to copy values from. For
example:
this_comp.layer("Solid 1").opacity
This expression first identifies a composition ("this_comp"), then a particular layer within that
comp, and finally an attribute of that layer. After Effects is being very careful to specify the
right layer, and not accidentally select a "Solid 1" in some other Comp in your project. You
will become very familiar with this kind of construction, as youll use it almost every time you
refer to any layer other than the current one.
By the way, there's nothing magic about the Pick Whip. It's really not much more than a
typing assistant, automatically typing the proper 'name' for whatever item you drag it to. You
could type these names yourself, with just as good results. You also should feel free to edit
the text created by the whip, or to use the whip to create just part of a more complex
expression.
Vector vs Array
What's the difference between a vector and an array? You may notice that the AE
documentation seems to use the terms interchangeably. Simply put, a vector is an array of
numbers.
An array is just a set of individual bits of data. Arrays can contain pretty much anything you'd
like. You could create an array of objects, an array of words, or an array that held a mix:
ralph=[10, this_layer, "bob"];
I'm not sure what you'd do with an array like ralph, but it's certainly a legal array. I think
you're most likely to encounter arrays of numbers (aka vectors) in After Effects, because
other types of arrays simply are less useful.
So, in these pages, I'll use the word 'array' when I'm talking about the general concept or
operations applicable to any kind of array. I'll use 'vector' when talking specifically about
arrays of numbers.
Indexing
If you have an array, you can extract just one of its values by following the array name with
a number in brackets indicating which of the values you want, e.g.
position[0];
This process is called indexing. Note that when indexing into an array, you start counting at
zero. That is, the first value in an array is selected by [0], the second is selected by [1],
and so on.
The example above will return the first value in the position vector the x-coordinate
while Position[1] would return the second value (the y-coordinate).
This can be confusing, because everything else in After Effects starts counting at 1. Its
important to remember that indexing into arrays always starts counting at zero.
Creating Arrays
You can pack several values into an array simply by listing them in brackets, separated by
commas:
my_vector=[10,20,30];
would create a new variable named my_vector, and put in it the three values 10, 20, and 30.
my_vector[1];
would return 20, the second value in my_vector (remember that indexing into arrays starts
counting at zero).
Dimensions
The number of values in an array is called its dimension. For instance, my_vector as listed
above has a dimension of 3. Position has a dimension of 2 (or 3, for 3D layers). Properties
which take scalar values, such as rotation and opacity, have a dimension of 1. (A number or
scalar really is a 1-dimensional vector.)
Note that multi-dimensional attributes such as position, and variables youve defined to
contain arrays, dont need to have their names written in bracketsAfter Effects already
knows they are arrays. You only need to do use brackets when putting together the array's
contents the array name doesnt need to be bracketed.
To avoid this problem, you should always start out by looking up the dimension expected by
your parameter, either in the After Effects documentation or in the tables Ive put
together here. This is the dimension your expression will need to produce.
Similarly, whenever you reference another parameter in your expression, look up its
dimension in these tables or the documentation. Youll need to adjust the values coming from
these parameters to match your needed output dimension. If you have two dimensions
coming in, and can output only one, you'll need to somehow reconcile the dimension
mismatch (e.g. by ignoring one component of your incoming data).
The following table lists the dimensions for many of After Effects most common parameters,
as well as the range of values they typically accept.
Layer Parameter
Dimensions
Units
Range
Common Range
anchor_point
2* [x, y, (z)]
pixels
inf
position
2* [x, y, (z)]
pixels
inf
scale
2* [width, height,
(depth)]
percentage
inf
100
rotation
degrees
inf
0360 (periodic)
opacity
percentage
0100
0100
orientation (3D-only)
3 [x, y, z]
degrees
inf
0-360 (periodic)
audio_levels
2 [left, right]
decibels
-19224
-4812
ambient
percentage
0100
0100
diffuse
percentage
0100
0100
specular
percentage
0100
0100
shininess
percentage
0-100
0-100
Remember that the pick whip will automatically correct dimension mismatches, by indexing
into vectors or by repeating scalars, as necessary.
Ranges of Values
While the pick whip attempts to fix errors from mismatched dimensions, it does not attempt
to make your expressions results particularly meaningful or useful. Thats up to you.
In particular, you may need to adjust the range of values from an incoming parameter in
order to make them better fit your target parameter. For instance, when we earlier used
rotation to drive opacity, you may have noticed that opacity maxed out after only 100
degrees of rotation. But what if wed wanted the layer to become fully opaque only after a
complete revolution (360 degrees)? Wed need to adjust the range of incoming values to
match our needs.
An easy way to scale a range of values is to first divide by the maximum incoming value, and
then multiply by your desired maximum outgoing value. For instance, in the rotation and
opacity example mentioned above, we want to scale the rotation range of 0360 to a range
of 0100 for opacity. So wed first divide by 360, then multiply by one hundred:
rotation / 360 * 100
Opacity will now use all 360 degrees of rotation:
How does this work? Simple: by dividing by 360, we effectively compress the incoming
rotation values to a range of zero to one. When we then multiply by one hundred, the
maximum value for opacity, we expand our values back out to a range of zero to one
hundred.
We can do a lot with this simple technique. For instance, we can create a wheel, where
changes in a layer's position will drive its rotation. We simply need to scale the position
values to produce the correct rotation: 360 degrees every time the wheel travels forward one
circumference. Basically, rotation=distance/circumference*360:
So how do we know that this is the right formula? How did we arrive at the final expression?
It may seem like a pretty big leap from the opacity example above, but it really isn't.
To start out, we know that our expression is going to link changes in position to changes in
rotation that's pretty much what a wheel does. But should position drive rotation, or
should rotation drive position? Either one will work. I decided to have position drive rotation
simply because it's more fun you can drag the layer around the comp window, and watch it
rotate as though it actually were rolling.
So we want to add an expression to the layer's rotation, and know that expression will
somehow use values from the layer's position parameter. This rough beginning gives us
something like:
rotation=position*?
I've decided to make things easier by saying that our wheel will only roll horizontally. This
lets us just use the X component of the layer's position (aka 'position[0]') to calculate how far
the layer has moved: it will start at zero at the left edge of the comp, and increase as the
layer travels to the right. (Remember that AE's coordinate system starts the upper left corner
of each comp.) So now we have:
rotation=position[0]*?
We know from experience that when a wheel travels a length equal to its circumference, it
rotates one full revolution. Otherwise, it would slip against the ground. So, using the
language we used above, we'll say that the wheel's circumference is our 'maximum' incoming
value. A full revolution, or 360 degrees, is the corresponding 'maximum' output value. So we
need to divide by the circumference and multiply by 360:
rotation=position[0]/circumference*360
Of course, one circumference and one revolution aren't really 'maximum' values the wheel
could travel and rotate further. But our expression doesn't care if these values are really
maximums or not. It just uses them to build an exchange ratio to convert values from one
range to another: 360 degrees of revolution for every circumference of movement forwards.
So now we need to define 'circumference'. A circle's circumference is equal to its diameter
times PI:
We can use our layer's width as its diameter (so long as it is in fact as wide as its layer).
Javascript includes a built in, highly accurate value for PI, which we can access by writing
'Math.PI' (of course, we also could just write '3.14' and we'd be OK):
circumference=width*Math.PI;
Finally, we can delete 'rotation=' from our basic formula, because that assignment is already
implied by the fact that our expression is applied to the rotation parameter. When we put
these pieces together, we get this final expression for our wheel, applied to its rotation
parameter:
distance=position[0];
circumference=width*Math.PI;
distance/circumference*360;
I'll leave it to you to figure out how to account for changes to the wheel layer's scale. In the
meantime, try applying this in situations where layer's don't typically roll around, e.g. type:
Click here to download the project file for these animations. (Windows users click here.)
You may be wondering why I've spent so much time on this. After all, you could easily
keyframe rotation and position together, and create a realistic looking wheel. Well, that may
be true for a wheel moving forward at a constant speed, but you'd find it very difficult to
make the wheel slow down or speed up without looking like it was slipping against the
ground. Changes in acceleration like this are very tough to do manually, but are handled
perfectly by an expression.
If you want more information about this example, I describe this same project in more
detail here.
The incoming data source, e.g. 'rotation', 'time', or a variable of your choice. The
values from t must be numbers (dimension of 1). Required.
t_min The minimum expected value for 't'. Optionalif t_min and t_max are omitted, After
Effects will assume values of 0 and 1, respectively.
t_max The maximum expected value for 't'. Optional.
value1 The minimum value to output. When t equals or is less than t_min, the method will
output value1. Value1 can be a number or a vectorthe results will have the same
dimension as value1. Required.
value2 The maximum value to output. When t equals or exceeds t_max, the method will
output value2. Value2 can be a number or vectorif it doesn't have the same
dimension as value1, After Effects will ignore components or append values of 1, as
necessary. Required.
To see how these arguments work together, consider this example:
linear(time, 0, 5, 0, 360);
In English, this expression would read something like: 'as time goes from 0 to 5, output
values from 0 to 360, with linear interpolation.' Applied to a layer's rotation parameter, this
expression would cause the layer to rotate 360 degrees over the first five seconds of the
comp.
If you try this, notice that the layer stops rotating at 5 seconds. This is a chief difference
between these methods and the hand-rolled 'divide by 5, multiply by 360' technique we used
earlier. The interpolation methods clamp their incoming and output values at the minimum
and maximums you specify.
Another difference is that you can specify different styles of interpolation: ease(), ease_in()
and ease_out(). These styles work exactly like their identically-named keyframe interpolation
styles (available via the Animation->Keyframe Assistant menu). You can use these
interpolation methods to provide a more natural progression between sets of valuesa
smoothness that would be harder to achieve with simple division and multiplication.
To see how the various ease styles work, consider the following animations, which each use
the same arguments, but with different interpolation methods:
Click here to download this project file. (Windows users, click here.)
These are stills because the animations don't export in Flash format very well. In any
case, they are more fun, and easier to understand, when you can interact with them
directly. Click here to download the project file. (Windows users click here.)
Whats an Object?
An object is just a container. Each object can contain other objects, attributes or methods.
For instance, a comp is a kind of object in After Effects. Each comp can contain other objects,
such as layers, or attributes such as duration or width. (Well discuss methods later.) All of
the After Effects elements youre familiar with comps, layers, opacity, etc either are
objects or are contained by objects.
Because objects can contain other objects, locating the element youre after can involve a
series of object identifiers. You should think in terms of hierarchy: start with the largest
container and work towards the smallest. In slightly more technical terms, you will always
start with a global object.
this_layer
this_comp
Comp
comp("name")
Comp
footage("name")
Footage
time
Number
value
Number
Whats in an Object?
After youve identified a global object, youll probably want to specify some attribute, method
or sub-object belonging to it. But how do you know what your choices are? Whats inside the
global object youve chosen? You can find this information in the tables Ive provided here, or
in the expressions language reference part of the After Effects User Guide.
First, you need to find out what kind of object you actually have that is, what kind of
object is returned by the specifier youve chosen. For instance, this_comp returns a comp
object (surprise!). Then, you can look in the reference material to see what objects of that
type contain. In this example, wed see that comp objects contain layer objects and attributes
such as width or duration (among many other elements).
So, after specifying this_comp, we could choose a particular layer within the current comp:
this_comp.layer("Solid 1")
This will return the layer named Solid 1 in the current comp. We could stop here, if we just
needed a layer object. Since we typically need a value or vector, however, we probably would
repeat the above process, this time looking up what objects, attributes and methods are
contained by layer objects.
But first, take a minute to notice the period separating the comp and layer identifiers. This is
basic Javascript syntax, a way of specifying that the second object is inside the first. To
build this kind of reference, you simply start with one object, then a period, then another
object (or method or attribute). You can repeat this process as long as necessary, stringing
references together until you arrive at the element you need.
Notice also that there are no spaces in object specifiers, except when referring to item
names, in quotation marks.
Now that we have a layer object, well identify an attribute or method we want to use. For
instance:
this_comp.layer("Solid 1").opacity
Again, a period separates the object and its attribute.
If you ever have trouble with this syntax, you can always let the pick whip help you. Simply
put the text cursor at the spot in your expression where you need the object reference, and
then drag the pick whip to the object or attribute you need. After Effects will automatically
insert the correct object reference. You can drag the pick whip to other windows, including
even the Project window.
In addition to the properties we listed earlier, layer objects contain the following attributes or
methods:
Layer Attribute or Method
Dimension
Units
width
Number
pixels
height
Number
pixels
start_time
Number
seconds
in_point
Number
seconds
out_point
Number
seconds
has_video
Boolean
Boolean
has_audio
Boolean
Boolean
active
Boolean
Boolean
audio_active
Boolean
Boolean
audio_levels
Property
2 [left, right]
decibels
index
Number
Number
parent
source
Comp or Footage
mask(index or name)
Mask
effect(index or name)
Effect
This list is not exhaustivelook in the tables Ive provided here or in the After Effects User
Guide for more information. The list is included here only to show that layer attributes can
return a wide variety of objects, including even other comps. You could easily have an object
reference that looked like:
this_comp.layer("Nested Comp").source.layer("Solid 1").position
Vector Math
Due to some limitations of Javascript, we cannot use the standard math operators +, -, /,
and * with vectors. Instead, you need to use special vector math methods:
add(vector1, vector2)
sub(vector1, vector2)
mul(vector1, number)
div(vector1, number)
Unfortunately, this means that vector math operations can quickly become hard to read. For
instance, a simple operation such as
(a-b)/2
becomes
div(sub(a,b),2);
Obviously, this is harder to decipher. Its also harder to write, and is more likely to introduce
a typo or other bug into your expression. In general, you want to keep things very simple
and very readable, because they are then more likely to work. So vector math seems to be a
problem.
One good solution is to break up operations like this into a series of simple steps. For
instance, we could rewrite the above example:
temp=sub(a,b);
div(temp,2);
This version is much easier to follow, and less likely to introduce bugs into your expression. I
strongly recommend that you break compound vector math operations up into a series of
simple steps, each containing just one operation.
Example
Finally, well use some of this material to put together a simple example, using basic
geometry. Just for fun, well reinvent the wheela layer that appears to roll when you drag
it.
First, lets take inventory of what we have, and what well need. We know that well apply our
expression to the rotation parameter of our wheel, and that well need to end up with a single
scalar value. So we can start by adding an expression to the rotation parameter.
We also know that we need to start with the layers position, since a change in position will
need to produce a change in its rotation. For our example, well assume the wheel is traveling
horizontally, so well only need:
position[0]
Common sense tells us that when the wheel has moved a distance equal to its circumference,
the wheel will have rolled one complete revolution, and the expression should produce 360.
Well worry about these specifics in a moment. For now, its only important to recognize that
how large the wheel is will determine how far it moves in a single revolution. So we need to
know how large our wheel is.
Assuming our wheel graphic is exactly as large as its layer (no blank space around it), we can
just use:
width;
But we cant just use width directly. Instead, we need to use the width to figure out the
wheels circumferencehow long its edge is. From basic geometry, we know that
circumference is equal to diameter times Pi. JavaScript helpfully gives us an accurate value
for Pi in "Math.Pi." So we can start be defining a variable for circumference:
circumference=width*Math.PI;
If the wheel is 100 pixels wide, its circumference will be about 314 pixels. But what if we
scale the wheel? To be accurate, we should adjust for scale when calculating the
circumference:
circumference=width*( scale[0]/100)*Math.PI;
Weve divided scale[0] by 100 because the scale attribute returns percentage values. Here,
we need scale represented as a decimal fraction, so that normal scale = 1 (instead of 100).
Next, well define a variable to represent the distance the wheel has traveled. In our
example, were going to assume that the wheel starts exactly at the left edge of the comp,
and so we can use:
distance=position[0];
Finally, we can put together the core of our expression:
(distance/circumference)*360;
We simply divide the distance traveled by the circumference to find out how many
circumferences weve traveled. Multiplying by 360 expresses the result in degrees (since 1
circumference equals 360, as mentioned earlier above). All together, the final expression is:
circumference=width*( scale[0]/100)*Math.PI;
distance=position[0];
(distance/circumference)*360
Now, as you drag your layer around, it will appear to roll perfectly, without slipping. This
may not seem like a big dealafter all, we couldve just done the math ourselves and set
rotation keyframesbut this expression will work even if the layer is accelerating or slowing
down. Thats pretty tough to do convincingly by hand.
Try applying this to individual text characters, or to objects that dont normally roll around.