Calculating frames per second in a game

后端 未结 19 641
天命终不由人
天命终不由人 2020-12-04 05:10

What\'s a good algorithm for calculating frames per second in a game? I want to show it as a number in the corner of the screen. If I just look at how long it took to render

相关标签:
19条回答
  • 2020-12-04 05:42

    JavaScript:

    // Set the end and start times
    var start = (new Date).getTime(), end, FPS;
      /* ...
       * the loop/block your want to watch
       * ...
       */
    end = (new Date).getTime();
    // since the times are by millisecond, use 1000 (1000ms = 1s)
    // then multiply the result by (MaxFPS / 1000)
    // FPS = (1000 - (end - start)) * (MaxFPS / 1000)
    FPS = Math.round((1000 - (end - start)) * (60 / 1000));
    
    0 讨论(0)
  • 2020-12-04 05:49

    There are at least two ways to do it:


    The first is the one others have mentioned here before me. I think it's the simplest and preferred way. You just to keep track of

    • cn: counter of how many frames you've rendered
    • time_start: the time since you've started counting
    • time_now: the current time

    Calculating the fps in this case is as simple as evaluating this formula:

    • FPS = cn / (time_now - time_start).

    Then there is the uber cool way you might like to use some day:

    Let's say you have 'i' frames to consider. I'll use this notation: f[0], f[1],..., f[i-1] to describe how long it took to render frame 0, frame 1, ..., frame (i-1) respectively.

    Example where i = 3
    
    |f[0]      |f[1]         |f[2]   |
    +----------+-------------+-------+------> time
    

    Then, mathematical definition of fps after i frames would be

    (1) fps[i]   = i     / (f[0] + ... + f[i-1])
    

    And the same formula but only considering i-1 frames.

    (2) fps[i-1] = (i-1) / (f[0] + ... + f[i-2]) 
    

    Now the trick here is to modify the right side of formula (1) in such a way that it will contain the right side of formula (2) and substitute it for it's left side.

    Like so (you should see it more clearly if you write it on a paper):

    fps[i] = i / (f[0] + ... + f[i-1])
           = i / ((f[0] + ... + f[i-2]) + f[i-1])
           = (i/(i-1)) / ((f[0] + ... + f[i-2])/(i-1) + f[i-1]/(i-1))
           = (i/(i-1)) / (1/fps[i-1] + f[i-1]/(i-1))
           = ...
           = (i*fps[i-1]) / (f[i-1] * fps[i-1] + i - 1)
    

    So according to this formula (my math deriving skill are a bit rusty though), to calculate the new fps you need to know the fps from the previous frame, the duration it took to render the last frame and the number of frames you've rendered.

    0 讨论(0)
  • 2020-12-04 05:49

    This is based on KPexEA's answer and gives the Simple Moving Average. Tidied and converted to TypeScript for easy copy and paste:

    Variable declaration:

    fpsObject = {
      maxSamples: 100,
      tickIndex: 0,
      tickSum: 0,
      tickList: []
    }
    

    Function:

    calculateFps(currentFps: number): number {
      this.fpsObject.tickSum -= this.fpsObject.tickList[this.fpsObject.tickIndex] || 0
      this.fpsObject.tickSum += currentFps
      this.fpsObject.tickList[this.fpsObject.tickIndex] = currentFps
      if (++this.fpsObject.tickIndex === this.fpsObject.maxSamples) this.fpsObject.tickIndex = 0
      const smoothedFps = this.fpsObject.tickSum / this.fpsObject.maxSamples
      return Math.floor(smoothedFps)
    }
    

    Usage (may vary in your app):

    this.fps = this.calculateFps(this.ticker.FPS)
    
    0 讨论(0)
  • 2020-12-04 05:50

    This might be overkill for most people, that's why I hadn't posted it when I implemented it. But it's very robust and flexible.

    It stores a Queue with the last frame times, so it can accurately calculate an average FPS value much better than just taking the last frame into consideration.

    It also allows you to ignore one frame, if you are doing something that you know is going to artificially screw up that frame's time.

    It also allows you to change the number of frames to store in the Queue as it runs, so you can test it out on the fly what is the best value for you.

    // Number of past frames to use for FPS smooth calculation - because 
    // Unity's smoothedDeltaTime, well - it kinda sucks
    private int frameTimesSize = 60;
    // A Queue is the perfect data structure for the smoothed FPS task;
    // new values in, old values out
    private Queue<float> frameTimes;
    // Not really needed, but used for faster updating then processing 
    // the entire queue every frame
    private float __frameTimesSum = 0;
    // Flag to ignore the next frame when performing a heavy one-time operation 
    // (like changing resolution)
    private bool _fpsIgnoreNextFrame = false;
    
    //=============================================================================
    // Call this after doing a heavy operation that will screw up with FPS calculation
    void FPSIgnoreNextFrame() {
        this._fpsIgnoreNextFrame = true;
    }
    
    //=============================================================================
    // Smoothed FPS counter updating
    void Update()
    {
        if (this._fpsIgnoreNextFrame) {
            this._fpsIgnoreNextFrame = false;
            return;
        }
    
        // While looping here allows the frameTimesSize member to be changed dinamically
        while (this.frameTimes.Count >= this.frameTimesSize) {
            this.__frameTimesSum -= this.frameTimes.Dequeue();
        }
        while (this.frameTimes.Count < this.frameTimesSize) {
            this.__frameTimesSum += Time.deltaTime;
            this.frameTimes.Enqueue(Time.deltaTime);
        }
    }
    
    //=============================================================================
    // Public function to get smoothed FPS values
    public int GetSmoothedFPS() {
        return (int)(this.frameTimesSize / this.__frameTimesSum * Time.timeScale);
    }
    
    0 讨论(0)
  • 2020-12-04 05:52

    Increment a counter every time you render a screen and clear that counter for some time interval over which you want to measure the frame-rate.

    Ie. Every 3 seconds, get counter/3 and then clear the counter.

    0 讨论(0)
  • 2020-12-04 05:52

    In (c++ like) pseudocode these two are what I used in industrial image processing applications that had to process images from a set of externally triggered camera's. Variations in "frame rate" had a different source (slower or faster production on the belt) but the problem is the same. (I assume that you have a simple timer.peek() call that gives you something like the nr of msec (nsec?) since application start or the last call)

    Solution 1: fast but not updated every frame

    do while (1)
    {
        ProcessImage(frame)
        if (frame.framenumber%poll_interval==0)
        {
            new_time=timer.peek()
            framerate=poll_interval/(new_time - last_time)
            last_time=new_time
        }
    }
    

    Solution 2: updated every frame, requires more memory and CPU

    do while (1)
    {
       ProcessImage(frame)
       new_time=timer.peek()
       delta=new_time - last_time
       last_time = new_time
       total_time += delta
       delta_history.push(delta)
       framerate= delta_history.length() / total_time
       while (delta_history.length() > avg_interval)
       {
          oldest_delta = delta_history.pop()
          total_time -= oldest_delta
       }
    } 
    
    0 讨论(0)
提交回复
热议问题