Manipulating Color with expressions can be a tricky thing. This is mainly because After Effects uses RGB to control color. Obviously we all use the color picker to get the color we want as the interface gives us clear feedback as to which color we're choosing. But tell me this... do you know the RGB value of say a light Ochre? Me neither!
Blending RGB values can be confusing with expressions and it's usually a lot easier to work with HSL (Hue, Saturation, Lightness) to modify colors. So if After Effects uses RGB, how do we convert things to HSL? Well, here's how!
There is a handy built in method called rgbToHsl(rgbaArray) which converts RGB values to HSL values. Here's how it works.
Let's say I have a Solid with a '˜Fill' effect on it.
The first thing I need to do is click the stopwatch for the Color parameter to create the expression. Now I need to create a variable that references and holds the Color values of the effect.
rgb = effect("Fill")("Color");
This information that's housed in my '˜rgb' variable is an Array that stores four values. Red, Green, Blue and Alpha (rgba). Each value goes between 0-1 not 0-255 as you might expect.
The next step is to convert this RGB array into an HSL array. I do this with my rgbToHsl() method. I now create a new variable called '˜hsl' that holds the conversion like this.
hsl = rgbToHsl(rgb);
I'm feeding the method the information I want to covert by placing my '˜rgb' variable between the brackets.
Now here's the important bit! I have a variable called '˜hsl' that now holds my converted RGB values from the color picker. In reality the array looks like this.
[ hsl, hsl, hsl, hsl ]; hsl is the value for Hue that ranges from 0-1. hsl is the value for Saturation that ranges from 0-1. hsl is the value for Lightness that ranges from 0-1.
hsl is the value for the Alpha that ranges from 0-1.Four parameters (hsla). Each part of the array has a reference number that counts from zero. It's inside this array that I can manipulate my color values. Before I do that I'm going to assign these (to be manipulated) values to a variable called '˜changeHsl' like this.
changeHsl = [hsl, hsl, hsl, hsl];
I need to do this as I need to reconvert these values back to RGB so the color picker can read them. I do this by using the reverse method hslToRgb(hslaArray). I do this by feeding the method my converted value from the '˜changeHsl' variable like so.
So here's the full expression:
rgb = effect("Fill")("Color"); hsl = rgbToHsl(rgb); changeHsl = [hsl, hsl, hsl, hsl]; hslToRgb(changeHsl);
Now at the moment this expression isn't doing anything as I haven't manipulated any values yet. So let's try a few things out!
Each layer in an After Effects composition has an Index number. These can come in handy when driving expressions based on duplicated layers. For instance, if I add this expression to the Position of a 3D layer...
[80 * thisLayer.index, position, position];
Each time time I duplicate the layer, the Solid will be moved 80px to the right. In a 3D Position array the first value is the X parameter. So I've said make the Position in X 80 times the layer Index. For Layer 1 this is 80px (80x1), for Layer 2 it's 160px (80x2) etc. Here you can see the result of multiple duplications.
thisLayer.index is very useful. So let's try this out with our HSL color array.
First off I'll set up the Index maths. I'll say...
(thisLayer.index - 1)
This will make the first Layer see no change as 1 minus 1 is 0. I'll then multiply this by 0.1.
((thisLayer.index - 1) * 0.1)
I have to keep within range of 0-1 so I'm turning the Index in a decimal. I'll then add this to the hsl value.
((thisLayer.index - 1) * 0.1) + hsl
I can now add this to my expression...
changeHsl = [((thisLayer.index - 1) * 0.1) + hsl, hsl, hsl, hsl];
Now in terms of Hue, Red (my fill color) has a value of 0. Every time I duplicate the Layer duplicate will effectively have a Hue value 0.1 higher than the last.
Here's the result:
We could do a similar thing with Saturation. This time I'll subtract the Index equation from the Saturation value.
changeHsl = [hsl, hsl - ((thisLayer.index) * 0.12), hsl, hsl];
Here's the result of duplication:
So hopefully you can see where this is going now.
This is actually quite important to know. Because all the values go from 0-1 any value higher than 1 have no effect. If you want to loop or cycle values like Hue (like you can on the Angle rotary control) you'll need to add a Modulo to it.
Modulo is a % sign followed by a number. Our highest value is 1 so we could say this.
changeHsl = [((thisLayer.index - 1) * 0.25 % 1) + hsl, hsl, hsl, hsl];
What happens is that when a value exceeds 1 it is wrapped back to 0 and any decimal place (remainder) is added to that 0. So 1.3 would become 0.3. Here's the result of the wrapping round of the Modulo on the Hue.
We could even assign a random values using random(min,max) instead.
changeHsl = [random(0, 0.99), random(0, 0.99), random(0, 0.5), hsl];
Because worried about the original values of my color, I don't need to reference the array values at all here.
Here's a fun one!
changeHsl = [hsl + (((thisLayer.index - 1) * 0.1) + (time*0.5)) % 1, hsl, hsl, hsl];
This rotates the Hue of the duplicates over time. Each Layer Hue is first offset by the Index value then we add the time value (each frame has a number) which can be sped up or slowed down by multiplying it with a number. Numbers below 1 slow it down, number above 1 speed it up. The whole value of the sum is capped with a Modulo at the end which rotates it!
You could do this with Lightness too.
changeHsl = [hsl, hsl, hsl - (((thisLayer.index - 1) * 0.05) + (time*0.9)) % 1, hsl];
This could be useful for creating interface elements like LED strips.
This is a really handy thing to know and has a ton of applications. To can attach your value for multiplying numbers to Expression Sliders for extra control over the effect. You can even set up a master color using a Color Control to change the overall color scheme.
You can also use it on any Color parameter like say Strokes or Multiple Strokes on a shape. Check out this article to see how you can use this technique for Shape Layer effects.
The possibilities of this of this simple expression are endless!!