Wykład z grafiki komputerowej II (3D) Jacek Matulewski (e-mail: [email protected]) http://www.fizyka.umk.pl/~jacek/dydaktyka/3d/ Grafika 3D Współrzędne jednorodne Wersja: 15 listopada 2007 Transformacje Podstawowe pojęcia grafiki 3D: • Transformacje – określane we współrzędnych sceny 3D translacja (glTranslatef), obrót (glRotatef) skalowanie (glScalef), pochylenie złożenie – dowolna macierz 4x4 (glMultMatrixf) • Transformacje muszą być ustalone przed narysowaniem wierzchołka, np..: glRotatef(45.0f, 0.0f, 1.0f, 0.0f); //kąt, kierunek osi glVertex3f(…); Transformacje • Współrzędne jednorodne (homogenous coordinates) • Wprowadzone w 1946 przez E. Maxwella (rzutowanie) • W 1965 L. Roberts użył ich do zunifikowania zapisu wszystkich transformacji: translacji, obrotów, skalowanie i pochylania • Opis punktów n-wymiarowej przestrzeni za pomocą n+1 współrzędnych • Obcinanie we współrzędnych jednorodnych może odbywać się w sześcianie zamiast w ściętym ostrosłupie (znacznie efektywniejsze numerycznie) Transformacje • We współrzędnych kartezjańskich (2D) obrót i translacja mogą być zapisane: oxy x0 t x oxx x0 o yx y0 t x o yy y0 t y o yx x0 o yy y0 t y x0 oxx x ˆ y O y T o 0 yx • We współrzędnych jednorodnych: x x0 oxx y H y o 0 yx 1 1 0 oxy o yy 0 t x x0 oxx x0 o yx y0 t x t y y0 o yx x0 o yy y0 t y 1 1 1 Macierze w C++ • Należy pamiętać, że macierze w C++ zapisywane są kolumnami (M[nr kolumny+rozmiar*nr wiersza]) • Oznacza to, że macierz 0 4 8 C 1 5 9 D 2 6 A E 3 7 B F możemy zadeklarować instrukcją float I[16]={0, 1, 2, I[4][4]={{0, 1, 3, 2, 3}, 4,{4, 5, 5, 6, 6, 7, 7}, 8,{8, 9, A, B, B}, 9, A, C,{C, D,D, E, E, F};F}}; W OpenGL macierze 1D Macierze w C++ • Jeżeli chcemy ułatwić sobie życie, możemy zdefiniować funkcję wykonującą transpozycję: 0 1 2 3 0 4 5 6 7 1 8 9 A B 2 C D E F 3 C 5 9 D 6 A E 7 B F 4 8 Macierze w C++ float* Transpozycja(float* M,int rozmiar=4) { for(int kolumna=0;kolumna<rozmiar;++kolumna) for(int wiersz=kolumna+1;wiersz<rozmiar;++wiersz) { float tmp=M[kolumna+rozmiar*wiersz]; M[kolumna+rozmiar*wiersz]=M[wiersz+rozmiar*kolumna]; M[wiersz+rozmiar*kolumna]=tmp; } return M; } Funkcja glMultMatrix Funkcja OpenGL glMultMatrixf wykonuje mnożenie bieżącej macierzy M (np. model-widok) przez macierz H podaną w argumencie tj. M → M·H (postmultiplication) Przykład użycia – mnożenie przez macierz jednostkową 1 0 0 0 0 0 0 1 0 0 0 1 0 0 0 1 W szablonie zmiany wprowadzać w funkcji TForm1::RysujScene przed rysowaniem figury glMatrixMode(GL_MODELVIEW); glLoadIdentity(); float I[16]={1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; glMultMatrixf(Transpozycja(I)); Funkcja glMultMatrix Efekt mnożenia przez macierz I: żadnych zmian Skalowanie Macierz skalowania we współrzędnych jednorodnych sx 0 0 0 0 0 sy 0 0 sz 0 0 0 0 0 1 glScalef(0.5,1,2); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); float S[16]={0.5,0,0,0, 0,1,0,0, 0,0,2,0, 0,0,0,1}; glMultMatrixf(Transpozycja(S)); Skalowanie Macierz skalowania jednorodnego we wszystkich kier. 1 0 0 0 0 1 0 0 0 1 0 0 0 1/ s 0 0 glMatrixMode(GL_MODELVIEW); glLoadIdentity(); float S[16]={1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,2}; glMultMatrixf(Transpozycja(S)); Odbicie Odbicie = „ujemne skalowanie” 1 0 0 0 0 1 0 0 0 1 0 0 0 1 / s 0 0 glMatrixMode(GL_MODELVIEW); glLoadIdentity(); float S[16]={-1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; glMultMatrixf(Transpozycja(S)); Obrót Macierz obrotu we współrzędnych jednorodnych rozkładana jest na obroty wokół osi (kąty Eulera): cos sin 0 0 sin 0 0 Obrót o kąt wokół osi Z 0 0 1 0 0 1 cos 0 1 0 cos 0 sin 0 0 0 0 0 sin cos 0 Obrót wokół osi X 0 0 0 1 cos 0 sin 0 kąt 0 0°sin cos 01 130° 0 0 0.8660 045°cos 0.7071 0 060° 0 10.5 90° osi Y Obrót wokół 0 sin 0 0.5 0.7071 0.8660 1 Obrót Obrót wokół osi Z o kąt 45° 0.7071 0.7071 0.7071 0.7071 0 0 0 0 0 0 0 0 1 0 0 1 glRotatef(45,0,0,1); float Rz[16]={0.7071,-0.7071,0,0, 0.7071, 0.7071,0,0, 0,0,1,0, 0,0,0,1}; glMultMatrixf(Transpozycja(Rz)); Obrót Obrót wokół osi X o kąt : 0 1 0 cos 0 sin 0 0 0 sin cos 0 0 0 0 1 #include <math.h> float constconst float a=20; a=20; float glRotatef(a,1,0,0); const ar=a*M_PI/180.0f; float Rx[16]= {1,0,0,0, 0,cos(ar),-sin(ar),0, 0,sin(ar),cos(ar),0, 0,0,0,1}; glMultMatrixf(Transpozycja(Rx)); Pochylenie • Macierz pochylenia (ang. skew) • Elementy pozadiagonalne • Nie ma odpowiednika w funkcjach OpenGL 1 1 00 0.2 0.2 11 0 0 0.4 0 0 0 00 0 0 0 0 1 0 0 1 Translacja • Macierz translacji we współrzędnych jednorodnych 1 0 0 0 0 0 1t x.5 1 0 t0y.5 0 1 t z1 0 0 11 glTranslatef(1.5,0.5,1); float T[16]={1,0,0,1.5, 0,1,0,0.5, 0,0,1,1, 0,0,0,1}; glMultMatrixf(Transpozycja(T)); Składanie transformacji • Złożenie translacji w kier. X i obrotu wokół osi Z cos sin 0 0 sin cos 0 0 0 t0xcos 1 0 0 1 0 0t xsin 1 0 00 0 0 1 10 0 0 tx 0 0 1 0 0 1 • Złożenie translacji w kier. X i obrotu wokół osi Z cos 0 1 0sin 1 0 0 0 0 0 0 0 sint x cos 0 t x sin 0cos0 sin 0 0 cos 1 00 1 0 0 0 0 01 0 0 1 0 0 0 0 0 1 0 0 1 Obrót wokół wyznaczonego punktu Obrót o 45° w płaszczyźnie XY wokół punktu (2,0,0): 1) Translacja o wektor [2,0,0] 2) Obrót wokół osi Z o 45° 3) Przesunięcie o wektor [-2,0,0] glTranslatef(2,0,0); glRotatef(45,0,0,1); glTranslatef(-2,0,0); Obrót wokół wyznaczonego punktu Obrót o 45° w płaszczyźnie XY wokół punktu (2,0,0): 1) Translacja o wektor [2,0,0] 2) Obrót wokół osi Z o 45° 3) Przesunięcie o wektor [-2,0,0] 1 0 0 0 0 0 t x cos cos sin sin 1 0 0 sin sin cos cos 0 1 0 00 00 0 0 1 00 00 00 t0x (1 1cos0 )0 t x 00 00 t x 0sin 1 0 0 11 00 0 0 1 0 00 11 0 1 0 0 1 Rzutowania • Rzutowanie równoległe na płaszczyznę XY (glOrtho) 1 0 0 0 0 0 0 x x 1 0 0 y y 0 0 0 z 0 0 0 1 1 1 • Rzutowanie perspektywiczne (glFrustum) 1 0 0 0 0 0 1 0 0 0 0 1d 0 0 0 0