Expression Shorts Auto Layer Offset 2D

March 04th 2012 08:00:40am

This week I show you how to have a layer automatically offset itself on the X, Y axis as well as it’s rotation value. All of this is controlled via a master control null for ease of use.
Last week involved a lot about Math.sin() and a special use for it to create a swinging string type of motion that involved stacking multiple layers, then parenting them and so forth.

The stacking aspect could also be expressioned and controlled in various ways, and in this two part episode I focus on offsetting the position and rotation of layers via expression as well as using Expression Control plugins. Lots to cover in this on so on to the video tutorial.

CHILD POSITION SOURCE CODE:

offsetX = thisComp.layer("Master Controller").effect("Position Offset")("Point")[0];
offsetY = thisComp.layer("Master Controller").effect("Position Offset")("Point")[1];
x = transform.position[0];
y = transform.position[1];
leader = thisLayer.index+1;
for(i=leader; i<= thisComp.numLayers; i++){
	y += offsetY;
	x += offsetX;
}
[x, y];

NOTE: The above expression is meant for the Position property of your Child layer.

CHILD ROTATION SOURCE CODE:

childR = thisComp.layer(index + 1).transform.rotation;
twist = thisComp.layer("Master Controller").effect("Twist")("Slider");
childR + twist;

NOTE: The above expression is meant for the Rotation property of your Child layer.

This week we get to learn some more new code and helpful tricks. The biggest new item is the for() loop. This is a very handy piece of code when you want to repeatedly run some code a specific amount of times. We also get to use a Point Control and Slider Control effect to help us create a master controller to control the whole thing. This example uses three starting layers, a null called "Master Controller", a solid called "Child", and a duplicate solid called "Leader".

for() – A for() loop is a native piece of Javascript code that, as you’ve seen in previous episodes of Expression Shorts, isn’t found in the standard After Effects menus anywhere. Anytime you hear about needing to know basic Javascript to be able to learn Expressions or Scripting, this would be one of those bits of code that falls into that category. Lucky for you though, I am explaining all of these as we use them because, just learning Javascript by itself will ultimately confuse you a bit when you start trying to use bits of Javascript in After Effects only to find out that not all of it is compatible and that mostly, only the foundation is needed, not the WEB specific stuff. Which is what Javascript is primarily known for, the web. Not enough people mention this when you are trying to figure it all out. Anyway, back to the for() loop. The for() loop is meant to run a group of code a specific amount of times. You give it three arguments …

for("START VALUE"; "END VALUE"; "INCREMENT/DECREMENT"){ Your code to run };
for(i = 0; i < 10; i++){ Your code to run };

Start Value: You assign a variable a value. In the above example we say i is equal to 0. Traditionally you declare the variable here, so it would look like, var i = 0; , but After Effects will allow it without the var within a for() loop. A variable can be named nearly anything. The only limits are, that it is case sensitive, and it MUST start with a letter or the underscore _ character only.

End Value: This will be the end value to stop processing on. We actually place a comparison equation here using our initial start value variable. We want to compare the start value to our end value to see if it’s true or false. Each time it returns true, the code will run once. If it returns false, the for() loop ends. Some of the Comparison Operators that we can use here are…

> //Greater than
< //Lesser than
>= //Greater than or equal to
<= //Lesser than or equal to
== //Equal to

Full list of Comparison Operators

Increment/Decrement: We use this to increase or decrease our starting value. So if you were to increase the value you add a double plus sign, ++, to the starting value variable like so, i++. If you wanted to decrease the value, you would use a double minus sign, i–.

Math.sin() – I’ve already given a full explanation of this one in the Math.sin() part 1 code breakdown section.

index – This is a straight forward layer expression, it is located under the Layer General group. It references the current layer’s index value. So layer 10 would have an index value of 10. This comes in handy when you want to dynamically reference a layer above or below the current one.

CHILD POSITION CODE BREAKDOWN:

offsetX = thisComp.layer("Master Controller").effect("Position Offset")("Point")[0];
offsetY = thisComp.layer("Master Controller").effect("Position Offset")("Point")[1];
x = transform.position[0];
y = transform.position[1];
leader = thisLayer.index+1;
for(i=leader; i<= thisComp.numLayers; i++){
	y += offsetY;
	x += offsetX;
}
[x, y];

Line 1: This first variable called offsetX is assigned the X value of our Point Controller effect. We have a null called "Master Controller" (thisComp.layer("Master Controller")), with a Point Controller effect applied (effect("Position Offset")("Point")). I’ve renamed the effect to be "Position Offset". Since we are only grabbing the X axis, it is defined by it’s array index number, [0]. This variable will allow us to use the Point Control effect to offset the X position by a set amount of pixels and also allows us to keyframe that value if we choose. When combined, we get the following line of code…

offsetX = thisComp.layer("Master Controller").effect("Position Offset")("Point")[0];

