Балуюсь созданием своего движка и игр под него и встал такой вопрос: как правильно сделать осещение? Методом умозаключений, проб и ошибок, решил сделать следующим образом:
1) Выделить для источников света n uniform размером в 3 float. В каждом таком векторе хранятся: координаты (первые два значения) и мощность источника света.
2) Во фрагментном шейдере для каждого пикселя на экране выщитывается расстояние до каждого источника света и соответственный коэффициент освещенности (1 - расстояние / мощность).
3) Коэффициент освещёности умножается на r, g & b и получаем выходной цвет.
Данный способ работает, но у него, конечно, есть очевидные недостатки: строго ограниченное количество источников света (ограниченное как заранее установленных в шэйдеры юниформ, так и общим количеством юниформ - 128, если не ошибаюсь) и большой объем рассчетов. Как сделать освещение более эффективно?
Это делается так:
Создаете отдельную текстуру, размером с экран. И фреймбуфер для нее.
В начале каждого кадра заполняете ее черным.
Переключаетесь на additive blending (glBlendFunc(GL_ONE, GL_ONE)).
Рисуете на нее белые круги с размыленными краями и черным фоном (то есть либо квадраты с текстурой, либо квадраты с хитрым шейдером) с центрами в источниках света.
(За счет additive blending этот черный фон не будет мешать соседним источникам света.)
Отключаете этот фреймбуфер и рисуете остальную графику как обычно.
Потом поверх всего рисуете ту текстуру освещения, с режимом смешивания (glBlendFunc(GL_ZERO, GL_SRC_COLOR)). По сути это умножение картинки на содержимое текстуры.
Все, получаете красивую картинку с освещением.
При таком подходе можно источники освещения плодить сотнями, вешая их на все подряд, без просадки FPS.
Возможны разные вариации:
Можно финальное смешивание проводить в отдельном шейдере.
Можно использовать цветное освещение, рисуя круги цветными.
Можно объединять свет от разных источников с помощью разных необычных функций смешивания.
Сборка персонального компьютера от Artline: умный выбор для современных пользователей