Я использую точечные источники света в своем двигателе Voxel, и я действительно изо всех сил пытаюсь получить хороший поток света, от 100% возле источника света до 0% в радиусе света.
У меня есть 5 аргументов для функции:
- Светлый цвет (Vec3)
- Интенсивность света (расстояние от света до расстояния, при котором спад составляет 100%)
- Расстояние от света до фрагмента
- Угол от фрагмента нормали к свету
- Положение света
Может кто-нибудь подтолкнуть меня в правильном направлении, чтобы создать функцию для расчета цвета фрагмента?
Изображение одного из моих экспериментов:
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);
}
if (dist < 9)
? В качестве альтернативы можно вычислитьatt
с помощью функции , которая возвращает 1 , если расстояние равно 0 и 0 , если расстояние равно 9. Напримерmix(1.0, 0.0, dist / 9.0)
Ответы:
Функция ослабления у вас есть,
довольно часто встречается в компьютерной графике - или, в более общем смысле,
1.0 / (1.0 + a*dist + b*dist*dist))
для некоторых настраиваемых параметровa
иb
. Чтобы понять, как работает эта кривая, полезно поиграть с параметрами в интерактивном режиме . Эта кривая хороша тем, что приближается к физически правильному закону обратных квадратов на больших расстояниях, но на коротких расстояниях она не достигает бесконечности. На самом деле,a = 0
это довольно хорошая модель сферической области освещения.Однако одним из недостатков этого метода является то, что свет никогда не падает до нуля на любом конечном расстоянии. Для практических целей в CG в реальном времени нам обычно нужно отключать свет на конечном расстоянии, как вы делаете с
if (dist < 9)
предложением. Однако радиус 9 слишком мал - с вашими настройками в функции ослабления, свет не приближается к нулю, пока dist не станет около 100.Вы можете рассчитать радиус света по
b
параметру в функции ослабления (поскольку квадратичный член доминирует на больших расстояниях). Допустим, вы хотите отключить свет, когда ослабление достигает некоторого значенияminLight
, например 0,01. Затем установитеЭто дает радиус 100 для
b = 0.01
иminLight = 0.01
. Кроме того, вы можете установить радиус и рассчитать,b
чтобы соответствовать:Для
radius = 9
иminLight = 0.01
, что даетb = 1.23
. Вы можете настроить его в любом случае, но главное, чтобы радиус и функция затухания совпадали, чтобы вы не отключали свет, пока функция затухания не станет очень низкой, и вы не увидите острого края.Все вышесказанное, есть альтернативные функции ослабления, которые вы можете использовать. Еще один довольно распространенный:
или немного любитель:
Поиграйте с параметрами для них. Эти кривые имеют преимущество, заключающееся в том, что они точно идут к нулю при заданном радиусе, и в то же время выглядят как закон естественных обратных квадратов.
источник
max
болееclamp
только из соображений производительности.