Використання двох термінів Френеля є правильним у тому сенсі, що будь-який заданий дифузний шлях пройде через поверхню двічі. Якщо ви вирішуєте дифузію, відстежуючи шлях через середовище, поки він знову не відскакує, тоді ви отримаєте два (або більше) термінів Френеля для цього шляху під час взаємодії з поверхнею.
Однак це не те, що ви робите з дифузним BRDF. Дифузне BRDF призначене для відображення середнього значення всіх можливих шляхів дифузії. У випадку Ламбертіана середнє моделюється як рівномірне відображення і єдине значення альбедо, що вимірює внутрішні втрати енергії під час дифузії, але можливі більш складні моделі. Принципово важливо: дифузне BRDF вже буде включати сукупний ефект деяких шляхів, що відображаються назад у середовищі, щоб розповсюджуватись далі, а деякі пропускати негайно. вже "запікається" в BRDF¹, і вам не потрібно повторювати його.1 - Fo u t
Що не включає термін Ламбертіана - це частина енергії, яка втрачається відбиттям, перш ніж світло потрапляє в середовище дифузії. Це залежить від зору, але залежить від точної глянсової часточки над ним. Немає втрат енергії на (неметалічному) поверхневому інтерфейсі, тому все, що не відображено, буде переломлено, тобто те, що ви насправді хочете, це інтегрувати загальну втрату енергії на поверхні за всіма вихідними напрямками, тобто .1 - ∫glossy_bsdf ( в , з )d вийти
Можливо попередньо обчислити наближення до цього інтегралу для конкретних BRDF. Кінцевий результат, як правило, залежатиме від напрямку подання, шорсткості матеріалу та IOR принаймні. В якості першого наближення можна припустити, що глянсова доля - це ідеально дзеркальний відбивач. Це дає вагу глянсового , це саме те, що ви вперше запропонували.1 - ∫глянцевийd out =1- Fя н
Додатково зауважте, що ламбертіанський BRDF - альбедо, поділений на і що косинусовий термін є мірою того, наскільки ослаблене надходить світло на поверхню; це стосується як глянцевого, так і дифузного відбиття.π
Отже, приблизно:
// Assuming for example:
// diffuse = albedo / PI;
// specular = my_favorite_glossy_brdf(in_dir, out_dir, roughness);
// fresnel = f0 + (1.0 - f0) * pow(1.0 - dot(E, H), 5.0);
// total_surface_reflection = fresnel
color = lightIntensity * dot(L, N) * Lerp(diffuse, specular, total_surface_reflection);
Ж