GLSL Light (затухание, цвет и интенсивность) формула

17

Я использую точечные источники света в своем двигателе Voxel, и я действительно изо всех сил пытаюсь получить хороший поток света, от 100% возле источника света до 0% в радиусе света.

У меня есть 5 аргументов для функции:

  1. Светлый цвет (Vec3)
  2. Интенсивность света (расстояние от света до расстояния, при котором спад составляет 100%)
  3. Расстояние от света до фрагмента
  4. Угол от фрагмента нормали к свету
  5. Положение света

Может кто-нибудь подтолкнуть меня в правильном направлении, чтобы создать функцию для расчета цвета фрагмента?

Изображение одного из моих экспериментов:

Voxel Engine Per-Fragment Lighting Test

Edit (текущий код запрошен Byte) Обратите внимание, что это всего лишь экспериментальный код с моей стороны. Я получил float att с сайта, и он работает, но далеко не идеально. :

void main()
{
// Light color
vec3 torchColor = vec3(1.0f, 1.0f, 1.0f);

float lightAdd = 0.0f;
for (int i=0; i<5; i++) {
    vec3 pos = lights[i];
    if (pos.x == 0.0f) continue;

    float dist = distance(vertex_pos, pos);
    if (dist < 9) {
        float att=1.0/(1.0+0.1*dist+0.01*dist*dist);
        vec3 surf2light = normalize(pos - vertex_pos);
        vec3 norm = normalize(normal);
        float dcont=max(0.0,dot(norm,surf2light));
        lightAdd += att*(dcont+0.4);
    }
}

vec3 textureColor = texture2D(texture, texture_coordinate).rgb;
vec3 torch_output = lightAdd * torchColor;

vec3 final_color = ((0.1+torch_output) * textureColor);

gl_FragColor = vec4(final_color, 1.0f); 
}
Basaa
источник
6
Вы все еще говорите такие вещи, как «изо всех сил, чтобы получить красивый , естественный свет » и «работает, но далеко не идеально ». Вы должны включить конкретный, точный язык. Мы не знаем, что для вас привлекательно, как выглядит естественный свет или что идеально.
MichaelHouse
2
Вы пытались удалить if (dist < 9)? В качестве альтернативы можно вычислить attс помощью функции , которая возвращает 1 , если расстояние равно 0 и 0 , если расстояние равно 9. Напримерmix(1.0, 0.0, dist / 9.0)
msell

Ответы:

39

Функция ослабления у вас есть,

att = 1.0 / (1.0 + 0.1*dist + 0.01*dist*dist)

довольно часто встречается в компьютерной графике - или, в более общем смысле, 1.0 / (1.0 + a*dist + b*dist*dist))для некоторых настраиваемых параметров aи b. Чтобы понять, как работает эта кривая, полезно поиграть с параметрами в интерактивном режиме . Эта кривая хороша тем, что приближается к физически правильному закону обратных квадратов на больших расстояниях, но на коротких расстояниях она не достигает бесконечности. На самом деле, a = 0это довольно хорошая модель сферической области освещения.

Однако одним из недостатков этого метода является то, что свет никогда не падает до нуля на любом конечном расстоянии. Для практических целей в CG в реальном времени нам обычно нужно отключать свет на конечном расстоянии, как вы делаете с if (dist < 9)предложением. Однако радиус 9 слишком мал - с вашими настройками в функции ослабления, свет не приближается к нулю, пока dist не станет около 100.

Вы можете рассчитать радиус света по bпараметру в функции ослабления (поскольку квадратичный член доминирует на больших расстояниях). Допустим, вы хотите отключить свет, когда ослабление достигает некоторого значения minLight, например 0,01. Затем установите

radius = sqrt(1.0 / (b * minLight))

Это дает радиус 100 для b = 0.01и minLight = 0.01. Кроме того, вы можете установить радиус и рассчитать, bчтобы соответствовать:

b = 1.0 / (radius*radius * minLight)

Для radius = 9и minLight = 0.01, что дает b = 1.23. Вы можете настроить его в любом случае, но главное, чтобы радиус и функция затухания совпадали, чтобы вы не отключали свет, пока функция затухания не станет очень низкой, и вы не увидите острого края.


Все вышесказанное, есть альтернативные функции ослабления, которые вы можете использовать. Еще один довольно распространенный:

att = clamp(1.0 - dist/radius, 0.0, 1.0); att *= att

или немного любитель:

att = clamp(1.0 - dist*dist/(radius*radius), 0.0, 1.0); att *= att

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

Натан Рид
источник
Большой! Хотя, я бы использовал maxболее clampтолько из соображений производительности.
Майк Вейр
4
@MikeWeir На самом деле привязка к [0, 1] бесплатна на многих графических процессорах. Это настолько распространенная операция, что они используют ее как модификатор команд.
Натан Рид