среда, 20 июля 2011 г.

Сегодня запись посвящена созданию 2д освещению. А именно рейтрейсингу теней. Оговорюсь сразу, Идею я практически полностью повзаимствовал (за исключением моих доработок) у Catalin Zima. Так как идея приглянулась, а алгоритм расписан, я приступил к созданию. Однако, у автора статьи были толи ошибки в описании, местами недоговорки, поэтому пришлось повозиться.
Итак. Как сказано у автора сначала надо отрендерить альфаканалы в пустой рендертаргет для получения ЧБ изображения. Сразу же следует первая оговорка. Центр рендертаргета это источник света. Так что если у Вас источник не ровно по центру, рендерить в рендертаргет надо все со смещением. Это важно!
Хорошо, дальше надо все это безобразие немного раскрасить. Точнее сказать надо погасить интенсивность "стенок" от центра к краю. Для наглядности в красном цвете
 Дальше начинается очень интересная часть процесса. Дело в том, что левую и правую часть изображения надо "развернуть"! Суть в том, чтобы представить картинку в виде песочных часов >< а далее растянуть треугольники до прямоугольников. И тоже самое сделать в вертикальной составляющей. Полученные результаты дадут нам каждый луч идущий из центра картинки до края, но все эти лучи будут параллельны и лежать на одной картинке. В разных цветовых каналах соотвественно. Получаем что-то вроде этого:
 После идет уменьшение картинки по горизонтали. Уменьшаем вдвое каждый раз, пока не получим картинку шириной 2 пикселя. На каждом шаге мы ищем минимальное значение пикселя (в понятии алгоритма минимальное зачение пикселя значит наиближайший к центру пиксель. Помните, мы градиентом уменьшали интенсивность?)
Стоит оговориться что тут обязательно надо отключить фильтрацию текстур на этом шаге, иначе вместо результата будет все ооочень плохо.
Как только мы получили наше изображение с шириной в 2 пикселя, мы знаем для каждого луча ближайшую преграду относительно центра.

Получение освещенной области теперь будем считать легко: берем расстояние от центра до текущего пикселя и сравниваем со значением дистанции взятым из соотвествующего пикселя в двупиксельной текстуре. Если расстояние меньше - область освещена, если нет - темная.
 
Все вышесказанное можно почитать в блоге автора, ссылку на который я дал раньше. Такой свет нас не устраивает, поэтому мы пройдемся размытием по гауссу.
И, еще раз по вертикали. Зачем тут синий? Чем синее точка, тем сильнее надо размыть (дальность от источника света).
Теперь эту область можно наложить через multiply на свою картинку. Это мы сделаем в финальном шаге. Так как мой пример что-то вроде пакмана, я через мультиплай добавлю "еду" для пакмана :)
Чтобы эффект был эффектнее, добавим нормалмеппинг на "пол". Рендереим саму сцену:
Рендерим стенки и точки-еду на пол:

И финал: Накладываем маску со светом через multiply:


Вопросов данная методика может породить больше чем ответов, поэтому не стесняйтесь спрашивать. На все отвечу.

Как это выглядит "в жизни"

4 комментария:

  1. Вот тут

    «Суть в том, чтобы представить картинку в виде песочных часов >< а далее растянуть треугольники до прямоугольников. И тоже самое сделать в вертикальной составляющей.»

    не смог понять что делается, лез смотреть в оригинал. Когда читал, думал, что под словами «представить в виде песочных часов» имеется ввиду какое-то преобразование с текстурой (а не мысленное выделение треугольников на картинке), а о том, что >< — не смайл, понял только когда уже набирал комментарий :)

    Тут бы код или картинка помогли бы. Но это так, ворчу просто :)

    ОтветитьУдалить
  2. Было:
    http://www.catalinzima.com/wp-content/uploads/2010/07/2_distancesmarked.png
    Стало:
    http://www.catalinzima.com/wp-content/uploads/2010/07/3_distortedXCopy.png

    ОтветитьУдалить
  3. Доброго времени суток.
    Пишу маленький платформер на С++ и OpenGL.
    Никак не могу освоить шаг 3.
    Что передавать в параметр TextureDimensions.x?
    Одинаков ли он на разных итерациях этого шага?

    ОтветитьУдалить
    Ответы
    1. О каком шаге номер три идет речь, можно уточнить?

      Удалить