Как отрисовывается графика в играх. Зачем нужны DirectX, Vulkan и какая вообще происходит магия, когда вы смотрите на экран игры
Мало кто задумывается о том, как компьютер получает команду отрисовать врага с автоматом в руках, а при стрельбе - нарисовать эффекты выстрела. В этой статье я простым языком расскажу, как формируется графика в играх и при чём тут DirectX, OpenGL и другие штуки, которые иногда просят обновиться (или установиться) при установке игры. Простым языком. Начнём.
Когда вы запускаете игру, она "выбирает", через что игра будет общаться с вашей видеокартой - ведь ей нужно как-то передавать видеокарте команды, что рисовать. Такой прослойкой являются графические API: DirectX, OpenGL, Vulkan и так далее.
Но что такое API? Это набор правил, которые позволяют приложениям общаться друг с другом. И почти каждое серьёзное приложение опирается на какие-то API. Скажу больше - даже ваши смартфоны целиком и полностью состоят из разных API (необязательно из вышеуказанных). Ведь вашей камере, например, нужно как-то понимать, что вы в приложении нажали кнопку "Фото".
Итак, принцип работы API в играх такой: вы запускаете игру → игра обращается к API (например, DirectX) → API передаёт данные драйверу видеокарты, который переводит их в понятный конкретной видеокарте вид → создаётся набор буферов кадра (swap chain), где один буфер показывается на экране, пока в другой в это время рисуется следующий кадр → когда новый кадр готов, буферы меняются местами — то, что было "черновиком", становится видимым кадром, а бывший видимый кадр превращается в черновик для следующего рендера.
Да, кстати, давайте всё-таки "отрисовку" далее по статье будем называть рендером или рендерингом. Так более профессионально, что ли. Поэтому далее в статье рендер = отрисовка.
Кадры в играх - самый важный компонент. Точнее, один из самых важных, но прям от них зависит невероятно многое. Если у вас слабый компьютер, ему требуется больше времени на отрисовку каждого кадра - отсюда и тормоза в играх (вообще причин может быть много, но это как вариант).
Дальше происходит компиляция шейдеров. Шейдеры - это маленькие программы, которые описывают, как видеокарта должна рендерить конкретный материал, эффект или свет. Проблема в том, что шейдер нужно скомпилировать под конкретную модель видеокарты заранее, иначе она "не поймёт", как это рисовать.
Поэтому когда вы видите полоску загрузки "компиляция шейдеров" - игра в этот момент заранее готовит для видеокарты все нужные инструкции, чтобы потом не компилировать их прямо во время игры (а это как раз вызывает те самые фризы и микрозависания).
Кстати говоря, на консолях компиляции шейдеров нет по той лишь причине, что разработчик заранее знает, какая видеокарта в условной Playstation 5, а поэтому там не нужны давать инструкции: инструкции уже "вшиты" в игру.
В некоторых играх (например, Atomic Heart) можно запустить игру до завершения компиляции - но тогда фризы будут случаться прямо в процессе, потому что видеокарта компилирует шейдеры на лету, по мере встречи с новыми эффектами. Потому что инструкции ещё все не получены.
Представьте, что вы строите дом без полной инструкции, а чертежи вам приносят по ходу стройки - стройка будет тормозить каждый раз на новом этапе. Когда бригадир заранее выдал все чертежи и ушёл - стройка идёт гладко, правда нужно дождаться, когда инструкции будут готовы.
После этого создаются буферы вершин объектов - каждый объект в игре состоит из набора вершин, которые и формируют его форму. Теперь видеокарта знает, как отрисовать этот объект, потому что все нужные данные и инструкции у неё есть.
Теперь про разницу между DirectX, Vulkan, Metal (только для macOS/iOS), OpenGL. Всё это - API, которые позволяют игре "общаться" с вашей видеокартой, передавая инструкции, что и как рендерить.
Отдельную статью про технические различия этих API я, возможно, напишу позже, а пока - что это значит для вас как для игрока. DirectX12, Vulkan и другие современные API умеют готовить команды рендеринга сразу в нескольких потоках процессора одновременно - в отличие от уже устаревших (но до сих пор поддерживаемых) DirectX11 и OpenGL, где почти всё идёт через один поток. Из-за этого в сценах с большим количеством объектов (толпы NPC, открытый мир) DX12/Vulkan теоретически должны меньше нагружать процессор и давать более высокий FPS.
Но есть нюанс: DX12/Vulkan сложнее реализовать правильно, и если разработчики где-то напортачили, вы получите не прирост производительности, а фризы и статтеры — потому что часть шейдеров компилируется прямо во время игры, а не заранее. Поэтому на практике совет такой: если ловите просадки FPS в динамичных сценах — пробуйте DX12/Vulkan; если ловите именно рывки и фризы — переключайтесь на DX11, он стабильнее просто потому, что старше и лучше обкатан драйверами. При этом ваша видеокарта должна поддерживать соответствующую версию DX. Например, видеокарты, выпущенные до 2015 года, DX12 не поддерживают.
Но тут возникает вопрос: а как сама игра "открывает рот", чтобы вообще что-то передать ("рассказать, что рисовать") через API? Ответ - процессор (CPU) вашего компьютера. И да, извиняюсь за такую, возможно, забавную аналогию, но зато понятную.
Цепочка выглядит так: процессор знает всю информацию об объекте, который нужно отрендерить — данные о вершинах, материалах, текстурах (CPU знает, как должен выглядеть объект, но сам его "не видит") → эта информация передаётся драйверу видеокарты через графическое API в виде команд-вызовов (draw call - буквально "вызов отрисовки") → драйвер переводит эти команды в машинные инструкции, понятные конкретной модели GPU → видеокарта выполняет эти инструкции и рисует объект в нужном месте экрана, для каждого пикселя определяя, что ближе к камере, а что дальше и должно быть скрыто (это и есть Z-buffer).
Вообще кстати про буфферы в играх нужно будет мне отдельную статью написать, уж очень много интересностей там, но, думаю, как-нибудь в другой раз.
Так вот, если уж совсем просто резюмировать нашу статью: CPU знает, как должен выглядеть объект в игре, передаёт это знание графическому API в виде команд, драйвер переводит эти команды на язык конкретной видеокарты, а сама видеокарта уже физически рисует объект на экране в конкретный кадр.
Если же за отведенное время что-то происходит нехорошее (от слабости вашей системы до плохой оптимизации игры), то либо процессор компьютера, либо процессор видеокарты не успевают за отведенное время нормальным образом подготовить следующий кадр, то у нас и происходят "фризы" в игре (ну или падение FPS, если говорить чуть более профессионально). Туда же можно отнести и такой термин, как bottleneck ("бутылочное горлышко"), но это уже тоже материал, возможно, для отдельной статьи.
Всем спасибо! Я надеюсь, что стало более-менее понятно, какая магия происходит, когда вы играете в игры:)
Об авторе поста:
Являюсь разработчиком игр и веду свой YouTube канал по созданию игр на Unreal Engine. Если интересно, то можете заглянуть и подписаться, поскольку показываю в своих видео, как создаются популярные игровые механики.

















