Успеть за 16 миллисекунд – подробная эволюция интерактивной графики и железа за последние 30 лет и при чем здесь STALKER

Жизнь кадра в Elden Ring. Взято у mamoniem.com/behind-the-pretty-frames-elden-ring

В посте собраны основные инновации за 30 лет истории компьютерной графики и развития GPU. Постарался не уходить в какие-то нердские цифро-дебри, а сфокусироваться на том что важно и видно массовому пользователю с сочными картинками и ссылками на статьи и демо для последующего изучения в время зимних каникул. Статья не претендует на научную точность, а скорее написана по приниципу – "я так вижу", поэтому тех кто найдет неточности приглашаю в комментарии.

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

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

Данный пост это – кроссовер двух мультивселенных Мистера Фроде и мистера Ярла которые объеденились чтобы создать лучшую статью про компьютерную графику в таймлайне ДТФ. Мистер Ярл ушел в тень и пилит свой 2Д движок с лучами и активно помогал в написании этого текста. Поставьте лайк его игре когда она выйдет.

мистер Ярл (@xyzw на DTF)
инди-разраб – jarl-game.com

Графические движки это технологии где прототип можно собрать за выходные учась еще в школе, а потом допиливать до идеала всю жизнь.

– каждый графический программист

Забайтив ДТФ на разборе проблем в UE5, я понял что многим в предыдущем посте интересно не только трястись, но и читать про современную графику в играх как в старые добрые времена до AI-кринжей и глобальных проблем в мире, и у меня появилась идея написать этот лонг. Современная графика в играх это очень объемная тема в которой так сходу не разобраться без соответствующего опыта, но если смотреть на тему с исторической перспективы, то многие вещи становятся намного понятнее.

Часть 0. Это база – Это знать надо

Для начала разберемся с самой простой базой. Графический движок это – технология которая отвечает за вывод графики на экран вашего устройства. Как правило, это самая вычислительно сложная часть современных игр, но далеко не единственная и не всегда самая большая по количеству кода. Технически, графический движок отвечает за сбор данных из сцены которые будут нужны для отрисовки кадра и собcтвенно за саму эту отрисовку используя собранные из сцены данные. Но так было не всегда.

Диаграмма анатомии generic-движка с разными скучными блоками которая призвана отбить весь энтузиазм при изучении компьютерной графики у новичков. Любителей таких картинок эта статья должна разочаровать.
Диаграмма анатомии generic-движка с разными скучными блоками которая призвана отбить весь энтузиазм при изучении компьютерной графики у новичков. Любителей таких картинок эта статья должна разочаровать.

В UE5 например кроме Нанита и Лумена которые у всех на слуху так же есть: материалы, редактор, ввод/вывод, сеть, менеджер и пайплайн для ассетов, движок анимаций, движок частиц, движок физики, навигация, ui, звук, плагины, блупринты, интеграция с ОС, разные экспортеры форматов, системы диагностики и прочие компоненты. Материалы, анимации и частицы тоже относятся к графике, хотя и не отвечают за расчет света напрямую. Тем не менее, сегодня остановимся на том как развивались именно графичеcкие компоненты – то что отвечает за то сколько света пришло в каждый пиксель вашего монитора из сцены, впрочем так было не всегда.

Наталья Татарчук из Bungie (позже глава рендеринга в Unity и Activision) рассказывает о том какой же крутой в Bungie движок и сколько всего он успевает сделать за 16 миллисекунд на PS3: gdcvault.com/play/1021926/Destiny-s-Multithreaded-Rendering
Наталья Татарчук из Bungie (позже глава рендеринга в Unity и Activision) рассказывает о том какой же крутой в Bungie движок и сколько всего он успевает сделать за 16 миллисекунд на PS3: gdcvault.com/play/1021926/Destiny-s-Multithreaded-Rendering

Еще давным-давно в 1986м мистер Каджия-сан из университета Юты в США вывел уравнение – золотой Грааль современной компьютерной графики, поиск решения к которому занимает лучшие умы индустрии вот уже почти 40 лет и которое объясняет взаимосвязь между светом который попадает на поверхность сцены (все объекты в игре) и светом который отражается в виртуальную камеру:

Это будет единственная формула которую я приведу в этой статье, без нее – никуда.
Это будет единственная формула которую я приведу в этой статье, без нее – никуда.

Несмотря на казалось бы сложную формулу, уравнение крайне интуитивно и просто для понимания и содержит всего два компонента: количество светового излучения в направлении камеры (слева) можно описать как сумму собственного излучения (L_e) материала поверхности и отражённого света (L_r), учитывая закон сохранения энергии и взаимодействие света с поверхностями через функции отражения (BRDF).

Суть проста – суммируем весь свет который пришел на поверхность и смотрим сколько поглотилось, а сколько отразилось в направлении камеры. Но есть нюанс...
Суть проста – суммируем весь свет который пришел на поверхность и смотрим сколько поглотилось, а сколько отразилось в направлении камеры. Но есть нюанс...

