Я работаю над реализацией области освещения в WebGL, подобной этой демонстрации:
http://threejs.org/examples/webgldeferred_arealights.html
Вышеупомянутая реализация в three.js была перенесена из работы ArKano22 поверх gamedev.net:
http://www.gamedev.net/topic/552315-glsl-area-light-implementation/
Хотя эти решения очень впечатляют, у них обоих есть несколько ограничений. Основная проблема с оригинальной реализацией ArKano22 заключается в том, что расчет диффузного члена не учитывает нормалей поверхности.
Я увеличил это решение уже несколько недель, работая с улучшениями redPlant для решения этой проблемы. В настоящее время у меня есть обычные расчеты, включенные в решение, но результат также ошибочен.
Вот предварительный просмотр моей текущей реализации:
Введение
Шаги для расчета диффузного члена для каждого фрагмента следующие:
- Проецируйте вершину на плоскость, на которой светит площадь, так что проецируемый вектор совпадает с нормальным/направленным светом.
- Убедитесь, что вершина находится на правильной стороне световой плоскости области, сравнивая вектор проекции с нормальным светом.
- Вычислите двумерное смещение этой проецируемой точки на плоскости из центра света/положения.
- Закрепите этот 2D-вектор смещения так, чтобы он находился внутри области света (определяемой его шириной и высотой).
- Вывести трехмерное мировое положение проецируемой и зажатой двумерной точки. Это ближайшая точка на ярлыке области до вершины.
- Выполните обычные диффузные вычисления, которые вы хотели бы для точечного света, взяв точечный продукт между вектором вершин к ближайшей точке (нормализованным) и нормальной вершиной.
Проблема
Проблема с этим решением заключается в том, что вычисления освещения выполняются из ближайшей точки и не учитывают другие точки на поверхности огней, которые могли бы еще больше осветить фрагмент. Позвольте мне попытаться объяснить, почему...
Рассмотрим следующую диаграмму:
Облачный свет перпендикулярен поверхности и пересекает его. Каждый из фрагментов на поверхности всегда будет возвращать ближайшую точку на область света, где пересекаются поверхность и свет. Поскольку нормаль поверхности и векторы вершин к свету всегда перпендикулярны, точечный продукт между ними равен нулю. Впоследствии расчет диффузного вклада равен нулю, несмотря на наличие большой площади света, нависшего над поверхностью.
Потенциальное решение
Я предлагаю вместо вычисления света от ближайшей точки света на площади, мы вычисляем его из точки на свету области, которая дает наибольший точечный продукт между вершиной к свету вектор (нормализованный) и нормаль вершины. На приведенной выше диаграмме это будет фиолетовая точка, а не синяя точка.
Помогите!
Итак, вот где мне нужна ваша помощь. В моей голове у меня довольно хорошее представление о том, как этот момент может быть получен, но у него нет математической компетентности для решения.
В настоящее время у меня есть следующая информация в моем шейдере фрагмента:
- позиция вершины
- vertex normal (единичный вектор)
- светлое положение, ширина и высота
- светлый нормальный (единичный вектор)
- light right (единичный вектор)
- загорается (единичный вектор)
- проецируемая точка из вершины на плоскость света (3D)
- прогнозируемое смещение точки от центра освещения (2D)
- зажатое смещение (2D)
- мировое положение этого зажатого смещения - ближайшая точка (3D)
Чтобы помещать всю эту информацию в визуальный контекст, я создал эту диаграмму (надеюсь, что это помогает):
Чтобы проверить мое предложение, мне нужна точка литья на свету области - представлены красными точками, так что я могу выполнить точечный продукт между вершиной до точки литья (нормализованный ) и нормальной вершины. Опять же, это должно дать максимально возможное значение вклада.
ОБНОВЛЕНИЕ!!!
Я создал интерактивный эскиз на CodePen, который визуализирует математику, которую я в настоящее время реализовал:
http://codepen.io/wagerfield/pen/ywqCp
Относительным кодом, на который следует сосредоточиться, является строка 318.
castingPoint.location
является экземпляром THREE.Vector3
и является недостающим фрагментом головоломки. Вы также должны заметить, что в левом нижнем углу эскиза есть 2 значения - они динамически обновляются, чтобы отображать точечный продукт между соответствующими векторами.
Я предполагаю, что для решения потребуется другая псевдоплоскость, которая выравнивается с направлением вершинной нормали И перпендикулярна плоскости света, но я мог ошибаться!