ДР/2013/Л5/medium (5т)

Вашата група = вашият факултетен номер MOD 3


Група 0:

Реализирайте шейдъра Oren-Nayar. Моделът има един параметър, sigma, който определя грапавината на обекта и варира от 0 до 1 (при 0 е идентичен с Lambert шейдъра). Обяснение на означенията в статията в Wiki:

  • Vi - e лъча от пресечната точка към лампата;
  • Vr - e лъча от пресечната точка към камерата;
  • Li - е яркостта и цвета на светлината, идващи в пресечната точка (и е както при Ламберт: lightColor * lightPower / distance²);
  • Lr - това е резултатът от шейдъра;
  • ρ/π - това са albedo и BRDF normalization - игнорирайте ги във вашата имплементация - приемете, че този член е 1;
  • θi - ъгъл между нормалата и Vi;
  • θr - ъгъл между нормалата и Vr;
  • ɸi и ɸr - азимутални ъгли на, респективно, Vi и Vr в равнината на повърхността на обекта. Представете си, че повърхнината на обекта е плоска (и, естествено, е перпендикулярна на нормалата). Проектирате векторите Vi и Vr в тази равнина - ще се получат два двумерни вектора, лежащи в нея. Търсеното cos(ɸi - ɸr) е всъщност косинуса от ъгъла между тези два двумерни вектора (като, когато този ъгъл е над 90° - цялата част от формулата с множителя B става 0).

С формулата от Wikipedia се смята lightContrib. T.e. шейдърът ви ще се държи идентично като при Lambert, но вместо входящата светлина да умножавате по dot(lightDir, N), ще я умножавате по формулата в статията.

Ако ползвате следната сцена би трябвало да получите картинка като тази. Всички топчета са с цвят (0.5, 0.5, 0.5). Предните две са, респективно, с Lambert и Phong, а задните 5 са с Oren-Nayar и параметри sigma = 0.0, 0.2, 0.4, 0.6 и 0.8.


Група 1:

В лекция 5, слайдове от 47 до 53, има описание на това що е то Model transform. След като го прочетете и осмислите, нека го реализираме!

Ще ни трябва един клас Transform, който съдържа една матрица 3x3 (в която ще пазим ротации и скалирания), и един вектор offset, в който ще имаме транслация.

Класът ще има следните методи:

  • reset - ресетира трансформацията до идентитет (единична матрица, offset = (0, 0, 0));
  • scale(x, y, z) - скалира матрицата по направления X, Y и Z;
  • rotate(yaw, pitch, roll) - ротира матрицата спрямо yaw, pitch и roll ъглите (подадените числа са в градуси). Т.е. завъртане около оста Z с roll градуса, около X с pitch градуса и около Y с yaw градуса;
  • translate(vec) - транслация с вектора vec;
  • point(p) - трансформира точката p (скалиране, ротация и транслация в този ред);
  • undoPoint(p) - обратното на point() (обратна транслация, обратна ротация и обратно скалиране в този ред);
  • direction(dir) - трансформира посоката dir (и point() и direction() приемат параметър Vector, но разликата е в действието - direction не включва транслацията, т.е. това трансформира посока на лъч например). Т.е. на входната посока трябва да ѝ се приложат скалиране и ротация, в този ред.;
  • undoDirection(dir) - обратното на direction() (обратна ротация и обратно скалиране, в този ред);

Добавете трансформацията като член на Node и добавете intersect() който трасира лъча с геометрията, като ще си представим, че сме подложили геометрията на трансформацията.
Node::intersect() приема и връща същите параметри като Geometry::intersect(). Входният лъч се подлага на обратната трансформация, резултатния лъч се пресича с геометрията,
и ако има пресичане, то IntersectionData се подлага на правата трансформация, преди да се върне.
Предвид интерфейса на Transform, подходящо ще е в него да пазите две матрици (права и обратна), както и един вектор offset. Естествено, матриците ще трябва да държите винаги в синхрон.

Заменете в raytrace() и testVisibility() - да се ползват Node::intersect() вместо Geometry::intersect() функциите.
Аранжирайте сцена с instancing.