Иногда сумму представляют как интеграл чем она по сути и является в пределе. Суммируют обычно по поверхности полусферы Ω поскольку таким образом проще всего учесть свет который пришел на точку поверхности со всех углов. Впрочем, на практике вместо сфер обычно используют приближения – октагедроны, хексагедроны или сферические гармоники.

Для упрощения вычислений попадающий на сферу свет обычно хранится в октагедроне.
Для упрощения вычислений попадающий на сферу свет обычно хранится в октагедроне.

Сложную аббревиатуру из формулы – BDRF можно понимать просто как материал поверхности который описывает как именно свет поглащается или отражается от данного материала под разными углами. В играх за это отвечают ваши любимые текстурки, нормали и прочие цветовые каналы которые задают свойства материалов.

Разные BRDF которые задают свойства материалов – дифузный цвет, отражаемость, шероховатость, прозрачность, плотность, рассеивание и пр.
Разные BRDF которые задают свойства материалов – дифузный цвет, отражаемость, шероховатость, прозрачность, плотность, рассеивание и пр.

При всей простоте уравнения, подвох заключается в том для его расчета на практике нужно сначала откуда-то получить эти самые значения света которые исторически принято разделать на две ортогональные задачи:

1. Lighting & Shadows. Или расчет освещения и теней – посчитать весь полученный свет от всех источников с учетом всех перекрытий, а с учетом вторичного отраженного света и материалов такими источниками становятся каждая точка сцены что совершенно не понятно на первый взгляд как это вообще можно посчитать. Внизу пример того как выглядит прямое освещение без учета отраженного света и освещение с учетом 1 и 12 отскакиваний (light bounces).

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

В честь Каджии был назван экспериментальный движок от Embark: github.com/EmbarkStudios/kajiya
В честь Каджии был назван экспериментальный движок от Embark: github.com/EmbarkStudios/kajiya

Для расчета такого уравнения методом трассировки путей требуются триллиарды операций и поскольку о расчетах освещения в конце 80х никто даже и мечтать не мог, то предлагаю от базы перейти к реалиям графики тех годов – конца 80х и середины 90х до появления графических ускорителей полигональной графики.

Часть 1. Эпоха до графических ускорителей

Разработчик Mario ставит галочки напротив Нанитов того времени.
Разработчик Mario ставит галочки напротив Нанитов того времени.

Я не супер эксперт в графике которая была в играх до моего рождения, поэтому очень кратко пробежимся по технологиям того времени. На заре компьютерной графики реального времени еще до появления GPU была примерно следующая экспозиция.

Большинство игр были в 2D или псевдо-3D, из инструментов отрисовки у программистов, за пределами каких нибудь станций SiliconGraphics (стоивших десятки или сотни тысяч долларов, которые позже подарили нам стандарт OpenGL), были лишь буфер кадра в который нужно было писать какие-то значения цвета из палитры. Буфер это просто участок памяти компьютера выделенный для какой-то задачи, в данном случае для коммуникации между графической программой (игрой) и контроллером VGA который подает команды на дисплей. Сами цвета и цветовые были крайне просты и графический API того времени мог вполне ограничиваться чем-то вроде:

  • getColor(x, y) – получить цвет на экране.
  • setColor(c, y, c) – записать цвет для позиции на экране.

Диаграмма графического API в DOS и все еще современного OpenGL версии 4.2.

Все остальное в те времена вы как разработчик должны были делать сами и чаще всего на ассемблере который вам прислал создатель консоли. CPU того времени были тоже совсем не такими как сегодня и например не обладали возможностью работы с дробными числами, а те которые умели делать такие трюки использовали свои форматы чисел которых до конца 90х было несколько штук, поэтому каждый разработчик либо ограничевался работой с целыми числами либо пилил свою библиотеку работы с математикой.

Немыслеммые технологии масштабирования текстур из Pole Position.
Немыслеммые технологии масштабирования текстур из Pole Position.

Авангардом графических технологий в играх в те времена были игровые автоматы стоившие тысячи или десятки тысяч долларов которые имели на борту устройства для работы с дробными числами, проекциями и текстурами которых еще десятилетие не будет на PC.

Представление дробных чисел в Марио на основе 16-битных целых чисел.
Представление дробных чисел в Марио на основе 16-битных целых чисел.

О том на какие ухищрения шли разработчики Марио для например только работы с дробными числами для плавной анимации скорости движения можно узнать из этого видео:

Для плавной анимации в те времена нужно было написать свой формат дробных чисел и методики его интерполяции (lerp) на ассемблере. А ты плачешь когда в Юнити нет готового скрипта в Asset Store.

На консолях того времени, таких как SNES, основные технологические новшества были сосредоточены на отрисовке, масштабировании, паралаксе и повороте битмап-текстур. Обычно консоль предлагала несколько режимов работы, каждый из которых имел свои ограничения на количество спрайтов, их палитру, а также размеры объектов и фона.

