Gamedev LectureСтатьи

Лекция #32. R.E.N.D.E.R.

Автор:

Disclaimer: некоторые реплики убраны, посты - передвинуты, опечатки - исправлены. полный лог

[19:59] <Zeux> Давайте начинать.
[19:59] <Zeux> Привет всем, спасибо, что пришли послушать.
[20:00] <Zeux> Сначала вкратце о лекции и правилах проведения
[20:00] <Zeux> Лекция о том, как сделан рендер в игре STALKER
[20:00] <Zeux> Лекция будет преимущественно проходить в +m режиме
[20:00] <Zeux> т.е. говорить могу только я
[20:00] <Zeux> и несознательные слушатели
[20:00] <Zeux> которые являются опами
[20:00] <Zeux> будут делаться перерывы на вопросы
[20:01] <Zeux> наверное, 2-3
[20:01] <Zeux> если у вас возникают вопросы по ходу лекции - пишите мне в приват.
[20:01] <Zeux> Логи лекции будут доступны
[20:02] <Zeux> наверное, через час после окончания
[20:02] <Zeux> так что если надо будет через пол часа куда-то срочно бежать - особо не переживайте, вы сможете прочитать то, что пропустили :)
[20:02] <Zeux> Теперь таки начнем.

[20:03] <Zeux> Эта лекция является своеобразным продолжением лекции про рендер в Обливионе (была примерно год назад). В начале той лекции я рассказывал, почему реверс игр возможен
[20:03] <Zeux> И рассказывал, как можно прореверсить большинство игр
[20:03] <Zeux> Повторяться я не буду.
[20:03] <Zeux> При анализе рендера Сталкера я использовал все тот же NV PerfHUD
[20:03] <Zeux> который доблестные разработчики все так же (как в Обливионе) забыли отключить в финале
[20:04] <Zeux> Так же были два полезных источника
[20:04] <Zeux> Один - исходники шейдеров Сталкера
[20:04] <Zeux> которые вынимаются из архивов с помощью утилиты
[20:04] <Zeux> STALKER Data Unpacker
[20:04] <Zeux> лежит где-то на ag.ru :)
[20:05] <Zeux> Второй - статья Олеся (программист графики Сталкера) в GPU Gems 2
[20:05] <Zeux> статья помогла значительно меньше (хотя и решила несколько вопросов), без исходников шейдеров - лекция появилась бы значительно позже
[20:05] <Zeux> и была бы менее подробной.

[20:05] <Zeux> Ну и напоследок, перед тем как начать основную часть
[20:06] <Zeux> В сталкере есть несколько режимов рендеринга
[20:06] <Zeux> 3, если быть точным
[20:06] <Zeux> Я буду рассматривать только самый совершенный
[20:06] <Zeux> который использует Deferred Shading
[20:06] <Zeux> Поехали.

[20:06] <Zeux> В Сталкере используется технология Deferred Shading
[20:07] <Zeux> Я чуть-чуть расскажу о ней
[20:07] <Zeux> чтобы людям, с ней не знакомым, было проще.
[20:07] <Zeux> Основная идеология "обычного" (forward) рендеринга - для каждого меша
[20:07] <Zeux> послать его на отрисовку, и в шейдерах (вершинном и пиксельном) выполнить освещение
[20:08] <Zeux> Когда у вас появляются несколько источников - возникают несколько вариантов решения проблемы "как осветить меш не 1 источником, а 4"
[20:08] <Zeux> В Doom 3 проблема решена так - каждый меш рисуется столько раз, сколько на него влияет источников (на самом деле, вроде немного больше).
[20:08] <Zeux> Очевидно, с этим подходом возникают проблемы - увеличивается сложность трансформации геометрии
[20:08] <Zeux> (особенно в случае "тяжелых" вершинных шейдеров - скелетная анимация)
[20:09] <Zeux> Возрастает нагрузка на CPU
[20:09] <Zeux> из-за увеличенного количества вызовов API
[20:09] <Zeux> В Oblivion проблема решена чуть более хорошо, но все равно на каждый меш может приходиться до 4 кажется вызовов отрисовки
[20:09] <Zeux> что не очень здорово.
[20:09] <Zeux> Очевидно, если вам нужно осветить сцену большим количеством источников (50? 100?)
[20:10] <Zeux> то про подобные подходы сразу можно забыть.
[20:10] <Zeux> И еще одна проблема - проблема overdraw. Когда вы рисуете меш, и в пиксельном шейдере производите сложные вычисления, то не факт, что получившийся пиксель в итоге
[20:10] <Zeux> (после отрисовки всей сцены)
[20:10] <Zeux> будет виден на экране
[20:11] <Zeux> Это решают сортировкой по расстоянию, дополнительным проходом, заполняющим глубину, и прочим
[20:11] <Zeux> Deferred Shading предлагает другое решение обоих проблем
[20:11] <Zeux> Рендеринг разбивается на 2 стадии. 1 - заполнение т.н. G-buffer
[20:11] <Zeux> G-buffer - это одна или несколько полноэкранных текстур
[20:11] <Zeux> (размером с экран)
[20:12] <Zeux> содержащих всю информацию, которая нужна для того
[20:12] <Zeux> чтобы осветить сцену источником света, положить на нее тени
[20:12] <Zeux> и т.д.
[20:12] <Zeux> Например, очевидно, что если у вас есть в каждом пикселе его позиция в скажем world space
[20:12] <Zeux> его нормаль
[20:13] <Zeux> и diffuse color, взятый из диффузной текстуры
[20:13] <Zeux> то этой информации достаточно, чтобы в каждом пикселе посчитать освещенность по модели скажем Фонга
[20:13] <Zeux> Посчитать, находится ли он в тени (если используются Shadow maps, например)
[20:13] <Zeux> и т.д.

