ДР/2011/Л12/6: Glossy BRDF

Glossy reflection BRDF

Добавете поддръжка на glossiness < 1 към eval()/spawnRay() методите на Reflection. За дефиниция на BRDF-а ще ползваме примера, даден в слайд 37 от лекция 11:

BRDF_Glossy(x, ω, ω') := max(0, cos(∠(reflect(ω), ω')))n * S(n)

Параметърът n (експонента), по подобие на Phong, задава разпръскването на грапавото отражение - по-висок експонент ще намали разпръскването. Множителят S(n) нормира сумарната мощност на отражението, така че интегралът от BRDF-а да е 1. Според WolframAlpha, интегралът от ненормираната функция е 2π/(n+1), така че нормиращият фактор е S(n) = (n+1)/2π.

За връзка между n и glossiness ползвайте n = 1 / (1 - glossiness) (glossiness = 1 си го разглеждайте като отделен случай - да се държи, както е сега).

В eval(): намерете отражението на w_in спрямо x.norm, измерете косинуса от ъгъла между това отражение и w_out, и ако е положителен, вдигнете го на n-та степен, и умножете по S(n) (n и S(n) дръжте преизчислени; например, сметнете ги във fillProperties).

В spawnRay(): копирайте кода от glossiness < 1 случая на Reflection::shade(). Вместо да генерираме много лъчи, ще генерираме един-единствен, по досегашната формула. Сметнете brdf-то по същия начин, както и в eval(), а за pdf трябва да зададете една конкретна вероятност, чието смятане е малко по-сложно (изисква анализ какво става със всички множители, при граничен преход на glossiness клонящо към 1). Т.е., ако ви е интересно, изследвайте, ако не - просто задайте за pdf = 1 / (4 * scaling).

Внимавайте за: да не забравите да отчетете ролята на lightMultiplier; и да проверявате, дали генерираният "грапаво-отразен" лъч не задълбава под повърхността (там постъпвайте както правехме в Refraction BRDF, при пълно вътрешно отражение).

Примери (@ 256 pathsPerPixel): smallpt_glossiness_0.7, smallpt_glossiness_0.95.jpg.