Неплохое видео о том как работает графика в SNES.

Помимо работы с числами и текстурами, одной из нерешенных проблем той эпохи оставалось представление сцены "на GPU". Форматы, которые сегодня кажутся очевидными, такие как вершины и треугольники, в то время конкурировали с квадами, вокселями и картами высот. Стандарты еще не были установлены, и велось множество экспериментов. Вот лишь несколько примеров:

Воксельный движок из Comanche (1992) который рендерил карту с помощью трассировки лучей:

По этой игре есть целая серия замечательных видео где автор пытается повторить данный метод рендеринга пользуясь API того времени.

У этого же автора есть платный курс разработки игр для PS1 после которого вас оторвут с руками. Не пропустите, на XYZ такого не расскажут! 
Пример одной и той же игры которая рендерится треугольниками на PS1 и квадами на Sega Saturn.
Пример одной и той же игры которая рендерится треугольниками на PS1 и квадами на Sega Saturn.

Вангеры, которые так же использовали трассировку лучей и нагибали PC того времени (конец 90х):

Разработчики Вангеров были очень упоротыми и довольно передовой командой по части визуала.
Разработчики Вангеров были очень упоротыми и довольно передовой командой по части визуала.

Думаю что эта эпоха официально закончилась благодаря четырем инновациям:

  • На рынок вышли домашние консоли, такие как PS1, с фиксированным графическим конвейером и поддержкой растеризации полигонов. Это было первое массовое устройство стоимостью $299 (эквивалент $581–$613 с учетом инфляции), оснащенное аппаратным ускорением полигонов и текстур. Однако первые консоли не поддерживали буфер глубины, из-за чего в анимации можно заметить артефакты, возникающие из-за того, что GPU не может правильно определить порядок отрисовки пересекающихся треугольников.
  • Джон Кармак и Майкл Абраш показали всему миру "как надо" выпустив Quake 1 и определив вектор развития графики в играх на следующие десятилетия. Они сделали выбор в пользу растеризации треугольников с использованием буфера глубины, что стало ключевым технологическим решением для дальнейшего прогресса. Рекомендую почитать книгу Black Book of Rendering Абраша на эту тему.
  • Производители графических ускорителей, которых в те годы часто называли "ускорителями Quake," представили такие графические API, как OpenGL, DirectX и Glide. Microsoft вскоре приобрела компанию, разработавшую DirectX, и превратила его в стандарт для игр на платформе Windows. Эти API начали унифицировать подходы к созданию графики, упростив разработку игр для различных аппаратных платформ. Однако ранние API были жестко привязаны к архитектуре GPU и CPU своего времени, что спустя 20 лет привело к серьезным проблемам. Индустрии пришлось пройти долгий и болезненный переход от OpenGL и DirectX 11 к более современным API, таким как Vulkan и DirectX 12. Эти новые API предоставляли разработчикам прямой контроль над аппаратными ресурсами, но требовали значительных изменений в подходах к разработке, что стало вызовом для многих студий.
  • Появились центральные процессоры с частотами до 1Gz и расширениями для мультимедия задач.
История развития графических API в 90е можно послушать в этом подкасте с основателем DirectX – RenderMorphics.

Зачем нужен буфер глубины и как работает растеризация?

Сложности алгоритмов рендеринга без использования буфера глубины.
Сложности алгоритмов рендеринга без использования буфера глубины.

Как работает рендеринг треугольников? Самый простой подход — это так называемый "алгоритм художника". Все треугольники в кадре сортируются по расстоянию до камеры и закрашиваются точками (фрагментами, пикселями) по порядку, начиная с самых дальних. Под закрашиванием подразумевается нанесение текстур или материалов на фрагменты (пиксели), расположенные внутри каждого треугольника. Этот процесс напоминает работу художника, который сначала рисует фон, а затем добавляет объекты на переднем плане. Именно таким способом выполнялся рендеринг во многих играх для PS1.

Боб Росс – знаменитый изобретатель Painter's Algorithm для рендеринга.
Боб Росс – знаменитый изобретатель Painter's Algorithm для рендеринга.

Главными недостатками этого метода являются два ключевых момента. Во-первых, треугольники приходится постоянно сортировать, что требует дополнительных вычислительных ресурсов. Во-вторых, если два треугольника пересекаются и частично заслоняют друг друга, становится неочевидно, в каком порядке их следует рисовать. Такие проблемы особенно часто возникают при анимации персонажей, где разные части модели нередко пересекаются.

Растеризация треугольников – основа современной интерактивной графики.
Растеризация треугольников – основа современной интерактивной графики.

