Random Motion



Deeper into the Abyss

Now that we have the basics of creating random motion down, we'll move on to adapting our basic random motion expression to other properties, and effects. First we'll go after the low-hanging fruit. The random expression for Position that we looked at in the previous section can easily be adapted to Rotation, Scale, and Opacity. But first let's look at modifying the Position expression to give one-dimensional motion.

Since we already have an expression for two dimensions, it's easy enough to adapt it to one dimension. In this case we will use narrow solids, and move them back and forth randomly in the x direction. Here's the code:

one-dimensional random motion


segMin = .3; //minimum segment duration
segMax = .7; //maximum segment duration
minVal = 0;
maxVal = thisComp.width;

end = 0;
j = 0;
while ( time >= end){
  j += 1;
  seedRandom(j,true);
  start = end;
  end += random(segMin,segMax);
}
endVal =  random(minVal,maxVal);
seedRandom(j-1,true);
dummy=random(); //this is a throw-away value
startVal =  random(minVal,maxVal);
y = position[1];
ease(time,start,end,[startVal,y],[endVal,y])

If you compare this expression to the final expression from the previous section you'll see that there are few differences. The main difference is that we have changed to a one-dimensional maximum Position. This is because we're only going to vary the x coordinate. The y coordinate will remain whatever it was before the expression was applied. In the next-to-the-last line of code, we set the variable "y" to position[1]. Then we use the random x position and the fixed y position to generate the side-to-side random motion.

Rotation

Now let's look at adapting our Position expression to Rotation. Again, we only need to make a few minor modifications to get it to work for Rotation. Here's what the code looks like:

random position and rotation


segMin = .3; //minimum segment duration
segMax = .7; //maximum segment duration
minVal = -720;
maxVal = 720;

end = 0;
j = 0;
while ( time >= end){
  j += 1;
  seedRandom(j,true);
  start = end;
  end += random(segMin,segMax);
}
endVal =  random(minVal,maxVal);
seedRandom(j-1,true);
dummy=random(); //this is a throw-away value
startVal =  random(minVal,maxVal);
ease(time,start,end,startVal,endVal)

You'll notice that this expression also looks very similar to the previous ones for Position. We've changed "minVal" and "maxVal" to be numbers that make sense for Rotation (-720 degrees to +720 degrees). The rest of the expression is exactly the same as before. It's important to note that this works even though Position is two dimensional and Rotation has only one dimension.

Scale

By now the basic random motion expression should start looking pretty familiar. It should come as no surprise that the expression for random Scale looks like this:

random position, rotation, and scale


segMin = .3; //minimum segment duration
segMax = .7; //maximum segment duration
minVal = 50;
maxVal = 200;

end = 0;
j = 0;
while ( time >= end){
  j += 1;
  seedRandom(j,true);
  start = end;
  end += random(segMin,segMax);
}
s = random(minVal,maxVal);
endVal = [s,s];
seedRandom(j-1,true);
dummy=random(); //this is a throw-away value
s = random(minVal,maxVal);
startVal = [s,s]
ease(time,start,end,startVal,endVal)

All we've really done here is to change the limits to something that makes sense for Scale and to use a temporary variable "s" to hold the random value of Scale so that we can end up with the x and y scale values being the same (uniform scaling). This is accomplished by the lines "endVal = [s,s];" and "startVal = [s,s]".

Opacity

To finish our sweep through randomizing of the transformations we'll look at Opacity. This code is identical to the expression for Rotation except that "minVal" and "maxVal" have been changed. Here's the code:

random position, rotation, scale, and opacity


segMin = .3; //minimum segment duration
segMax = .7; //maximum segment duration
minVal = 10;
maxVal = 100;

end = 0;
j = 0;
while ( time >= end){
  j += 1;
  seedRandom(j,true);
  start = end;
  end += random(segMin,segMax);
}
endVal =  random(minVal,maxVal);
seedRandom(j-1,true);
dummy=random(); //this is a throw-away value
startVal =  random(minVal,maxVal);
ease(time,start,end,startVal,endVal)

Color

The use of the random expressions isn't just limited to the transform properties. Here's an example where the expression has been applied to the Color property of the Path Text effect. The only modification necessary was to change "minVal" and "maxVal" to numbers that make sense for Color. In the expressions world, color is represented by the four-dimensional color vector [red,blue,green,alpha]. The color channel values can range from 0 to 1.0. So if you're used to thinking of a color channel in terms of values between 0 and 255, it can take some getting used to. Here's the code:

random colors


segMin = .3; //minimum segment duration
segMax = .7; //maximum segment duration
minVal = [0,0,0,1];
maxVal = [1,1,1,1];

end = 0;
j = 0;
while ( time >= end){
  j += 1;
  seedRandom(j,true);
  start = end;
  end += random(segMin,segMax);
}
endVal =  random(minVal,maxVal);
seedRandom(j-1,true);
dummy=random(); //this is a throw-away value
startVal =  random(minVal,maxVal);
ease(time,start,end,startVal,endVal)

While we're in the neighborhood, let's take a look at an example of an extremely simple expression for Color that you can use with Particle Playground. Here's the expression:

random colored particles


random([0,.5,.5,1],[0,1,1,1])

This expression will select only colors with half to full intensity blue and/or green values (no red). Note that this expression works without the need for seed-random() because particles remember their birth color so all we need to do is change the color every frame.


3D

Adapting our random Position expression from 2D to 3D is surprisingly simple. All that's necessary is to add a third dimension to "minVal" and "maxVal" and turn on the 3D switch for your layers. In this example, We've got the camera rotating in an arc around the 3D layers to better demonstrate the movement in the z direction. Here's the code:

