Algorithms
Mathematics
Programming
Working with 3D-graphics
Game development
February 16

Reflective Shadow Maps: Часть 1

Original author: Eric Polman
Translation
image

Привет, Хабр! Представляю вашему вниманию перевод статьи «Reflective Shadow Maps» автора Eric Polman.

Reflective Shadow Maps (RSM) (отражающие карты теней) ― это алгоритм, расширяющий “простые” shadow map. Алгоритм учитывает свет, рассеянный после первого попадания на поверхность (diffuse). Это означает, что кроме прямого освещения, вы получаете непрямое освещение. В данной статье я разберу алгоритм из официальной статьи, чтобы объяснить его по-человечески. Я также кратко расскажу о shadow mapping.

Shadow mapping


Shadow Mapping (SM) ― это алгоритм генерации теней. Согласно алгоритму, мы храним расстояние от источника освещения до объекта в карте глубины. На рисунке 1 показан пример карты глубины. В ней хранится расстояние (глубина) для каждого пикселя.

image
Рисунок 1: Данное изображение демонстрирует карту глубины. Чем ближе пиксель, тем он ярче.

Таким образом, когда у вас есть карта глубины с точки зрения источника освещения, вы затем рисуете сцену с точки зрения камеры. Чтобы определить, освещен ли объект, вы проверяете расстояние от источника освещения до объекта. Если расстояние до объекта больше значения, хранимого в карте теней (глубины), объект находится в тени. Это означает, что объект не должен быть освещен. На рисунке 2 показан пример. Вы совершаете эти проверки для каждого пикселя.

image
Рисунок 2: Расстояние от источника освещения до пикселя в тени больше, чем расстояние, хранимое в карте теней.

Reflective Shadow Mapping


Теперь, когда вы поняли основную концепцию Shadow Mapping, мы продолжим с Reflective Shadow Mapping (RSM). Данный алгоритм расширяет функциональность “простых” shadow maps. Помимо данных о глубине, вы также храните world-space (в мировой системе координат) позицию, world-space нормали и flux (световой поток). Я объясню, зачем вам нужны эти данные.

Данные


World-space позиция


В RSM world-space позицию нужно хранить для того, чтобы определить расстояние между пикселями. Это полезно для расчета затухания света. Свет затухает (становится менее концентрированным), когда проходит определенное расстояние. Расстояние между двумя точками в пространстве используется для расчета интенсивности освещения.

Нормали


Нормали (world-space) используются для расчета отражения света от поверхности. В случае RSM они также используются для определения, является ли данный пиксель источником освещения для другого пикселя. Если две нормали практически совпадают, они не будут давать друг другу много отраженного света.

Luminous Flux (световой поток)


Flux ― это световая интенсивность источника освещения. Ее единицей измерения является люмен, термин, который в настоящее время вы можете увидеть на упаковках лампочек. Алгоритм сохраняет flux для каждого пикселя, пока рисуется карта теней. Flux рассчитывается умножением интенсивности света на коэффициент отражения. Для directional light (направленный источник освещения) вы получите равномерно освещенное изображение. Для spot light вы также учитываете угол падения. Затухание и принимающий косинус (между нормалью и light вектором) не берутся в расчет, так как это учитывается, когда вы считаете непрямое освещение. В данной статье не будут рассматриваться подробности. На рисунке 3 изображены текстуры для spot light из официальной статьи.

image
Рисунок 3: Изображены четыре карты, содержащиеся в RSM. Слева направо: карта глубины, world-space позиции, world-space нормали, flux.

Применение данных


Теперь, когда данные сгенерированы (теоретически), пришло время применить их к финальному изображению. Когда вы отрисовываете финальное изображение, вы рассчитываете влияние каждого источника освещения на каждый пиксель. Помимо простого освещения пикселей, используя источники освещения, теперь вы также используете Reflective Shadow Map.

Наивным подходом к расчету вклада освещения является проход по всем текселям в RSM. Вы проверяете, не попадает ли свет из текселя в RSM на пиксель, который вы рассчитываете. Это делается, используя world-space позиции и world-space нормали. Вы рассчитываете направление от world-space позиции в текселе RSM до пикселя. Затем вы сравниваете его с нормалью, используя скалярное произведение векторов. Любое положительное значение означает, что пиксель должен быть освещен с помощью flux, который храниться в RSM. Рисунок 4 демонстрирует данный алгоритм.

image
Рисунок 4: Демонстрация вклада непрямого освещения, основываясь на world-space позициях и нормалях.

Shadow maps RSMs) по своей природе большие (512x512=262144 пикселя), так что проверка каждого текселя далека от оптимальности. Вместо этого лучше всего сделать определенное количество сэмплов из карты. Количество сэмплов зависит от того, насколько мощное у вас железо. Недостаточное количество сэмплов может дать такие артефакты, как полосы или мерцания.

Тексели, которые в наибольшей степени будут влиять на результат освещения, находятся ближе всего к рассчитываемому пикселю. Метод сэмплинга, который собирает большинство сэмплов рядом с координатами пикселя, даст лучшие результаты. Данный метод называется “importance sampling” (сэмплинг по важности). В официальной статье описывается, что плотность сэмплинга уменьшается с квадратом расстояния от пикселя, который мы рассчитываем.

Также нам необходимо масштабировать интенсивность сэмплов с учетом коэффициента, зависящего от расстояния. Это связано с тем, что тексели, расположенные дальше, хоть и сэмплируются реже, но в действительности оказывают влияние тем же количеством flux. Поэтому у дальних пикселей нужно увеличить интенсивность, чтобы сгладить неравенство, сохраняя при этом небольшое количество сэмплов. На рисунке 5 показано, как это работает.

image
Рисунок 5: Importance sampling. Больше сэмплов берется из центра и сэмплы масштабируются коэффициентом, основанным на их расстоянии от центральной точки. Заимствовано из статьи о RSM.

Дополнительно
В качестве точки (s,t) берется проекция текущего пикселя на shadow map. А координаты сэнмплинга относительно (s,t) рассчитываются заранее и передаются массивом в шейдер.

К сэмплу вы должны относиться как к точечному источнику освещения. Вы используйте значение flux в качестве light color и только те источники освещения, которые находятся напротив пикселя.

Заключение


В официальной статье более подробно рассказывается о других оптимизациях этого алгоритма, но я остановлюсь на этом. В разделе Screen-Space Interpolation описывается, как вы можете увеличить производительность, но я думаю для начала importance sampling будет достаточно.

Во второй части представлена реализация RSM.
+23
2.4k 45
Comments 9