Домашни - Лекция 7 / 2024
- Forums:
На тази страница са описани домашните работи към лекция №7. Има 3 леки задачи по 4 точки, от които можете да решите само една.
Вашата група = вашият факултетен номер MOD 3
За база на вашия код ползвайте таг: homework7
Крайният срок за предаване на домашните е 17-ти Май (Петък), 0:59.
Група 0: Прозорец без сянка
Вече в лекция 6 обсъждахме сюрреалистичния ефект, който се получава като направим сфера с IOR = 1.01: тя изглежда като ефирен сапунен мехур, но пък хвърля тежка и черна сянка... за съжаление, дори и при по-често срещан IOR (наример 1.45, стъкло), но подходяща форма на обекта, хвърлящ сянката, се получават нереалистично наситени сенки. Често срещан пример - искаме да си направим прозорец.
Ще искаме да можем да си изрендим следната сцена:
Заменете setupScene() със следният код.
За да можем да поддържаме такива полупрозрачни обекти:
- добавете параметър shadowTransparency на Node. Той е float число от 0 (напълно непрозрачен обект, това е стойността по подразбиране) до 1 (напълно прозрачен).
- Модифицирайте visible(), така че да връща float число: произведението на shadowTransparency-тата на всички Node-ове по пътя между start и end). Ако няма нито един обект по пътя, резултатът, естествено, е 1.
- Резултатът от 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 няма значение дали се добавя символа като единица или не, съответно не е оказвало влияние на предишните домашни.