650 likes | 835 Views
Podstawy programowania grafiki 3D z użyciem biblioteki OpenGL. dr inż. Piotr Steć. Czym jest OpenGL. Biblioteka programistyczna Interfejs pomiędzy sprzętem a programistą Uniezależnia programistę od platformy sprzętowej i programowej
E N D
Podstawy programowania grafiki 3D z użyciem biblioteki OpenGL dr inż. Piotr Steć
Czym jest OpenGL • Biblioteka programistyczna • Interfejs pomiędzy sprzętem a programistą • Uniezależnia programistę od platformy sprzętowej i programowej • Bazuje na bibliotece Iris GL opracowanej przez Silicon Graphics • Wszystkie nowoczesne karty graficzne wspierają sprzętowo funkcje OpenGL • Pierwsza wersja powstała w 1992r.
Zalety OpenGL • Całkowite uniezależnienie od możliwości karty graficznej • Prosty i przejrzysty kod programu • Program wygląda prawie tak samo we wszystkich językach programowania i na wszystkich platformach systemowych • Biblioteka jest darmowa i można jej używać we własnych programach bez ograniczeń
Dane wierzchołków Operacje na wierzchołkach Ewaluacja i budowanie prymitywów Lista wyświetlania Rasteryzacja Operacje na Bufor Operacje T worzenie ramki pikselach na fragmentach tekstur Dane pikseli Jak działa OpenGL Schemat potoku renderującego
Listy wyświetlania • Dwa tryby pracy OpenGL: • immediate mode – komendy graficzne wykonywane są natychmiast • retained mode – komendy graficzne przechowywane są w listach • Listy mogą być wielokrotnie wykonywane
Ewaluacja • Blok ten przekształca dane sterujące na parametry i współrzędne przestrzenne • Może generować: • Powierzchnie NURBS • Mapowanie tekstur • Wektory normalne • Informację o kolorze
Operacje na wierzchołkach i budowanie prymitywów • Wierzchołki obiektów poddawane są transformacjom • Obiekty 3D są rzutowane na płaszczyznę 2D (ekran) • Obcinane są niewidoczne części obiektów • Obliczane jest oświetlenie obiektów
Operacje na pikselach • Pobieranie bitmap z pamięci • Konwersja formatów pikseli • Skalowanie • Filtracja • Kopiowanie
Tworzenie tekstur • Tworzenie tekstur z bitmap • Łączenie wielu bitmap w teksturę • Organizacja pamięci tekstur • Generowanie MIPMap • Filtracja tekstur
Rasteryzacja • Zamiana danych wektorowych, parametrów oświetlenia i materiałów na tzw. fragmenty: • wierzchołki łączone są liniami • wielokąty są wypełniane z uwzględnieniem cieniowania • Fragment jest surowym odpowiednikiem piksela, czyli jednego punktu na ekranie • Fragment zwykle zawiera więcej informacji niż piksel, np. głębię czy wartości buforów specjalnych
Operacje na fragmentach • Teksturowanie • Obliczanie wartości mgły • Mieszanie z buforem alfa • Uwzględnianie szablonów • Operacje na buforze Z • Operacje logiczne • Wynik końcowy: piksel zapisany do bufora ramki
Bufor ramki • Pamięć przechowująca piksele, które mają być wyświetlone na ekranie • Wielkość bufora ramki zależy od wielkości okna w którym wyświetlana jest grafika • OpenGL może obsługiwać wiele buforów ramki • Najczęściej stosuje się 2 bufory ramki: • Jeden jest wyświetlany (front), drugi jest używany do rysowania (back) • Po zakończeniu rysowania bufory zamieniane są miejscami (podwójne buforowanie) • W przypadku wyświetlania stereo, stosowane są 4 bufory (po 2 na jedno oko)
Składnia komend OpenGL • Wszystkie komendy rozpoczynają się przedrostkiem gl np. glClearColor() • Wszystkie stałe rozpoczynają się przedrostkiem GL_, np. GL_FRONT • Komendy są tworzone według jednego schematu: glColor3f( typ parametrów biblioteka liczba parametrów komenda
Przyrostki komend i typy parametrów np. glVertex2i(33,150); glvertex3f(12.34,100.1,0.5);
Szkielet programu • Inicjalizacja biblioteki • Ustalenie wielkości okna i typu kamery • Opcjonalnie: zmiana parametrów kamery i zmiennych środowiska • Rysowanie obiektów • Jeśli nie koniec, to skok do 3 • Zwalnianie zasobów
Pliki nagłówkowe • W bibliotekach używających OpenGL należy podłączyć odpowiednie pliki nagłówkowe#include <GL/gl.h> #include <GL/glu.h> • Opcjonalnie można użyć pomocniczej biblioteki#include <gl/glaux.h> • Biblioteka glaux nie jest częścią standardu, jest nieoficjalna i nie jest standardowo dostępna. Należy samodzielnie zdobyć plik glaux.lib
Kontekst urządzenia • Kontekst urządzenia pod Windows pozwala na rysowanie • Ogólnie jest to ten element okna, który widzimy na ekranie (ale można uzyskać kontekst urządzenia również dla elementów niewidocznych) • Globalna zmienna przechowująca kontekst:HDC hdc; • Pobieranie kontekstu w czasie inicjalizacji:hdc=GetDC(Handle); • Zwalnianie kontekstu na końcu programu:ReleseDC(Handle, hdc);
Format piksela • Format piksela jest niezależny od aktualnego trybu kolorówPIXELFORMATDESCRIPTOR pfd; ZeroMemory( &pfd, sizeof( pfd ) ); pfd.nSize = sizeof( pfd ); pfd.nVersion = 1; pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; pfd.iPixelType = PFD_TYPE_RGBA; pfd.cColorBits = 24; pfd.cDepthBits = 16; int iFormat = ChoosePixelFormat( hDC, &pfd ); SetPixelFormat( hDC, iFormat, &pfd );
Kontekst renderingu • Jest dla OpenGL tym samym, czym jest kontekst urządzenia dla Windows • Globalna zmienna przechowująca identyfikator:HGLRC hRC; • Tworzenie kontekstu (można utworzyć kilka):hRC = wglCreateContext( hDC ); • Wybieranie aktywnego kontekstu:wglMakeCurrent( hDC, hRC ); • Zwalnianie kontekstu na końcu programu:wglMakeCurrent( NULL, NULL ); wglDeleteContext( hRC );
Parametry wyświetlania • Obszar okna, na którym będzie rysowana scena:glViewport(0, 0, ClientWidth, ClientHeight); • Przełączenie w tryb edycji kamery:glMatrixMode(GL_PROJECTION); • Wyzerowanie kamery:glLoadIdentity(); • Parametry projekcji:gluPerspective(45.0,(double)ClientWidth/(double)ClientHeight,0.1,100.0);
Rysowanie obiektów • Czyszczenie bieżącego bufora:glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); • Kolor czyszczący bufor można ustalić dowolnie funkcją (przed rysowaniem):glClearColor(0.0f, 1.0f, 0.0f, 0.0f); • Przełączenie w tryb edycji obiektów:glMatrixMode(GL_MODELVIEW); • Wyzerowanie transformacji:glLoadIdentity(); • Wprowadzenie przesunięcia:glTranslatef(-1.5f,0.0f,-6.0f);
Rysowanie obiektów c.d. • Narysowanie trójkąta (dowolna ilość komend glVertex): glBegin( GL_TRIANGLES ); glColor3d( 1.0, 0.0, 0.0 ); glVertex3d( 0.0, 1.0, 0.0 ); glColor3d( 0.0, 1.0, 0.0 ); glVertex3d( -1.0, 0.0, 0.0 ); glColor4d( 0.0, 0.0, 1.0 ,0.5); glVertex3d( 1.0, 0.0, 0.0 ); glEnd(); • Zamiana buforów ramki SwapBuffers( _hdc ); //za
Rysowanie trójkątów 1 2 5 3 6 4
4 1 4 1 0 0 5 3 5 3 2 2 4 1 4 1 0 0 5 3 5 3 2 2 Punkty i linie
7 4 2 1 2 1 0 0 5 6 4 3 3 Wielokąty GL_QUADS GL_POLYGON
Rysowanie pasów trójkątów • glBegin(GL_TRIANGLE_STRIP); 5 1 3 7 4 2 6
2 3 1 1 3 5 6 0 2 4 4 7 5 Pasy czworokątów i wachlarze trójkątów GL_TRINGLE_FAN GL_QUAD_STRIP
Kolory w OpenGL • Kolor najczęściej jest podawany w postaci składowych RGB lub RGBA, gdzie A określa przeźroczystość • Każda składowa przyjmuje wartości z zakresu <0, 1> • Taka reprezentacja jest niezależna od bieżącego trybu kolorów • Kolor zmieniany jest komendą glColor np. glColor3d( 1.0, 0.0, 0.0 ); (czerwony) • Raz ustawiony kolor obowiązuje dla wszystkich rysowanych po zmianie obiektów
Współrzędne jednorodne • Punkt w przestrzeni reprezentowany jest przez cztery współrzędne (x,y,z,w) • Wsp. jednorodne reprezentują ten sam punkt wtedy, gdy jeden zestaw jest wielokrotnością drugiego, np. (2,1,1,4) i (4,2,2,8) • Przynajmniej jedna ze współrzędnych musi być różna od zera ((0,0,0,0) – niedopuszczalne)
Przekształcenia 3D • Translacja glTranslatef(-1.5f,0.0f,-6.0f); • Skalowanie glScale(2.5f,1.0f,0.5f);
Obroty 3D glRotatef(33.0,1.0,0.0,0.0); Pierwszy parametr: kąt obrotu, Pozostałe trzy określają oś obrotu XYZ (w tym przypadku oś X)
Macierz jednostkowa • Macierz oznaczająca brak przekształceń • glLoad Identity();
Składanie przekształceń • OpenGL przechowuje przekształcenia w postaci macierzy • Wywoływanie funkcji glTranslate, glRotate, glScalepowoduje mnożenie bieżącej macierzy, przez macierz odpowiedniego przekształcenia • Przekształcenie musi być dokonane przed narysowaniem obiektu
Przykład przekształceń glTranslatef(-1.5f,0.0f,-6.0f); glBegin( GL_TRIANGLES ); glColor3d( 1.0, 0.0, 0.0 ); glVertex3d( 0.0, 1.0, 0.0 ); glColor3d( 0.0, 1.0, 0.0 ); glVertex3d( -1.0, 0.0, 0.0 ); glColor4d( 0.0, 0.0, 1.0 ,0.5); glVertex3d( 1.0, 0.0, 0.0 ); glEnd(); glTranslatef(3.0f,0.0f,0.0f); glBegin(GL_QUADS); glVertex3f(-1.0f, 1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 0.0f); glVertex3f( 1.0f,-1.0f, 0.0f); glVertex3f(-1.0f,-1.0f, 0.0f); glEnd();
Wektory normalne • Wektor normalny jest to wektor prostopadły do danej powierzchni • Wektory krawędziowe: 2 V12 0 V10 1
Wektory normalne c.d. • Wektor normalny można uzyskać mnożąc wektorowo dwa wektory krawędziowe • Zwykle wektory normalne muszą być znormalizowane, czyli muszą mieć długość 1
Światło • Oświetlenie jest obliczane dla każdego wierzchołka obiektu • Aby można było obliczyć wartość oświetlenia, musi być podany wektor normalny dla wierzchołka • Jasność wnętrza wielokąta jest interpolowana na podstawie jasności jego wierzchołków, tzw. cieniowanie Gouraud’a
Cieniowanie płaskie Cieniowanie gładkie Cieniowanie
Komponenty składowe oświetlenia • Światło otoczenia (ambient) • Światło rozproszone (diffuse) • Światło odbite (specular)
Dokładność cieniowania a gęstość siatki 16 24 36 100
Tworzenie świateł • Włączenie oświetlenia:glEnable(GL_LIGHTING); • Włączenie pierwszego światła:glEnable(GL_LIGHT0); • Kolejne światła mają identyfikatoryGL_LIGHTi, gdzie i jest numerem światła np. GL_LIGHT3 • Do zmian parametrów światła służy funkcja glLightfv • Nowe parametry są pamiętane aż do kolejnej zmiany
Parametry światła • Składowa otoczenia (ambient)GLfloat light_ambient[] = { 0.1, 0.1, 0.1, 1.0 };glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient); • Składowa rozproszenia (diffuse)GLfloat light_diffuse[] = { 0.8, 0.8, 0.8, 1.0 };glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); • Składowa odbicia (specular)GLfloat light_specular[] = { 1.0, 1.0, 1.0, 1.0 };glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular); • Pozycja światła w przestrzeniGLfloat light_position[] = {-9.0, 5.0, 1.0, 1.0 };glLightfv(GL_LIGHT0, GL_POSITION, light_position);
Materiały • Podstawowe parametry materiału, tak jak w przypadku świateł, to: ambient, diffuse i specular • Dodatkowo można określić: • Stopień gładkości powierzchni – shininess • Świecenie własnym światłem - emission
Parametry materiałów • Do zmiany parametrów materiału służy funkcja glMaterialfv • Nowe parametry obowiązują dla wszystkich obiektów rysowanych po zmianie • Materiał można określić osobno dla przedniej i tylniej ściany obiektu: GL_FRONT – przód, GL_BACK – tył, GL_FRONT_AND_BACK – dwie strony jednocześnie
Składnia funkcji glMaterialfv GLfloat mat_diff[] = { 0.1, 0.5, 0.8, 1.0 }; glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_diff);
Stos macierzy • Zależności hierarchiczne pomiędzy obiektami realizowane są za pomocą stosu macierzy • OpenGL nie manipuluje bezpośrednio obiektami, jest to biblioteka która rysuje obiekty 3D • To, gdzie zostanie narysowany obiekt zależy od bieżącej macierzy przekształcenia • Macierze można odkładać na stos macierzy i pobierać je z niego • glPushMatrix – odkłada macierz na stos • glPopMatrix – pobiera macierz ze stosu
Użycie stosu macierzy glTranslatef(3,3,0); RysujNadwozie(); glPushMatrix(); glTranslatef(-1.5,-1.5,0); RysujKolo(); glPopMatrix(); glPushMatrix(); glTranslatef(1.5,-1.5,0); RysujKolo(); glPopMatrix(); glPushMatrix(); glTranslatef(-1.5,1.5,0); RysujKolo(); glPopMatrix(); glPushMatrix(); glTranslatef(1.5,1.5,0); RysujKolo();
Tekstury • Teksturami są zwykle bitmapy, czyli tablice zawierające wartości kolorów pikseli • W kartach obsługujących tzw. shader’y możliwe są tekstury proceduralne • Standardowo tekstura powinna być kwadratem, którego długość boku jest potęgą 2 (w najnowszych kartach graficznych usunięto to ograniczenie)