GLSL Формула світла (ослаблення, кольору та інтенсивності)


17

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

У мене є 5 аргументів для функції:

  1. Світлий колір (Vec3)
  2. Інтенсивність світла (відстань від світла до відстані, де випадання становить 100%)
  3. Відстань від світла до фрагмента
  4. Кут від фрагмента нормальний до світла
  5. Положення світла

Чи може хто-небудь підштовхнути мене в правильному напрямку, щоб створити функцію для обчислення кольору фрагмента?

Зображення одного з моїх експериментів:

Тест освітлення на фрагменти двигуна Voxel

Редагувати (поточний код запитує Байт) Зауважте, що це лише якийсь код експерименту з моєї сторони. Я отримав 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); 
}

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] фактично безкоштовне на багатьох графічних процесорах. Це настільки поширена операція, що вони мають її як модифікатор інструкцій.
Натан Рід
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.