Here’s my approach:
Add a layer named “control” with two sliders, “ground” and “ease”. Set ground to the desired y coordinate for the ground plane and ease to how many pixels above the ground plane you want to start the transition.
Then use this for the Position value expression
yVelocity = 200; //pixels per second
oscFreq = 1.5; //oscillations per second
oscDepth = 35; //oscillation depth (pixels)
drift = 25; // drift (pixels per second: - = left, + = right)
ground = thisComp.layer("control").effect("ground")("Slider");
ease = thisComp.layer("control").effect("ease")("Slider");
y_origin = transform.position.valueAtTime(0)[1];
x_position = transform.position[0];
y_position = y_origin+yVelocity*time;
z_position = transform.position[2];
if (y_position>ground-ease && y_positionground){
y_position=ground;
oscDepth = 0;
}
y_distance = y_position-y_origin;
pos = [x_position+oscDepth*Math.sin(oscFreq*Math.PI*2*time) + drift*y_distance/100, y_position, z_position];
pos
and this for the Y Rotation
yVelocity = 200; //pixels per second
oscFreq = 1.5;
maxTilt = 15; //degrees
ground = thisComp.layer("control").effect("ground")("Slider");
ease = thisComp.layer("control").effect("ease")("Slider");
y_origin = transform.position.valueAtTime(0)[1];
y_position = y_origin+yVelocity*time;
if (y_position>ground-ease && y_positionground){
maxTilt = 0;
}
tilt=maxTilt*Math.cos(oscFreq*Math.PI*2*time);
tilt
Now the animation will smoothly stop at the ground place regardless of starting position.
If you duplicate this to multiple layers the oscillation and motion will be synchronized, so you’ll want to add other random values for some of the variables. Or change the settings for each layer.