ComFreek
ComFreek

Reputation: 29424

Create smooth rotation in given time interval (+- x%)

I have got a cube in my scene which I want to rotate at a specific start velocity and in a given time interval.
In addition, the cube's end angle should be the same as the start angle. Therefore, I thought of allowing +- 5% deviation of the time interval.

Here is my current status: http://jsfiddle.net/5NWab/1/.
Don't wonder that is currently working. The problem occurs if I change the time interval, e.g. by '3000': http://jsfiddle.net/5NWab/2/.

The essential move() method of my cube:

Reel.prototype.move = function (delta) {
    if (this.velocity < 0 && this.mesh.rotation.x == 0) {
        return false;
    }

    // Create smooth end rotation
    if (this.velocity < 0 && this.mesh.rotation.x != 0) {
        this.mesh.rotation.x += Math.abs(delta * this.speedUp * 0.5 * this.timeSpan);
        if (Math.abs(this.mesh.rotation.x - 2 * Math.PI) < 0.1) {
            this.mesh.rotation.x = 0;
        }
    }

    else {
        this.mesh.rotation.x += delta * this.velocity;

        this.time -= delta;
        this.velocity = this.speedUp * this.time;
    }
}

The problem is that I cannot think of a solution or method in order to accomplish my topic. It would not be so complex if I the variable delta would be constant.
It should be around 60fps = 1000/60 because I'm using requestAnimationFrame().

I have also found this question which could help finding the solution.

I think the code should either

But what is when the angle is a hemicycle away from the desired one (i.e. 180° or PI)?

In order to clarify my question, here are my knowns and unknowns:

Known:

I want the cube to have the same start angle/position at the end of the rotation. Because the FPS count is not constant, I have to shorten or lengthen the time interval in order to get the cube into the desired position.

Upvotes: 1

Views: 1744

Answers (2)

Phil H
Phil H

Reputation: 20141

If you want the rotation to end at a particular angle at a particular time, then I would suggest that instead of continually decrementing the rotation as your current code (2012-09-27) does, set the target time and rotation when you initialise the animation and calculate the correct rotation for the time of the frame recalculation.

So if you were doing a sine-shaped speed curve (eases in and out, linearish in the middle, nice native functions to calculate it), then (pseudocode not using your variables):

//in init
var targetTime = now + animationTime;
// normalize the length of the sine curve
var timeFactor = pi/animationTime;
var startAngle = ...
var endAngle = ...
var angleChange = endAngle - startAngle;

// inside the animation, at some time t
var remainingT = targetTime - t;
if(remainingT <= 0) {
    var angle = endAngle;
} else {
    var angle = startAngle + cos(remainingT * timefactor) * angleChange;
}

[Edited to add startAngle into andle calculation]

Because the cos function is odd (i.e. symmetric about the origin), as t approaches targetTime, the remainingT approaches zero and we move backward from pi to 0 on the curve. The curve of the sin shape flattens toward zero (and pi) so it will ease out at the end (and in at the beginning. There is an explicit zeroing of the angle at or past the targetTime, so that any jitter in the framerate doesn't just push it into an endless loop.

Upvotes: 1

voithos
voithos

Reputation: 70552

Here's one possible method, although it's not quite as good as I'd like: http://jsfiddle.net/5NWab/8/

The idea is to decrease the speed gradually, as you were doing, based on the amount of time left, until you get to a point where the amount of distance that the cube has to rotate to reach it's starting rotation (0) becomes greater than or equal to the amount of rotation that can possibly be made given the current velocity and the current amount of time left. After that point, ignore the time left, and slow down the velocity in proportion to the amount of rotation left.

This works fairly well for certain timeSpans, but for others the ending slowdown animation takes a little long.

Upvotes: 1

Related Questions