[20:14] <Zeux> Поэтому в первой стадии вся сцена рендерится в G-buffer
[20:14] <Zeux> здесь происходит заполнение текстур позицией, нормалью, и прочим
[20:14] <Zeux> потом для каждого источника на экран рисуется примитив (для простоты - full screen quad)
[20:14] <Zeux> с хитрым пискельным шейдером
[20:15] <Zeux> пиксельный шейдер читает информацию из G-buffer (позицию, нормаль, diffuse цвет, etc.)
[20:15] <Zeux> и производит вычисление освещенности для данного источника
[20:15] <Zeux> Если отрендерить 100 квадов с разными параметрами источника с аддитивным блендом
[20:16] <Zeux> получится суммарная освещенность сцены от 100 источников.
[20:16] <Zeux> Замечу, что при этом геометрическая стоимость - практически нулевая
[20:16] <Zeux> (трансформировать 4 вершины на каждый источник)
[20:16] <Zeux> Количество вызовов - по 1 на каждый источник
[20:16] <Zeux> Однако, pixel cost - все еще большой
[20:17] <Zeux> Главная проблема - если в forward renderer вы можете балансировать нагрузку между VS и PS
[20:17] <Zeux> вынося часть вычислений освещенности в VS
[20:17] <Zeux> то здесь вам приходится делать все в PS
[20:17] <Zeux> с одной стороны - проблема, с другой - освещение юниформное - т.е. везде попиксельное :)
[20:18] <Zeux> Общее введение в DS на этом я завершу. Я не рассчитываю, что тем, кто не знает, что такое DS, стало все понятно - это не цель лекции - по DS есть набор статей и tutorial-ов
[20:18] <Zeux> Но надеюсь, что кто-то что-то понял. Сейчас я буду рассказывать, как DS реализован в сталкере - что-то станет более понятно (надеюсь): )

[20:19] <Zeux> Итак.
[20:19] <Zeux> В Сталкере G-buffer представлен тремя текстурами
[20:20] <Zeux> все три - формата A16B16G16R16F
[20:20] <Zeux> т.е. 4 канала, каждый канал - half (16-битный float)
[20:21] <Zeux> В первой текстуре находится нормаль в каналах RGB
[20:21] <Zeux> нормаль - в view space
[20:21] <Zeux> и, гм, hemi - в A
[20:21] <Zeux> что такое hemi я потом скажу :)
[20:22] <Zeux> во второй текстуре - позиция в каналах RGB
[20:22] <Zeux> тоже view space
[20:22] <Zeux> и индекс материала - в A
[20:22] <Zeux> значений индекса 4 штуки.
[20:22] <Zeux> т.е. 4 варианта материала
[20:22] <Zeux> в третьей текстуре в RGB находится цвет
[20:23] <Zeux> диффузный
[20:23] <Zeux> в четвертом канале - gloss коэффициент
[20:23] <Zeux> контролирующий количество спекуляра.
[20:23] <Zeux> Итак, первой задачей является - заполнить эти 3 текстуры.
[20:24] <Zeux> Для этого каждый видимый меш сцены рисуется в 3 текстуры с использованием MRT (из пиксельного шейдера возвращаются 3 цвета, каждый попадает в свою текстуру)

[20:24] <Zeux> Теперь начинаются интересные вещи
[20:25] <Zeux> Вершины в мешах типично занимают 32 байта для статической геометрии
[20:25] <Zeux> 24 или 28 - для моделей персонажей и монстров
[20:25] <Zeux> что в них хранится.
[20:25] <Zeux> object space позиция вершины - float3 (12 байт)
[20:26] <Zeux> нормаль - byte4 (точнее, d3dcolor; 4 байта)
[20:26] <Zeux> касательная и бинормаль - так же
[20:26] <Zeux> 2 текстурных координаты - каждая в short2 (4 байта)
[20:27] <Zeux> это для статики, с монстрами потом
[20:27] <Zeux> первая текстурная координата используется для выборки из всех текстур, кроме лайтмапа
[20:27] <Zeux> вторая - для выборки из лайтмапа, в котором записано статическое освещение
[20:27] <Zeux> лайтмап оригинально - с их старого рендера
[20:28] <Zeux> который "статическое освещение" и про который рассказано не будет :)
[20:28] <Zeux> текстурные координаты изначально имеют range -32768..32767 (потому как short)
[20:28] <Zeux> для лайтмапа текс. координата просто делится на 32768
[20:29] <Zeux> получается значение [-1, 1] (используется реально [0,1]), этого хватает, т.к. тайлинг не нужен
[20:29] <Zeux> а лайтмапы - 2048х2048.
[20:29] <Zeux> текстурные координаты делятся на 1024
[20:29] <Zeux> получается значение [-32, 32]
[20:29] <Zeux> так вот
[20:30] <Zeux> как вы наверное заметили, в нормали, бинормали и касательной - остаются свободные компоненты - по 1 на вектор
[20:30] <Zeux> tangent.w и binormal.w - используются для повышения точности текстурных координат
[20:30] <Zeux> в них хранится значение [0, 1], которое прибавляется к текстурной координате перед делением на 1024.
[20:31] <Zeux> В свободной компоненте нормали хранится дополнительный фактор освещенности - скорее всего, статически просчитанный Ambient Occlusion

Страницы: 1 2 3 4 5 6 7 Следующая »

#GSC, #render, #reverse engineering, #S.T.A.L.K.E.R.

10 мая 2007 (Обновление: 17 сен 2009)