Internals of "Dirt" game rendering engine (ru)
Этот пост посвящается памяти Колина Макрея.
Привет, друзья. Материалы по Dirt'у у меня были уже в основном готовы с середины июня, но множество всяких обстоятельств (хороших в основном :)) заставили отложить финальное оформление готового репорта до осени. И вот, набравшись сил, я решил завершить начатое.
Стандартная ремарка: компьютер A64 X2 4200+, GF8800GTX, WinXP SP2, 2GB RAM. Игра реверсилась в максимальных настройках в разрешении 1024х768.
Рендер игры оказался технологичным, и достаточно простым для реверсинга. Назначение практически всех шагов отрисовки, используемых текстур и констант были понятны сходу. Не требовалось долгих и утомительных анализов асмового кода шейдеров.
Первым этапом рисуется динамическая миникарта. Это фрагмент карты плюс индикаторы машинок соперников и индикатор нашего транспортного средства. Рисуется квадратами по 2 треугольника на каждый draw call.
Следующим идет генерация динамической кубемапы для отраж ений. Фотографируем сцену с позиции камеры. Автомобили, кусты, людей и всякую мелочевку не рисуем.
Далее велосити буфер + scene depth. Используется текстура формата A16R16G16B16F. В rg каналах 2D вектор смещения точки с предыдущего кадра. Всё так же как и в моем предыдущем обзоре Lost Planet. В b глубина сцены во view space (т.е. не нормализированная). Этот RT используется в практически всех остальных этапах отрисовки.
Dynamic ambient occlusion pass. Нет, это не тот AO, который описан в GPU Gems 2. :) Это такая терминология разработчиков. В этом проходе создается RGBA8 текстура размеров в 8 раз меньше размеров вьюпорта (т.е. 128х96 в нашем случае).Используется только R канал, в который отрисовываются автомобили в определенном (небольшом) радиусе от камеры. Далее эта текстура размывается по горизонтали и вертикали, и используется как мягкая тень от машинок при рендеринге земли и объектов на ней.
Следующий пункт – тени. Использются 3 R32F 2Kx2K текстуры. Все они центрированы по камере и покрывают разные площади.
Затем, используя scene depth текстуру и все 3 шадовмапы разработчки создают т.н. маску тени.
Это достигается путем исполнения огромного шейдера в 250 инструкций. Зная scene depth и позицию пикселя в пространстве экрана можно вычислить его позицию в пространстве камеры. Затем стандартный SM. Из-за того, что приходится блендить 3 карты и тут же применять PCF и получаем столь длинный код. На маске с тенями всё ещё достаточно хорошо видны артефакты теней и PCF алгоритма, поэтому полученная текстура ещё разок легко размывается, благо это уже обычное изображение, а не глубина сцены. Можно отметить, что при таком подходе размытые участки с тенью могут вылезти за пределы мешей на которых они лежат, образуя артефакты. Именно поэтому, используется лёгкое размытие. На финальной картинке артефактов невидно.
Когда все подготовительные работы закончены, начинается основной проход. Front to back всё как надо. Сначала машинки. Шейдеры тут используются достаточно тяжёлые с точки зрения текстурной нагрузки. Для рендеринга авто используются диффузная текстура, карта нормалей, маска грязи, амбиент кубемапа, кубемапа с реалтайм отражениями, текстура с посчитанными тенями, текстура с повреждениями и спекулярная текстура с повреждениями. Все текстуры большие (1Kx1K)
Dirt map:
Карта грязи имеет формат DXT5, и в своих каналах содержит: Маску для грязи одного цвета (red):
Маску для грязи второго цвета (blue):
Коэффициент затемнения грязевого слоя. Он являет собой результат формулы вертикального вектора (перпендикулярного земли) и нормали модели авто в этой точке. Используется вариация формулы wrap-around освещения (или напрямую, не суть важно)
сolour * clamp(N.L+factor)/(1+factor)
Это сделано для того, чтобы угол в 90 градусов и больше не превращал всё в черноту.
В альфе содержится маска областей, которые не должны быть загрязнены (либо загрязнены частично). Эти области обычно включают надписи на авто.
Вот картиночки чистых и грязн ых машинок:
Освещаются машинки (как и всё остальное в игре) одним солнышком. Авто, при максимальное детализации помещается в 100 DIPов. По мере отдалённости мелкие детали в авто не рисуются. LOD'а шейдеров нет. Водители и зрители скинятся софтварно. Для отрисовки земли/дорог используются несколько фотографий местности c воздуха (размером 512x512) и несколько текстур деталей. Для бленда слоев предназначена следующая текстура (оригинальный размер 1024^2, слои отдельно рядом):
Для всех диффузных текстур есть сопутствующая нормалмапа. Всё освещается попиксельно, от солнца.
Деревья SpeedTree’шные. В конце полусфера неба, на текст уре которого нарисованы самый дальний слой леса. Все модели хранятся в своих VB/IB. Выравнивания по cache-friendly sizes отсутвует. Используемые вертексформаты декларируют вертексы с размерами 28, 36, 40, 48 и 60 байт (некоторые меши освещаются повертексно). Частицы мягкие. Для сглаживания пересечений геометрии используется текстура со scene depth информацией подготовленная ранее. Получилась вот такая картинка:
Затем в 5 этапов даунсемплим картинку до 1х1 с посчитанной scene luminance. Используя velocity буфер и яркость сцены блурим и модифицируем освещение финальной картинки соответсвенно. К слову motion blur используется даже в главном меню игры.
Затем блурим ещё 2 раза для создания glow областей. Финальное изображение:
UI поэлементно, можно было батчить лучше. Буквы – модельки. Текст батчится побуквенно, т.е. все одинаковые буквы, если вст речается несколько раз, отрисовываются за 1 draw call.
Вот и всё, собственно. Хотелось бы отметить, что для для этого исследования не потребовался PIXWin вообще. 4-м перфхудом экспортил текстуры и рендертаргеты. 5-м же модифицировал шейдеры, чтобы понять как работают неочевидные вещи.