Растеризация с учетом глубины же добавляет к процессу вычисления цвета еще и расчет глубины. В этом случае, если глубина фрагмента одного треугольника оказывается меньше глубины фрагмента другого, то его цвет заменяет цвет предыдущего треугольника в итоговом изображении. Это простое, но эффективное решение. Однако в 90-е годы к нему пришли через многочисленные эксперименты. Кроме того, метод оказался более требовательным к оборудованию того времени и изначально реализовывался в виде программной симуляции. Метод все еще иcпользуется в абсолютном большинстве игр не смотря на альтернативный методы вроде трассировки лучей.

То самое видео из демо с презентации PS1 где можно заметить артефакты рендеринга без z-буфера: https://www.youtube.com/watch?v=k7Lk7idveeU

Часть 2. Фиксированные вычисления на GPU

С приходом Quake 1, PS1 и первых графических ускорителей началась эпоха полигонов. В эту эпоху происходят следующие заметные сдвиги в графике.

Текстурирование обычно определяет цвет каждого пикселя полигона, обращаясь к исходному изображению.       
Текстурирование обычно определяет цвет каждого пикселя полигона, обращаясь к исходному изображению.       

Во первых появляются ранние графичекие ускорители. По сути рание ускорители это конвейеры для параллельной обработки вершин и растеризации треугольников на отдельной плате с своей VRAM памятью которая оптимизирована под высокую пропускную способность нежели низкие задержки как в обычной RAM. Это выражается например в том что чтение из VRAM работает сразу по строкам.

Мы отправляем пакеты (значения длиной 32 бита) в порт GPU, указывая, что нужно отрисовать. Подробности о рендеринге для PS1 можно почитать в этом блоге: https://pikuma.com/blog/how-to-make-ps1-graphics
Мы отправляем пакеты (значения длиной 32 бита) в порт GPU, указывая, что нужно отрисовать. Подробности о рендеринге для PS1 можно почитать в этом блоге: https://pikuma.com/blog/how-to-make-ps1-graphics

Особенностью VRAM было её устройство, позволяющее эффективно обрабатывать данные целыми строками. Также чтение данных из VRAM происходило с использованием механизма двойного порта (dual-port), что давало возможность одновременно записывать и читать данные. Это обеспечивало высокую производительность при работе с графическими текстурами, буферами кадра и глубины, но также накладывало ограничения на её использование в задачах, требующих произвольного доступа к памяти с низкими задержками.

Невероятная по меркам картинка была возможно благодаря умному управлению ресурсами сцены и разбиению на части которые динамически подгружались из CD. Марк Церни уже тогда просек зачем играм будет нужен быстрый SSD через 20 лет. Гений!
Невероятная по меркам картинка была возможно благодаря умному управлению ресурсами сцены и разбиению на части которые динамически подгружались из CD. Марк Церни уже тогда просек зачем играм будет нужен быстрый SSD через 20 лет. Гений!

Во вторых, разработчики начали осваивать методы разбивки больших 3D-сцен на части, чтобы эффективнее использовать ограниченную память PS1 и огромный по тем временам объем CD. Например, в игре Crash Bandicoot студия Naughty Dog одной из первых применила инновационный подход: части карты, расположенные рядом друг с другом, хранились на смежных страницах CD-диска. Это позволяло быстро загружать необходимые ассеты, одновременно повышая качество текстур и геометрии без значительного увеличения времени загрузки.

Классное видео с обзорами трюков на которые шли Naughty Dog того времени.

Кстати еще одним из ограничений на PS1 было отсутствие FPU что не позволяло делать точные вычисления для трансформаций и проекций вершин, что, как здесь любят выражаться, являлось причиной "тряски" вызванной использованием таблиц для сортировки глубины (OT – ordering table).

Причина "тряски" в PS1 – отсутствие математических сопроцессоров.

Трансформация вершин в системе гомогенных координат это из одна из фундаментальных операций в современной компьютерной графике.

Джем Юксель из университета Юты рассказывает про 3D трансформации на курсе интерактивной графики. Источник: https://www.youtube.com/watch?v=1z1S2kQKXDs
Джем Юксель из университета Юты рассказывает про 3D трансформации на курсе интерактивной графики. Источник: https://www.youtube.com/watch?v=1z1S2kQKXDs

В свою очередь Джон Кармак придумал механизм BSP – разбиения сцены с помощью плоскостей для быстрого вычисления видимых объектов в кадре что стало одной из ключевых технологий Quake

Как работает BSP

Ещё одной технологией, применённой id Software в Quake, стало запекание освещения (lightmaps). Этот метод предусматривал предварительный расчёт освещения сцены с учётом статичных источников света. Результаты записывались в текстуры низкого разрешения, называемые lightmaps, которые накладывались на геометрию уровня. Для имитации динамического освещения, например, от взрывов или выстрелов, в игре использовалась комбинация запечённых текстур и добавочного освещения, которое рассчитывалось в реальном времени. Это делалось аппаратно, так как большинство GPU того времени поддерживали умножение двух текстурных слоёв в фиксированном конвейере до прихода шейдеров.

