Wykład rozpoczyna się o 15:30 a ćwiczenia o 17:10 w poniedziałki, sala G-1-03. Zapraszam również na konsultacje (pokój C-2-29 lub online, terminy w USOSwebie).
Na ćwiczeniach można mieć trzy nieusprawiedliwione nieobecności bez ponoszenia konsekwencji. Przy większej ich liczbie proszę się spodziewać dodatkowych projektów, przepytywania sprawdzającego znajomość zagadnień poruszanych na opuszczonych zajęciach, itp. rzeczy.
W razie nieobecności proszę sprawdzić na tej stronie, co Państwa ominęło i nadrobić braki. Podobnie jeśli nie zdążycie zrobić w trakcie zajęć wszystkich zadań — stają się one wtedy automatycznie zadaniami domowymi. Możecie nad nimi pracować zdalnie po zalogowaniu się do linii komend na serwerze spk-ssh.if.uj.edu.pl, albo na domowym komputerze po zainstalowaniu na nim potrzebnego oprogramowania.
Oceny z ćwiczeń wystawiane są na podstawie:
Przykładowe projekty 2D, od banalnego (dla tych, którym wystarczy dst) do bardziej skomplikowanych:
Program generujący opatrzone legendą wykresy kołowe albo słupkowe na podstawie danych wczytywanych z plików TSV.
Zliczanie nie nachodzących na siebie przedmiotów (jasne przedmioty na ciemnym tle, lub ciemne na jasnym).
Prostowanie i przycinanie zdjęć kartek A4.
Wtyczka do GIMP-a używająca GEGL w trybie wielowątkowym.
Projekt 3D powinien bazować na bibliotece OSG. Musi zawierać dwie rzeczy, modyfikowanie stanu sceny (skokowe lub w postaci płynnej animacji) oraz reagowanie na akcje użytkownika (klawiatura i / lub myszka). Przykładowe tematy:
Interaktywna plansza do jakiejś gry (szachy, warcaby, itp.). Modele pionków i figur mogą być ściągnięte z Internetu. Gracz klika myszką najpierw w piona, potem w docelowe pole; aplikacja wyświetla animację przesunięcia, następnie odwraca planszę o 180° aby ruch mógł wykonać drugi gracz.
Strzelanie z armaty do celów rozstawionych na łące. Wystrzelona kula powinna lecieć po krzywej balistycznej.
Gra w znajdowanie wyjścia z labiryntu. Tu konieczne będzie przesuwanie kamery, tak aby przez cały czas wyświetlał się widok z oczu postaci gracza. Wystarczy, jeśli w labiryncie będą tylko ściany, bez żadnych potworów. Zmiany tekstur i inne rzeczy przerywające monotonię mile widziane.
Wyścig Formuły 1, kamera powinna podążać nieco z tyłu za bolidem gracza. Wykrywanie kolizji z samochodami rywali i bandami bocznymi. Proszę nie skupiać się niepotrzebnie na jakości grafiki i estetyce — nie o to chodzi w tych projektach zaliczeniowych.
Aby zaliczyć przedmiot trzeba zaliczyć ćwiczenia i zdać egzamin ustny. Wpisywana do indeksu ocena z egzaminu może być co najwyżej o jeden stopień wyższa od oceny z ćwiczeń (a więc osoba, która zaliczy ćwiczenia na +dst nie ma szans na bdb jako ocenę końcową).
Egzamin zaplanowany jest na poniedziałek 2 lutego 2026, sala G-1-03. Egzaminuję po dwie osoby na raz. Proszę samodzielnie wpisać się na listę (Galla Anonima oczywiście można z niej usunąć).
James D. Foley, Wprowadzenie do grafiki komputerowej, WNT 1995 (jest w naszej czytelni).
Część materiału (np. opis systemów SRGP i SPHIGS) się zdezaktualizowała, ale książkę warto przeczytać z uwagi na rozdziały omawiające macierzową reprezentację przekształceń geometrycznych i rzutowań, modele koloru, czy też algorytmy oświetlenia.
Ryszard Tadeusiewicz, Przemysław Korohoda, Komputerowa analiza i przetwarzanie obrazów, Wydawnictwo FPT 1997 (dostępna online).
Proszę przestudiować rozdziały 3 i 5, opisane w nich metody przetwarzania obrazów rastrowych wykorzystywane są na naszych zajęciach. Pozostałe rozdziały można przejrzeć bardziej pobieżnie. Zdezaktualizowane informacje o parametrach kamer i specjalizowanych układów scalonych proszę pominąć.
Dokumentacja biblioteki OpenCV (dostępna online). Główna witryna jest pod adresem opencv.org.
Najlepiej zacząć od modułu „OpenCV Tutorials”, a dokładnie od jego podrozdziałów „The Core Functionality (core module)” i „Image Processing (imgproc module)”.
Antonio Torralba, materiały do kursu „Advances in Computer Vision” (dostępne online).
Do ewentualnego szybkiego przejrzenia jako ponadprogramowa ciekawostka. Pokazują że matematyczne podejście do przetwarzania obrazów rastrowych, o którym mówiliśmy na zajęciach, jest podstawą algorytmów widzenia komputerowego.
Dokumentacja bibliotek GD oraz Cairo.
Cairo wykorzystuje postscriptowy model tworzenia grafiki, jeśli ktoś go nie pamięta to trzeba go sobie odświeżyć.
PostScript Language Reference, Third Edition (dostępne online) oraz PDF Reference, Second Edition, version 1.3 (dostępne online).
Dla osób chcących sobie przypomnieć wektorowy model grafiki używany w tych językach opisu strony.
Rui Wang, Xuelei Qian, OpenSceneGraph 3.0 Beginner’s Guide, Packt Publishing 2010 (dostępna w czytelni).
Podstawowy podręcznik do nauki korzystania z biblioteki OSG. Rozdział 2 i odwołania do CMake w pozostałych rozdziałach proszę zignorować, bo OSG jest już zainstalowany w naszej pracowni (jest częścią Ubuntu). Rozdziały 4-5 zawierają kluczowe informacje o tworzeniu i zarządzaniu grafem sceny, należy je dokładnie przestudiować.
Rui Wang, Xuelei Qian, OpenSceneGraph 3 Cookbook, Packt Publishing 2012 (dostępna w czytelni).
Kontynuacja poprzedniej książki. Zawiera kilkadziesiąt recept pokazujących jak rozwiązać konkretne problemy, od „oblicz współrzędne prostopadłościanu ograniczającego dany zbiór obiektów”, przez rzeczy dotyczące siatek, kamer i animacji, do optymalizacji scen z setkami tysięcy obiektów.
Rafał Stęgierski, Programowanie OpenGL, UMCS 2011 (dawniej była dostępna online).
Praktyczne wprowadzenie do OpenGL 1.x, nie omawia wersji 2.0 i nowszych. Dla chcących sobie przypomnieć jak działały klasyczne akceleratory grafiki 3D, jeszcze nie obsługujące programów cieniująch (tzw. shaderów).
Sumanta Guha, Computer Graphics Through OpenGL: From Theory to Experiments, 2nd Edition, CRC Press 2015 (dostępna w czytelni).
Podręcznik kładący silny nacisk na matematyczne podstawy grafiki 3D. Do opisu każdej z funkcji kart OpenGL dołączone są obszerne teoretyczne wyjaśnienia oraz przykładowe programiki i eksperymenty do samodzielnego wykonania. Dwa ostatnie rozdziały poświęcone są programowalnemu potokowi renderowania, takiemu jaki definiuje specyfikacja OpenGL 4.3.
OpenGL Wiki (dostępne online).
Dobre źródło informacji o współczesnym OpenGL.
Po zalogowaniu się w pracowni do Linuksa można je znaleźć w katalogu /home/palacz/ZGK/. W miarę postępu zajęć będę tam uaktualniał slajdy z wykładu, dodawał przykładowe programy, pliki danych, itp.
Materiały są również widoczne po zalogowaniu się na wydziałowy serwer zdalnego dostępu, czyli spk-ssh.if.uj.edu.pl.
Przypomnienie podstawowych informacji o fizjologii wzroku i rastrowych formatach grafiki 2D. Rasteryzacja figur geometrycznych, biblioteka GD jako przykład prostego narzędzia służącego do tworzenia obrazów rastrowych, zarządzanie pamięcią w takich bibliotekach (ppm*.c).
Jeśli ktoś z Państwa nie ma aktywnego konta linuksowego, musi je sobie odnowić u pana Damiana Lisa. A na dzisiejszych zajęciach może pracować pod Windows i zrealizować tyle z poniższych punktów, ile się da.
Przeanalizuj i uruchom gd01.c oraz gd02.c. Spróbuj narysować kilka dodatkowych kresek.
Znajdź i przejrzyj dokumentację biblioteki GD. Jakie są jej możliwości? Czy potrafi rysować krzywe Béziera? A elipsy? Czy można zmienić grubość kreski? Czy rysowane przez GD figury zawsze są w jednolitym kolorze, czy też daje się np. narysować odcinek, który na jednym końcu jest czerwony, na drugim pomarańczowy, a w środku płynnie przechodzi od jednej barwy do drugiej?
Samodzielnie uważnie przejrzyj ppm01.c … ppm03.c. Upewnij się, że rozumiesz sposób, w jaki przydzielana i zorganizowana jest pamięć. Ta wiedza przyda się za kilka tygodni, gdy będziemy omawiać bibliotekę OpenCV.
Zmodyfikuj procedurę uj_image_fill_rectangle tak, aby
dla argumentów spoza dopuszczalnego zakresu rysowała tylko ten fragment
prostokąta, który mieści się w ramach współrzędnych rastra. Innymi słowy,
zaimplementuj w tej procedurze przycinanie rysowanego prymitywu. Starannie
rozważ wszystkie możliwe przypadki nieprawidłowych argumentów.
Dla zainteresowanych: zaimplementuj procedurę
uj_image_draw_line w oparciu o któryś z omawianych algorytmów
rasteryzacji odcinków. Zastanów się nad tym, jak w efektywny sposób przycinać
odcinek do rozmiarów rastra.
Wykład: przypomnienie podstawowych informacji o językach PostScript, PDF i formacie SVG, oraz o używanym w nich modelu tworzenia grafiki wektorowej. Zapoznanie się z podstawami biblioteki Cairo.
Ćwiczenia:
Przeanalizuj przykłady od cairo01.c do cairo04.py.
Spróbuj ręcznie skompilować cairo02.c. Użyj polecenia pkg-config --cflags --libs cairo aby się dowiedzieć jakie przełączniki trzeba podać kompilatorowi.
Przeanalizuj Makefile i zobacz w jaki sposób GNU make pozwala w swoich receptach odwoływać się do wyników zwracanych przez pkg-config.
Uruchom cairo04.py (albo pisząc ./cairo04.py, albo python3 cairo04.py). Sprawdź czy wygenerowane obrazki są takie same jak te z cairo02.c (powinny być).
Zapoznaj się ogólnie z API
biblioteki Cairo. Nieco uważniej przejrzyj sekcje poświęcone transformacjom oraz pomocniczemu typowi cairo_matrix_t.
Albo w C, albo w Pythonie napisz i przetestuj procedurę rysującą dwie-trzy
proste figury. Jako argument procedury powinien być przekazywany kontekst
graficzny, czyli wskaźnik typu cairo_t * bądź odpowiadający mu
pythonowy obiekt.
Zastąp pojedyncze wywołanie tej procedury czterema wywołaniami, przeplatając je modyfikacjami macierzy transformacji układu współrzędnych użytkownika tak, aby każde wywołanie rysowało figury w innym miejscu. Spróbuj tak dobrać transformacje, aby zamiast oryginalnych figur otrzymać cztery pomniejszone o 50% kopie ułożone w prostokąt 2 na 2.
Sprawdź jak wygląda fraktal znany jako trójkąt Sierpińskiego. Gdy się
chwilę zastanowić, widać że algorytm jego rysowania można wyrazić używając
rekursji (w teorii: nieskończonej, w praktyce: do poziomu dobranego tak, aby
rysunek miał zadowalającą dokładność). Zaimplementuj ten algorytm jako funkcję
języka C void sierpinski(cairo_t * cr, int level) bądź jej
pythonowy odpowiednik. Dla level równego zero procedura ma
rysować trójkąt; dla level większego od zera ma trzy razy
wywoływać samą siebie, za każdym razie odpowiednio transformując układ
współrzędnych i przekazując wartość level-1 jako argument.
Wykład: mini-kurs Octave’a (open-source’owy odpowiednik MATLAB-a) i omówienie używanej w tym środowisku reprezentacji obrazów rastrowych.
Ćwiczenia:
Zapoznaj się z Octave. Oprócz trybu linii poleceń ma ono okienkowy interfejs użytkownika — jeśli je uruchomisz na swoim własnym komputerze, to pewnie właśnie w tym okienkowym trybie wystartuje. Przejrzyj oraz spróbuj uruchomić omawiane na wykładzie octave01.m i octave02. Upewnij się, że rozumiesz jak wszystko w nich działa.
Załaduj z dysku dwa obrazy o tych samych rozmiarach, a następnie zrób z nich kolaż: lewa połowa pierwszego sklejona z prawą połową drugiego. Otrzymany obraz zapisz na dysk.
Konwersja kolorowego obrazu do odcieni szarości. Zaimplementuj dwie
wersje: w pierwszej użyj wzoru (r + g + b) / 3, w drugiej
0.299 * r + 0.587 * g + 0.114 * b. Porównaj otrzymane wyniki.
Czy widzisz między nimi różnice? Który z nich wydaje się mieć jasność bliższą
kolorowemu oryginałowi?
Dana jest macierz liczb zmiennoprzecinkowych. W jaki sposób sprawdzić czy wartości w niej się znajdujące nie wykraczają poza przedział [0, 1]? A jak przyciąć nielegalne wartości do dozwolonego zakresu?
Octave traktuje wszystkie stałe liczbowe jako wartości zmiennoprzecinkowe
podwójnej precyzji, co za tym idzie po wykonaniu x = 7 zmienna
x będzie miała typ double. W jaki sposób można
wymusić zmianę typu tej stałej, powiedzmy na 8-bitową liczbę całkowitą albo na
wartość boolowską? Jakie są zasady tych konwersji (kierunek zaokrąglania,
jakie liczby są uznawane za prawdę a jakie za fałsz, itp.)?
Co się dzieje, gdy w wyniku dodawania wartości typu uint8
otrzymamy wynik wykraczający poza przedział dopuszczalnych wartości tego typu?
To nie jest arytmetyka ze szkoły podstawowej, nie jest też arytmetyka modulo,
więc co?
Dla zainteresowanych: przejrzyj kod w plikach cairo1?.py.
A teraz coś z zupełnie innej beczki: naukowcy z AGH proszą wszystkich chętnych o wypełnienie ankiety „Sztuczna inteligencja w obliczeniach i symulacjach”. Warto kilka minut poświęcić aby pomóc im w badaniach.
Wykład: obraz rastrowy jako macierz próbek ciągłej funkcji dwuargumentowej, wybrane operacje na rastrach (skalowanie czyli resampling, filtry splotowe, filtry nieliniowe: gradient Sobela, filtr medianowy, filtry adaptacyjne), LUT.
Ćwiczenia:
Przejrzyj dostępną w Internecie (odnośniki są w slajdach) dokumentację Octave’a i jego pakietów. Znajdź funkcję skalującą obrazy oraz funkcje pozwalające przetwarzać je filtrami splotowymi. Trochę poeksperymentuj, ale nie tylko na wczytanych z plików obrazach, lecz również na ręcznie stworzonej macierzy 10 x 10 reprezentującej obraz w odcieniach szarości. Macierz musi być nieduża — chodzi o to, aby dało się ją całą objąć wzrokiem, i aby dało się naocznie sprawdzić czy wartości w macierzach będących wynikami operacji są zgodne z Waszymi oczekiwaniami.
Zamiast dokumentacji Octave’a można przeglądać MATLAB-ową, być może uznacie ją za bardziej profesjonalnie przygotowaną. Proszę nie zapomnieć o przejrzeniu dokumentacji pakietu „Image Processing Toolbox” i / lub jego octave’owego odpowiednika.
Może się okazać, że Octave oferuje kilka różnych dróg wykonania jakiejś operacji na rastrze. Na przykład można się spodziewać, że będzie dostępna ogólna funkcja do obliczania splotów jedno- i dwuwymiarowych funkcji dyskretnych, oraz jej specjalizowana wersja przeznaczona dla obrazów. Proszę się postarać znaleźć wszystkie takie warianty i ustalić czym się w działaniu różnią.
Opracuj sekwencję poleceń, które pozwolą przeskalować obraz dowolnych wymiarów tak, aby był nie większy niż 128 x 128. Zachowaj proporcję wysokości do szerokości.
Napisz wykonywalny skrypt, który używając tej sekwencji skaluje podane mu jako argumenty wywołania pliki graficzne. Nie modyfikuj tych, które już mają wymiary mniejsze lub równe 128 x 128.
Opracuj fragment kodu, który sprawdza jakiego typu jest raster wczytany do macierzy z pliku. Jeśli jest to raster RGB, skonwertuj go do rastra greyscale. Upewnij się, że macierz po konwersji ma odpowiedni typ, dokładnie taki jaki miałaby gdyby plik na dysku był w odcieniach szarości.
Binaryzacja, przekształcenia morfologiczne. GIMP jako przykład aplikacji korzystającej z filtrów rastrowych. Wstępny rzut oka na bibliotekę OpenCV.
Ćwiczenia najpierw z Octave’a, potem z OpenCV:
Przy pomocy gradientu Sobela znajdź krawędzie na obrazku z odrzutowcem. Obrysuj je na czerwono (tzn. do wszystkich pikseli należących do wykrytych krawędzi wstaw wartość FF0000), zapisz wynik w pliku PNG. W tym zadaniu można albo użyć odpowiedniej bibliotecznej funkcji (łatwiejsze), albo samodzielnie złożyć gradient Sobela z dwóch masek Sobela według wzoru podanego na wykładzie (trudniejsze).
Zbinaryzuj pokazaną na wykładzie fotografię kartki A4. Czy w otrzymanym obrazie jest dobra separacja pomiędzy obiektem (kartka) a tłem (blat biurka)? Jeśli są usterki, to jakimi operacjami można próbować je usunąć?
Dla zainteresowanych: napisz skrypt wygładzający obrazy przy pomocy adaptacyjnego filtru konwolucyjnego. Kryterium wyboru przetwarzanych pikseli oraz dokładną postać maski wygładzającej możecie Państwo dobrać wedle własnego gustu.
Zajrzyj na witrynę OpenCV, sprawdź jak jest zorganizowana dokumentacja tej biblioteki. Zlokalizuj tutoriale oraz strony ze specyfikacją API. Pamiętaj, że wersja dokumentacji musi odpowiadać wersji biblioteki, z której korzystasz — na spk-ssh jest wersja 4.5.4.
Zorientuj się, jak OpenCV reprezentuje obrazy rastrowe. Musi mieć jakiś
typ pozwalający dynamicznie przydzielać pamięć w zależności od wymiarów
obrazu, liczby kanałów (od jednego do czterech: obrazy mono, RGB i RGBA)
i używanego typu liczb (uint8_t, float lub
double). Sprawdź czy tak jak w Octave wielokanałowe obrazy
są reprezentowane jako trójwymiarowe macierze, czy też może OpenCV zawsze
używa macierzy dwuwymiarowych (ale wtedy w pojedynczym elemencie macierzy
musi być zapamiętana więcej niż jedna liczba, jak to jest robione?).
Sprawdź jakie funkcje służą do wczytywania i zapisywania obrazów, i jakie formaty plików graficznych są obsługiwane. Spróbuj ręcznie wypełnić macierz wzorkiem (np. takim jak w ppm01.c) i zapisać do pliku. Czy wygenerowany plik otwiera się poprawnie w programach do przeglądania / obróbki grafiki?
OpenCV ma w nazwie „computer vision”, dzisiejszy wykład jest więc ogólnym rzutem oka na problemy, którymi zajmują się specjaliści od wizji komputerowej (patrz slajdy prof. Torralby). Wykracza to poza zakres naszego przedmiotu, ale warto zobaczyć jak wykorzystywane są idee, o których mówiliśmy na zajęciach (obraz jako macierz liczb, filtrowanie obrazów, itd.).
Na ćwiczeniach wybór tematów projektów 2D. Najlepiej byłoby, gdyby te projekty udało się Państwu oddać już w grudniu lub ewentualnie na początku stycznia, bo potem do zrobienia macie jeszcze projekt 3D.
Ćwiczenia (proszę pisać w C++, nie w Pythonie):
Przypominam, że w katalogu /home/palacz/ZGK/ są pliki-przykłady octave* oraz opencv*, jest też Makefile z receptą kompilacji dla wymagających tego kroku przykładów. Zachęcam do ich przejrzenia i przetestowania.
Przepisz do OpenCV skrypt, który skalował z zachowaniem proporcji podane
mu w linii komend pliki graficzne tak, aby ich wymiary były nie większe niż
128 x 128. Wykorzystaj funkcję cv::resize.
Porównaj możliwości oferowane przez resize() z tym, co potrafi
jej octave’owy odpowiednik, czyli imresize(). Sprawdź m.in. jakie
metody interpolacji oferuje jedna i druga.
Znajdź odpowiedniki octave’owych instrukcji związanych z filtrami konwolucyjnymi. Napisz program, który przetwarza podane mu w linii komend pliki graficzne, w zależności od podanego przełącznika rozmywając je, wyostrzając filtrem unsharp, lub przetwarzając filtrem wykrywającym krawędzie. O filtrze unsharp nie mówiliśmy na wykładzie, sami musicie więc znaleźć w literaturze jego definicję. Nie nadpisuj oryginalnych plików, zamiast tego wyniki obliczeń zapisuj do wynik*.png.
Krótkie przypomnienie podstawowych wiadomości o aplikacjach 3D.
Ćwiczenia (można pisać w C++ albo w Pythonie, jak kto woli):
Jednym z rodzajów łamigłówek są zagadki rysunkowe, wymagające odnalezienia wszystkich szczegółów, którymi różnią się dwa obrazki. Przykłady patrz tu, tu albo tu. Zaprojektuj i zaimplementuj z użyciem OpenCV program pomagający rozwiązywać zagadki tego typu. Przyjmij, że programowi podaje się jako argumenty dwie nazwy plików PNG o takiej samej liczbie wierszy i kolumn.
Zastanów się, czy opracowany przez Ciebie algorytm mógłby być używany przez aplikację śledzącą obraz z kamery obserwującej jakiś plac na zewnątrz budynku, np. parking, i podnoszącą alarm gdy coś się na placu zacznie dziać. Rozważ m.in. następujące czynniki: wraz ze zmianami pór dnia stopniowo zmienia się oświetlenie placu; zapalenie lamp to nagła zmiana oświetlenia; drgania budynku będą przenosić się na kamerę, odbierany z niej obraz będzie przesuwał się o kilka pikseli w tę i z powrotem. Zaproponuj modyfikacje algorytmu, które wyeliminują błędne alarmy wynikające z tych czynników.
W przyszłym tygodniu wspólnie przedyskutujemy wnioski, do których Państwo doszliście.
Dla zainteresowanych: spróbuj napisać taki program-dozorcę.
Zacznij od stworzenia szkieletowego kodu przetwarzającego nie pojedynczy obraz, lecz ciąg obrazów pobieranych z webcama bądź pliku wideo (w /home/palacz/ZGK/ jest przykładowy film z lecącymi gęśmi). Najlepiej byłoby gdyby program wyświetlał dwa okna: w jednym oryginalny obraz, w drugim obraz po przetworzeniu (na początek powinno być to coś banalnie prostego, np. binaryzacja).
Gdy szkielet będzie już poprawnie działał wypełnij go właściwym algorytmem nadzorującym parking.
Podstawy biblioteki OpenSceneGraph (OSG). Analiza przykładów osg01.cpp i osg02.cpp.
Dyskusja nad tym, jak analizować obraz z kamery obserwującej parking.
Ćwiczenia:
Skompiluj i uruchom oba przykładowe programy omawiane na wykładzie.
Sprawdź w jaki sposób Viewer domyślnie ustawia osie układu
współrzędnych. Możesz np. przerobić przykład osg01.cpp tak, aby
wyświetlał białą sferę w punkcie o współrzędnych (0,0,0), czerwoną w (5,0,0),
zieloną w (0,5,0) i niebieską w (0,0,5).
Przejrzyj pobieżnie dokumentację API biblioteki OSG. Sama specyfikacja API raczej nie wystarczy aby nauczyć się korzystania z OSG, bo wylicza tylko klasy i metody bez wyjaśnienia czym są ani jak ich używać. Potrzebny będzie podręcznik, taki jak książka Wanga.
Model małpki Zuzanny jest ładowany z pliku w formacie OBJ. Jakie inne
formaty 3D są obsługiwane przez funkcję osgDB::readNodeFile?
Spróbuj znaleźć odpowiedź w książce albo w sieci.
Znajdź gdzieś w sieci, np. na
OpenGameArt, kilka modeli 3D w różnych
formatach. Spróbuj je załadować i wyświetlić. Użyj węzłów typu
osg::MatrixTransform i sprawdź, jak przy ich pomocy można
pozycjonować, obracać i skalować ładowane modele.
Krótki wykład o matematycznych narzędziach używanych w animacji, m.in. omówienie metod pozwalających tworzyć naturalnie wyglądające animacje ruchu i obrotów.
Ćwiczenia:
Napisz program wyświetlający trzy małpie głowy.
Dodaj małpkom drewnianą estradę, na której mogłyby stać (tzn. narysuj prostopadłościan obłożony jakąś ściągniętą z sieci teksturą desek).
Spróbuj stworzyć prostą animację. Możesz np. użyć klasy
AnimationPath (patrz podręcznik) i kazać jednej z małpich główek
podrygiwać w górę i w dół.
Dodaj obsługę klawiatury. Proponuję zacząć od bardzo prostej rzeczy: jeśli
użytkownik nacisnął A, wykonaj printf("naciśnięto A\n"). Dopiero
po upewnieniu się, że wykrywanie naciśniętych klawiszy działa poprawnie można
zastąpić printf instrukcjami modyfikującymi stan sceny (np.
obracającymi jedną z małpek w lewo bądź w prawo).
Podczas wykonywania ćwiczeń prawdopodobnie znajdziesz część odpowiedzi na pytania z przyszłotygodniowego quizu.
Przypomnienie podstawowych informacji o OpenGL, a potem analiza sposobów przekazywania z aplikacji do karty graficznej danych opisujących renderowaną bryłę. Wiedza o tym, jak to na niskim poziomie działa, czasem się przydaje — OpenSceneGraph jest przecież nakładką na OpenGL, więc jeśli wiemy co jest optymalne z punktu widzenia OpenGL, to będziemy też wiedzieć jak efektywnie używać OSG.
W drugiej części wykładu, już bez slajdów: sposoby wyświetlania grafiki 2D / 3D w przeglądarce internetowej. Możliwości rozciągają się od klasycznego wstawiania w środek strony plików grafiki rastrowej lub wektorowej (SVG w formie odrębnego pliku lub wplecione w kod HTML), przez animowanie tej grafiki (animowane GIF-y, animacje CSS, SMIL, interaktywne animacje kontrolowane z poziomu JavaScript), do pisania w JavaScripcie programów rysujących dowolne rzeczy na kanwie HTML5. Kanwa wymaga utworzenia kontekstu rysowania, dopiero za jego pośrednictwem można wywoływać operacje graficzne. Współczesne przeglądarki udostępniają trzy typy kontekstów: 2D, WebGL 1.0, WebGL 2.0. Czwarty typ, WebGPU, jest ciągle trochę eksperymentalny ale od połowy 2025 r. Firefox i Chrome / Edge go obsługują.
Generowanie rysunków wewnątrz przeglądarki często jest robione przy pomocy jakiejś wyspecjalizowanej javascriptowej biblioteki. Dostępnych jest np. wiele bibliotek do tworzenia dynamicznych wykresów biznesowych, i kto wie czy nie jeszcze więcej bibliotek wspomagających pisanie przeglądarkowych gier.
Istnieje też javascriptowa wersja OSG, choć w 2018 r. autor przestał ją dalej rozwijać. Zainteresowani mogą mimo wszystko rzucić okiem na witrynę OSG.JS (szczególnie ważne są przykłady użycia, bo OSG.JS nigdy nie miała porządnej dokumentacji) oraz przejrzeć kod źródłowy w repozytorium na GitHubie. Autor starał się zachować jak największe podobieństwo do oryginalnej biblioteki, choć oczywiście OSG.JS nie jest zaimplementowana w C++ i zamiast OpenGL używa WebGL.
Quiz sprawdzający znajomość OSG API (lub umiejętność sprawnego wyszukiwania potrzebnych informacji w dokumentacji OSG, na jedno wychodzi):
Graf sceny nie zawsze jest drzewem, wierzchołki czasem mają więcej niż
jednego rodzica. Co za tym idzie w klasie Node musi być jakiś
bardziej skomplikowany mechanizm niż hipotetyczna metoda Node *
getParent(). Jaki i jak działa?
W jaki sposób OSG reprezentuje stan kontekstu OpenGL, czyli położenie
tych rozmaitych przełączników, które można przestawiać przez
glEnable / glDisable?
Jak obliczyć prostopadłościan ograniczający (ang. bounding box)
dla danej Geode?
Czy MatrixTransform ma jakieś metody, które ułatwiłyby
tworzenie macierzy reprezentujących złożone transformacje (obróć o 45°,
potem przesuń o 0.8 wzdłuż osi X)?
Co reprezentują klasy Light
i LightSource?
W jaki sposób w OSG jest reprezentowana kamera patrząca na scenę?
Czy możemy sami ustawić jej parametry, zamiast zdawać się na to jak ją
automatycznie skonfiguruje Viewer?
Jaka jest różnica pomiędzy ref_ptr
a observer_ptr? Z jakimi inteligentnymi wskaźnikami wprowadzonymi
w C++11 można je porównać?
W podręczniku opisana jest dość skomplikowana procedura znajdowania
obiektu, w który kliknięto myszką. Wynik zwracany jest nie jako
Node *, lecz jako NodePath. Dlaczego?
Ćwiczenia:
Proszę przejrzeć przykłady osg03.cpp i osg04.cpp, zwracając uwagę na znaczenie poszczególnych instrukcji.
Jeśli nie pamiętasz rodzajów świateł używanych przez OpenGL, to sobie te wiadomości teraz przypomij.
Weź program z trzema małpkami na estradzie i spróbuj zmienić aranżację
oświetlenia. Ulokuj światło GL_LIGHT0 w pobliżu pierwszej
małpiej głowy. Ustaw jego własności tak, aby było to kolorowe światło typu
spotlight.
Teraz dodaj innokolorowe GL_LIGHT1 i GL_LIGHT2
wiszące nad pozostałymi dwiema głowami. Oceń uzyskany efekt: czy przypomina
przedstawienie teatralne, w którym każdy aktor ma swój własny reflektor
punktowy?
Poeksperymentuj z ustawianiem położenia kamery. Może spróbuj połączyć to z obsługą klawiatury, tak aby kamera przesuwała się po naciśnięciu klawiszy strzałek?
Prawdopodobnie konieczne okaże się wyłączenie domyślnego manipulatora,
który jest automatycznie tworzony przez osgViewer::Viewer
i pozwala przy pomocy myszki dowolnie przesuwać kamerę. Jeśli i nasz kod,
i ten manipulator będą próbowały kontrolować punkt widzenia kamery, to możemy
spodziewać się konfliktu między nimi.
Ogólny rzut oka na zastosowanie grafiki komputerowej w projektowaniu inżynierskim. Omówienie podobieństw i różnic w stosunku do podejścia używanego w aplikacjach, gdzie grafika pełni rolę czysto dekoracyjną (np. w grach). Częścią wykładu są dwa filmy z Youtube’a:
Na dzisiejszych ćwiczeniach macie Państwo wybór: można pracować nad projektami albo zająć się poniższymi zadaniami dotyczącymi OpenGL.
Ćwiczenia:
Dla zainteresowanych: przestudiuj pliki osg05.cpp
i phong_*.glsl składające się na przykład demonstrujący użycie
programowalnych shaderów. Zaimplementowany w nich model oświetlenia to
klasyczny model Phonga z modyfikacją Blinna, który od zawsze był wbudowany
w karty OpenGL. Zaimplementowano go używając współczesnej składni
(in i out zamiast attribute
i varying), ale odwołując się do danych przetwarzanych przez
stały potok renderujący. Przykład dzięki temu (mam nadzieję) wypełnia pewną
lukę: dostępne w Internecie przykłady shaderów albo pochodzą z czasów OpenGL
2.0 i używają starej składni, albo są w pełni współczesne i operują na danych
wyspecyfikowanych przez programistę (i zanim się zrozumie działanie shadera,
trzeba wcześniej zrozumieć co te dane sobą reprezentują).
Dla szczególnie zainteresowanych: zastanów się, czy dałoby się przyspieszyć
działanie shaderów z powyższego przykładu. Zacznij od ustalenia, które
wartości zmieniają się pomiędzy kolejnymi wierzchołkami, które pomiędzy
fragmentami, a które pozostają ustalone dla wszystkich wierzchołków
i fragmentów. Czy są jakieś wyrażenia, w których oba argumenty są ustalone?
Jeśli tak, to wynik można wyliczyć z wyprzedzeniem i zapisać do dodatkowej
zmiennej uniform. Czy zamiast obliczać pewne wyrażenie we
fragment shaderze dałoby się policzyć je w vertex shaderze i interpolować
otrzymany wynik? Co by się zmieniło, gdyby przyjąć że
GL_LIGHT_MODEL_LOCAL_VIEWER ma wartość false? Co,
gdyby wszystkie wierzchołki miały przypisany ten sam kolor?
Wykład o typach krzywych i powierzchni używanych w systemach CAD. Do tego kilka poglądowych filmów z Youtube’a:
Ćwiczenia:
Proszę podjąć próbę znalezienia odpowiedzi na następujące pytanie: jak to jest możliwe, że format SVG pozwala na stosowanie filtrów rastrowych do wektorowo opisanych figur? Osoby, które odszukają niezbędne informacje i będą potrafiły w jasny oraz kompletny sposób wyjaśnić jak to wszystko działa dostaną plusa za aktywność.
Analizę tego problemu najlepiej chyba byłoby zacząć od upewnienia się, że faktycznie jest to możliwe. Proponuję więc uruchomienie Inkscape’a, narysowanie w nim protokąta albo krzywej Béziera, a następnie zajrzenie do menu „Filters” i zaaplikowanie któregoś z dostępnych tam filtrów do stworzonego przed chwilą kształtu. Wiele z tych filtrów powinno być znajomych: to dokładnie te same efekty, które można znaleźć w menu GIMP-a lub Photoshopa, i które zazwyczaj się implementuje przy pomocy filtrów konwolucyjnych.
Po zapisaniu stworzonego obrazka do pliku można wyświetlić zawartość tego pliku (SVG to format XML-owy) i zobaczyć, jak taki filtr jest definiowany. To powinno dać Wam punkt startowy, od którego będzie mogli rozpocząć przeglądanie specyfikacji SVG.
Zastanów się, jak w aplikacji używającej biblioteki Cairo do rysowania prostokątów i elips zaimplementować efekt rozmazania (ang. motion blur) lub cienia (ang. drop shadow). Sama Cairo nie ma funkcji do filtrowania piksel po pikselu, trzeba albo użyć dodatkowej biblioteki (np. OpenCV), albo własnoręcznie napisać odpowiedni kod. Główne pytanie brzmi: jak to dodatkowe przetwarzanie rastra zintegrować z Cairo?
Dla zainteresowanych: aby sprawdzić, czy przekazywanie danych rzeczywiście działa napisz program rysujący rozmyte figury.
Resztę czasu proszę wykorzystać na kończenie projektów zaliczeniowych.
Zamiast normalnego wykładu i ćwiczeń będzie oddawanie projektów oraz wystawianie zaliczeń. Mam nadzieję, że trzy godziny zegarowe nam na to wystarczą. Spóźnialscy będą mogą oddać swoje projekty na dowolnym dyżurze w sesji.
Przypominam, że w następny poniedziałek, czyli 2 lutego, jest pierwszy termin egzaminu. Można do niego podejść nawet jeśli ćwiczenia nie są jeszcze zaliczone z powodu nieoddania projektów, ale oczywiście oficjalne wpisanie oceny z egzaminu do USOSweb nastąpi dopiero po zaliczeniu ćwiczeń.
Post factum: trzy godziny nie wystarczyły. Osoby, od których nie zdążyłem odebrać projektów zapraszam więc w piątek na Teams, zapiszcie się na listę na odpowiadającą Wam godzinę.