Grafika Komputerowa 3D

Transkrypt

Grafika Komputerowa 3D
Grafika Komputerowa 3D
Etap drugi
Należy wybrać i zrealizować w scenie z etapu pierwszego dowolny zestaw z podanych
poniżej efektów tak, aby zgromadzić odpowiednią liczbę punktów. Nie można za drugi etap
otrzymać więcej niż 20 punktów, ale nadmiar punktów przechodzi na kolejny etap.
Poszczególne efekty nie muszą ze sobą współpracować, a zatem włączenie jednego efektu
może powodować wyłączenie innych, jeśli to ułatwi implementację.
Uwaga dla piszących w C/C++ z użyciem OpenGL:
W nagłówku gl.h znajdują się tylko deklaracje dotyczące jednej z pierwszych wersji
standardu. Z późniejszych rozszerzeń wygodnie jest korzystać przy pomocy OpenGL SDK
dostępnego pod adresem http://oss.sgi.com/projects/ogl-sample/GLsdk.zip albo The OpenGL
Extension Wrangler Library dostępnego pod adresem http://glew.sourceforge.net/ .
Ostateczny termin oddania projektu to 12 grudnia.
W razie pytań dotyczących szczegółów realizacji poszczególnych zadań zapraszam na
laboratoria we wtorki 10:15-12:00 w 317.
1. Filtrowanie tekstur
Wprowadzenie
Teksturowanie w ogólności polega na wyznaczeniu przekształcenia odwzorowującego piksele
na ekranie w obszar obrazu tekstury (zbiór tekseli). Poza przypadkami szczególnymi
wyznaczony obszar tekstury rzadko pokrywa się z pojedynczym tekselem. W celu uzyskania
atrakcyjnego efektu na ekranie, wylicza się kolor piksela jako średnią ważoną kilku tekseli.
Filtr powiększenia stosowany jest, gdy obraz piksela jest mniejszy od rozmiaru teksela. Do
wyboru mamy dwa rozwiązania: najbliższy teksel środka piksela (czyli brak filtrowania) oraz
dwuliniową interpolację pomiędzy kolorami czterech sąsiednich tekseli.
Filtr pomniejszenia stosowany jest, gdy obraz piksela jest większy od rozmiaru teksela. W
takim przypadku zwykle używa się mipmap, czyli ciągu coraz mniejszych tekstur (poziomów
mipmap), w którym pojedynczy teksel kolejnej tekstury jest średnią wartością czwórki tekseli
poprzedniej tekstury. Filtrowanie przy pomniejszeniu może polegać na: wyborze najbliższego
teksel środka piksela, dwuliniowej interpolacji pomiędzy kolorami czterech sąsiednich tekseli
odpowiedniego poziomu mipmap, trzyliniowej interpolacji mipmap, na którą składa się
wykonanie dwuliniowej interpolacji w dwóch sąsiednich poziomach mipmap i wykonanie
liniowej interpolacji tak uzyskanych kolorów.
Zadania
A) Wybierz przynajmniej jeden obiekt w scenie. Upewnij się, że ma on przypisane
współrzędne tekstury. Nałóż teksturę i włącz liniowy filtr dla powiększenia.
[2 pkt]
[+2 pkt] – za renderowanie „skyboxa”, czyli wewnętrznej strony ścian sześcianu otaczającego
scenę, z nałożoną na niego mapą sześcienną („cubemap texture”) zamiast zwyczajnego
zestawu tekstur dwuwymiarowych; sześcian nie powinien podlegać wpływowi świateł w
scenie, a jego tekstura powinna mieć włączone filtrowanie liniowe dla powiększenia
B) Nałóż na wybrany obiekt w scenie teksturę z wygenerowanymi poziomami mipmap i użyj
filtrowania trzyliniowego mipmap.
[2 pkt] – wersja podstawowa
[+1 pkt] – za dodanie interfejsu umożliwiającego zmianę poziomu mipmap wybieranego
podczas teksturowania przez DirectX lub OpenGL, co w efekcie powoduje rozmycie lub
wyostrzenie obrazu na powierzchni obiektu (służy do tego instrukcja
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, ...) w OpenGL lub
ustawienie device.SamplerState[i].MipMapLevelOfDetailBias w DirectX Managed)
2. Automatyczne generowanie i przekształcenia współrzędnych tekstury
Wprowadzenie
DirectX oraz OpenGL umożliwiają automatyczne generowanie współrzędnych tekstury na
podstawie położenia wierzchołka w scenie lub w układzie kamery. Dodatkowo istnieje
możliwość zdefiniowania macierzy przekształcenia dla współrzędnych tekstury.
Można wyróżnić dwa zastosowania automatycznego generowania współrzędnych tekstury:
rzutowanie równoległe lub perspektywiczne obrazu na powierzchnię siatek oraz mapowanie
środowiska.
W pierwszym przypadku postępujemy podobnie jak podczas rzutowania geometrii do widoku
z kamery - mnożymy pozycje wierzchołków przez zadaną macierz, ale tym razem wynik
traktowany jest jako współrzędne tekstury, a nie pozycja na ekranie. Jeśli przykładowo
potraktujemy lampę jak drugą kamerę w scenie, w wyniku takiego rzutowania otrzymamy
współrzędne wierzchołków siatki trójwymiarowego obiektu w układzie lampy. Jeżeli podczas
teksturowania obiektu wykorzystamy te właśnie współrzędne tekstury efektem będzie
projekcja pewnego obrazu rzucanego przez lampę na powierzchnię obiektu.
Podczas mapowania środowiska najlepiej jest wykorzystać mapę sześcienną. Mapa
sześcienna to szóstka dwuwymiarowych tekstur przypisanych poszczególnym ścianom
sześcianu. Współrzędne tekstury dla mapy sześciennej to trójka liczb, które wyznaczają
kierunek promienia wychodzącego ze środka takiego sześcianu. Teksel pobrany dla danych
współrzędnych tekstury odpowiada przecięciu tego promienia z powierzchnią sześcianu.
Mapowanie środowiska uzyskamy, jeśli wykorzystamy jako współrzędne mapy sześciennej
nakładanej na pewien obiekt, wektory odbicia promienia biegnącego od obserwatora
względem płaszczyzny stycznej do powierzchni (wyznaczonej przez wersor normalny).
W DirectX Managed do automatycznego generowania współrzędnych tekstury na podstawie
współrzędnych wierzchołka siatki i ewentualnie normalnej w tym wierzchołku (przy
mapowaniu środowiska) służą instrukcje postaci:
device.TextureState[0].TextureCoordinateIndex = ...;
device.TextureState[0].TextureTransform = ...;
Do przekształcenia współrzędnych tekstury przypisanych do obiektu służy instrukcja postaci:
device.SetTransform(TransformType.Texture0, ...);
W OpenGL odpowiednie są to polecenia postaci:
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, ...);
glTexGenfv(GL_S, GL_OBJECT_PLANE, ...);
glEnable(GL_TEXTURE_GEN_S);
glMatrixMode(GL_TEXTURE);
Zadania
A) Wykonaj rzutowanie perspektywiczne pewnego obrazu rzucanego przez światło
reflektorowe (np. lampę) na stół i obiekty na nim.
[5 pkt]
B) Nałóż na blat stołu (lub inny obiekt sceny) teksturę poprzez wykorzystanie dwóch spośród
trzech współrzędnych wierzchołków blatu stołu (lub innego obiektu sceny) do
automatycznego wygenerowania współrzędnych tekstury.
[2 pkt]
C) Wykonaj mapowanie środowiska - renderuj odbicia mapy sześciennej w pewnym
niepłaskim obiekcie sceny.
[5 pkt]
3. Mieszanie alfa (przezroczystość)
Wprowadzenie
Mieszanie alfa polega na wykorzystaniu dodatkowej czwartej składowej koloru jako
współczynnika w równaniu, które na podstawie koloru już zapisanego w buforze (destination
color - dst_color, destination alpha - dst_alpha) oraz koloru właśnie rysowanego obiektu
(source color - src_color, source alpha - src_alpha) obliczy nową wartość koloru w buforze.
W przypadku przezroczystości odpowiedni wzór to src_alpha * src_color + (1-src_alpha) *
dst_color. Mieszanie addytywne z kolei to wzór postaci src_alpha * src_color + dst_color.
Trudna część realizacji przezroczystości związana jest z tym, że kiedy na ekranie nakłada się
na siebie kilka warstw powierzchni przezroczystych nie można ich rysować w dowolnej
kolejności. Aby otrzymać poprawny efekt trzeba je uporządkować według relacji zasłaniania.
W przypadku mieszania addytywnego kolejność rysowania obiektów jest dowolna.
W przypadku bryły wypukłej realizacja przezroczystości jest prosta: wystarczy wykorzystać
„backface culling” aby przy dwukrotnym rysowaniu tej samej bryły w pierwszej kolejności
narysować jej tylnią część, a następnie przednią. Jeśli mamy kilka brył, dla których kule
opisane na nich są rozłączne, to możemy uporządkować je, sortując na podstawie odległości
środków tych kul od kamery. Możemy też wykorzystać równanie płaszczyzny, która rozdziela
obiekty. W zależności od tego po której stronie płaszczyzny będzie się znajdować w danym
momencie kamera, będziemy wiedzieć, które obiekty należy narysować jako pierwsze.
Zadania
A) Narysuj poświatę na około obiektu. Po narysowaniu obiektu narysuj jeszcze jego
powiększoną kopię, ale tym razem bez teksturowania, używając innego materiału (np. w
kolorze czerwonym) i z włączonym mieszaniem addytywnym.
[2 pkt]
[+3 pkt] - za podświetlenie obiektu tylko po najechaniu na niego kursorem myszy
B) Umieść w scenie kilka (minimum trzy) rozłącznych wypukłych brył (kul, walców,
stożków, sześcianów) z nałożoną dowolną teksturą i przypisanym materiałem. Niech kanał
alfa podczas ich rysowania będzie brany z materiału, a kolor niech będzie iloczynem koloru
tekstury i koloru materiału. Zapewnij poprawne wyświetlanie przezroczystości (rysowanie
powierzchni poszczególnych brył w kolejności od najdalszej do najbliższej).
[6 pkt]
4. Multiteksturowanie
Wprowadzenie
Multiteksturowanie polega na obliczeniu koloru powierzchni obiektu na podstawie kolorów
pobranych z więcej niż jednej tekstury jednocześnie. Obliczenie koloru zwykle przebiega w
ten sposób, że na początku mieszany jest kolor uzyskany w wyniku obliczeń oświetlenia z
kolorem pierwszej tekstury, a potem uzyskany kolor jest mieszany z kolorem kolejnej tekstury
itd.
Zadania
A) Użyj przynajmniej dwóch różnych tekstur by uzyskać określony sposób pokolorowania
powierzchni obiektu.
[2 pkt]
B) Kalkomania. Naklej pewien znak dany w postaci tekstury z kanałem alfa na powierzchnię
(może być to powierzchnia płaska) oteksturowanego już obiektu. Zapewnij prosty interfejs do
obracania, zmiany położenia i wielkości kalkomanii (należy w tym celu wykorzystać macierz
przekształcenia współrzędnych tekstury omawianą w poprzednim punkcie).
[+3 pkt]
5. Lustro
Wprowadzenie
Zrealizowanie poprawnego (nie przybliżonego) efektu płaskiego lustra wymaga wykonania
trzech przebiegów rysowania geometrii:
- najpierw rysowana jest oryginalna scena;
- następnie rysowana jest powierzchnia płaskiego lustra (test bufora głębokości musi być w
tym przebiegu ustawiony na mniejsze lub równe, jeśli rysujemy drugi raz te same piksele;
przed rysowaniem należy wyczyścić bufor szablonu i ustawić operację bufora szablonu tak,
aby piksele lustra miały w nim ustawioną niezerową wartość; bufor szablonu – „stencil
buffer” – to kolejny bufor obok bufora głębokości i buforów koloru bufor związany z
kontekstem renderowania, więc tworząc kontekst renderowania trzeba upewnić się, że
zostanie utworzony także bufor szablonu);
- wreszcie rysowana jest cała scena jeszcze raz, ale odbita względem płaszczyzny lustra
(przed rysowaniem trzeba wyczyścić bufor głębokości, oraz ustawić test bufora szablonu tak,
aby rysowanie odbywało się tylko tam, gdzie widać piksele lustra, a więc gdzie w buforze
szablonu jest niezerowa wartość; jeśli za lustrem znajdują się obiekty w oryginalnej scenie, to
albo trzeba je zignorować w tym przebiegu, albo włączyć obcinanie rysowanej geometrii
płaszczyzną lustra).
Można dodać ewentualnie czwarty przebieg i narysować półprzezroczystą powierzchnię lustra
w określonym kolorze lub określoną teksturą (np. teksturą rys). Przy rysowaniu odbitej sceny
należy pamiętać o odbiciu również świateł. Odbicie geometrii (i świateł) uzyskuje się poprzez
ustawienie odpowiednio macierzy przekształcenia świata. Po wykonaniu tego dodatkowo
zmieni się orientacja trójkątów, zatem trzeba zmodyfikować odpowiednio ustawienia
„backface culling”. Szczególnej uwagi wymaga rysowanie bilbordów odbitych w lustrze.
Zadania
[5 pkt] – podstawowy efekt lustra
[+1 pkt] – jeśli za lustrem znajduje się geometria i jest prawidłowo obcinana
[+1 pkt] – jeśli lustro jest półprzezroczyste i ma kształt elipsy
[+1 pkt] – jeśli w lustrze widać odbite bilbordy, które ustawiają się prawidłowo do kamery
6. Płaszczyzny obcinania
Wprowadzenie
DirectX oraz OpenGL umożliwiają zdefiniowanie, zwykle do sześciu, płaszczyzn obcinania
geometrii sceny („user clipping planes”). Tylko ta część geometrii sceny, która znajduje się po
przedniej stronie aktywnych płaszczyzn obcinania jest rysowana. Do definiowania i włączania
płaszczyzn obcinania w OpenGL służą polecenia: glEnable(GL_CLIP_PLANE0+i),
glClipPlane(...). W DirectX Managed służy do tego struktura device.ClipPlanes.
Zadanie
Płaszczyznę można zdefiniować jednoznacznie podając dowolny jej punkt i wektor
prostopadły do niej (normalną). Niech w scenie zostanie wykorzystana płaszczyzna obcinania,
która przechodzi przez środek stołu i której normalną można dowolnie obracać. Należy
narysować scenę dwukrotnie, z różnymi ustawieniami kolorów i tekstur, w pierwszym
przebiegu obcinając geometrię po jednej stronie płaszczyzny, w drugim przebiegu po
przeciwnej stronie płaszczyzny. Wystarczy jeśli połowa sceny będzie rysowana normalnie,
przy użyciu kolorowych materiałów i tekstur, a druga połowa bez użycia tekstur przy pomocy
szarych materiałów, ale można oczywiście wybrać w dowolny inny sposób dwa różne
zestawy tekstur, materiałów i świateł.
[5 pkt] – podział sceny płaszczyzną na dwie części renderowane z różnymi ustawieniami
kolorów, świateł, tekstur
7. Bilbordy
Wprowadzenie
Bilbordem nazywamy półprzezroczystą bitmapę, nałożoną na prostokąt, którego orientacja w
przestrzeni dopasowuje się automatycznie do widoku z kamery, podczas gdy położenie środka
bilbordu w scenie, oraz jego rozmiary w układzie świata, są stałe. Będziemy zajmować się
dwoma wariantami bilbordów. Pierwszy to bilbord, który obraca się tylko wokół jednej osi.
Jako przykład można sobie wyobrazić prostokąt z teksturą drzewa, którego obrót ograniczony
jest do osi pnia drzewa. Drugi to bilbord, który ustawia się zawsze prostopadle do kierunku
patrzenia. Takie bilbordy wykorzystywane są często w połączeniu z systemami cząstek, na
przykład do wizualizacji dymu.
W przypadku wielu bilbordów, trzeba pamiętać o poprawnym rozwiązaniu problemu
przezroczystości. Istnieją na to dwa sposoby: test alfa oraz mieszanie alfa. W przypadku testu
alfa, w kanale alfa tekstury zapisana jest maska kształtu, który chcemy wyświetlić. Piksele,
którym odpowiada wartość alfa nie spełniająca testu nie są ani rysowane na ekranie, ani
uwzględniane w buforze głębokości. Brzegi kształtu uzyskane w ten sposób są poszarpane
(problem aliasingu), ale nie ma potrzeby rysowania bilbordów w ustalonej kolejności. Dużo
bardziej atrakcyjne efekty zapewnia mieszanie alfa (alpha blending), kiedy to możemy w
teksturze bilbordu określić stopień przezroczystości każdego jej fragmentu. W takim
przypadku konieczne jest sortowanie bilbordów po współrzędnej głębokości w układzie
kamery i rysowanie od najdalszych do najbliższych.
Zadanie
Umieść w scenie półprzezroczysty bilbord
[3 pkt]
[+1 pkt] – za oba rodzaje bilbordów
[+1 pkt] – za możliwość przełączania sposobu renderowania przezroczystości pomiędzy
testem alfa oraz mieszaniem alfa
[+1 pkt] – za poprawne sortowanie dla co najmniej dwóch bilbordów renderowanych z
użyciem mieszania alfa
[+2 pkt] – za zrealizowanie systemu cząstek, czyli zbioru bilbordów poruszających się w
czasie, z których stare bilbordy (cząstki) giną po spełnieniu pewnych ustalonych warunków, a
na ich miejsce tworzone są nowe bilbordy w punkcie (lub na powierzchni obiektu) zwanym
generatorem cząstek
8. Mgła
Wprowadzenie
Karty graficzne wspomagające grafikę 3D pozwalają dokonać interpolacji pomiędzy
wyliczonym kolorem piksela, a zadanym kolorem mgły, na podstawie położenia
renderowanego fragmentu powierzchni względem kamery. W prostszym przypadku
interpolacja odbywa się na podstawie współrzędnej z w układzie kamery i jest wykonywana
sprzętowo dla każdego piksela, w bardziej złożonym na podstawie odległości od kamery
(range based fog) i wtedy obliczenia mgły wykonywane są dla wierzchołków trójkątów. Mgła
często jest używana do tego, by ukryć fakt obcięcia geometrii dalszą płaszczyzną obcinania w
rzutowaniu perspektywicznym.
Zadanie
Dodać dowolny rodzaj mgły do sceny, z możliwością jej włączania/wyłączania i zmiany
gęstości.
[4 pkt]
9. Renderowanie do tekstury
Renderowanie do tekstury polega na tym, że tworzony obraz nie zostaje zapisany w buforze
koloru, tylko w teksturze. W kolejnym przebiegu renderowania, gdy renderowany jest już
obraz do buforu koloru, tekstura ta może zostać wykorzystana do nałożenia na obiekty w
scenie. Przykładowo możemy wyobrazić sobie monitor umieszczony w scenie, na który
nakładana jest tekstura widoku tej właśnie sceny.
Ciekawe efekty można uzyskać łącząc renderowanie do tekstury z renderowaniem
prostokątów pełnoekranowych. Renderowanie prostokąta pełnoekranowego polega na:
ustawieniu jednostkowej macierzy dla projekcji i przekształceń widoku/świata, narysowaniu
pojedynczego prostokąta równoległego do ekranu, który wypełni całe okno widoku. Jeśli
ustawimy kanał alfa dla koloru materiału prostokąta pełnoekranowego, oraz nałożymy na jego
powierzchnię teksturę z wyrenderowanym właściwym obrazem sceny, możemy:
a) uzyskać efekt rozmycia ruchu (gdy nie czyścimy nigdy bufora koloru, a rysując
prostokąt pełnoekranowy z nałożonym obrazem sceny, używamy mieszania typowego
dla przezroczystości: src_alpha * src_color + (1-src_alpha) * dst_color; wielkość efektu
zależy od wartości kanału alfa koloru materiału prostokąta)
b) uzyskać efekt poświaty (gdy renderujemy kilka wersji prostokąta pełnoekranowego z
nałożoną teksturą z widokiem sceny i z przypisanym stałym kanałem alfa, z których
każda kolejna jest nieco większa i używamy mieszania addytywnego: src_alpha *
src_color + dst_color)
W DirectX Managed instrukcje przydatne do realizacji renderowania do tekstury to:
new Texture(device, w, h, 1, Usage.RenderTarget, Format.X8R8G8B8, Pool.Default);
device.SetRenderTarget(...); (dodatkowo może się przydać obiekt klasy
RenderToSurface). W OpenGL na nowszych kartach, wspierających odpowiednie
rozszerzenie, warto skorzystać z instrukcji podobnych jak poniżej:
glGenFramebuffersEXT(1, &fbo);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
GL_TEXTURE_2D, colorTex, 0);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
GL_TEXTURE_2D, depthTex, 0); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,...);, na
prawie wszystkich kartach graficznych można skorzystać z jednej prostej instrukcji:
glCopyTexImage2D(...);W tym drugim przypadku odbywa się faktycznie kopiowanie z
bufora koloru do tekstury, więc tekstura musi mieć identyczne rozmiary i format jak bufor
koloru (trzeba wziąć pod uwagę, że starsze karty graficzne mogą nie obsługiwać tekstur,
których wymiary nie są potęgami dwójki). Czasem w OpenGL można poradzić sobie bez
renderowania do tekstury z pomocą bufora akumulacji, którego z kolei nie ma DirectX.
Zadania
Wykorzystaj wyrenderowany obraz jako teksturę w scenie.
[2 pkt]
Zrealizuj opisane powyżej: rozmycie ruchu lub efekt poświaty.
[4 pkt]
10. Proceduralne generowanie tekstur
Wprowadzenie
Szum Perlina dobrze modeluje wiele zjawisk ze świata przyrody, dlatego jest powszechnie
wykorzystywany w grafice komputerowej między innymi do: zaburzeń powierzchni wody
stojącej, generowania rzeźby górzystego terenu, tworzenia tekstur chmur, dymu, mgły,
drewna i marmuru. Matematycznie jest to suma kilku tzw. oktaw szumu (funkcji losowej o
rozkładzie równomiernym, wartości średniej zero i zadanej maksymalnej amplitudzie), z
których każda kolejna oktawa powstaje przez dwukrotne zwiększenie amplitudy i dwukrotne
zmniejszenie częstotliwości (co odpowiada dwukrotnemu rozciągnięciu w każdym
wymiarze). Więcej informacji pod adresem
http://freespace.virgin.net/hugo.elias/models/m_perlin.htm . Teksturę szumu Perlina można
znaleźć wpisując w wyszukiwarce obrazów „Perlin noise”.
Zadanie
Utworzyć i użyć w scenie tekstury drewna lub marmuru wygenerowanej na podstawie szumu
Perlina. Wyobraźmy sobie falę rozchodzącą się z określonego punktu płaszczyzny:
z(x,y) = A * cos( B*r(x,y) + C) + D
, gdzie A, B, C, D to pewne stałe, a r(x,y) to odległość punktu płaszczyzny od źródła fali.
Jeśli pobierzemy wartość dwuwymiarowego szumu Perlina dla współrzędnych (x,y),
zaburzymy nią wartość promienia r(x,y), a otrzymaną wartość z(x,y) wykorzystamy do
zmieszania w odpowiedniej proporcji dwóch kolorów, to otrzymamy obraz, który może
przypominać słoje drewna. Można poeksperymentować również z innymi rodzajami fal niż
fala kulista np. ze złożeniem kilku fal płaskich:
cos(a1*x+b1*y+c1)*f1+...+cos(an*x+bn*y+cn)*fn
, gdzie a1,...,an, b1,...,bn, c1,...,cn, f1,...,fn to pewne stałe.
Wartość szumu Perlina najprościej pobrać z piksela wczytanej w programie odpowiedniej
bitmapy znalezionej w internecie.
[6 pkt]

Podobne dokumenty