March 04th 2012 08:30:58am
In part 2 of this episode, we look at creating the same layer offset in 3D by adding an extra control for the Z axis.
For this setup we use the new CS5.5 3D Point Control effect and add some new bits of code for the Z axis. The code breakdown is almost identical, but be sure to pay attention to the minor changes as well as they will make a difference in having the expression work correctly.
3D CHILD POSITION SOURCE CODE:
offsetX = thisComp.layer("Master Controller").effect("Position Offset")("3D Point")[0];
offsetY = thisComp.layer("Master Controller").effect("Position Offset")("3D Point")[1];
offsetZ = thisComp.layer("Master Controller").effect("Position Offset")("3D Point")[2];
x = transform.position[0];
y = transform.position[1];
z = transform.position[2];
leader = thisLayer.index+1;
for(i=leader; i<= thisComp.numLayers; i++){
y += offsetY;
x += offsetX;
z += offsetZ;
}
[x, y, z];
NOTE: The above expression is meant for the Position property of your Child layer.
3D 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 Z Rotation property of your 3D Child layer.
In part 1 I explained about 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 will reuse this in part 2 as well. This example uses three starting layers, a null called "Master Controller", a solid called "Child", and a duplicate solid called "Leader". All of these layers have their 3D Layer option enabled.
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–.
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")("3D Point")[0];
offsetY = thisComp.layer("Master Controller").effect("Position Offset")("3D Point")[1];
offsetZ = thisComp.layer("Master Controller").effect("Position Offset")("3D Point")[2];
x = transform.position[0];
y = transform.position[1];
z = transform.position[2];
leader = thisLayer.index+1;
for(i=leader; i<= thisComp.numLayers; i++){
y += offsetY;
x += offsetX;
z += offsetZ;
}
[x, y, z];
Note: For lines 1, 2, and 3, we are connecting the expression to the 3D Point Control effect (CS5.5 only). In part 1 we used a standard Point Control. If you are not using CS5.5 or higher, then you can still use the Point Control and just add a Slider Control to hold the Z value or you can just use three individual Slider Controls instead. One for each axis, X, Y, and Z.
Line 1: This first variable called offsetX is assigned the X value of our 3D Point Controller effect. We have a null called "Master Controller" (thisComp.layer("Master Controller")), with a 3D Point Controller effect applied (effect("Position Offset")("3D 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 3D Point Control effect to offset the X position by a set amount of pixels and also allows us to keyframe that value is we choose. When combined, we get the following line of code…
offsetX = thisComp.layer("Master Controller").effect("Position Offset")("3D 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")("3D Point")[1];
Line 3: This is a new line of code for our 3D version. We do the same for the Z axis and create a variable called offsetZ. Since we are assigning it the Z axis we use it’s array index value which is [2].
offsetZ = thisComp.layer("Master Controller").effect("Position Offset")("3D Point")[2];
Line 4: Next we create a variable called x and assign it the current layer’s X Position axis.
x = transform.position[0];
Line 5: 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 6: This also a newly added line of code for our 3D version. We create a variable called z and assign it the current layer’s Z Position axis. This will help in determining the current layer’s Z position for use later.
z = transform.position[2];
Line 7: Now we create a variable called leader. No 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 8 & 12: 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 9: 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 10: We do the exact same thing as line 7, only we use our X axis values.
x += offsetX;
Line 11: We now need to update our z variable as well now too. This will create our offset that moves the layers back or forward on the Z axis.
z += offsetZ;
Line 13: And finally we create our final three item output array by using open and close brackets, [ ], and placing our x, y and z variables inside it.
[x, y, z];
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 do not need to do anything differently from the part 1 explanation, 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.
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;
Thanks for viewing this post and I hope you keep checking out future posts as well as past ones. See you next time.