Как происходит рендеринг кадра в GTA V

Серия игр Grand Theft Auto прошла долгий путь с момента своего первого релиза в 1997 году. Примерно 2 года назад Rockstar выпустила GTA V. Просто невероятный успех: за 24 часа игру купило 11 миллионов пользователей, побито 7 мировых рекордов подряд. Опробовав новинку на PS3, я был весьма впечатлен как общей картинкой, так и, собственно, техническими характеристиками игры.
Ничто так не портит впечатление от процесса, как экран загрузки, но в GTA V вы можете играть часами, преодолевая бескрайние сотни километров без перебоев. Учитывая передачу солидного потока информации и свойства PS3 (256 Mb оперативной памяти и видеокарта на 256 Mb), я и вовсе удивился, как меня не выбросило из игры на 20-ой минуте. Вот где чудеса техники.
В этой статье я расскажу о проведенном анализе кадра в версии для ПК в среде DirectX 11, которая съедает пару гигов как оперативки, так и графического процессора. Несмотря на то, что мой обзор идет со ссылкой на ПК, я уверен, что большинство пунктов применимо к PS4 и в определенной степени к PS3.

Анализ кадра

Итак, рассмотрим следующий кадр: Майкл на фоне любимого Rapid GT, на заднем плане прекрасный Лос-Сантос.

Осторожно! Трафик!
В GTA V используется система отложенного рендеринга, работающая со множеством HDR буферов. На мониторе такие буферы не отображаются корректно, а потому я воспользовался методом Рейнхарда, чтобы все снова привести к формату 8-бит на канал.

Environment Cubemap (кубическая текстура окружающей среды)

В первую очередь, визуализируем кубическую текстуру окружающей среды. Данная текстура генерируется в реальном времени для каждого отдельно взятого кадра, что впоследствии позволяет создавать реалистичные отражения. Она выносится на первый план.
Как создается кубическая текстура? Для тех, кто не знаком с техникой, поясню. Это как делать панорамные снимки: поставив камеру на штатив, представьте, что вы стоите прямо в центре большого куба и по одной фотографируете все 6 его граней, каждый раз поворачиваясь на 90°.
В игре задействован тот же принцип: каждая грань превращается в HDR-текстуру 128x128. Первая грань располагается следующим образом:

Та же схема повторяется для 5 оставшихся граней, и в итоге мы получаем кубическую текстуру (cubemap):

Так куб выглядит снаружи

Так он выглядит изнутри (к сожалению, вставить панорамное изображение, представленное в первоисточнике в виде js-скрипта, не удалось)

Для каждой грани предусмотрено более 30 вызовов процедуры отрисовки, ячейки графической сетки весьма низкополигональны, а потому отрисовывается только «пейзаж» (местность, небо, некоторые здания), персонажи и авто остаются нетронутыми.
Вот почему в игре, если смотреть из автомобиля, панорама выглядит отлично, а другие машины и персонажи — нет.

От кубической текстуры к текстуре двойного параболоида

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

Куб в «развороте» и полученные «полушария»

Для чего нужны подобные трансформации? Думаю, все дело (как всегда) в оптимизации: в кубической текстуре шейдеры фрагментов, теоретически, имеют доступ к 6 граням размером 128х128, в то время как в случае с текстурой двойного параболоида все сводится к 2 «полушариям» 128х128. Кроме того, поскольку большую часть времени камера находится на крыше автомобиля, большинство запросов поступает в верхнюю полусферу.
Проекция двойного параболоида сохраняет детали отражения верхней и нижней части объекта за счет некоторых погрешностей сторон. Для GTA это прекрасно: крыши и капоты машин, как правило, показаны сверху, а потому важно, чтобы именно это отражение было качественным.
Плюс края кубических карт нередко оставляют желать лучшего: если точность отображения текстур зависит от расстояния до объекта, то в пределах граней могут обнаруживаться отдельные швы, особенно по контурам, а в графических процессорах старшего поколения и вовсе не предусмотрены фильтры граней. Для двойных параболоидов эта проблема неактуальна, т.к. текстуры остаются четкими, независимо от расстояния, и никакие швы не мешают восприятию картины в целом.
Дополнение: в комментариях я отметил, что, по всей вероятности, в GTA IV также использовали карту двойного параболоида, хотя и не в процессе пост-обработки кубической текстуры. Ячейки графической сетки преобразованы напрямую с помощью шейдера вершин.

