ДР/2024/Л5/hard (7т)
- Forums:
Считаме, че тази задача е трудна - try it on your own risk! Не поемаме отговорност в случай на изгубени много часове в коденето ѝ :)
Задачата е за всички студенти.
Целта на задачата е да се оптимизира алгоритъма за пресичане с булеви обекти, като се направи малко по-умно. В момента се търсят всички пресечни точки на лъча с геометриите, а това може да е излишно в много от случаите. Булевата функция може да се окаже удовлетворена още на първата или втората пресечна точка: например, ако имаме CsgDiff обект, при който лявата геометрия е доста по-голяма от дясната (да речем, една голяма сфера, върха на която е отрязан от куб: в болшинството случаи е достатъчно да проверим къде е първата пресечна точка с куба, и да видим, че лъча не пресича сферата въобще). По-точно, искаме да реализираме следния алгоритъм:
- Намираме дали сме вътре в геометриите - но ще ползваме друг метод, който не е базиран на пресичания;
- Намираме най-близките пресечни точки с всяка от двете геометрии;
- Подобно на стария алгоритъм, смятаме initial - дали сме вътре в CSG-то при ray.start;
- Взимаме по-близката от двете пресечни точки и проверяваме дали булевото условие е изпълнено при нея (като, подобно на стария алгоритъм, трябва да обърнем inside флага за съответната геометрия преди да направим проверката). Ако функцията връща стойност, различна от initial - край, намерили сме пресечна точка → изход;
- В противен случай, изхвърляме по-близката от двете пресечни точки, и, за нейната геометрия, намираме следващата пресечна точка чрез Geometry::intersect(), актуализираме оставащото разстояние до другата пресечна точка, и отиваме на стъпка 3;
- Ако в даден момент се окаже, че нямаме повече пресечни точки с никоя от геометриите, край - нямаме пресичане.
- Да се добави абстрактен метод isInside() на класа Geometry, и да се имплементира за Cube и Sphere (за Plane можете да сложите просто едно return false; тъй като не го ползваме);
- Да се слеят функционалностите на CsgOp::findAllIntersections и CsgOp::intersect; т.е. findAllIntersections не трябва да се вика въобще.
Правилните сметки при т.5 са критични - там е най-трудното в задачата (т.е. да осчетоводим правилно разстоянието, което трябва да се върне в крайното IntersectionInfo, включая всичките biasing стъпки).
Архитектурно, трябва да се направят следните промени:
Докато пишете вашата реализация, ползвайте tag homework5 без промени по setupScene() и се водете от времето за рендериране, което програмата ще ви изписва - то е ориентир как сте се справили с оптимизацията. Най-добре разкарайте анимацията (напр., вмъкнете едно "break" точно след displayVFB() извикването). При добро решение, би трябвало да можете да смъкнете времето с поне 3 пъти. Ако разкарате RoundedEdgesCube обекта от setupScene и оставите само простия CSG обект вляво (той е доста по-лек и при него оптимизацията не оказва чак такова влияние), с цел да си тествате разработката по-бързо, ускорението пак трябва да е осезаемо: поне 15-20%. Препоръчваме ви да оставите стария код наличен и с някакъв флаг да може да превключвате между двата. Не забравяйте да сверите картинката от стария метод с новия - не би трябвало да има никакви разлики!
Comments
По-сложен пример за тестване
Здравейте, тъй като доста от предадените решения се справят с основната постановка на сцената, но не се справят с малко по-сложен вариант, прилагам следните промени които може да добавите в setupScene() така че да тествате решенията си. Следния код трябва да се добави в края на функцията:
nodes.push_back(Node{ createRoundedEdgesCube(Vector(0, 10, -15), 20, 8), new Phong(Color(0.1, 0.4, 0.9), Color(1, 1, 1), 125.0f)});
nodes.push_back(Node{ createRoundedEdgesCube(Vector(0, 40, 100), 80, 10), new Phong(Color(0.4, 0.9, 0.1), Color(1, 1, 1), 125.0f)});
const Vector spCenter=Vector(50, 30, 15);
Geometry *reSphere=createRoundedEdgesCube(Vector(spCenter) - Vector(0, 0, 20), 40, 8);
Geometry* sphere=new Sphere(spCenter, 30);
nodes.push_back(Node{ new CSGDiff(sphere, reSphere), globeMat});
И реда който добавя сферата (ред 97-ми в main.cpp) трябва да се закоментира / изтрие. Съответно с тези промени трябва да получите нещо подобно при първия кадър. Като времето от ~26 секунди е при използването на бавния вариант.
Алтернативно за да се сдобиете с промените, може да приложите следния пач върху homework5 tag-a. Прилагането се извършва с:
git am 0001-Add-more-complex-examples-to-the-task.patch