Правилно решение на така поставената задача ще ви даде 5 точки. Допускат се две точки бонус, ако се справите със следния проблем: ако трансформацията съдържа скалиране,
то подаваното data.dist на Geometry::intersect няма да бъде вярно (т.е. числото там ще е адекватно в световната метрика, но няма да е същото в каноничното пространство). Ако измислите как да се справите с този проблем, така че да няма дефекти при ренденето на скалирани геометрии, ще получите още 2 точки.


Група 2:

Да се добави възможност камерата да се позиционира чрез "lookAt" система.

Т.е. да се напише метод setPosition(), приемащ три параметъра:

- pos - позиция на камерата;
- lookAt - това е точка от сцената, която е "целта", към която гледа камерата. Т.е., лъча, изстрелян през средата на кадъра, трябва да отива в посока на точката lookAt;
- upDir - вектор, задаващ ориентацията "нагоре". Влияе, например, на roll ъгъла - досега в нашите сцени upDir беше винаги (0, 1, 0), но ако го зададем (0, -1, 0), би следвало кадъра да се обърне с главата надолу.

Методът трябва да зададе стойности Camera::pos, както и на yaw, pitch и roll ъглите (може да приемете, че методът ще бъде извикан преди Camera::beginRender()).

За да тествате реализацията си, можете да пробвате да задавате за стойности на lookAt центровете на обектите в сцената - би следвало камерата да се обръща фронтално към тях.

Реализацията ви трябва да работи коректно и когато имаме gimbal lock - т.е., ако човек зададе на камерата да гледа право към пода, upDir трябва да работи, както би очаквал човек - промяната на upDir да оказва влияние на "завъртането на пода".

Comments

Група 1

За функциите point(p), undoPoint(p), direction(dir), undoDirection(dir) прилагаме скалирането и ротациите в даден ред, но никъде не съхраняваме отделните ротации и скалирането. Условието коректно ли е?

Тъй като ротациите стават околко центъра на координатната система, когато едно тяло бъде завъртяно то се отмества. Това означава ли, че фигурите трябва да са в (0, 0, 0) и да се преместват само и единствено чрез offset вектора, т.е. да премахнем предишния начин на отместване, в който всяка геометрия има вектор за център (почти всяка)?

Скалирането също става спрямо центъра на координанатната система.

Точно така

Окей е ротациите и скалирането да ползват една матрица. Целта на условието "в този ред" е, защото този ред дава смислени резултати. Т.е., можеш да очакваш, че когато потребителят вика методите на Transform (от initializeScene() примерно), първо ще се викне scale() и после rotate().

Относно ротациите - да, точно така. Ще смятаме, че вече всички геометрии няма да им се ползва center/pos вектора, а ще се създават в (0, 0, 0) и ще се транслират посредством трансформацията си.

Група 1

https://lh6.googleusercontent.com/-PPj7kxfKb2A/UoaG4IRXBMI/AAAAAAAAADE/X...

Модфицирах createNode да връща адреса на Node-a, който създава.

Този проблем се появява при скалиране. Не ми се струва логично да е заради това, че не променям data.dist в каноничното пространство.

Друг проблем

Не, друг проблем е - виж тук.

scale()

Нормално ли е след като ми скалира обекта да го мести..
смисъл колкото е по скалиран толко - повече го отмества по X,Y,Z в зависимост по коя компонента съм го скалирал..

void Transform::scale(double x,double y, double z)
{
if(x==0)x=1;if(y==0)y=1;if(z==0)z=1;
T.m[0][0] *= x;
T.m[1][1] *= y;
T.m[2][2] *= z;
T_inv = inverseMatrix(T);
}

също така след като го ротирам също ми го отмества ползвам готовите ротейт матрици и ги умножавам по моята Т , създавам си обектите в (0,0,0) и после ги translate-вам до там където искам да са.. (това работи - учудващо :D ) идеи ?

скалиране

Разбира се.
Операцията "скалиране", която прилагаш, всъщност е невярна. Виж този пример - правилното скалиране (във втория ред) променя не само елементите по главния диагонал.