Line 2: We do the same for the Y axis and create a variable called offsetY. Since we are assigning it the Y axis we use it’s array index value, [1].

offsetY = thisComp.layer("Master Controller").effect("Position Offset")("Point")[1];

Line 3: Next we create a variable called x and assign it the current layer’s X Position axis.

x = transform.position[0];

Line 4: Then we create a variable called y and assign it the current layer’s Y Position axis. This is important, because we will need the current layer’s position in order to tell After Effects where we want the next layer to be.

y = transform.position[1];

Line 5: Now we create a variable called leader. Now don’t get confused here, because we also have a layer called Leader, but these are two different references. The layer Leader is merely the first layer in the group that everyone attaches to. This leader variable is defining the current layer’s leader, basically who it’s going to follow. So for this variable we assign it the layer below itself. This is done dynamically by using, thisLayer.index + 1. It first determines it’s index number then adds 1 to it which gives us the next layer below in the timeline.

leader = thisLayer.index+1;

Line 6 & 9: Now the heavy hitter. This is our for() loop. We’ve stated that our start value is going to be our leader variable which we assigned to i. So based on line 5’s explanation i will equal 3. Why 3 and not 0 or 1? Well assuming you placed your layers in the same order as I did in the video, you would have "Master Controller" as layer 1, "Child" as layer 2, and "Leader" as layer 3. So since our expression is on layer 2, our index is 2, then we add 1 which gives us 3. So right now i=3, next we check and compare i to see if it is less than or equal to the number of layers we have in our composition (i<= thisComp.numLayers). We have 3 layers in our composition and i=3 right now, so is 3<=3? Yes it is. The for() loop returns true and runs our code once, then starts the cycle all over again by increasing i by 1 (i++). So we now have 4<=3, is that true? Nope, so the for() loop returns false and stops. All this thinking happens on every frame in your timeline, so you can imagine if you had a ton of layers, After Effects has got a lot to think about. This process is what will also end up finding your duplicate Child layers as you add more of them. Each of those layers will be doing the same expression looking at the layer below it, ultimately running your code (line 7 & 8) which does the math to figure out the new X and Y position for the layer. Simple really once you get the idea of how it is thinking, but confusing to take it all in at first.

for(i=leader; i<= thisComp.numLayers; i++){
}

Line 7: We now create a new value for our previous variable y. It was equal to our Y Position value earlier, but we are going to modify it now since our for() loop returned true. Since the for() loop returned true that means there are more layers it found and we need to offset our current Y Position value accordingly. We do this by adding our current Y Position value, y, to our master offset for Y, offsetY. We could write this two ways, we could say y = y + offsetY, or we could condense down the code writing a bit and just say y += offsetY. They mean the same thing. So what we are doing is taking our current y value, say 200 and adding our offset, say 20, to it to get a new Y Position value of 220. The next layer in line would do it’s expression and see the previous layer’s Y Position at 220 and it would add 20 to get 240 for it’s Y value and so forth. This is what creates the offsetting position values.

y += offsetY;

Line 8: We do the exact same thing as line 7, only we use our X axis values.

x += offsetX;

Line 10: And finally we create our final output array by using open and close brackets, [ ], and placing our x and y variables inside it.

[x, y];

CHILD ROTATION CODE BREAKDOWN:

childR = thisComp.layer(index + 1).transform.rotation;
twist = thisComp.layer("Master Controller").effect("Twist")("Slider");
childR + twist;

Line 1: For our Rotation expression, we create a variable called childR and it is assigned the Rotation value from the layer below itself. This is done dynamically by using index + 1, like we did in line of the Position code breakdown above.

childR = thisComp.layer(index + 1).transform.rotation;

Line 2: We now tie our Twist Slider Control effect to a variable also called twist. no reason behind having the same name other than making it clear for us what we are controlling. The Slider Control effect was placed on our "Master Controller" null and renamed to Twist just like our Point Control effect that we used earlier.

twist = thisComp.layer("Master Controller").effect("Twist")("Slider");

Line 3: To get the final result we simply add the two variables together. Now why did we add them together? Couldn’t we just use the twist value alone? Well, yes, we COULD use just the one variable, twist, but our layers would simply just use the twist value as is. Say our twist slider was set to 20, the rotation value for ALL Child layers would be set to just 20. This might be what you want perhaps, they would just move as one uniform block. Similar to when you Parent a layer, it just grabs the literal value as is. For this example though we want to have each layer grab the current Rotation value from the layer below itself,then add to it. This is what gives us that twisting look, by adding a set value to the previous total rotational value.

childR + twist;

Thank you again to all of the viewers out there watching this series, and also to those of you who keep spreading the word, I really appreciate it.

Check out part 2 for a 3D version.

Checkout more:
Photogrammetry Explained
Project Info List Exporter After Effects Script
Free Function Friday Ep.21 – collectCompCameras
Merch
After Effects ExtendScript Training: Ep. 13