Домашни - Лекция 7 / 2024

На тази страница са описани домашните работи към лекция №7. Има 3 леки задачи по 4 точки, от които можете да решите само една.

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

За база на вашия код ползвайте таг: homework7
Крайният срок за предаване на домашните е 17-ти Май (Петък), 0:59.


Група 0: Прозорец без сянка

Вече в лекция 6 обсъждахме сюрреалистичния ефект, който се получава като направим сфера с IOR = 1.01: тя изглежда като ефирен сапунен мехур, но пък хвърля тежка и черна сянка... за съжаление, дори и при по-често срещан IOR (наример 1.45, стъкло), но подходяща форма на обекта, хвърлящ сянката, се получават нереалистично наситени сенки. Често срещан пример - искаме да си направим прозорец.

Ще искаме да можем да си изрендим следната сцена:


Заменете setupScene() със следният код.

За да можем да поддържаме такива полупрозрачни обекти:

  1. добавете параметър shadowTransparency на Node. Той е float число от 0 (напълно непрозрачен обект, това е стойността по подразбиране) до 1 (напълно прозрачен).
  2. Модифицирайте visible(), така че да връща float число: произведението на shadowTransparency-тата на всички Node-ове по пътя между start и end). Ако няма нито един обект по пътя, резултатът, естествено, е 1.
  3. Резултатът от visible() ползвайте в Lambert::computeColor() за да връщате частични яркости от 0 до lightIntensity / distSqr.

Забележете, че двете сферички в примера са с различни shadowTransparency параметъра!


Група 1: По-красива текстурна интерполация

В commit 679845 съм добавили билинейна интерполация при извличане на цветовете от BitmapTexture::sample() метода. Заради нуждата от тясно съгласуване с размерите на текстурата, реалният код е в Bitmap::getFilteredPixel().

Разгледайте първо какво прави този метод.

След което си свалете файла minitex.bmp в data/ директорията на hexray проекта, и заменете използването на floor.bmp с minitex.bmp в setupScene().

Изрендената сцена ще ви илюстрира проблема на билинейната интерполация, когато се ползва за много голям zoom. Единичните ярки пиксели в текстурата се показват като странни четирилъчи звездички, и като цяло получените цветни петна (напр., вижте червената, зелената и синята точка долу вдясно) са със структура, която изглежда неестествено. Идеално бихме искали там да имаме кръгче или заоблено квадратче.

Един начин да постигнем по-приемливи резултати е да ползваме друг вид интерполация.

Линейната интерполация работи, в 1D, като интерполира между две стойности - A и B, и използва параметър p, който е реално число между 0 и 1 (ако p = 0, то ние сме "при А"; ако p = 1, тогава сме "при B"). За междинните стойности (0 < p < 1), ползваме (A * (1 - p) + B * p).

При билинейната интерполация имаме 4 пиксела (горен ляв, горен десен, долен ляв, долен десен) и две числа между 0 и 1 - p и q, съответно дробните стойности по х и по y. Изчисленият цвят е

<резултат> = <горен_ляв> * (1 - p) * (1 - q) + <горен_десен> * p * (1 - q) + <долен_ляв> * (1 - p) * q + <долен_десен> * p * q;

Тази схема, сама по себе си, не е лоша - проблемът е, че използваме p и q директно, без никакво заглаждане.

Помислете си какво ще се случи ако имате дълга редица от тъмни пиксели, и след което рязко започнат дълга редица ярки пиксели:

Сивата крива е резултатът от интерполацията. Тя е математически "вярна", но наличието на прекъсната първа производна в началото и края на прехода е нещо, което се забелязва от човешкото око в изображението и създава структура.

Вместо това, интерполацията може да е гладка, и да е с непрекъсната първа (поне) производна:

Накратко задачата се свежда до това да си направите функция f: [0, 1] → [0, 1], която да преобразува простата рампа горе до нещо по-гладко като това долу. После вместо p и q във формулата за билинейна интерполация горе, ползвайте f(p) и f(q). Каква точно формула ще използвате е по ваш избор и вкус. Ако се затруднявате с измислянето ѝ, попитайте за hint в Moodle.

Най-добре интерполиращата функция напишете в нов метод на Bitmap, например getSmoothFilteredPixel(), която да ползвате от BitmapTexture, за да може да сравнявате лесно резултатите преди/след подобрението ви.


Група 2: Render hardspots

  • В main.cpp, разкоментирайте ред 105 (добавянето на Reflection слой на floorShader);
  • Намалете MAX_RAY_DEPTH на 5
  • Изрендете с нормално. Ще забележите как рендерът се мота много в долната част на сферата, но не става ясно съвсем къде точно
  • Добавете един bool в началото на main.cpp, например SHOW_HARDSPOTS;
  • Ако SHOW_HARDSPOTS==true, използвайте много по-фин размер на bucket-ите - извикайте getBucketsList с по-малък параметър, вместо default-ния 64, примерно 8 или 12.
  • За всеки bucket, докато се ренди, засечете колко време му отнема, например ползвайте std::chrono::steady_clock. Сумирайте двете времена - Pass 1 и Pass 3
  • Минете отново по buckets списъка и оцветете частично пикселите на съответните buckets с цвят, отговарящ на релативното време за изрендване на бъкета. Тежките bucket-и оцветете в червено, най-леките в зелено, а помежду им в междинни цветове

Резултатът ще е нещо подобно.

Не се изисква изобщо да докарате точно същият резултат - оформете кода за оцветяването и градацията на цветовете по начин, който на вас ви се вижда смислен.


Подробности как да изготвите и изпратите решението си вижте в темата домашни с git.

Comments

Нумерология за групите

Прегледайте пак примера (отдолу на страничката за домaшно 4) за пресмятане на Група от Факултетен номер, конкретно в случая с букви. Като конкретно тези Факултетни номера са в следния вид:

#MI#######

Като конкретно символа след M e главно i, т.е. не е единица и не трябва да се ползва при пресмятане на групите за домашни. Тъй като ползваме (mod 3) за тази домашна, включването на това i, като 1-ца във Факултетния номер би сменило групата на тези Факултетни номера.
Все пак пример:
0MI8080808 → 8080808 (mod 3) ≡ 2 → Група 2

ПС: При модул от 4 или 5 няма значение дали се добавя символа като единица или не, съответно не е оказвало влияние на предишните домашни.