Layer Space Transforms
Case Study: 2D Auto Orientation
Layer space transforms are extremely powerful and useful once you understand how to use them. They are designed to allow you to transform to and from layer, comp, or world coordinates. Unfortunately, there is no layer transform for Rotation and Orientation. When does this become an issue? There are at least a couple of situations where it can be extremely useful to know what a layer's Rotation or Orientation would be relative to world coordinates.
One such case occurs when a layer is a child of another layer. When you rotate the parent, child's orientation in world space changes but its Rotation value does not. So you can't tell just by looking at the properties of the layer itself what its orientation/rotation is in world space.
The other situation occurs when you turn on auto orientation for a layer. As the layer moves along its path, its world orientation changes but its Rotation and Orientation parameters do not.
Suppose we want other layers in the comp to assume the same rotation/orientation as our child or auto-oriented layer. How do we do it? In this case study we're going to look at a 2D expression which will give us a 2D layer's auto orientation value. As a bonus, it turns out this same expression works in the case of the child layer as well.
So where do we start? It turns out that After Effects provides us with just the tool we need in the form of one of the more obscure layer space transforms - namely "toWorldVec". The "regular" layer space transforms convert a point's coordinates from one coordinate system to another. The vector versions of these transforms do something entirely different.
Let's take a quick look at the comp that generated the little movie above:
The red arrow is named "leader". It has been keyframed to move in a figure-8 pattern and auto orientation to path has been turned on. You'll notice that in the image above, even though the arrow is clearly rotated with respect to the comp, its rotation value is zero. You can also see the expression that has been applied to the Rotation property of each of the yellow follower layers (note that the rotation value for these layers is not zero). Here's the expression:
L = thisComp.layer("leader"); u = L.toWorldVec([1,0]); radiansToDegrees(Math.atan2(u,u))
Let's dig in and see how this thing works
First we better do a quickie review of vectors in After Effects. Vectors are entities that have length and direction. Vectors don't carry any position information - just length and direction. So the vector from [0,0] to [1,0] is the same as a vector from [5,5] to [6,5] (they both have length 1 and point in the same direction as the x axis). Since position doesn't matter, any vector can be defined by assuming its tail is at [0,0] in the relevant coordinate system and specifying the end point. That will establish both length and direction. AE uses that convention in the vector transforms - i.e. you specify the end point, AE assumes the vector originates at [0,0]. The length is determined by how far the end point is from the origin ([0,0]). So that means any point in space can be interpreted by After Effects as either a point at an [x,y] location, or as a vector that runs from [0,0] to [x,y]. This vector will have some angle relative to the x-axis. The trick to this whole thing is picking a vector in the layer's local coordinate system that, when translated to the world coordinate system by toWorldVec, will give us the angle of rotation.
Examine the following diagram:
Let's take a look at what's going on here. We have a blue solid with keyframed movement which is denoted by the "layer motion path". The layer has auto orient turned on so the layer is rotated with respect to world coordinates but its Rotation value does not reflect this and remains at 0. Notice that as the layer follows its path, its local x axis always points in the direction the layer is moving. This provides the key to the solution. What we do is define a unit vector, "u"(which is just a vector of length 1) along the x axis.
In the layer's coordinate system, the vector starts at [0,0] and ends at [1,0]. Now comes the fun part. We use "toWorldVec" to translate our layer's x-axis unit vector to the equivalent vector in world space (also shown as "u" in the diagram). This vector also starts at [0,0] (but in world coordinates) and the end value is not [1,0] - it is something else. We will denote it by its x and y components (u and u). So, when we plug the layer's unit vector endpoint of [1,0] into toWorldVec, the result will be [u,u]. This is all the info we need to calculate the rotation angle in world coordinates. Using a little trig, we know that the tangent of our angle (theta in the diagram) is y divided by x, or u/u. So if we take the arc tangent of u/u we will get the rotation angle (in radians, which we simply convert to degrees).
Even if you didn't follow all of that, just know that you can use the expression above to obtain any 2D layer's world rotation, even if it is a child layer or has auto orient turned on.