Каждый световой источник мог влиять на окружающую геометрию, создавая мягкие тени и градиенты. Для достижения этого применялся алгоритм расчёта освещённости, учитывающий не только прямые лучи света, но и отражённый свет (глобальное освещение), хотя на раннем этапе это делалось весьма упрощённо. При изменении освещения в процессе игры, lightmap частично обновлялся или комбинировался с временными текстурами, создавая эффект динамических изменений, таких как мигающий свет от огня или мерцание взрывов.

Пример карты из Quake соответсвующее ей дерево BSP для быстрого поиска объектов в кадре. Как это работает рекомендую посмотреть у Simon Dev.
Пример карты из Quake соответсвующее ей дерево BSP для быстрого поиска объектов в кадре. Как это работает рекомендую посмотреть у Simon Dev.

Этот подход позволял достичь высокого уровня визуального реализма при ограниченных ресурсах процессоров и видеокарт того времени, оставаясь производительным и эффективным.

В это время появляются и первые алгоритмы сглаживания, направленные на устранение "лесенок" (aliasing) в изображении. Они основываются на теореме Котельникова-Шеннона из теории обработки сигналов, которая говорит, что для точного восстановления сигнала частота выборки должна быть не менее чем в два раза выше максимальной частоты сигнала. В графике это означает необходимость более высокой частоты выборки для корректного отображения текстур и геометрии с мелкими деталями.

Supersample Anti-Aliasing – SSAA
Supersample Anti-Aliasing – SSAA

Один из первых и наиболее точных методов сглаживания — SSAA (Supersample Anti-Aliasing). Он работает путем рендеринга изображения с разрешением, в несколько раз превышающим целевое (например, в 2x или 4x), а затем уменьшения его до нужного размера. Такой подход обеспечивает максимально плавные края объектов и точное устранение артефактов, так как сглаживание происходит на уровне всей сцены. Однако этот метод требует значительных вычислительных ресурсов, что делает его не практичным в современных играх. Более современные методы использовали больше выборок только для фрагментов с большей частотоой.

В то же время графический конвейер GPU оставался жестко фиксированным, что, грубо говоря, лишало разработчиков возможности программировать собственные алгоритмы рендеринга на GPU с использованием шейдеров. Это значительно ограничивало потенциал для реализации таких задач, как, например, сложная анимация или продвинутые алгоритмы затемнения.

Основные стадии программируемого графического конвйера: сборка примитивов, вертексные шейдеры, растеризация, фрагментные шейдеры.
Основные стадии программируемого графического конвйера: сборка примитивов, вертексные шейдеры, растеризация, фрагментные шейдеры.

Первые видеокарты с аппаратной поддержкой DirectX 8.0-8.1 появились в начале 2000-х годов. Они впервые позволили писать программы для обработки вершин и пикселей. DirectX 9, выпущенный в 2002 году, ввел полноценную поддержку программируемых шейдеров, что стало важным шагом к отказу от фиксированного конвейера.

Расчет затенения от источников света с помощью фрагментных шейдеров.

Часть 3. Динамические свет и тени, физический рендеринг

К играм этой эпохи я отношу все что вышло начиная от Doom3, Far Cry и Half Life 2 и заканчивая Crysis 2. Давайте разберемся в основных инновациях.

То самое демо UE3 из 2004 которое погубило российский AAA-геймдев нулевых.

С появлением DirectX 9 и первых GPU с поддержкой программируемого конвейера разработчики получили новый инструмент — шейдеры. Эти небольшие программы, исполняемые непосредственно на GPU, позволяли разработчикам задавать собственные алгоритмы для обработки вершин и пикселей, что открывало большие возможности для кастомизации графики. DirectX 9 ввел поддержку вершинных (vertex shaders) и пиксельных шейдеров (pixel shaders) версии 2.0, которые дали возможность задавать более сложное освещение, текстурирование и спецэффекты. Например, можно было реализовать динамические тени, HDR-освещение или реалистичные отражения, которые раньше были очень ограниченны на фиксированном конвейере.

Коррина Ю, главный архитектор движка Halo 3 из Microsoft рассказывает о том какой крутой у них движок и какие в нем красивые шейдеры:  https://www.youtube.com/watch?v=j1m_8H_k10Q
Коррина Ю, главный архитектор движка Halo 3 из Microsoft рассказывает о том какой крутой у них движок и какие в нем красивые шейдеры:  https://www.youtube.com/watch?v=j1m_8H_k10Q

Примерно в это время игры начали рассчитывать прямое освещение из уравнения рендеринга в реальном времени, что стало важным шагом вперед. Однако расчет непрямого освещения, которое добавляет реалистичность за счет отраженного света, оставался сложной задачей. Потребовались еще 15–20 лет технологического прогресса, включая развитие трассировки лучей и гибридных методов, чтобы научиться рассчитывать непрямое освещение в реальном времени без запекания.