Выбраковка и уровень детализации

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

Генерирование G-буфера

«Основная» доля рендеринга происходит именно здесь. Все видимые ячейки графической сетки отрисовываются одна за другой, но вместо немедленного расчета степени затенения вызовы отрисовки лишь фиксируют необходимую информацию в отдельных буферах, получивших название G-Buffer. GTA V использует технологию MRT, что позволяет каждому вызову отрисовки фиксировать до 5 специальных команд.
При последующей компиляции буферов удается вычислить итоговые показатели затенения для каждого пикселя. Отсюда и название «отложенный» в противовес «прямому» шейдингу, при котором каждый вызов отрисовки отвечает за самостоятельный расчет итогового показателя затенения пискелей.
На данном этапе прорисовываются только непрозрачные объекты, так как прозрачные детали, вроде стекла, требуют дополнительной отложенной обработки, которая выполняется позже.
Генерирование G-буфера

Генерирование на 15%

Генерирование на 30%

Генерирование на 50%

Генерирование на 75%

Генерирование на 100%

За воспроизведение всех этих эффектов отвечают цели рендеринга – LDR-буферы (RGBA с 8 битами на канал), хранящие различную информацию, которая позже понадобится для расчета итоговых показателей затенения:

• Диффузная карта: сохраняет «исходный цвет» ячейки. По сути, она представляет собой свойство материала и, фактически, не меняется при различном освещении. Но видите белые блики на капоте автомобиля? Примечательно то, что в GTA V затенение рассчитывается на основе поступающего солнечного света до формирования, собственно, диффузной карты. Необходимая информация о «смешивании» хранится в альфа-канале (подробнее об этом позже).

• Карта нормалей: сохраняет векторы нормалей для каждого пикселя (R, G, В). Здесь также используется альфа-канал, хотя я и не уверен, каким образом: похоже, он выполняет функцию бинарной маски для отдельных растений, расположенных рядом с камерой;

• Карта бликов. Здесь хранится информация, связанная с бликами / отражениями:

  • Красный: насыщенность блика;
  • Зеленый: глянец (гладкость);
  • Синий: насыщенность промежуточных бликов (обычно постоянный показатель для всех пикселей с изображением одного и того же материала).

• Карта освещенности: судя по всему, красный канал хранит данные об освещенности каждого пикселя за счет солнечного света (основан на данных нормалей пикселей, их положении и направлении поступающих солнечных лучей). Я не совсем уверен насчет зеленого канала, но, похоже, что он отвечает за освещенность за счет дополнительных источников света. Синий канал – данные об эмиссионных свойствах пикселей (ненулевое значение для неоновых ламп). Существенная часть альфа-канала не задействована, разве что для маркировки пикселей, соответствующих коже персонажа или изображению растительности.

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

Глубина слева и шаблон справа соответственно

Карта глубины: в ней фиксируется информация о расстоянии каждого пикселя до камеры.
Интуитивно можно было бы ожидать, что отдаленные пиксели будут белыми (глубина 1), а те, что ближе, — темнее. Но это не тот случай: видимо, в GTA V использовали логарифмический Z-буфер, изменив Z. Но зачем? Похоже, дело в числах с плавающей запятой, которые в процессе кодировки гораздо точнее, если их значение близко к 0. Так, изменив Z, можно вводить куда более точные данные о глубине отдаленных объектов, которые, в свою очередь, устраняют Z-погрешности. Учитывая продолжительность игровой сессии, не воспользоваться таким приемом было просто невозможно. Хотя, GTA V и не открыли Америку, ведь аналогичная техника встречается в той же Just Cause 2, например.
Шаблон: используется для идентификации различных отрисованных ячеек, присваивая общий ID всем пикселям определенной группы ячеек. Вот, например, некоторые значения в шаблоне:

  • 0x89: персонаж, управляемый игроком;
  • 0x82: автомобиль, управляемый игроком;
  • 0x01: неигровые персонажи;
  • 0x02: транспортные средства, включая машины, велосипеды и так далее;
  • 0x03: растительность и листва;
  • 0x07: небо.

