Skip to content

Commit

Permalink
Keep physics steps consistent over multiple frames
Browse files Browse the repository at this point in the history
To avoid stuttering when the physics FPS does not match the screen
refresh at all (60 FPS physics on a 144 or 120 Hz screen), we need to
keep track of the typical number of physics steps accumulated over the
last N frames; otherwise, the same logic as before with single frame
tracking applies. The next accumulated update count should be a stored
typical value for it or one higher. Changes to the typical value
happen only if a threshold is surpassed.
  • Loading branch information
zmanuel committed Mar 7, 2018
1 parent 572e7a9 commit 9a55346
Showing 1 changed file with 57 additions and 8 deletions.
65 changes: 57 additions & 8 deletions main/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1239,8 +1239,17 @@ class _TimerSync {
// current difference between wall clock time and reported sum of animation_steps
float time_deficit;

// typical value for physics_steps is either this or this plus one
int typical_physics_steps;
// number of frames back for keeping accumulated physics steps roughly constant.
// value of 12 chosen because that is what is required to make 144 Hz monitors
// behave well with 60 Hz physics updates. The only worse commonly available refresh
// would be 85, requiring CONTROL_STEPS = 17.
static const int CONTROL_STEPS = 12;

// sum of physics steps done over the last x frames
int accumulated_physics_steps[CONTROL_STEPS];

// typical value for accumulated_physics_steps[x] is either this or this plus one
int typical_physics_steps[CONTROL_STEPS];

protected:
// returns the fraction of p_frame_slice required for the timer to overshoot
Expand All @@ -1261,17 +1270,54 @@ class _TimerSync {
time_accum += ret.animation_step;
ret.physics_steps = floor(time_accum * p_iterations_per_second);

int min_typical_steps = typical_physics_steps[0];
int max_typical_steps = min_typical_steps + 1;

// given the past recorded steps and typcial steps to match, calculate bounds for this
// step to be typical
bool update_typical = false;

for (int i = CONTROL_STEPS - 2; i >= 0; --i) {
int steps_left_to_match_typical = typical_physics_steps[i + 1] - accumulated_physics_steps[i];
if (steps_left_to_match_typical > max_typical_steps ||
steps_left_to_match_typical + 1 < min_typical_steps) {
update_typical = true;
break;
}

if (steps_left_to_match_typical > min_typical_steps)
min_typical_steps = steps_left_to_match_typical;
if (steps_left_to_match_typical + 1 < max_typical_steps)
max_typical_steps = steps_left_to_match_typical + 1;
}

// try to keep it consistent with previous iterations
if (ret.physics_steps < typical_physics_steps) {
if (ret.physics_steps < min_typical_steps) {
ret.physics_steps = floor(time_accum * p_iterations_per_second + get_physics_steps_change_threshold());
typical_physics_steps = ret.physics_steps;
} else if (ret.physics_steps > typical_physics_steps + 1) {
update_typical = true;
} else if (ret.physics_steps > max_typical_steps) {
ret.physics_steps = floor(time_accum * p_iterations_per_second - get_physics_steps_change_threshold());
typical_physics_steps = ret.physics_steps - 1;
update_typical = true;
}

time_accum -= ret.physics_steps * p_frame_slice;

// keep track of accumulated step counts
for (int i = CONTROL_STEPS - 2; i >= 0; --i) {
accumulated_physics_steps[i + 1] = accumulated_physics_steps[i] + ret.physics_steps;
}
accumulated_physics_steps[0] = ret.physics_steps;

if (update_typical) {
for (int i = CONTROL_STEPS - 1; i >= 0; --i) {
if (typical_physics_steps[i] > accumulated_physics_steps[i]) {
typical_physics_steps[i] = accumulated_physics_steps[i];
} else if (typical_physics_steps[i] < accumulated_physics_steps[i] - 1) {
typical_physics_steps[i] = accumulated_physics_steps[i] - 1;
}
}
}

return ret;
}

Expand Down Expand Up @@ -1313,8 +1359,11 @@ class _TimerSync {
last_cpu_ticks_usec(0),
current_cpu_ticks_usec(0),
time_accum(0),
time_deficit(0),
typical_physics_steps(1) {
time_deficit(0) {
for (int i = CONTROL_STEPS - 1; i >= 0; --i) {
typical_physics_steps[i] = 0;
accumulated_physics_steps[i] = 0;
}
}

// start the clock
Expand Down

0 comments on commit 9a55346

Please sign in to comment.