Особенности симуляции реального времени в Unity3D
Валерия Пудова
4 декабря 2020
Введение
Анализ особенностей программирования процессов реального времени в дискретной системе симуляции на примере Unity3D.
Цель документа — подтвердить или опровергнуть, что методы Update или FixedUpdate не гарантируют точность внутренних часов (Time). Документ должен ответить на два вопроса:
- Может ли быть гарантирован вызов метода
FixedUpdateчерез равные промежутки времени? - Может ли
FixedUpdateбыть вызван предсказуемое число раз за определённый промежуток реального времени?
Ниже вопросы сформулированы более конкретно, и на них даны ответы.
Вызывается ли FixedUpdate в реальном времени?
Если fixedDeltaTime равна 10 мс, будет ли метод вызываться строго каждые 10 миллисекунд?
Нет, не будет.
Время обновления физики (TFPU — time for physics update) в зависимости от ситуации может быть меньше или больше, чем fixedDeltaTime.
Будет ли гарантировано, что за реальное время T метод FixedUpdate будет вызван согласно выражению:
Nfu = T / Fdt
где:
Nfu— количество вызововFixedUpdateT— реальное времяFdt— значениеfixedDeltaTime
Нет, не будет.
В ситуации, когда TFPU больше, чем fixedDeltaTime, физический движок не сможет достичь времени T, даже если загрузит процессор эксклюзивно. Поскольку физика пытается догнать реальное время и непрерывно выполняется Nfus раз подряд, пока fixedTime меньше T, это приводит к замораживанию рендеринга на неопределённое время (Frame-skipping mode).
Чтобы минимизировать этот эффект, существует параметр maximumDeltaTime. Он не позволяет физике выполняться подряд дольше заданной величины. Когда произведение fixedDeltaTime * Nfus достигает значения, большего или равного maximumDeltaTime, физика «откладывает» обновление, пропуская фрагмент реального времени (Wall of molasses mode).
Иначе говоря, время в виртуальном мире не может быть гарантированно синхронизировано с реальным временем. Об этом чётко написано в руководстве Unity3D:
If frame will take longer than specified value, then less physics and other fixed frame rate updates will be performed. That will temporarily slow down the gameplay, but will allow frame rate to catch up, avoiding nasty stuttering.
Может ли Time.time быть рассинхронизировано с Time.fixedTime?
Не может. Одно зависит от другого, что может быть описано упрощённой формулой:
Tvn = Tvn-1 + Fdt * Nfus
где:
Tvn— время в кадреnTvn-1— время в кадреn-1Fdt— значениеfixedDeltaTimeNfus— количество вызововFixedUpdateмеждуTnиTn-1
Вывод
Unity3D не манипулирует значением timeScale и не замедляет время. Вместо этого, когда TFPU больше Fdt и если Fdt * Nfus превышает maximumDeltaTime, Unity3D принудительно прерывает обновление физики, отдавая предпочтение другим операциям (например, рендерингу). Это косвенно замедляет время внутри Unity3D.
- Система не может гарантировать вызов метода
FixedUpdateчерез равные промежутки времени. - Система не может вызвать
FixedUpdateпредсказуемое число раз за определённый промежуток реального времени.
Когда система испытывает нехватку вычислительных ресурсов, используется один из двух возможных сценариев (иногда называемых):
- Frame-skipping mode — подтормаживание рендеринга при нормальной скорости анимаций.
- Wall of molasses mode — замедление анимаций физических объектов при нормальной скорости рендеринга.
То же самое справедливо и для других движков.