Все эти буферы были сгенерированы благодаря 1900 с лишним вызовам отрисовки.
Обратите внимание, что рендеринг выполнен как будто «задом наперед», что позволяет оптимизировать все необходимые операции с учетом сравнения глубины фрагмента со значением буфера глубины на стадии растеризации: в процессе отрисовки сцены очень многие детали проваливают тест глубины, так как перекрываются близко расположенными пикселями, отрисованными ранее. Если очевидно, что пиксель не пройдет тест глубины, графический процессор может автоматически его пропустить, даже не запуская шейдер. Если же мы имеем дело с шейдерами тяжелых пикселей, уместен только стандартный прямой порядок рендеринга, в то время как «обратный» (алгоритм художника) окажется в этом случае самым неэффективным.
А сейчас хотелось бы сказать пару слов о роли альфа-канала в диффузной карте. Посмотрите на скриншот:

Приближенный фрагмент дифузной карты

Видите, что некоторых пикселей не хватает? Это особенно заметно на примере деревьев. Как будто в спрайтах отсутствуют отдельные тексели.
Я уже обращал внимание на эту особенность раньше, запуская игры на PS3, причем тогда был весьма озадачен. Может быть все дело в чрезмерном уменьшении спрайта текстуры? Но теперь я знаю, что это не так, ведь компиляция элементов произведена верно.
Такая модель, действительно, выглядит странно, почти как шахматная доска. Возможно ли что… игра делает рендеринг только для 1 из 2 пикселей?
Чтобы уточнить, я заглянул в D3D байт-код. И вот, пожалуйста:

<code class="cpp hljs">dp2 r1.y, v0.xyxx, l(<span class="hljs-number">0.5</span>, <span class="hljs-number">0.5</span>, <span class="hljs-number">0.0</span>, <span class="hljs-number">0.0</span>) <span class="hljs-comment">// Dot product of the pixel's (x,y) with (0.5, 0.5)</span> frc r1.y, r1.y <span class="hljs-comment">// Keeps only the fractional part: always 0.0 or 0.5</span> lt r1.y, r1.y, l(<span class="hljs-number">0.5</span>) <span class="hljs-comment">// Test if the fractional part is smaller than 0.5</span> </code>

