Programowanie grafiki 3D Podstawy OpenGL cz.1 Operacje na macierzach Transformacje 3D Scena 3D Ograniczanie, okrawanie i obcinanie Prymitywy biblioteki GLUT
Operacje na macierzach Wszystkie operacje przekształceń 2D i 3D w OpenGL wykonywane są na macierzach o wymiarach [4x4]. Istnieją trzy typy macierzy służące do różnych celów: • GL_MODELVIEW – służąca do transformacji modelowanych obiektów, • GL_PROJECTION – służąca do transformacji punktu widzenia i sposobu rzutowania, • GL_TEXTURE – służąca do przekształcania tekstur nakładanych na obiekty. Rodzaj macierzy na, której w danej chwili pracujemy wybieramy funkcją: void glMatrixMode(GLenum mode) Jako parametr przekazujemy jeden z trzech wymienionych wcześniej typów. Pracę z każdą macierzą musimy rozpocząć od jej zainicjalizowania funkcją: void glLoadIdentity(void) UWAGA! Wszystkie macierze w OpenGL stosują konwencję używaną w matematyce a nie w C++. Oznacza to, że kolejne elementy macierzy ułożone są w pamięci kolumnami, a nie wierszami.
Operacje na macierzach Jeśli zajdzie potrzeba macierz można przemnożyć przez inną macierz: void glMultMatrixd (const GLdouble *m) void glMultMatrixf (const GLfloat *m) Aby ułatwić korzystanie z macierzy zapisanych w konwencji C++ wprowadzono funkcje: void glMultTransposeMatrixd (const GLdouble *m) void glMultTransposeMatrixf (const GLfloat *m) Aktualną macierz można również podmienić inną macierzą: void glLoadMatrixd (const GLdouble *m) void glLoadMatrixf (const GLfloat *m) void glLoadTransposeMatrixd (const GLdouble *m) void glLoadTransposeMatrixf (const GLfloat *m)
Operacje na macierzach W celu ułatwienia wielokrotnego wykonywania tych samych czynności w OpenGL dla każdego typu macierzy wprowadzono niezależne stosy, na które można je odkładać funkcją: void glPushMatrix(void) Zdjęcie macierzy ze stosu wykonuje funkcja: void glPopMatrix(void) Nieprawidłowe operacje na stosie mogą wygenerować błędy: • GL_STACK_UNDERFLOW • GL_STACK_OVERFLOW
Operacje na macierzach Wszystkie transformacje geometryczne w bibliotece OpenGL realizowane są poprzez operacje macierzowe. Z każdym przekształceniem związana jest jedna macierz. Składanie przekształceń odpowiada mnożeniu macierzy. Mnożenie macierzy nie jest przemienne! obrót void glRotatef(GLfloat angle,GLfloat x, GLfloat y, GLfloat z) void glRotated(GLdouble angle, GLdouble x, GLdouble y, GLdouble z) skalowanie void glScalef(GLfloat x, GLfloat y, GLfloat z) void glScaled(GLdouble x, GLdouble y, GLdouble z) przesunięcie void glTranslatef(GLfloat x, GLfloat y, GLfloat z) void glTranslated(GLdouble x, GLdouble y, GLdouble z)
Operacje na macierzach glMatrixMode(GL_MODELVIEW); glLoadIdentity( ); glTranslatef(0.2,0.3,0.5); glScalef(1.5,1.5,0.5); glRotatef(30,1.0,0.0,0.0); glRotatef(45,0.0,1.0,0.0); glRotatef(-20,0.0,0.0,1.0); • Aktywujemy pracę na macierzy przekształcania obiektów. • Ładujemy macierz jednostkową • Mnożymy macierz jednostkową przez macierz przesunięcia o wektor (0.2,0.3,0.5). • Skalujemy obiekt 1.5 razy w kierunku osi x i y oraz 0.5 razy w kierunku osi z. • Obracamy wokół osi x przeciwnie do ruchu wskazówek zegara o 30 stopni. • Obracamy wokół osi y przeciwnie do ruchu wskazówek zegara o 45 stopni. • Obracamy wokół osi z zgodnie z ruchem wskazówek zegara o 20 stopni. … sekcja definiująca obiekt na którym mają działać transformacje …
Operacje na macierzach glMatrixMode(GL_MODELVIEW); glLoadIdentity( ); glTranslatef(0.2,0.3,0.5); glScalef(1.5,1.5,0.5); glRotatef(30,1.0,0.0,0.0); glRotatef(45,0.0,1.0,0.0); glRotatef(-20,0.0,0.0,1.0); • Aktywujemy pracę na macierzy przekształcania obiektów. • Ładujemy macierz jednostkową • Mnożymy macierz jednostkową przez macierz przesunięcia o wektor (0.2,0.3,0.5). • Skalujemy obiekt 1.5 razy w kierunku osi x i y oraz 0.5 razy w kierunku osi z. • Obracamy wokół osi x przeciwnie do ruchu wskazówek zegara o 30 stopni. • Obracamy wokół osi y przeciwnie do ruchu wskazówek zegara o 45 stopni. • Obracamy wokół osi z zgodnie z ruchem wskazówek zegara o 20 stopni. kolejność wykonywania operacji … sekcja definiująca obiekt na którym mają działać transformacje …
SCENA 3D Standardowo obszar renderingu w OpenGL pokrywa się z wielkością okna tuż po jego inicjalizacji, a początek układu współrzędnych leży w lewym, dolnym narożniku okna. Obszar renderowania można zmienić funkcją: void glViewport(GLint x, GLint y, Glsizei width, Glsizei height) aktualne rozmiary okna można uzyskać funkcją z biblioteki GLUT: int glutGet(GLenum type) podając jako parametr wywołania: GLUT_WINDOW_WIDTH lub GLUT_WINDOW_HEIGHT OpenGL oferuje dwa sposoby rzutowania sceny: ortogonalne i perspektywiczne. Ani OpenGL ani GLUT nie zmieniają obszaru renderingu po zmianie rozmiarów okna. Programista musi o to zadbać samodzielnie.
SCENA 3D Bryłę obcięcia w rzutowaniu ortogonalnym definiuje funkcja: void glOrtho(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far)
SCENA 3D Bryłę obcięcia w rzutowaniu perspektywicznym stanowi ostrosłup o wierzchołku leżącym w początku układu współrzędnych. Ostrosłup ten definiuje funkcja: void glFrustum(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far)
SCENA 3D Biblioteka GLU udostępnia dodatkową funkcję, która pozwala definiować bryłę obcięcia w sposób bardziej „fotograficzny”. Służy do tego funkcja: void gluPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar); fovy – oznacza kąt widzenia obrazu w pionie aspect – proporcje boków, czyli stosunek w do h zNear i zFar mają takie samo znaczenie jak poprzednio
SCENA 3D Standardowo obserwator (kamera) w OpenGL umieszczony jest w punkcie o współrzędnych (0,0,0), patrzy w kierunku ujemnych wartości osi z, a jego kierunek „do góry” wskazuje oś y. Do zmiany położenia obserwatora* stosuje się funkcję biblioteki GLU: void gluLookAt(GLdouble eyex, GLdouble eyey, GLdouble eyez, GLdouble centerx, GLdouble centery, GLdouble centerz, GLdouble upx, GLdouble upy, GLdouble upz) Gdzie (eyex,eyey,eyez) definiuje punkt, w którym znajduje się obserwator, (centerx,centery,centerz) określa punkt, na który obserwator patrzy, (upx,upy,upz) jest wektorem wskazującym kierunek „do góry”. *Tak naprawdę to nie obserwator zmienia swoje położenie, tylko układ współrzędnych zostaje odpowiednio przekształcony.
Ograniczanie i okrawanie Bryłę obcięcia można ograniczyć do zadanego obszaru korzystając z funkcji: void gluPickMatrix(GLdouble x, GLdouble y, GLdouble width, GLdouble height, const GLint viewport[4]) (x,y) – środek nowej bryły obcięcia width – szerokość bryły obcięcia w pikselach height – wysokość bryły obcięcia w pikselach viewport – aktualne rozmiary okna renderingu (można je pobrać ze zmiennej stanu GL_VIEWPORT) Okrawanie polega na ograniczaniu renderowania sceny do prostokąta, zdefiniowanego we współrzędnych ekranowych. Służy do tego funkcja: void glScissor (GLint x, GLint y, GLsizei width, GLsizei height) Okrawanie można włączyć lub wyłączyć parametrem GL_SCISSOR_TEST.
Obcinanie Obcinanie polega na zdefiniowaniu dodatkowych płaszczyzn uzupełniających bryłę obcięcia. Dzięki nim bryła obcięcia może mieć kształt różny od ostrosłupa ściętego. Płaszczyzny definiuje się funkcją: void glClipPlane (GLenum plane, const GLdouble *equation) plane określa numer płaszczyzny. Pierwszych sześć płaszczyzn (co najmniej tyle gwarantuje specyfikacja) ma swoje predefiniowane stałe: GL_CLIP_PLANE0, GL_CLIP_PLANE1, GL_CLIP_PLANE2, GL_CLIP_PLANE3, GL_CLIP_PLANE4, GL_CLIP_PLANE5, pozostałe można tworzyć według wzoru: GL_CLIP_PLANEi=GL_CLIP_PLANE0 + i. Liczba płaszczyzn zdefiniowana w implementacji to GL_MAX_CLIP_PLANES. Płaszczyzna zdefiniowana jest przez równanie: Ax+ By + Cz + D = 0 *equation jest wskaźnikiem na tablicę zawierającą współczynniki (A,B,C,D)
Prymitywy biblioteki GLUT Sfera: void glutSolidSphere (GLdouble radius, GLint slices,GLint stacks); void glutWireSphere (GLdouble radius, GLint slices,GLint stacks); Sześcian: void glutSolidCube (GLdouble size); void glutWireCube (GLdouble size); Stożek: void glutSolidCone (GLdouble base, GLdouble height, GLint slices, GLint stacks); void glutWireCone (GLdouble base, GLdouble height, GLint slices, GLint stacks);
Prymitywy biblioteki GLUT Torus: void glutSolidTorus (GLdouble innerRadius, GLdouble outerRadius, GLint nsides, GLint rings); void glutWireTorus (GLdouble innerRadius,GLdouble outerRadius, GLint nsides, GLint rings); Dwunastościan: void glutSolidDodecahedron (void); void glutWireDodecahedron (void); Ośmiościan: void glutSolidOctahedron (void); void glutWireOctahedron (void);
Prymitywy biblioteki GLUT Czworościan: void glutSolidTetrahedron (void); void glutWireTetrahedron (void); Dwudziestościan: void glutSolidIcosahedron (void); void glutWireIcosahedron (void); Czajniczek: void glutSolidTeapot (GLdoublesize); void glutWireTeapot (GLdoublesize);
Prymitywy biblioteki GLUT Model czajnika został stworzony w 1975 przez informatyka Martina Newella, członka pionierskiej grupy zajmującej się wczesnymi pracami nad grafiką komputerową na Uniwersytecie Utah. Za źródło danych posłużył prawdziwy czajnik firmy Melitta, kupiony przez żonę Newella rok wcześniej - egzemplarz ten jest obecnie elementem stałej ekspozycji w Boston Computer Museum.
Prymitywy biblioteki GLUT
test