Роман МарченкоСтатьи

PainKiller: Технологии рендера

Автор:

Как-то давно, я уже реверсил рендер пейнкиллера, но только очень поверхностно. А так как о моем мини-исследовании рендера FlatOut'а я неожиданно получил очень положительные отзывы, то решил серьезно заняться этой, несоменно, великолепной игрой.

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

Итак, реверсил я на максимальных настройках графики ("insane" в параметрах конфиграции) , на видеокарте GF6600.

Рендер игрового кадра состоит из следующих этапов:

  • Если на уровне есть вода, то рисуется рефлекшин мапа. Никаких упрощений геометрии и шейдеров, по сравнению с основным проходом (их детальное описание см. дальше), я не заметил. Рисуется все, что видно в главную камеру. Т.е. теоретически можем поиметь эффект внезапного исчезновения/появления отражений невидимых в камеру объектов. Практически же, я пытался поймать эту ситуацию (не долго правдаJ). Не поймал.
  • Тени для монстров. Для каждого используется RTT (render target texture) A8R8G8B8 128х128.
  • Блурим эти текстуры каждую по 2 раза простым 4 tap фильтром, используя смещения координат.
  • Получаем
    Изображение

  • Монстрики. Используется хардварный скининг. Точно количество костей не знаю, но учитывая что vs.1.1, смею предположить что около 20. Модель содержит, естественно, больше, поэтому она разбивается на несколько сабмешей, по костям. Количество влияний на вершину - 4. Скиненные персонажи рисуются в 1 проход, поэтому освещаются сразу.
  • Поддерживаются, похоже, только directional источники, коих может быть до 5 штук. Пиксельного шейдера нет. Освещение посчитанное в vs, умножается на диффузную текстуру (которая, кстати, очень качественная).
    Текстура монстрика (оригинальный размер 1024x1024):
    Изображение

  • Первый проход на объекты. FFP + простые шейдеры (1.1).
  • При отрисовке земли используется 2 диффузные текстуры с рисунком камешков и травички, которые блендятся по заданной маске. Также используется лайтмапа.

    Пример маски блендинга для земли:
    Изображение

    Пример лайтмапы для земли:
    Изображение

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

    Лайтмапа для объектов (оригинальный размер 1024x1024):
    Изображение

  • Вода. Первый проход.
  • Сложные шейдеры, до конца не осилил :) Приводить их не буду.
    Большое количество входных параметров. Vs - 56 инструкций, ps - 31 инструкция. В этом проходе накладываем reflections, анимируя её используя 2 dudv карты. Волнение геометрии создаем анимацией вершин в vs. Я вообще обнаружил повертексную анимацию, только после того, как шейдер проанализировал, и увидел, что там меняется позиция вершины. Так думал, что вода плоская.

  • Второй проход для воды.
  • Освещаем её 4-мя направленными (directional) источниками повертексно.

    В арсенале PainKiller'а есть еще один тип воды. Без честных отражений, с использованием лайтмап. Такой тип используется на уровнях, где воды много.
    Например в локации C5L1_City_On_Water. Первый же тип используется на первом уровне аддона Battle Out Of Hell: C6L1_Orphanage. Думаю, что мощный редактор позволяет по-разному варьировать параметры воды, чтобы получить нужный визуальный стиль.

  • Небо.
  • До 4-х слоев. Компоненты трехслойного неба:
    полусфера, внутри чашечка в зените, потом опять полусфера. Эти слои блендятся стандартным альфаблендом (srcalpha, invsrcalpha), и используют шейдеры точно такие же как при рендеринге земли. Неиспользованные слои (вспомним, что при рендеринге земли используется 2 текстуры для комбинирования) заменяются dummy текстурой.

    Пример текстур неба:
    Оригинальный размер 2048х512
    Изображение

    Оригинальный размер 1024x1024
    Изображение

    Оригинальный размер 1024x1024
    Изображение

  • Второй проход на сцену - освещение. Тут все что земля, что остальные статические объекты рисуются одинаково. Освещение осуществляется от одного точечного источника, попиксельно. Весь процесс достаточно хитрый. Для учета расстояния используется текстура аттенюации такого содержания:
  • Изображение

    В вертексном шейдере мы вычисляем расстояние от источника света до вершины. Поделив полученное расстояние на дистанцию влияния источника, мы пакуем вектор так, что все расстояния на которые влияет источник попадают в диапазон [-1,1]. Скейлим дальше в [0,1]. Получили текстурные координаты для лукапа в текстуру аттенюации (так как address mode установлен в clamp, то все лукапы за пределами текстуры будут происходить по ее границе). В нашем примере используется простой кружочек, что означает простое постепенное ослабление освещения с расстоянием. Но задав, например тот же кружочек, но инвертировав его цвет, мы получим освещёнными дальние объекты, но неосвещённые ближние. В общем вариантов масса.

    Основные стетйты тендера установлены в:
    Depth write = false
    Srcblend = one
    Dstblend = one

    Т.е. получаем блендинг pixel color + incoming color

  • Третий проход на статику (только если включены тени). Рисуем геометрию, проективно накладывая текстуры с тенюшками от монстриков. Ничего особо интересного, разве что, тени еще больше разблуриваются (2 лукапа на текстуру).
  • Партиклы. Используются динамические VB/IB. FFP.
  • Оружие. Sm30. Normal mapping от нескольких (я видел 2) directional источников освещения. Тут все стандартно, за исключением того, что normal map'ы у них не в tangent, a в model space. Просто источники они тоже поворачивают в model space. Анимации оружия скинтся хардварно (на вертекс влияет 2 кости)
  • Normal map оружия (оригинальный размер 1024х1024):
    Изображение

    Specular mask хранится в альфа канале normal map'ы (оригинальный размер 1024х1024)
    Изображение

    Диффузная карта (оригинальный размер 1024х1024):
    Изображение

  • Downsample картики, с небольшим color remap'ом, для выделения ярких областей.
  • Separable Gaussian blur. Горизонтальный, вертикальный, 13х13. Получили bloom текстуру.
  • Блум текстура:
    Изображение

  • Блендинг с блум тектурой. FFP. Блендим по формуле: blurred текстура + текстура сцены.
  • Полученный результат отлично выглядит на динамическом небе.

  • UI. Ингейм интерфейса в painkiller почти нет. Думаю именно по этому он сделан так ужасно J Рисуется поэлементно, группировок никаких нет. Зато в startup menu разработчики постарались. Особенно убило окно конфигурации кнопок. Несколько скринов из под NVPerfHUD'а:
  • Изображение
    Изображение
    Изображение
    Изображение

    3 раза перетиреть почти весь экран, причем такими маленькими квадратиками, это надо уметь :) 2000 дипов.

  • Demon mode. Кто не играл, это такой режим, когда собираешь 66 душ, и превращаешься в бессмертного психа-убийцу. :)
  • Процесс рендеринга таков:
    Рисуем сцену нормально в RTT. Затем из нее делаем ч.б. картинку (способ стандартный: dp3 pixel, float3(0.3, 0.59, 0.11). Потом рисуем монстров специальным шейдером, который используя нормали и градиентную текстуру выделяет границу объекта красным цветом. И, напоследок, используя dudv bump map, вносим в картинку искажения. Для получения motion blur эффекта блендим предыдущий и текущий кадр используя весовые коэффициенты.
    Demon mode shader

    Градиентная текстура:
    Изображение

    Получаем вот такую картинку:
    Изображение

    Страницы: 1 2 Следующая »

    #reverse engineering

    16 ноября 2006