Прежде всего, я знаю, что Application.targetFrameRate
существует, и он выполняет достаточно хорошую работу, но я хочу что-то более точное. Для меня это ограничивает частоту кадров до 60,3, когда установлено 60, и около 204, когда установлено 200. Кстати, они измеряются в сборках (не в редакторе) с использованием RTSS 7.2 .
Поэтому я решил создать свой собственный ограничитель кадров в Unity, используя таймеры низкого уровня, но по какой-то причине он просто не работает правильно. Вот мой код:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Threading;
using System;
public class FrameLimiter : MonoBehaviour
{
private FrameLimiter m_Instance;
public FrameLimiter Instance { get { return m_Instance; } }
public double FPSLimit = 300.0;
private long lastTime = HighResolutionDateTime.UtcNow.Ticks;
void Awake()
{
m_Instance = this;
}
void OnDestroy()
{
m_Instance = null;
}
void Update()
{
if (FPSLimit == 0.0) return;
lastTime += TimeSpan.FromSeconds(1.0 / FPSLimit).Ticks;
var now = HighResolutionDateTime.UtcNow.Ticks;
if (now >= lastTime)
{
lastTime = now;
return;
}
else
{
SpinWait.SpinUntil(() => { return (HighResolutionDateTime.UtcNow.Ticks >= lastTime); });
}
}
}
По сути, это синглтон, который должен выполняться перед любым другим сценарием в порядке выполнения сценария, и он блокирует выполнение до тех пор, пока не будет достигнуто нужное время.
Способ, которым он работает, заключается в том, что он отслеживает точное время, когда он последний раз позволил визуализировать кадр (он получает текущее время из очень точного таймера низкого уровня, , подробнее об этом ) , Затем при каждом вызове своей функции Update()
она добавляет 1.0 / FPSLimit
секунд, чтобы получить время, когда должен быть представлен следующий кадр, а затем, если текущее время меньше этого времени, оно блокирует выполнение до тех пор, пока эта временная метка не будет достиг.
SpinWait
- это просто эффективный способ блокировать выполнение без закрепления ЦП, как это делает пустой цикл while
. Но только для записи, я тоже попробовал пустой цикл while
и получил те же результаты, за исключением гораздо более высокой загрузки ЦП.
Итак, если вы понимаете, как этот код должен работать, вы должны увидеть, что теоретически это должно очень точно фиксировать частоту кадров, особенно учитывая, что этот таймер имеет точность лучше 1 мкс (0,001 мс) в соответствии с Microsoft .
Но, несмотря на все это, я получаю около 58,8 FPS, когда я устанавливаю это значение на 60 , что я действительно не понимаю. Я запускаю сборку в эксклюзивном полноэкранном режиме с отключенной V-синхронизацией. Кстати, я получаю гораздо более высокую частоту кадров без ограничений, поэтому базовая производительность игры не проблема.
Буду признателен за любую помощь!