Я хотел бы «обойти» классический подход к объему света отложенного освещения.
Обычно, когда вы хотите воздействовать на пиксели в объеме точечного света, вы можете просто визуализировать сферическую сетку.
Я хотел бы попробовать другой способ сделать это, идея состоит в том, чтобы визуализировать куб, который охватывает сферу, куб «ограничивает» сферу, поэтому центр каждого лица является точкой сферы. Тогда вам нужно только знать с вашей точки зрения, какой фрагмент был бы частью круга (сферы на вашем экране), если бы вместо этого вы визуализировали сферу.
Таким образом, главная проблема состоит в том, чтобы знать, какой фрагмент должен быть отброшен.
Как я мог это сделать:
В шейдер фрагмента у меня есть мои координаты мира «камеры», мои координаты мира фрагмента, мой центр мира сферы и радиус моей сферы.
Таким образом, у меня есть прямая линия, вектор ориентации которой моделируется точками мира фрагмента камеры.
И я могу построить свое сферное уравнение.
Наконец я могу знать, пересекает ли линия сферу.
Это правильно сказать, что с моей точки зрения, если линия пересекает сферу, таким образом, этот фрагмент должен рассматриваться как выделенный фрагмент (фрагмент, который был бы визуализирован, если бы я визуализировал сферу)?
При этом проверка «длина (фрагмент — сфераЦентр) <=phereRadius «здесь на самом деле ничего не значит, потому что фрагмент не находится на сфере.
И что?
Стандартное решение для отложенного затенения для источников света — визуализация полноэкранного четырехугольника. Вместо этого цель рендеринга сферы состоит в том, чтобы не выполнять кучу расчетов для фрагментов, которые находятся за пределами действия источника света. Это означает, что центр этой сферы является источником света, а его радиус представляет собой максимальное расстояние, на которое источник оказывает влияние.
Таким образом, длина от фрагмента (то есть восстановленного из данных вашего g-буфера, а не фрагмента, созданного кубом) до центра сферы очень важна. Это длина между фрагментом и источник света. Если это больше, чем радиус сферы (AKA: максимальный радиус действия света), то вы можете отбросить фрагмент.
Или вы можете просто позволить своим расчетам ослабления света сделать ту же работу. В конце концов, чтобы огни не выглядели так, как будто они обрезаны, радиус сферы должен также использоваться с какой-либо формой ослабления света. То есть, когда фрагмент находится на этом расстоянии, ослабление света должно быть либо 0, либо иным образом пренебрежимо малым.
Таким образом … не имеет значения, визуализируете ли вы сферу, куб или полноэкранный квад. Вы можете либо отбросить фрагмент, либо позволить затуханию света выполнить свою работу.
Однако, если вы хотите сохранить производительность, отбросив фрагмент перед чтением любого из g-буферов, вы можете сделать это. Предполагая, что у вас есть доступ к пространству камеры в центре сферы / куба в FS:
Преобразуйте положение фрагмента куба в пространство камеры. Вы можете сделать это путем обратного преобразования gl_FragCoord
, но, вероятно, было бы быстрее просто передать положение камеры в фрагментный шейдер. Это не так, как ваш VS делает много работы или что-то еще.
Поскольку позиция камеры находится в пространстве камеры, она уже представляет направление от камеры к сцене. Так что теперь, используйте это направление для выполнения часть пересечения луча / сферы. А именно, вы останавливаетесь, как только вычисляете дискриминант (чтобы избежать дорогостоящего квадратного корня). Дискриминант это:
float A = dot(cam_position, cam_position);
float B = -2 * (dot(cam_position, cam_sphere_center);
float C = (dot(cam_sphere_center, cam_sphere_center)) - (radius * radius)
float Discriminant = (B * B) - 4 * A * C;
Если дискриминант отрицательный, отбросьте фрагмент. В противном случае, делайте ваши обычные вещи.
Других решений пока нет …