diff --git a/core/src/processing/core/PApplet.java b/core/src/processing/core/PApplet.java index 85f0fb81a..ca37ca75a 100644 --- a/core/src/processing/core/PApplet.java +++ b/core/src/processing/core/PApplet.java @@ -713,7 +713,7 @@ public class PApplet implements PConstants { * @see PApplet#frameRate(float) * @see PApplet#frameCount */ - public float frameRate = 10; + public float frameRate = 60; protected boolean looping = true; @@ -2434,9 +2434,34 @@ public class PApplet implements PConstants { } else { // frameCount > 0, meaning an actual draw() // update the current frameRate - double rate = 1000000.0 / ((now - frameRateLastNanos) / 1000000.0); - float instantaneousRate = (float) (rate / 1000.0); - frameRate = (frameRate * 0.9f) + (instantaneousRate * 0.1f); + + // Calculate frameRate through average frame times, not average fps, e.g.: + // + // Alternating 2 ms and 20 ms frames (JavaFX or JOGL sometimes does this) + // is around 90.91 fps (two frames in 22 ms, one frame 11 ms). + // + // However, averaging fps gives us: (500 fps + 50 fps) / 2 = 275 fps. + // This is because we had 500 fps for 2 ms and 50 fps for 20 ms, but we + // counted them with equal weight. + // + // If we average frame times instead, we get the right result: + // (2 ms + 20 ms) / 2 = 11 ms per frame, which is 1000/11 = 90.91 fps. + // + // The counter below uses exponential moving average. To do the + // calculation, we first convert the accumulated frame rate to average + // frame time, then calculate the exponential moving average, and then + // convert the average frame time back to frame rate. + { + // Get the frame time of the last frame + double frameTimeSecs = (now - frameRateLastNanos) / 1e9; + // Convert average frames per second to average frame time + double avgFrameTimeSecs = 1.0 / (double) frameRate; + // Calculate exponential moving average of frame time + final double alpha = 0.05; + avgFrameTimeSecs = (1.0 - alpha) * avgFrameTimeSecs + alpha * frameTimeSecs; + // Convert frame time back to frames per second + frameRate = (float) (1.0 / avgFrameTimeSecs); + } if (frameCount != 0) { handleMethods("pre");