По сути, мы видим условие (X+ Y)% 2 == 0, которое соблюдается только для одного пикселя из 2 (где х и у — координаты пикселя).
Это лишь одна из причин выбраковки пискелей (вторая это значение альфа
Информация о том, какие ячейки отрисовывались в рассмотренном «выборочном» режиме, хранится на альфа-канале диффузной карты, как видно на картинке

Альфа-канал диффузной карты

Так почему же некоторые модели отрисовывались именно так? Может, это помогало сохранить заливку или параметры затенения? Я вовсе не хотел сказать, что графические процессоры не предусматривают подобную детализацию: пиксели закрашиваются не по отдельности, а группами 2х2. И речь не о производительности, дело в уровне детализации: такая модель делает закрашенные ячейки более прозрачными за счет разных уровней детализации.



Этот метод называется альфа-стипплинг.

Тени

В игре используются CSM (каскадные карты теней): 4 карты теней формируют текстуры 1024x4096. Каждая карта теней предназначена для разной видимости. Чем чаще повторяются действия, тем шире пирамида видимости камеры, тем больше панорама кадра. Благодаря такому подходу тени объектов возле игрового персонажа имеют более высокое разрешение, чем тени отдаленных предметов. Вот краткий обзор информации о глубине 4 карт:

Карты теней

Этот процесс может потребовать немало энергии, так как приходится делать ререндеринг сцены целых 4 раза, но отсечение по пирамиде видимости позволяет опустить обработку ненужных полигонов. В данном случае CSM были созданы в результате 1000 вызовов отрисовки.
Имея эти данные глубины, можно рассчитать тень для каждого пикселя. Информация о тенях сохраняется в цели рендеринга: тени, отбрасываемые в результате попадания прямых солнечных лучей, фиксируются в красном канале, тени от облаков в – в красном и зеленом.
В картах теней предусмотрен шаблон сглаживания (если вы внимательно посмотрите на текстуру, изображенную ниже, увидите в красном канале упомянутый ранее эффект шахматной доски). Это позволяет сгладить границы теней.
Позже эти пробелы восполняются: тени от солнца и облаков объединяются в один буфер, производится определенное размытие по глубине, а результат сохраняется в альфа-канале карты бликов.

Тени от солнца и облаков (зеленым)

Размытые тени

Несколько слов о размытии: техника не из дешевых, т.к. приходится отдельно заниматься разными текстурами. Таким образом, чтобы облегчить задачу, как раз перед выполнением размытия создается «облегченная» текстура: масштаб буфера тени снижается до 1:8 и делается легкое размытие пиксельным шейдером посредством четырехкратного повторения команды Grab (). Это позволяет примерно оценить общее количество полностью освещенных пикселей. Впоследствии, когда понадобится полное размытие, в первую очередь, считывается информация об «облегченном» варианте процедуры: как только шейдеру попадается полностью освещенный пиксель, он автоматически выдает единицы и ему не приходится запускать трудоемкий процесс полномасштабного размытия.

Преграждение окружающего света в экранном пространстве

Здесь мы имеем дело с созданием линейной версии буфера глубины, на основе которой формируется карта SSAO (преграждение окружающего света в экранном пространстве).


Четкое изображение

Размытое изображение

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

Комбинация G-буфера

Так, настало время объединить все сгенерированные буферы!
Пиксельный шейдер считывает данные из различных буферов и определяет окончательное значение затенения пикселей в HDR.
В случае если мы работаем с ночными сценами, фонари и прочие элементы освещения будут постепенно, один за другим, накладываться поверх сцены.

И мы получаем итоговое изображение:

Картинка становится все приятнее, хотя по-прежнему не хватает океана, неба, прозрачных объектов… Но сначала о главном: нужно доработать образ Майкла.

Subsurface Scattering (подповерхностное рассеивание)

Есть вопросы с затенением кожи Майкла: на лице встречаются очень темные участки и создается впечатление, будто это плотный пластик, а не тело человека.
Вот для чего нам понадобится SSS. Рассеивание имитирует натуральное освещение кожи. Посмотрите на уши или губы: благодаря SSS они выглядят гораздо реальнее, в них появляется здоровых розоватый оттенок.


Но как удалось запустить SSS отдельно для образа Майкла?
Во-первых, вырезается только силуэт. Тут на помощь приходит сгенерированный ранее буфер шаблона: всем пикселям Майкла присвоено значение 0x89. Таким образом, мы можем сконцентрироваться именно на них, но ведь нужно применить SSS только к коже, а не к одежде.
На самом деле, когда объединяли все G-буферы, помимо показателей затенения, хранящихся в RGB, отдельные данные были зафиксированы и в альфа-канале. А точнее, альфа-каналы карты освещенности и карты бликов использовались для создания бинарной маски: пиксели, соответствующие коже Майкла и изображению некоторых растений, помечались единицей в альфа-канале. Другим пикселям, в частности, пикселям одежды, присваивалось значение альфа 0.
Таким образом, можно применить SSS, имея в качестве исходных данных скомбинированную информацию из цели G-буфера и буфера, сравнивающего показатели глубины и шаблона.
Да, может показаться, что столь незначительные локальные трансформации не стоят таких серьезных вычислений. И, возможно, вы были бы правы, если бы не одно но: играя в игру, мы инстинктивно смотрим на лицо, а потому обработка, касающаяся этой части тела, позволяет максимально приблизить игру к реальности. В GTA V SSS применяется как к образу главного героя, так и в случае с неигровыми персонажами.

Вода

В рассматриваемой сцене в кадр попало не так много воды, но все же: океан на заднем плане, пару бассейнов тут и там.
Визуализация воды в GTA V сосредоточена в двух направлениях — отражение и преломление.
Созданный ранее логарифмический Z-буфер позволяет сгенерировать вторую версию, на этот раз линейную с разрешением вдвое меньше исходного.
Океан и бассейны отрисовываются по очереди в режиме MRT. Так одновременно достигается несколько целей:

Слева диффузия воды, справа непрозрачность

  • Диффузная карта воды: фиксирует исходный цвет воды.
  • Карта непрозрачности воды: в красном канале, по сути, сохраняется информация об отдельных свойствах непрозрачности воды (например, для океана это всегда 0,102, для бассейнов — 0,129). В зеленом канале помечено, насколько глубоко пиксель расположен относительно поверхности воды (глубокие пиксели соответствуют менее прозрачной воде, что требует подключения диффузной карты, в то время как пиксели воды с поверхности гораздо прозрачнее).
  • Обратите внимание: все бассейны визуализируются без привязки к условиям, даже если их, практически, перекрывают данные других ячеек, они все равно хранятся в красном канале. Что касается зеленого канала, где учитываются только реально видимые пиксели, исключительно «водные» пиксели попадают на готовое изображение.

Теперь можем объединить предварительно созданные буферы и сгенерировать карту преломления:


Карта преломления для воды

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

Изображение перед добавлением воды

Преломление на плоскости, отражение и карты рельефа

Изображение после добавления воды

Атмосфера

Создаем карту так называемых объемных теней: она помогает затемнить атмосферу / туман, которые непосредственно не освещены солнцем.

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

Базовое изображение

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

Базовое изображение с добавлением тумана

После визуализируется небо.

И в самом конце, вслед за ним, отрисовываются облака.

Конечное изображение

На самом деле, рендеринг неба осуществляется путем единственного вызова отрисовки: графическая сетка неба образует огромный купол, покрывающий всю сцену (см. справа).
На этом этапе задействованы отдельные текстуры, напоминающие эффект шума Перлина.
Так же визуализируются и облака: на горизонте появляется обширная сетка, на этот раз в форме кольца. Одна карта нормалей и одна карта плотности позволяют визуализировать облака: это большие бесшовные текстуры 2048x512 (соединяются по дуге с левой и правой сторон).

Слева плотность облаков, справа нормаль

Прозрачные объекты

Теперь займемся всеми прозрачными объектами: очки, лобовое стекло, пылинки в воздухе…

Всего-то потребуется 11 вызовов отрисовки, правда, при обработке пыли придется неоднократно обращаться к инстансингу.


Итоговое изображение

Сглаживание разрядности

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

Самое время все исправить: запускаем пиксельный шейдер для пост-обработки – и он считывает данные буфера исходного цвета и альфа-канала диффузной карты, чтобы выяснить, какие пиксели сглажены. Для каждого пикселя может понадобиться до 2 соседних пикселей, чтобы определить конечный цвет «сглаженного» элемента.

После сглаживания

Это отличный трюк, ведь с его помощью все изображение «выравнивается» за один подход: причем разнообразие геометрических форм в той или иной сцене роли не играет.
Заметим, однако, что данный фильтр неидеален: в отдельных случаях, видимо, он не справился, я все равно заметил эффект шахматной доски и на PS3, и на ПК.

Тональная компрессия и свечение

До этого обрабатываемое изображение сохранялось в формате HDR: каждый RGB канал хранится в виде 16-битного индекса с плавающей запятой, что позволяло существенно расширить диапазон интенсивности освещения. Но мониторы не способны отображать столь различные значения и сводят все к RGB цвета с 8 битами на канал.
Тональная компрессия осуществляет конвертирование этих значений цвета из HDR в LDR. Есть несколько функций, с помощью которых один формат заменяется другим. Классический вариант, получивший широкое распространение, — метод Рейнхарда (именно его я использовал при создании скриншотов, опубликованных ранее) — дает результаты, близкие к окончательному виду игры.
Но разве в GTA V, действительно, использовали метод Рейнхарда? Придется опять залезть в байт-код шейдера:

<code class="cpp">// Suppose r0 is the HDR color, r1.xyzw is (A, B, C, D) and r2.yz is (E, F) mul r3.xy, r1.wwww, r2.yzyy // (DE, DF) mul r0.w, r1.y, r1.z // BC [...] div r1.w, r2.y, r2.z // E/F [...] mad r2.xyz, r1.xxxx, r0.xyzx, r0.wwww // Ax+BC mad r2.xyz, r0.xyzx, r2.xyzx, r3.xxxx // x(Ax+BC)+DE mad r3.xzw, r1.xxxx, r0.xxyz, r1.yyyy // Ax+B mad r0.xyz, r0.xyzx, r3.xzwx, r3.yyyy // x(Ax+B)+ DF div r0.xyz, r2.xyzx, r0.xyzx // (x(Ax+BC)+DE) / (x(Ax+B)+DF) add r0.xyz, -r1.wwww, r0.xyzx // (x(Ax+BC)+DE) / (x(Ax+B)+DF) - (E/F) </code>

Так, так… что тут у нас? Именно уравнение типа (x(Ax+BC)+DE) / (x(Ax+B)+DF) - (E/F) ознаменовало прорыв Джона Хэбла в киноиндустрии в 2009 году.

Оказывается, в GTA V и речи не идет о методе Рейнхарда, но ведь и принцип из Uncharted 2, согласно которому не обесцвечиваются черные области, тоже не годится.
Процесс преобразования в LDR осуществляется следующим образом:
Разрешение буфера HDR снижается до ¼ от исходного значения.

  • Вычислительный шейдер определяет среднюю яркость буфера, выводя результат в виде текстуры 1х1.
  • Рассчитывается новая экспозиция, за счет чего сцена будет яркой/темной.
  • Фильтр яркости запрашивает только пиксели, имеющие яркость выше определенного значения (задается экспозицией).
  • В этой сцене всего несколько пикселей прошли фильтрацию: некоторые освещенные участки на автомобиле с высокой отражающей способностью.
  • Показатели буфера яркости неоднократно сокращаются вплоть до 1/16 от исходных, а затем увеличиваются до 1/2 от исходных.
  • К исходным HDR пикселям добавляется свечение, а затем при помощи конвертера из Uncharted 2, цвет преобразуется в LDR. Одновременно производится гамма-коррекция, позволяющая заменить линейные каналы на sRGB.

Конечный результат во многом зависит от экспозиции. Приведем, буквально, несколько примеров влияния этого параметра:

Экспозиция изменяется постепенно, кадр за кадром, резких изменений вы не увидите.

Так была предпринята попытка имитировать природу человеческого глаза: вы заметили, что после длительного пути по темному туннелю и внезапного выезда на солнце окружающая обстановка некоторое время воспринимается слишком яркой? Затем перестает «резать глаз» и становится «нормальной», а экспозиция адаптируется к новому значению. Похоже, в GTA V пошли еще дальше, максимально приблизив адаптацию экспозиции по линии «Темный → Яркий» к аналогичным свойствам человеческого глаза.

Сглаживание и искажение объектива

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

До искажения

После искажения

Пользовательский интерфейс

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

Мини-карта

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

Изображение перед добавлением мини-карты

На этом этапе мини-карта отправляется в буфер основного изображения, поверх нее добавляется пару небольших иконок и виджетов.
Да, времени потратили немало, но оно того стоило: вот вам финальный кадр во всей красе!

Всего потребовалось 4155 вызовов отрисовки, 1113 текстур и 88 целей рендеринга.

Перевод статьи!
ua-hosting.company

796 0 850 18
4
2016-01-15
Спасибо! Очень познавательно.
2016-01-16
даже не знал что столько тонкостей))
2016-01-23
Вообще ничего не понял, но было интересно почитать про свою любимую игру.
2016-02-02
Скоро добавится реальный pathtracing и тогда графика будет выглядеть как видео. Осталось дождаться выхода nvidia паскаль и будущее под ногами...
RENDER.RU