habrahabr

2D система освещения для Unity3D, работающая на GPU

  • воскресенье, 18 января 2015 г. в 02:11:12
http://habrahabr.ru/post/248149/



Всем привет. Как известно, Unity3D отсутствует поддержка освещения для 2D игр. В Asset Store можно найти такую систему, но у неё есть один недостаток — она работает на CPU и потребляет весьма много ресурсов (64-4096 рейкастов за кадр на каждый источник света). Поэтому я решил сделать своё освещение, производительности которого хватило бы для мобильных устройств. Для этого вычисления были перенесены на GPU. Получилось что-то похожее свет Terraria или Starbound.

Ссылка на демку. Скриншоты взяты из неё.

Всё освещение считается на небольших текстурах, в примере используются 160х88 пикселей. При повышении разрешения можно добиться очень мелкой сетки, которую будет сложно заметить, правда это уже не для мобильных платформ. Из-за того, что вычисления производятся на таких небольших текстурах можно использовать довольно тяжелые шейдеры.

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

Теперь подробнее, в порядке отрисовки.

Препятствия света



Текстура препятствий света. RGB каналы. Эта и последующие похожие текстуры имеют масштаб 400%

Вот такую текстуру выдает камера. Черные области полностью прозрачны, белые — полностью непрозрачные. Также поддерживаются цветные области, например, полностью красный пиксель будет блокировать красную часть света и пропускать зеленую и синюю.

Свет окружения



Источники света окружения


Источники света окружения. Альфа канал


Итеративно генерируемая текстура света окружения


Так выглядит немного усиленный свет окружения, без обычных источников освещения

Тут всё несколько сложнее. Такой тип освещения я реализовал для того, чтобы добавить слабый свет на то пространство, где нет источников света. В примере с помощью него реализована неяркая подсветка всего свободного пространства. RGB канал управляет цветом, альфа канал силой свечения. Главное отличие этого типа света от обычных источников состоит в том, что он считается итеративно и не имеет направления.

Алгоритм расчета для одного пикселя:

  1. Берем начальное значение пикселя из предыдущей итеративной текстуры.
  2. Вычитаем из пикселя силу препятствия из текстуры препятствий.
  3. Прибавляем к пикселю силу свечения из текстуры источников света окружения.
  4. Прибавляем к пикселю усредненное значение соседних пикселей


Источники света



Источники света

Обычные источники — главная часть системы освещения. Для их рисования используется нечто похожее на спрайты. Весь цвет исходит из центра, хотя при желании точку можно перенести куда угодно.
Для источников света доступно несколько шейдеров с трассировкой пути и один без неё. Шейдеры с трассировкой различаются по количеству трассируемых точек. Я использую два таких — один на 9 точек, работающий с Shader Model 2.0, другой на 20 точек для Shader Model 3.0. Шейдер без трассировки пути используется для систем частиц, так как ему не нужна какая-либо дополнительная информация для работы.

Алгоритм трассировки путя:

  1. Берем яркость пикселя из текстуры.
  2. Находим позицию источника света и текущего пикселя в текстуре препятствий.
  3. Уменьшаем текущую яркость на значения пикселей препятствий, которые лежат между двумя точками из предыдущего шага.


Смешивание и наложение света



Свет источников + свет окружения

После того, как свет источников и свет окружения отрендерен можно смешивать их друг с другом. Для этого текстуры умножаются на свою альфу и складываются. Затем всё это накладывается на изображение игры и выводится на экран.


Скриншоты результата, большее разрешение по клику.

И напоследок плюсы и минусы


Плюсы:
  • Вычисления происходят на GPU.
  • Источниками света являются обычные спрайты, соответственно можно делать источник света любой формы.
  • Каждый источник света потребляет очень мало ресурсов.
  • Работает на мобильный устройствах, потребляя ~8 мс за кадр на Nexus 4.
  • Полностью динамическое освещение. Препятствия можно создавать и уничтожать на лету без всякой потери производительности.
  • Поддержка света окружения.
  • Сама по себе система генерирует 6 DrawCalls, все источники света можно уместить один плюс еще один для света окружения.
  • Разноцветные источники света и препятствия.
  • Возможность эмитить источники света в системе частиц. Производительность почти не отличается от обычных партиклов.
  • Гибкие настройки качества.

Минусы:
  • Система освещает по сетке, в следствии чего мелкие препятствия могут игнорироваться. На мощных платформах можно сделать сетку очень мелкой.
  • Необходимо генерировать меши для света окружения и препятствий.
  • Размер камер, в которых создается освещение должен быть больше размера игровой камеры, чтобы корректно отображались источники света за экраном.
  • Вычислительная сложность системы почти не зависит от количества источников. Это означает, что если она потребляет 8 мс за кадр с 10 источниками света, то без источников она так и будет потреблять около 8 мс.


P.S. При наличии интереса сообщества доработаю и выложу в Asset Store.