В это сложно поверить сегодня, но в те времена Стив Джобс и Джон Кармак презентавали GeForce 3 и новый Doom 3 на конференции Apple.

В период 2004–2006 годов в видеоиграх произошел значительный прорыв в использовании шейдерных эффектов, таких как стенсил-тени (stencil shadows). Этот метод, применяющий буфер трафарета, позволял создавать динамические и точные тени, особенно в сценах с несколькими источниками света.

Сегодня stencil-тени уже не используются.
Сегодня stencil-тени уже не используются.

Такие технологии использовались в играх, как Doom 3, чтобы значительно усилить атмосферу за счет контрастного освещения и реалистичных теней. Однако стенсил-тени имели ограничения: излишнюю резкость теней, которая не всегда выглядела естественно, и сложность работы с источниками света разного типа. Со временем разработчики начали переходить на технологии Shadow Mapping, дополняя их методами сглаживания, такими как Percentage-Closer Filtering (PCF), что позволило добиться более мягких и реалистичных теней.

Мягкие тени методом PCF из FEAR (2005).
Мягкие тени методом PCF из FEAR (2005).

Шейдерная вода с применением зеркальной трансформации (Planar Reflections) стала еще одним новшеством в то время — благодаря пиксельным шейдерам разработчики смогли создавать реалистичные эффекты преломления, отражения и движущейся поверхности воды, как это было видно, например, в Far Cry:

Шейдерная вода в FarCry 2004 даже в 2024 смотрится красиво.
Шейдерная вода в FarCry 2004 даже в 2024 смотрится красиво.

Кроме того, появилась поддержка освещения на уровне пикселя (per-pixel lighting), которая заменила устаревшее освещение на уровне вершин (vertex lighting). Этот подход обеспечивал более точную симуляцию освещения, позволяя учесть мелкие детали текстур и геометрии.

Справа вершиное освещение – справа пиксельное.
Справа вершиное освещение – справа пиксельное.

С усложнением методов разработчики стали переходить к более гибкому на тот момент методу отложенного рендеринга. Суть отложенного метода в том что сначала все данные о геометрии сцены (позиции, нормали, цвета) записываются в специальные буферы (G-буфер) при первичном проходе GPU, а расчеты освещения выполняются на втором этапе на основе этой информации. Это позволяет эффективно обрабатывать множество динамических источников света, избегая повторного рендеринга объектов для каждого источника света.

Сюжет про технологии рендеринге в STALKER 2007

Первой игрой, которая применила отложенный рендеринг (deferred rendering), стала S.T.A.L.K.E.R.: Shadow of Chernobyl вышедшая в 2007 году. Снизу можно видеть изменения в качестве финальной картинке после перехода на новый рендер (из промо материалов игры):

Крайне достойная на момент выхода картинка учитавая открытый мир игры.
Крайне достойная на момент выхода картинка учитавая открытый мир игры.

Однако разработчики начали экспериментировать с этой технологией еще на стадии создания игры, начиная с начала 2000-х.

Успеть за 16 миллисекунд – подробная эволюция интерактивной графики и железа за последние 30 лет и при чем здесь STALKER

Пример G-буфер отложенного рендеринга из Killzone: цвет, зеркальная интенсивность, нормали, зеркальная шероховатость, векторы движения, глубина.

Успеть за 16 миллисекунд – подробная эволюция интерактивной графики и железа за последние 30 лет и при чем здесь STALKER

С появлением мульти-текстурирования и шейдеров разработчики получили возможность записывать данные о неровностях поверхности прямо в текстуры что позволило примять продвинутые эффекты с довольно низкой вычислительной стоимостью.

Крышесносное демо CryEngine 2

Важным новшеством графических ускорителей того времени помимо увеличения производительности и объемов памяти стал переход на унифицированную архитектуру ядер где один и тот же тип вычислительных ядер отвечал как за операции над вершинами, так и за операции над пикселями что еще больше приблизило программирование GPU к гибкости программ для CPU (хотя различия все равно очень значительные). Первым графическим процессором с унифицированной шейдерной архитектурой стал NVIDIA GeForce 8800 GTX, выпущенный в ноябре 2006 года. Хотя для справки еще в 1993 был ускоритель Rendition который имел программируемые ядра похожие на Cuda, но он проиграл гонку производительности в Quake картам с фиксированными конвейерами.

NVIDIA GeForce 8800. Помню как я писал кипятком когда мне родители купили эту карту в 2006м.
NVIDIA GeForce 8800. Помню как я писал кипятком когда мне родители купили эту карту в 2006м.

Заключительными для той эпохи стали такие технологии как AO и подповерхностное рассеивание впервые использованные в Crysis.

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

SSAO в первом Crysis.
SSAO в первом Crysis.
Успеть за 16 миллисекунд – подробная эволюция интерактивной графики и железа за последние 30 лет и при чем здесь STALKER

