Мультипоточность в играх

Как игровые движки решают проблемы с проседанием FPS и какие новые проблемы это может вызвать

Мультипоточность в играх

Я задумался об этой статье недавно, когда у меня в игре снова началось "дрожание". Дрожание - вообще очень жуткая штука для новичков в программировании игр, потому что это не какая-то забытая точка с запятой, компилятор вам об этом не сообщит. Эти баги проявляются только в специфических случаях и становятся заметны только на немалых скоростях. И самое главное - вам о них не расскажут в уроках на YouTube, только на форумах и под специфическими ключевыми словами, впрочем постоянно ударяясь в теорию и не давая никаких однозначных советов.

Что такое дрожание? Представьте себе игровую камеру и движущийся объект. Оба движутся параллельно и с одинаковой скоростью. Камера смотрит на объект и видит, что он движется. Но дёрганно: иногда сдавая чуть-чуть назад, иногда вперёд, причём это происходит не плавно, а по-разному в каждом отдельном кадре.

Зелёный квадрат - камера. Красный - объект. Оба движутся с одинаковой скоростью, но у каждого из них разная скорость обновления, а потому в объективе камеры объект трясётся
Зелёный квадрат - камера. Красный - объект. Оба движутся с одинаковой скоростью, но у каждого из них разная скорость обновления, а потому в объективе камеры объект трясётся

Почему так происходит? Потому что камера и объект обновляются в разных потоках. У первого потока задержка в 0.015 секунд, у второго в 0.020 секунд. Поэтому из-за несовпадения частоты позиции объектов не синхронизированы.

Разбитие игры на потоки - это стандартная практика в современных движках, говорим ли мы о Unity, об Unreal Engine или каком-то другом. В разных движках это по разному, но принцип всегда один: логика отделена от рендера и работает параллельно. С одной стороны, чтобы тяжёлая логика не мешала плавной отрисовке игры, с другой стороны чтобы тяжёлые графические эффекты не мешали логике игры.

Потому что падение производительности для обоих процессов для игры очень критично. Я уж не буду говорить о шутерах, где каждый пропущенный кадр может стать роковым и привести к поражению. Падение FPS очень плохо влияет на визуальную составляющую игры и, что хуже, снижает отзывчивость управления. А падение скорости обработки логики может приводить к багам (например, физическим, ведь все физические процессы в игровом мире дискретны).

Но, как и во всех остальных играх, любая многопоточность плодит много проблем, связанных с синхронизацией. Конечно, игровые движки позаботились о том, чтобы игровой программист вообще не сталкивался с ситуациями гонки за ресурсами, устареванием данных, блокировкой, организацией и синхронизацией потоков. Но тем не менее, стоит засунуть логику или рендер не в те потоки - отлов лагов и их исправление будет на порядок сложнее (впрочем, не так сложно). Поэтому устройство движка стоит держать в уме и учитывать с самого начала разработки. И это касается не только вашего личного кода, например я только недавно узнал, что встроенные системы частиц в Unity тоже должны быть синхронизированы с камерой отдельно через специальную опцию.

Хотя и это ещё не всё, помимо потока логики и потока рендера, в игре может быть ещё огромное количество других потоков: поток чтения данных из файла, поток чтения данных из сети, сама логика игры может быть тоже поделена на несколько потоков. Опять же, это всё не то, чтобы ускоряет производительность. Просто одни процессы не простаивают в ожидании других процессов. Потому что в современном мире компьютеры уже достигли невероятных высот и всё, что их теперь сдерживает - это недостаточно эффективный код.

11
2 комментария