random 3D position


segMin = .3; //minimum segment duration
segMax = .7; //maximum segment duration
minVal = [0.1*thisComp.width, 0.1*thisComp.height,0];
maxVal = [0.9*thisComp.width, 0.9*thisComp.height,400];

end = 0;
j = 0;
while ( time >= end){
  j += 1;
  seedRandom(j,true);
  start = end;
  end += random(segMin,segMax);
}
endVal =  random(minVal,maxVal);
seedRandom(j-1,true);
dummy=random(); //this is a throw-away value
startVal =  random(minVal,maxVal);
ease(time,start,end,startVal,endVal)

3D Rotation

Converting our Random rotation expression to 3D is simply a matter of making the layer 3D and applying the expression to the x, y, and z Rotation properties. The code is identical to the one-dimensional Rotation expression. Here's the code again just for reference:

random 3D rotation


segMin = .3; //minimum segment duration
segMax = .7; //maximum segment duration
minVal = -720;
maxVal = 720;

end = 0;
j = 0;
while ( time >= end){
  j += 1;
  seedRandom(j,true);
  start = end;
  end += random(segMin,segMax);
}
endVal =  random(minVal,maxVal);
seedRandom(j-1,true);
dummy=random(); //this is a throw-away value
startVal =  random(minVal,maxVal);
ease(time,start,end,startVal,endVal)

3D Orientation

Another flavor of 3D rotation can be created by applying a variation of our random Rotation expression to the three-dimensional Orientation property of a 3D layer instead of the individual x, y, and z Rotation properties. The only modification necessary is to make "minVal" and "maxVal" three-dimensional. Here's the code:

random 3D rotation


segMin = .3; //minimum segment duration
segMax = .7; //maximum segment duration
minVal = [0,0,0];
maxVal = [720,720,720];

end = 0;
j = 0;
while ( time >= end){
  j += 1;
  seedRandom(j,true);
  start = end;
  end += random(segMin,segMax);
}
endVal =  random(minVal,maxVal);
seedRandom(j-1,true);
dummy=random(); //this is a throw-away value
startVal =  random(minVal,maxVal);
ease(time,start,end,startVal,endVal)

Master Control

In the examples where we have multiple properties being randomized, each property expression is operating independently from the others. That means, for example, that a new Rotation segment may begin in the middle of a Position move. That can be very useful and may be what you want, but it would also be nice to be able to sync all the randomness of a single layer so that each new segment contains a new position move, a new rotation, a new opacity, etc, and that they all ease in and out together. Fortunately, there's a way to do this. Remember that expressions can't get at variables in other expressions and there are no true global variables. All that's visible to other expressions is the final output value.


So how do we get all these expressions for all these different properties to have the same random timing? We use an Expression Control (in a way that it probably wasn't intended to be used). We'll use a Point Control as a read-only global variable. Why a Point Control? A Point Control is two-dimensional and we need to make the segment start time and end time available to each of the layer's expressions so that they will be in sync. So our basic strategy is to move all the start and stop time calculations to a Point Control expression so that it will accessible to the layer's other expressions. Then we'll modify the other expressions to pick up the timing information from the Point Control. There's one other little detail. The Point Control will calculate the start and stop times, but how do we make sure that the other expressions are able to get the same random property at each frame of the segment? I mean, in the previous self-contained versions, we were using the segment index as the random seed because we knew it would be unique to the segment, but that information is not available (it's hidden inside the Point Control expression). Well, it turns out we can use the start and stop times as random seeds and they will work just fine because they are also unique within the segment. Here's the code for the Point Control:

synchronized position, rotation, and scale


segMin = .75; //minimum segment duration
segMax = 1.0; //maximum segment duration

end = 0;
j = 0;
while ( time >= end){
  j += 1;
  seedRandom(j,true);
  start = end;
  end += random(segMin,segMax);
}
[start,end]

Notice that the random Position, Rotation, and Scale changes for each layer are now synchronized (I've made the segments longer in this example - between .75 and 1.0 seconds - so that you can more easily observe the synchronization.) You'll note that all that's in this code is the calculation of the segment start and stop times. Now let's look at how we would modify the random Position expression to make use of this:


minVal = [0.1*thisComp.width, 0.1*thisComp.height];
maxVal = [0.9*thisComp.width, 0.9*thisComp.height];

start = effect("Point Control").param("Point")[0];
end = effect("Point Control").param("Point")[1];
seedRandom(start,true)
startVal =  random(minVal,maxVal);
seedRandom(end,true)
endVal =  random(minVal,maxVal);
ease(time,start,end,startVal,endVal)

This is just what's left of the random Position expression with added code to pick up the segment start and stop times from the Point Control, and the code that uses those values as the two seeds for the random number generator. For completeness, here's the modified code for Rotation:


minVal = -720;
maxVal = 720;

start = effect("Point Control").param("Point")[0];
end = effect("Point Control").param("Point")[1];
seedRandom(start,true)
startVal =  random(minVal,maxVal);
seedRandom(end,true)
endVal =  random(minVal,maxVal);
ease(time,start,end,startVal,endVal)

And here's the modified code for scale:


minVal = 50;
maxVal = 200;

start = effect("Point Control").param("Point")[0];
end = effect("Point Control").param("Point")[1];
seedRandom(start,true)
s =  random(minVal,maxVal);
startVal = [s,s];
seedRandom(end,true)
s =  random(minVal,maxVal);
endVal = [s,s]
ease(time,start,end,startVal,endVal)

In the next section we'll look at some more complex, special-purpose applications of the random motion expression.




previous next