ДР/2015/12/2

Layered BRDF

Реализирайте BRDF, отговарящ на досегашния слоест шейдър. Моделирайте шейдъра чрез Монте-Карло семплиране - процедурата eval() трябва да избере само един, случаен слой, от всички, и да викне неговия eval() метод. Аналогично за spawnRay(). Самото избиране на слоевете направете с importance sampling. Приемете, че прозрачностите на слоевете няма да са цветни, а само тонове на сивото. Като пример:

най-долен слой: плътност 1.0 (100%)
среден слой: плътност 0.3
най-горен слой: плътност 0.1

Тук трябва да организирате случаен процес, който:
- в 10% от случаите избира най-горния слой и ползва неговите eval()/spawnRay();
- в 30% от останалите 90% (тоест, 27%) избира средния слой;
- в останалите случаи избира най-долния слой.

За да тествате реализацията си, в smallpt.qdmg заменете шейдъра на glassSphere: от "refr" на "glass". Резултатът ще е нещо подобно (при numPaths = 256).

Comments

importance sampling

Как по-точно трябва да използваме importance sampling? Каква трябва да ни е функцията f(x), която използваме в сумата - номера на слоя не звучи логично, защото ще влияе на крайния резултат, а може да променяме реда както си искаме, а ако f(x) връща 1 винаги, то сякаш се обезмислят вероятностите и за други варианти не се сещам... И също защо eval трябва да ми връща резултат от произволен слой, при положение че лъчът out се е генерирал от точно един определен слой?

Пояснение

Значи - трябва да реализирате Layered::eval() и Layered::spawnRay поотделно, макар и кодът в двете ще е много подобен. Давам пример за eval. В него, функцията f(x) е eval()-а на някой от слоевете. Иначе текста за "eval връща произволен слой" е в смисъл че, за разлика от shade(), където се оценяваха shade()-овете от всички слоеве и се сумираха, тук трябва да оценим само един eval(), от всичките. Кой точно ще изберем за конкретния лъч - се избира чрез описания в условието случаен процес.

f(x)

Под f(x) имах предвид функцията от importance sampling за генериране на индекса на слоя, който да вземем. Нали формулата беше, ако x е произволно число, сума(по брой семпли) от f(x)/r(x) и довършваме като разделим тази сума на броят семпли. Имам идеята, че importance sampling трябва върне число и най-близкото до него ми определя самият слой, но самото f(x) ми е трудно да определя какво трябва да връща... Иначе всичко останало си дойде на мястото.

няма сумиране

Вътре в Layered::eval() нямаш сумиране; сумирането се извършва отвън - в renderSample, а всичко, което pathtrace прави, е да съставя x и f(x) - където x е един абстрактен многомерен вектор, съставен от всички случайни избори, изникнали при строежа на пътя (как да бъде избран първоначалният лъч от камерата; как да се отрази от първия Lambert; как да семплира лампата; кой слой от Layered да избере и т.н. и т.н.). Т.е. x в случая е абстрактна променлива от тип път, а f(x) е оценката на този път (цвят), т.е. това, което връща pathtrace.

А иначе генерирането на индекса на слоя, който трябва да се вземе от Layered не е такава директна функция. При всички случаи ще трябва, пряко или косвено, да сметнеш вероятностите, лъча да бъде отразен от всеки от дадените слоеве. Нека тези вероятности означим p1, p2, ..., pN. Очакваме те да се сумират до 1.
След което, подход да си избереш слой без importance sampling би бил - избираш си случаен слой, равномерно (i = rnd.randint(1, N)) и оценяваш този слой, умножавайки по вероятността му (понеже това е приносът му към слоестия шейдър) и делиш на вероятността да си избрал точно този слой, 1/n, (return layeri->eval() * pi / (1.0/n)).
С importance sampling трябва да избираш числото i с неравноделна вероятност. Как може да направиш това?
Теглиш си едно случайно double число, α, между 0 и 1. Ако 0 ≤ α < p1, то избираш слой 1. Ако p1 ≤ α < p1 + p2, избираш слой 2 и така нататък - интервалът 0..1 разделяш на области, с големина пропорционална на вероятностите p и гледаш в коя област се е паднало случайното число. Да речем си изтеглил слой i. Тук трябва да върнеш layeri->eval() * pi / pi, т.е. тук pi се съкращават (първото pi е от приноса на този слой; второто е от вероятността този слой да се падне).