My code calculates average FPS. Every 0.4s it updates the FPS text. Every 2s it resets the number of average FPS. I need to calculate accurate and smooth FPS (so any temporary spikes will be eliminated). So is this FPS counter code will follow my requirements?

[RequireComponent(typeof(TMP_Text))] public class FpsCounter : MonoBehaviour { private struct AverageFloat { public float Average => _value / _count; private float _value; private int _count; public void Add(float number) { _value += number; _count++; } public void Reset() { _value = 0f; _count = 0; } } [SerializeField] private float _averageValueCollectionTime = 2f; [SerializeField] private float _refreshFrequency = 0.4f; private float _timeSinceFpsReset = 0f; private float _timeSinceUpdate = 0f; private AverageFloat _fpsValue; private TMP_Text _text; private void Start() { _text = GetComponent<TMP_Text>(); } private void Update() { if (_timeSinceFpsReset > _averageValueCollectionTime) { _timeSinceFpsReset = 0; _fpsValue.Reset(); } _fpsValue.Add(1f / Time.unscaledDeltaTime); _timeSinceFpsReset += Time.deltaTime; if (_timeSinceUpdate < _refreshFrequency) { _timeSinceUpdate += Time.deltaTime; return; } int fps = Mathf.RoundToInt(_fpsValue.Average); _text.text = fps.ToString(); _timeSinceUpdate = 0f; } } 
2

2 Answers

You could use InvokeRepeating in order to reset / refresh your number of average FPS, in addition to Time.frameCount to get the number of frames.

So... It's better to calculate FPS with exponentially weighted moving average. This solution gives more accurate and smooth results.

[RequireComponent(typeof(TMP_Text))] public class FpsCounter : MonoBehaviour { [SerializeField] [Range(0f, 1f)] private float _expSmoothingFactor = 0.9f; [SerializeField] private float _refreshFrequency = 0.4f; private float _timeSinceUpdate = 0f; private float _averageFps = 1f; private TMP_Text _text; private void Start() { _text = GetComponent<TMP_Text>(); } private void Update() { // Exponentially weighted moving average (EWMA) _averageFps = _expSmoothingFactor * _averageFps + (1f - _expSmoothingFactor) * 1f / Time.unscaledDeltaTime; if (_timeSinceUpdate < _refreshFrequency) { _timeSinceUpdate += Time.deltaTime; return; } int fps = Mathf.RoundToInt(_averageFps); _text.text = fps.ToString(); _timeSinceUpdate = 0f; } } 

_expSmoothingFactor must be set from 0 to 1. It determines how much smoothing will be applied. 0.9 value is most optimal (higher value = more smoothing).

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.