OpenGL - maszyna stanu Oprogramowanie i wykorzystanie stacji roboczych Wykład 7 Dr inż. Tomasz Olas olas@icis.pcz.pl Instytut Informatyki Teoretycznej i Stosowanej Politechnika Częstochowska OpenGL posiada zmienne przechowujace wiele wewnętrznych stanów i ustawień. Ta kolekcja jest nazywana Maszyna stanu OpenGL. Wiele zmiennych stanu jest dwustanowa: do właczenia stanu służy funkcja glenable. do wyłaczenia stanu służy funkcja gldisable. Przykład: // Włączenie oświetlenia glenable(gl_lighting);... // Wyłączenie oświetlenia gldisable(gl_lighting); 1/32 Wykład 7 p Zmienne stanu Grupy atrybutów Do odczytania wartości zmiennej stanu służa funkcje: glgetbooleanv(), glgetdoublev(), glgetfloatv(), glgetintegerv(), glgetpointerv() i glisenabled(). Do odczytywania niektórych zmiennych stanu służa specjalne funkcje, np. glgetlight*(), glgeterror(), czy glgetpolygonstipple(). Przykład: GLboolean islighting; glgetbooleanv(gl_lighting, &islighting); std::cout << (islighting == GL_TRUE? "true" : "false") << " ; "; GLfloat c[4]; glgetfloatv(gl_current_color, c); std::cout << c[0] << "," << c[1] << "," << c[2] << "," << c[3]; Przykładowy wynik działania: false ; 1,1,1,1 W bibliotece OpenGL poszczególne stany sa połaczone w grupy atrybutów: GL_ACCUM_BUFFER_BIT accum-buffer GL_ALL_ATTRIB_BITS GL_COLOR_BUFFER_BIT color-buffer GL_CURRENT_BIT current GL_DEPTH_BUFFER_BIT depth-buffer GL_ENABLE_BIT enable GL_EVAL_BIT eval GL_FOG_BIT fog GL_HINT_BIT hint GL_LIGHTING_BIT lighting GL_LINE_BIT line GL_LIST_BIT list GL_PIXEL_MODE_BIT pixel GL_POINT_BIT point GL_POLYGON_BIT polygon GL_POLYGON_STIPPLE_BIT polygon-stipple GL_SCISSOR_BIT scissor GL_STENCIL_BUFFER_BIT stencil-buffer GL_TEXTURE_BIT texture GL_TRANSFORM_BIT transform GL_VIEWPORT_BIT viewport 3/32 Wykład 7 p
Stos atrybutów Parametry rysowania punktów Do umieszczenia na stosie grupy atrybutów służy funkcja: void glpushattrib(glbitfield mask) Do zdjęcia ze stosu umieszczonych tam atrybutów służy funkcja: void glpopattrib(void) Przykład: glcolor3f(1.0f, 0.0f, 0.0f); drawline(0.0f, 0.0f, 2.0f, 0.0f); glpushattrib(gl_current_bit); glcolor3f(1.0f, 1.0f, 1.0f); drawline(0.0f, 0.0f, 2.0f, 2.0f); glpopattrib(); drawline(0.0f, 0.0f, 0.0f, 2.0f); Ustalenie rozmiaru punktu void glpointsize(glfloat size); size: przybliżona średnica (w pikselach) rysowanych punktów. Nie wszystkie średnice punktów sa dostępne: GLfloat sizes[2]; GLfloat step; // Obsługiwany zakres wielkości punktów // Obsługiwany przyrost wielkości punktów // Pobranie zakresu obsługiwanych wielkości i przyrostu wielkości glgetfloatv(gl_point_size_range, sizes); glgetfloatv(gl_point_size_granularity, &step); Rysowanie okragłych punktów (zamiast prostokatnych): glenable(gl_point_smooth); 5/32 Wykład 7 p Parametry rysowania linii (I) Parametry rysowania linii (II) Ustalenie grubości linii void gllinewidth(glfloat width); width: przybliżona grubość linii (w pikselach). Określenie dostępnych wartości: GLfloat sizes[2]; GLfloat step; // Obsługiwany zakres wielkości punktów // Obsługiwany przyrost wielkości punktów // Pobranie zakresu obsługiwanych wielkości i przyrostu wielkości glgetfloatv(gl_line_width_range, sizes); glgetfloatv(gl_line_width_granularity, &step); Rysowanie linii przerywanych: glenable(gl_line_stipple); Określenie wzoru używanego podczas rysowania linii: gllinestipple(glint factor, GLushort pattern); factor - Mnożnik określajacy ile pikseli linii odpowiada pojedynczemu bitowi wzorca przerywania [1-255]. pattern - 16 bitowy wzorzec przerywania (jako pierwszy implementowany jest bit najmniej znaczacy) 7/32 Wykład 7 p
Ograniczenia glbegin() - glend() Prymitywy Najważniejszymi informacjami dotyczacymi wierzchołków sa ich współrzędne określane poprzez funkcję glvertex*(). Ponadto można określić dodatkowe informacje dotyczace wierzchołków, np. kolor, wektor normalny, współrzędne mapowania tekstury, itp. Funkcjami jakie moga być użyte wewnatrz pary glbegin() i glend() sa: glvertex*(), glcolor*(), glindex*(), glnormal*(), gltexcoord*(), gledgeflag*(), glmaterial*(), glarrayelement(), glevalcoord*(), glevalpoint*(), glcalllist(), glcalllists(). GL_POLYGON - ograniczenia 9/32 Kierunek Wszystkie wielokaty musza być płaskie (wszystkie wierzchołki wielokata musza leżeć na jednej płaszczyźnie). zgodny z ruchem wskazówek zegara clockwise winding (CW) przeciwny do ruchu wskazówek zegara counterclockwise winding (CCW) Krawędzie wielokata nie moga się przecinać, sam zaś wielokat musi być wielokatem wypukłym (nie może posiadać żadnych wcięć) 3 2 2 1 3 1 11/32
Kierunek w OpenGL Tryby rysowania wielokatów Do określenia orientacji wielokatów w OpenGL służy funkcja: void glfrontface(glenum mode) mode przyjmuje wartości: GL_CW lub GL_CCW Przykład: // określenie, że wielokąty o kolejności krawędzi zgodnej // z ruchem wskazówek zegara są widoczne od frontu glfrontface(gl_cw); // określenie, że wielokąty o kolejności krawędzi przeciwnej // do ruchu wskazówek zegara są widoczne od frontu glfrontface(gl_ccw); Wielokaty nie musza być wypełnione bieżacym kolorem. Domyślnie wielokaty sa rysowane jednolitym kolorem, można jednak to zmienić nakazujac, aby były rysowane jedynie jako sylwetki lub nawet jako punkty (sa wtedy rysowane jedynie wierzchołki). glpolygonmode(glenum face, GLenum); face - Określa stronę wielokata, do której będzie się odnosić dane wywołanie funkcji: GL_FRONT - przednia strona, GL_BACK - tylna strona, GL_FRONT_AND_BACK - obie strony. mode - Określa nowy tryb rysowania. Domyślnym trybem jest GL_FILL dajacy wypełnione wielokaty. GL_LINE powoduje rysowanie jedynie sylwetek wielokatów (zewnętrznych krawędzi), zaś GL_POINT powoduje rysowanie jedynie punktów w wierzchołkach wielokata. Kierunek wielokatów - przykład 13/32 Wypełnianie wielokatów void drawtriangle(int x1, int y1, int x2, int y2, int x3, int y3) glbegin(gl_triangles); glvertex3i(x1, y1, 0); glvertex3i(x2, y2, 0); glvertex3i(x3, y3, 0); glend(); void MyGLWidget::paintGL() glclear(gl_color_buffer_bit); glloadidentity(); //glfrontface(gl_cw); glpolygonmode(gl_front, GL_FILL); glpolygonmode(gl_back, GL_LINE); Wypełnianie wielokatów glenable(gl_polygon_stipple); a następnie glpolygonstipple(const GLubyte *bitmap); bitmap - wzorzec bitowy o wymiarach 32x32 bity (Jedynki we wzorcu sa rysowane bieżacym kolorem wypełniania, zera nie sa rysowane). drawtriangle(0, 0, 1, 0, 0, 1); drawtriangle(1, 0, 0, 1, 1, 1); 15/32
Przesunięcie Skalowanie Przesunięcie jest operacja przemieszczajac a punkty o określona wartość w danym kierunku. Skalowanie powoduje zwiększenie lub zmniejszenie obiektu we wszystkich trzech osiach o zadane współczynniki. Do określenia przesunięcia należy określić wektor przesunięcia d. gltranslate[df](type dx, TYPE dy, TYPE dz); dx - współrzędna x wektora przesunięcia, dy - współrzędna y wektora przesunięcia, dz - współrzędna z wektora przesunięcia. Skalowanie nie musi być jednorodne. Można go użyć do ściśnięcia lub rozciagnięcia obiektu. Do skalowania służy funkcja: glscale[df](type x, TYPE y, TYPE z); Obrót 17/32 Transformacje - przykład (I) class MyGLWidget : public QGLWidget public: MyGLWidget(QWidget* parent = NULL, const char* name = NULL); Obrót jest dokonywany poprzez określenie kata o jaki maja zostać obrócone punkty oraz wektora wyznaczajacego oś obrotu. glrotate[df](type angle, TYPE x, TYPE y, TYPE z); angle - kat obrotu w stopniach, x, y, z - współczynniki wektora obrotu. Obrót jest wykonywany w kierunku przeciwnym do ruchu wskazówek zegara. 19/32 protected: void initializegl(); void paintgl(); void resizegl(int w, int h); void keypressevent(qkeyevent* event); GLfloat zroll; ;
Transformacje - przykład (II) Rzutowanie równoległe void MyGLWidget::paintGL() glclear(gl_color_buffer_bit); glloadidentity(); glrotatef(zroll, 0.0f, 0.0f, 1.0f); drawtriangle(-1, -1, 1, -1, 0, 1); Rzutowanie równoległe jest często używane w projektowaniu architektonicznym i programach CAD. W OpenGL do określenia rzutu równoległego służy funkcja glortho. glortho(gldouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far); void MyGLWidget::keyPressEvent(QKeyEvent* event) if (event->key() == Qt::Key_Left) zroll -= 3.0f; updategl(); if (event->key() == Qt::Key_Right) zroll += 3.0f; updategl(); 21/32 Rzutowanie perspektywiczne (I) Rzutowanie perspektywiczne (II) Ustalanie rzutu perspektywicznego przy użyciu funkcji glfrustum: glfrustum(gldouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far); Ustalanie rzutu perspektywicznego przy użyciu funkcji gluperspective: gluperspective(gldouble fovy, GLdouble aspect, GLdouble znear, GLdouble zfar); fovy - szerokość kata widzenia w pionie (w stopniach), aspect - używany do wyznaczenia konta widzenia w poziomie. 23/32
Pozycja kamery Zmiana pozycji kamery Do zmiany położenia kamery może zostać wykorzystana transformacja: gltranslatef(0.0, 0.0, -10.0); rysuj_kwiatek(); 25/32 Funkcja glulookat Definiowanie widoku (I) Funkcja glulookat umożliwia umieszczenie obserwatora (kamery) w pewnym punkcie w przestrzeni i określenie kierunku w którym obserwator patrzy (zwrócona jest kamera). void glulookat(gldouble eyex, GLdouble eyey, GLdouble eyez, GLdouble centerx, GLdouble centery, GLdouble centerz, GLdouble upx, GLdouble upy, GLdouble upz); Do ustalenia obszaru okna (widok), przeznaczonego do wykorzystania przez OpenGL służy funkcja glviewport glviewport(glint x, GLint y, GLsizei width, GLsizei height); eyex, eyey, eyez - punkt obserwacji (współrzędne kamery), centerx, centery, centerz - określa kierunek patrzenia (kierunek w którym zwrócona jest kamera), upx, upy, upz - określa kierunek do góry z miejsca patrzenia. 27/32
Definiowanie widoku (II) Bufor głębokości (I) void MyGLWidget::resizeGL( int w, int h ) if (h == 0) h = 1; if (w > h) glviewport((w - h)/2, 0, h, h); else glviewport(0, (h - w)/2, w, w); Gdy jest rysowany piksel przypisywana jest mu wartość (zwana wartościa z) określajac a odległość punktu tego piksel od obserwatora. Później gdy w tym samym miejscu ekranu ma zostać narysowany piksel, wartość z nowego piksel jest porównywana z wartościa z piksel już narysowanego. Jeżeli jest większa, oznacza to, że jego punkt jest bliżej obserwatora, więc stary piksel jest zasłaniany przez nowy. glmatrixmode( GL_PROJECTION ); glloadidentity(); if (ortho) glortho(-1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f); else gluperspective(60.0f, 1.0f, 0.1, 2.0); glmatrixmode(gl_modelview); Bufor głębokości (II) 29/32 Bufor głębokości - przykład Właczenie bufora głębokości: glenable(gl_depth_test); Bufor głębokości musi być wyzerowany za każdym razem gdy przystępujemy do narysowania sceny. // Wyczyszczenie okna i bufora głębokości glclear(gl_color_buffer_bit GL_DEPTH_BUFFER_BIT); glcolor3f(0.0f, 0.0f, 1.0f); glbegin(gl_quads); glvertex3f(0.1f, 0.1f, 0.1f); glvertex3f(0.5f, 0.5f, 0.1f); glend(); glcolor3f(1.0f, 0.0f, 0.0f); glbegin(gl_triangles); glvertex3f(0.5f, 0.0f, 0.0f); glvertex3f(0.0f, 0.5f, 0.0f); glend(); Bufor głębokości wyłaczony glvertex3f(0.1f, 0.5f, 0.1f); glvertex3f(0.5f, 0.1f, 0.1f); glvertex3f(0.0f, 0.0f, 0.0f); Bufor głębokości właczony 31/32