Влияние SSAO на рендеринг растительности:

SSS в CryEngine
SSS в CryEngine

Подповехностное рассеивание (SSS) это эффект при котором свет может проникать внутрь модели и выходить в другом месте. Эта технология крайне важна для реалистичного рендеринга кожи, воды, растительности и прочих полупрозрачных материалов.

Часть 4. Новые графические API, физически коректный рендеринг, глобальное освещение и трассировка лучей

После интенсивного прогресса графических и центральных процессоров 2000с стало очевидно что имеющиеся GAPI основанные еще на предположениях о развитии архитектуры из конца 80х все хуже подходят для задач современной графики, а именно:

1. Скрывают наличие у графического процессора нескольких очередей задач для одновременной работы над графическими и возможно другими вычислениями (например физики или симуляции) в асинхронном режиме.

2. Берут на себя управление ресурсами что было бы намного удобнее делать движку игры поскольку он лучше осведомлен о жизненных циклах этих ресурсов (какие текстуры и когда нужно загрузить и выгрузить).

3. Не умеют работать с мультипроцессорными системами из-за наличия конечный автомат для управления состоянием.

4. Требуют компиляцию шейдеров в рантайме.

Успеть за 16 миллисекунд – подробная эволюция интерактивной графики и железа за последние 30 лет и при чем здесь STALKER

Собcтвенно именно для решения этих задач AMD и создала Mantle (мантия) которая потом вышла наружу и стала Vulkan (вулкан). В истории создания Mantle принимали участие не только специалисты из AMD, но и разработчики игровых движков из DICE, Valve, Unity и Epic Games. Впоследсвии вслед за AMD другие компании представили похожие API – DX12, Metal и WebGPU которые решают в общем-то схожие проблемы похожим образом. Графический драйвер при этом должен остаться простым брокером ресурсом между программами и графическими ядрами. По крайней мере там это задумывалось. Кому интересно клубже копнуть в эту историю советую почитать очень подробный тред 2014 года где объясняются минусы старых gapi (сообщение он пользователя Promit). Минусом появления новых GAPI стало их количество, сегодня AAA игре нужно поддерживать несколько GAPI + консолей что несомненно сказывается на качестве оптимизации.

Если вам хочется понять как работают современные API в одном предложении то все примерно сводится к двум понятиям – ресурсы и команды. Сначала вы выделяете ресурсы на GPU – текстуры, вершины и разные буферы, а потом посылаете команды для обработки и вывода. Позже GPU сообщает что все готово и вы можете начинать работать над новым кадром.

PBR шейдер в Blender

В начале 2010х игры стали переходить на модель материалов основанной на PBR придуманную в Pixar. Физически корректный рендеринг (Physically Based Rendering, PBR) — это подход к визуализации разработанный Pixar, который основывается на законах физики для более реалистичного отображения света и материалов. Он моделирует взаимодействие света с поверхностями на основе физических свойств, таких как отражательная способность (albedo), шероховатость (roughness), металличность (metalness) и энергетическая консервация.

Бликовая модель Бекмана: увеличение значений шероховатости от 0.001 до 1.0.       
Бликовая модель Бекмана: увеличение значений шероховатости от 0.001 до 1.0.       

Истоки PBR уходят в области научной визуализации и киноиндустрии, но в игровой индустрии он начал активно внедряться в начале 2010-х годов с появлением движков, таких как Unreal Engine 4 и Unity 5. PBR заменил более упрощенные модели освещения, обеспечивая единый подход к работе с материалами при любых условиях освещения. Это позволило разработчикам добиться более реалистичной и консистентной графики, что стало важным шагом вперед для современных игр.

Техно-демо UE4

Глобальное освещение (Global Illumination, GI) — это подход, учитывающий не только прямой свет от источников, но и отраженный свет, который распределяется по всей сцене, создавая реалистичные тени, мягкое освещение и естественные переходы света.

Все методы GI как правило имеют следующую структуру – представление сцены (пробы, воксели, сурфели), структуру для ускорения трассировки лучей (SDF, BHV, Окто-дерево) и какой-то метод шумоподавления или накопления лучей.

Так выглядит RTX до шумо-подавления. Если тебя ДФТер будут обманывать по поводу скорого RTX в играх – знай, это все маркетинг и реальная ситуация далека от того что показывают в презентациях.
Так выглядит RTX до шумо-подавления. Если тебя ДФТер будут обманывать по поводу скорого RTX в играх – знай, это все маркетинг и реальная ситуация далека от того что показывают в презентациях.
Так выглядит RTX после шумо-подавления и разных трюков. Источник: https://www.youtube.com/watch?v=907-bLuiN_0
Так выглядит RTX после шумо-подавления и разных трюков. Источник: https://www.youtube.com/watch?v=907-bLuiN_0

