Search code examples
c++calculus

Framerate independent acceleration/decceleration?


I'm writing a particle simulator in C++.

I move particles around by adding their velocity to their position at each time step.

The value of the time step is a percentage of the current frame. So full frame time step is 1, half frame time step is .5, quarter frame time step is .25, etc. The total simulation steps is frameCount/timeStep...so the smaller the time step, the greater the total number of steps simulated.

Keeping basic movement across time steps the same is very simple. The equation is:

position = position + velocity * timeStep; //10 full frames later, end position is always the same

However, it gets too complicated for my current understanding of math once I try to change the velocity over time too. For example, if I do this:

velocity = velocity * .95f;
position = position + velocity * timeStep; //10 full frames later, end position dependent on time step

The results across different time steps are no longer the same. I know this is because if I'm increasing the total number of steps calculated by decreasing the time step, I'm also decreasing the velocity that many more times too, which will have a big impact on the final position of the particle.

How can I modify the velocity over time in such a way that I get identical results across different time steps?


Solution

  • Velocity is change in position over time. You've correctly calculated that in your equation.

    position = position + velocity * timeStep;
    

    Acceleration is change in velocity over time. So you just use the same equation, but modify the variables accordingly. That is, change position to velocity, and velocity to acceleration. The time step stays the same.

    velocity = velocity + acceleration * timeStep;
    

    If you want to simulate friction, then what you do is multiply the velocity by some constant friction value and the time step, and subtract this from the acceleration. But this value should only be used for the frame, and not be stored in the actual acceleration value.

    float temp_accel = acceleration - friction * velocity * timeStep;
    

    Then modify your velocity according to temp_accel.

    velocity = velocity + temp_accel * timeStep;
    

    If your acceleration is zero, then you can take that out of the equation:

    float temp_accel = -friction * velocity * timeStep;