This Expression Shorts episode, explores Math.sin() in greater detail. In this part 1 episode I show you how to create pendulum style motion, swinging style motion with decay, and circular motion. This weeks short happens to be not so short so I’ve created two parts and have included multiple code breakdowns. So get ready to learn some handy code.
So I touched on Math.sin() a little bit in last weeks tutorial, but have saved all the heavy details for this weeks post, along with some useful examples of what you can do with it. This will be a multi-page read, so make sure you don’t miss any of the code breakdown pages.
DISCLAIMER: For readers that copy and paste the following Expression code below, be aware that double quotes are currently showing as smart quotes. This is a PVC article default that I cannot override at the moment. I am looking for a workaround, but in the meantime you will need to make sure you paste the Expression code into a blank simple text document, NOT a rich text one, first to convert all code to simple text, then copy that and paste that into your Expression field in After Effects. Use TextEdit on Mac or NotePad on PC for this. If you paste directly into the Expression field without this step, you will end up keeping the smart quote formatting and it will cause a syntax error when you try to run the Expression. Just a heads up.
PENDULUM SOURCE CODE:
swingMaxDistance = 75;
swingSpeed = 5;
easeTimeSpan = 6;
easeSpeed = 1;
easeVal = ease(time*easeSpeed, 0, easeTimeSpan, swingMaxDistance, 0);
Math.sin(time*swingSpeed) * easeVal;
So we get to learn some more new expression code this week. Namely ease() and Math.sin(). You may remember the linear() expression used in the Auto Fade Layer tutorial awhile back, well ease() is a close relative to linear() and should be just as easey to learn.
ease() – This expression is identical to the linear() expression with the exception that it will ease the values together, so that it gradually starts and stops. So think of a car starting it’s drive when a light turns green, it slowly gets up to speed, going from 0 up to 35 (imagine that it’s a responsible driver ;)) and then starts to slow down once it reaches the next red light, going 35 down to 0. It’s that simple. ease() contains the same five input values as linear()…
ease(time, tMin, tMax, value1, value2);
time: Is the master source of information. You can use time, a layer’s position, rotation, opacity, etc…
tMin: The minimum value you want to use from the master source, time.
tMax: The maximum value you want to use from the master source, time.
value1: The start value that maps to the tMin value.
value2: The finish value that maps to the tMax value.
There are also more ease expressions available too if you only want to ease one way…
easeIn(time, tMin, tMax, value1, value2);
easeOut(time, tMin, tMax, value1, value2);
Math.sin() – Here is the hero of today’s code, Math.sin(). The entire swinging motion occurs from this expression. Math.sin() creates a sine wave (fancy definitions), an occilating value positive and negative from the original starting value it is given. There are two values that you can give this expression to effect it’s output. The first being it’s source value, Math.sin(SOURCE VALUE). This is traditionally assigned to time, since time’s value increases exponentially with each frame of your After Effects timeline. The second value isn’t really mentioned anywhere, it literally is an optional modifier where we basically multiply the resulting output value of Math.sin() by another value. This increases it’s overall resulting value. You do this by using the “*” multiplication operator. So Math.sin(time)*20 will produce a value 20 times greater. In addition to modifying the final result, you can also modify the speed of time in the same way. So Math.sin(time*2)*20 will make time move 2 times as fast with the same 20 times greater value.
Here is a visual example of the same principle.
PENDULUM CODE BREAKDOWN:
1) swingMaxDistance = 75;
2) swingSpeed = 5;
3) easeTimeSpan = 6;
4) easeSpeed = 1;
5) easeVal = ease(time*easeSpeed, 0, easeTimeSpan, swingMaxDistance, 0);
6) Math.sin(time*swingSpeed) * easeVal;
NOTE: The above expression is meant to be placed on the Rotation property of a layer. It can be easily changed to work on most layer properties though. Rotation is just one example.
Line 1: We assign a variable named swingMaxDistance a value of 75. In this case we are referring to pixels. This will be used to…well…….define the maximum distance to swing. You want to try and name your variables as clearly as possible like this so it is easier to read your overall code when it’s done. You’ll thank me someday for telling you this, especially when you start writing hundreds of lines of code. 🙂
swingMaxDistance = 75;
Line 2: We assign a variable called swingSpeed a value of 5 and, you guessed it, it defines the speed of the swing.
swingSpeed = 5;
Line 3: This variable called easeTimeSpan is assigned a value of 6. We use this variable to determine how long the maximum time should be for it to take to ease down to a stop. This will be in a ratio of seconds, so it is currently 6 seconds long.
easeTimeSpan = 6;
Line 4: We assign the easeSpeed variable a value of 1 which will be how fast the ease will animate during the above easeTimeSpan duration. A value of 1 will be realtime. A value of, say 2, will be twice as fast and therefore will override how long the easeTimeSpan duration will be. So if we go 75 to 0 in 6 seconds at a speed of time times 1 (realtime), it will take 6 seconds to complete the journey. If we were to speed up time and go from 75 to 0 in 6 seconds at a speed of time times 2 (twice as fast), then we would complete that journey in half the time. So it would only take 3 seconds instead of 6.
easeSpeed = 1;
Line 5: Next we create a variable called easeVal. This variable is unique because we are now using the ease() interpolation expression. For this we assign the first value time*easeSpeed, so it is time and we multiply time times our easeSpeed variable, which is 2. This means we are moving at twice the speed of realtime. We then assign our tMin and tMax values. In this case we use 0 for our tMin and we use easeTimeSpan for our tMax. This is basically telling the ease() expression that we want it to create values from 0 seconds to 6 seconds in our timeline. Next we define our output value1 and value2. For these we assigned swingMaxDistance and 0. So our ease() expression now knows that we want it to create a starting value of 75 (easeTimeSpan) and an ending value of 0. Now those last four assignments we just made simply determine when to start the action, when to end the action, what the starting output value is and what the ending output value is. So “0, easeTimeSpan, swingMaxDistance, 0” could also be written as “0, 6, 75, 0”, but we use variables instead for organization, clarity when reading the code and to easily change a single value used in multiple lines of code all at once.
easeVal = ease(time*easeSpeed, 0, easeTimeSpan, swingMaxDistance, 0);
Line 6: The final line of code and the master output that creates our resulting animation. Math.sin() is creating our oscilating value over time, we’ve then sped up time by multiplying time times our swingSpeed, which is set to 5, Math.sin(time*swingSpeed). Same as saying Math.sin(time*5). Now, we then are multiplying that overall value by our easeVal variable, so at it’s highest value the code is basically saying, Math.sin(time*5)*75, but we are using the ease() expression so the 75 value is progressively getting smaller over time like so…
at 0 seconds, Math.sin(time*5)*75
at 2 seconds, Math.sin(time*5)*55.5
at 4 seconds, Math.sin(time*5)*19.4
at 6 seconds, Math.sin(time*5)*0
That decrease in the final multiplying value is what makes our swinging motion slow down until we eventually multiply by 0 and get 0 as our value. Cool huh? 🙂
Math.sin(time*swingSpeed) * easeVal;
Continue onto page two for more code breakdowns of the other two examples that were shown in the video.
DISCLAIMER: For readers that copy and paste the following Expression code below, be aware that double quotes are currently showing as smart quotes. This is a PVC article default that I cannot override at the moment. I am looking for a workaround, but in the meantime you will need to make sure you paste the Expression code into a blank simple text document, NOT a rich text one, first to convert all code to simple text, then copy that and paste that into your Expression field in After Effects. Use TextEdit on Mac or NotePad on PC for this. If you paste directly into the Expression field without this step, you will end up keeping the smart quote formatting and it will cause a syntax error when you try to run the Expression. Just a heads up.
LINE CIRCULAR MOTION SOURCE CODE:
x = effect(“Write-on”)(“Brush Position”)[0];
y = effect(“Write-on”)(“Brush Position”)[1];
swingMaxDistance = 125;
swingSpeed = 3;
easeTimeSpan = 60;
easeSpeed = 10;
easeVal = ease(time*easeSpeed, 0, easeTimeSpan, swingMaxDistance, 0);
sway = Math.sin(time * swingSpeed) * swingMaxDistance;
counterSway = Math.cos(time * swingSpeed) * swingMaxDistance;
[sway+x, counterSway+y];
In this code breakdown we get to expand upon the Pendulum setup and create some circular motion by simply changing a few lines of code. I introduce another new math expression here alled Math.cos(). This would be the counterpart for Math.sin().
Math.cos() – (fancy definitions) This expression is the counterpart to Math.sin() and allows for a circular motion when combined with Math.sin(). On a technical level it is identical to Math.sin(), only it’s delayed a little bit. That delay helps create the curve for our circle.
LINE CIRCULAR MOTION CODE BREAKDOWN:
1) x = effect(“Write-on”)(“Brush Position”)[0];
2) y = effect(“Write-on”)(“Brush Position”)[1];
3) swingMaxDistance = 125;
4) swingSpeed = 3;
5) easeTimeSpan = 60;
6) easeSpeed = 10;
7) easeVal = ease(time*easeSpeed, 0, easeTimeSpan, swingMaxDistance, 0);
8) sway = Math.sin(time * swingSpeed) * swingMaxDistance;
9) counterSway = Math.cos(time * swingSpeed) * swingMaxDistance;
10) [sway+x, counterSway+y];
NOTE: The above expression is meant to be placed on the “Brush Position” property of the Write-on plugin.
Line 1: We create a variable called x and assign it the X position parameter of the Brush Position property. This will allow us to later change the X position value via the traditional slider control.
x = effect(“Write-on”)(“Brush Position”)[0];
Line 2: We create a variable called y and assign it the Y position parameter of the Brush Position property. This will allow us to later change the Y position value via the traditional slider control.
y = effect(“Write-on”)(“Brush Position”)[1];
Line 3: This line we reuse the same variable name that we setup for the Pendulum expression, only we assign it a value of 125 this time.
swingMaxDistance = 125;
Line 4: This line we reuse the same variable name that we setup for the Pendulum expression, only we assign it a value of 3 this time.
swingSpeed = 3;
Line 5: This line we reuse the same variable name that we setup for the Pendulum expression, only we assign it a value of 60 this time.
easeTimeSpan = 60;
Line 6: This line we reuse the same variable name that we setup for the Pendulum expression, only we assign it a value of 10 this time.
easeSpeed = 10;
Line 7: This line we reuse the same variable name and variable assignments that we setup for the Pendulum expression.
easeVal = ease(time*easeSpeed, 0, easeTimeSpan, swingMaxDistance, 0);
Line 8: This line we switch things up and create a variable called sway and assign it our Math.sin() setup we had on the Pendulum expression. the reason for assigning this value to a variable this time is that we are going to be using more than one Math input. So for the same organization and readability reasons, we’ll set it up this way. We still have control of the time pacing with swingSpeed and we also still control the multiplier with swingMaxDistance.
sway = Math.sin(time * swingSpeed) * swingMaxDistance;
Line 9: This variable will be called counterSway and we are going to assign it the Math.cos() expression. We still use the same time * swingSpeed and * swingMaxDistance code here as in line 8. Both of these lines (8 & 9) provide us the full motion needed to create a circlular movement.
counterSway = Math.cos(time * swingSpeed) * swingMaxDistance;
Line 10: Our final line is the output for our Brush Position. We need an X and a Y value for the expression to work and that is because the Brush Position has two values, one for X and one for Y. So we need to create an array with open and close brackets, [ ]. We then enter our first value, which applies to our X axis, [sway+x]. What this is doing is taking our sway variable value, Math.sin(), and adding x which is the current X Brush Position value to it. This allows us to move the X Brush Position while still keeping our Math.sin() animation. We then add our Y axis output value making sure to put a comma between the X axis and Y axis values like so, [sway+x, counterSway+y]. For the Y axis we use our counterSway variable to create the curve needed to complete our circular movement. We also added the y variable to it so we can move the Y axis as well while keeping the Math.cos() animation. This can get a little confussing, but hopefully by naming the variables the way we did, it should help you understand what it is doing. You can reverse the direction the circle is drawn by swapping the the sway and counterSway variables, [counterSway+x, sway+y].
[sway+x, counterSway+y];
LAYER CIRCULAR MOTION SOURCE CODE:
x = transform.position[0];
y = transform.position[1];
z = transform.position[2];
swingMaxDistance = 100;
swingSpeed = 3;
easeTimeSpan = 60;
easeSpeed = 10;
easeVal = ease(time*easeSpeed, 0, easeTimeSpan, swingMaxDistance, 0);
sway = Math.sin(time * swingSpeed) * swingMaxDistance;
counterSway = Math.cos(time * swingSpeed) * swingMaxDistance;
[x, counterSway + y, sway + z];
CODE BREAKDOWN:
1) x = transform.position[0];
2) y = transform.position[1];
3) z = transform.position[2];
4) swingMaxDistance = 100;
5) swingSpeed = 3;
6) easeTimeSpan = 60;
7) easeSpeed = 10;
8) easeVal = ease(time*easeSpeed, 0, easeTimeSpan, swingMaxDistance, 0);
9) sway = Math.sin(time * swingSpeed) * swingMaxDistance;
10) counterSway = Math.cos(time * swingSpeed) * swingMaxDistance;
11) [x, counterSway + y, sway + z];
NOTE: The above expression is meant to be placed on a layer Position property.
This expression is nearly identical to the line circular motion code breakdown, so I’m not gonna fully explain this one. The only differences are that we added a variable for the Z Position axis of our layer (line 3) and in the final output array (line 11) as well as linking our x and y variables (line 1 & 2) to the layer Position instead of the Write-on plugin Brush Position property.
In part 2 of the Math.sin() series, I show another cool trick that you can use Math.sin() for. Continue on to part 2.
Filmtools
Filmmakers go-to destination for pre-production, production & post production equipment!
Shop Now