В историческом порядке в играх использовались следующие основные методы для расчета GI: запекание (light baking) из Части 2 про Квейк, где освещение предварительно рассчитывалось и сохранялось в текстурах, стало первым подходом, широко применяемым с 1990-х, еще до шейдеров.

Далее появился радиозити (radiosity), использующий сетку для расчета непрямого освещения на основе диффузных отражений. Популярный метод в ранних 2000-х, таким способом например пользовались Valve в Counter Strike: Source.

Античный метод расчета GI – Radiosity из Source

Затем пришел динамичный вокселизированный GI (Voxel GI или Svogi) который можно увидеть в, например, в CryEngine 3, который использовал объемные сетки для динамического освещения.

Voxel Cone Tracing
Voxel Cone Tracing

Этот метод все еще применяется в Kingdom Come:

Svogi даже сегодня выдает приемлемую картинку.

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

Svogi удалось реализовать даже в версии для Switch

Октодерево помогает оптимизировать поиск данных и минимизировать использование памяти. Для расчета непрямого освещения лучи света "трассируются" через октодерево, определяя, как свет отражается от поверхности и распространяется в сцене. Это обеспечивает реалистичное распределение света, включая мягкие тени, окрашивание объектов (color bleeding) и динамические изменения освещения. Чтобы сократить нагрузку на производительность, используются sparse-техники (разреженная структура данных), позволяющие хранить только те воксели, которые действительно содержат информацию, исключая пустые области. Также применяется ограничение глубины и разрешения октодерева для управления производительностью.

SSGI релизация на WebGL: realism-effects-obeqz.vercel.app

В 2010-х стал широко использоваться Screen Space Global Illumination (SSGI), рассчитывающий непрямое освещение на основе данных из буфера экрана. Его реализация есть например в UE4 и Unity, но также есть и в других движках в том числе и для веба:

И, наконец, последние достижения включают трассировку лучей (Ray Tracing), позволяющую достичь максимально реалистичного глобального освещения в реальном времени. Но конечно и здесь не все так просто.

На практике трассировка стала возможно благодаря трем вещам:

  • Новый тип шейдера пересечения которые вызывается в месте пересечения луча со сценой.
  • Безбайндинговый рендеринг (bindless rendering) позволяет обращаться к ресурсам (таким как текстуры и буферы) через их глобальные идентификаторы, вместо привязки к фиксированным слотам. Это особенно важно для трассировки лучей, где требуется динамический доступ к большому количеству ресурсов, например, для обработки множества материалов и текстур в сложных сценах, без лишних переключений состояния GPU, поскольку вы заранее не знаете куда попадет луч в отличие от растерезации.

  • RTX-ядра — это специализированные аппаратные модули для трассировки лучей, которые ускоряют обход BVH-дерева и вычисление пересечений лучей с примитивами, разгружая CUDA-ядра и позволяя трассировке работать быстрее.

Один из передовых методов управляемой выборки лучей – ReStir. Современная база для графического программиста.

На текущий момент честная трассировка для всего в играх все еще слишком сложна для вычисления и на практике применяются различные трюки и гибридные методы для того чтобы переиспользовать или перенаправлять лучи из предыдущих кадров для улучшения качества метода. Другие проблемы возникают при использовании трассировки с декалями или анимированными объектами которые не всегда доступны шейдеру пересечения что приводит к артефактам. Про это можно более подробно прочитать в прошлом посте.

Если коротко, то Lumen от Unreal Engine 5 комбинирует трассировку лучей с пробами и SDF (Signed Distance Fields) для реализации глобального освещения и отражений с минимальной нагрузкой на GPU, в теории делая его доступным даже для консолей.

RTXGI от NVIDIA использует трассировку лучей в сочетании с динамическими пробами освещения (lighting probes) для создания реалистичных эффектов непрямого света, поддерживая изменения сцены в реальном времени.

При одинаковых вычислительных ресурсах ReSTIR сходится к референсу гораздо быстрее чем честный Path Tracing.
При одинаковых вычислительных ресурсах ReSTIR сходится к референсу гораздо быстрее чем честный Path Tracing.

ReStir (Reservoir-Based Spatiotemporal Importance Resampling) — это инновационный алгоритм трассировки, который оптимизирует выборку света, позволяя использовать большое количество источников света с высокой детализацией, минимизируя шум и затраты на вычисления. Эти методы объединяют физически корректное освещение с эффективной оптимизацией, позволяя разработчикам создавать графику кинематографического уровня в реальном времени.

Ребята из EA SEED рассказывают про их опыт с трассировкой. Томашь на превью это один из создателей Tiny Glade.

Что почитать/посмотреть на эту тему на каникулах

Ну во первых всем кому интересна графика – очень рекомендую курс от профессора университета Юты. Это просто топ

Во вторых есть буквально библия современной графики – PBRT которая доступна бесплатно:

Есть также много каналов на YouTube и блогов, но лучше просто оставлю ссылку со всеми материалами на одной странице:

227227
2424
44
33
22
45 комментариев