Programowanie układów graficznych Autor: Aleksander Dawid Wykład + Labolatorium 1. OpenGL obsługa podstawowej funkcjonalności GPU 2. GLSL programowanie przetwornika wierzchołków i fragmentów 3. CUDA programowanie ogólnego przeznaczenia 4. OpenCL rozwiązanie niezależne od sprzętu. Aleksander Dawid 2001-2016 rok 1
OpenGL Silicon Graphics (IRIS GL stacje graficzne) Biblioteka -przestrzeń 3D -rzutowanie -prymitywy graficzne -operacje na barwach HISTORIA 1992 - powstaje wersja 1.0 specyfikacji OpenGL przenośnej między platformami. OpenGL Architecture Review Board (SG,HP,IBM) Aleksander Dawid 2001-2012 rok 2
OpenGL 1995 - wersja 1.1 tej biblioteki z wieloma poprawkami przyśpieszającymi wyświetlanie grafiki. OpenGL nie należy do języków opisu sceny. Scena tworzona jest w OpenGL z wielokątów poprzez wywoływanie odpowiednich procedur Języki programowania Pascal,C/C++,Visual Basic,Python,Java Aleksander Dawid 2001-2012 rok 3
OpenGL (WINDOWS) OpenGL nie ma funkcji obsługujących operacje: -wejścia/wyjścia -interakcje z użytkownikiem -zarządzanie oknami. WINDOWS Wprowadzono w wersjach Win95 OSR2 WinNT 3.51/4.0 Obsługa okien w OpenGL - funkcje wiggle. Aleksander Dawid 2001-2012 rok 4
OpenGL (AUX) Wywołania funkcji w OpenGL są zgodne z konwencją wywoływania funkcji w języku C. Biblioteki w systemie WIN32 glaux.lib - Auxiliary(pomocnicza)przenośna glaux.h przedrostek funkcji: aux opengl32.dll gl.h gl glu32.dll glu.h glu Aleksander Dawid 2001-2012 rok 5
OpenGL (AUX) Biblioteka aux raczej jest pewną osnową dla wywoływania f. OpenGL. Zaletą jej jest to, że na każdej platformie wygląda ona tak samo. OpenGl32.dll właściwe wywołania OpenGL. Glu32.dll biblioteka pomocnicza rysowanie skomplikowanych obiektów cylindry, walce, NURBS. Aleksander Dawid 2001-2012 rok 6
OpenGL (Typy danych) OpenGL w celu przenośności między platformami wprowadza swoje typy danych. Glbyte,Glshort,Glint,Glsize,Glfloat, Glclampf,Gldouble,Glclampd,Glubyte, Glboolean,Glushort, Gluint, Glenum, Glbitfield. glclamp - color amplitude Aleksander Dawid 2001-2012 rok 7
OpenGL (Konwencje nazw) <Przedrostek biblioteki><rdzeń polecenia><opcjonalnie liczba argumentów><opcjonalnie typ argumentów> glcolor3f(...) gl - gl.h Color - nazwa 3f - 3 argumenty float. Aleksander Dawid 2001-2012 rok 8
OpenGL (Biblioteka aux) Przewidziana jako wspomaganie dla OpenGL w postaci implementacji przenośnej między systemami. Podstawowe operacje inicjalizujace wej/wyj. Aleksander Dawid 2001-2012 rok 9
OpenGL (kod aux) #include <windows.h> #include <gl\gl.h> #include <gl\glaux.h> void CALLBACK RenderScene(void) { glclearcolor(0.0f, 0.0f, 1.0f, 1.0f); glclear(gl_color_buffer_bit); glcolor3f(1.0f, 0.0f, 0.0f); glrectf(100.0f, 150.0f, 150.0f, 100.0f); glflush(); } void main(void) { auxinitdisplaymode(aux_single AUX_RGBA); auxinitposition(100,100,450,450); auxinitwindow("test2"); auxmainloop(renderscene); } Aleksander Dawid 2001-2012 rok 10
OpenGL (kod aux) auxinitdisplaymode(aux_single AUX_RGBA); Tryb wyświetlania: AUX_SINGLE - pojedynczy bufor AUX_RGBA - tryb kolorów. auxinitposition(100,100,450,450); Pozycja i wymiary okna. auxinitwindow("test2"); Nazwa okna auxmainloop(renderscene); Główna pętla renderowania obrazu. Aleksander Dawid 2001-2012 rok 11
OpenGL (kod aux) glclearcolor(0.0f, 0.0f, 1.0f, 1.0f); Kolor używany do czyszczenia ekranu. Krok koloru - 0.00006 glclear(gl_color_buffer_bit); Wykonanie czyszczenia ekranu. glcolor3f(1.0f, 0.0f, 0.0f); kolor rysowania. glrectf(100.0f, 150.0f, 150.0f, 100.0f); rysujemy prostokąt. Aleksander Dawid 2001-2012 rok 12
OpenGL (kod aux) glflush(); Przetwarzaj dotychczasowe komendy. Nagłówki #include <windows.h> #include <gl\gl.h> #include <gl\glaux.h> Aleksander Dawid 2001-2012 rok 13
Skalowanie okna wyświetlania. Nasz rysunek jest w rzeczywistości w przestrzeni 3D z=0. Przy zmianie wymiarów okna wyświetlania nasz obrazek też powinien być odpowiednio przeskalowany. Do tego służy funkcja auxreshapefunc(far* func), gdzie argumentem jest funkcja zwrotna o następującym prototypie. void CALLBACK ChangeSize(Glsizei w, Glsizei h) funkcja ta otrzymuje wysokość i szerokość z okna macierzystego przy każdej próbie przeskalowania go. Aleksander Dawid 2001-2012 rok 14
Skalowanie okna wyświetlania. Możemy użyć tego do odwzorowania naszego układu współrzędnych na układ współrzędnych ekranu za pomocą funkcji; DEFINIOWANIE WIDOKU glviewport(glint x,glint y, Glint w, Glint h); x,y - prawy dolny róg widoku w,h - szerokość, wysokość Aleksander Dawid 2001-2012 rok 15
Skalowanie okna wyświetlania. DEFINIOWANIE BRYŁY OBCINANIA Po zmianie rozmiaru okna musimy przedefniować bryłę obcinania aby stosunki współrzędnych zostały takie same. Stosunek współrzędnych (aspect ratio) to stosunek ilości pixeli odpowiadający jednostce osi pionowej do ilości pikseli na osi poziomej. 1.0 równe ilości pikseli na osiach. Rzutowanie równoległe glortho(gldouble lewa, Gldouble prawa, GLdouble dolna, GLdouble górna, Gldouble blizsza, Gldouble dalsza); Aleksander Dawid 2001-2012 rok 16
Skalowanie okna wyświetlania. DEFINIOWANIE BRYŁY OBCINANIA glloadidentity(); - macierz jdnostkowa. glortho() modyfikuje istniejące obcinanie. Void CALLBACK ChangeSize(Glsizei w, Glsizei h){ if(h==0) h=1; glviewport(0,0,w,h); glloadidentity(); if(w<=h) glortho(0.0f, 250.0f, 0.0f, 250.0f*h/w, 1.0,-1.0); else glortho(0.0f, 250.0f*w/h, 0.0f, 250.0f, 1.0,-1.0); } auxreshapefunc(changesize); Aleksander Dawid 2001-2012 rok 17
Animacje. Animacje w bibliotece pomocniczej osiągamy przez funkcje; auxidlefunction() gdzie argumentem jest funkcja o prototypie void CALLBACK IdleFunction(void); Funkcja jest wywoływana w momencie bezczynności programu. Nie jest wywoływana w momencie skalowania okna. Z animacją wiąże się problem wyświetlania. Najczęściej wyświetlanie nie nadąża za procesem rysowania co przejawiać się może w miganiu rysowanego obiektu. Aleksander Dawid 2001-2012 rok 18
Animacje. W celu uniknięcia takiego zjawiska stosuje się podwójne buforowanie. Obraz naszej sceny nie jest rysowany na bufor ekranu tylko do pomocniczego bufora, a z niego dopiero a ekran. auxdisplaymode(aux_double,aux_rgba) auxswapbuffers(); Aleksander Dawid 2001-2012 rok 19
Klawiatura. Biblioteka AUX pozwala nam modyfikować naszą scenę przez klawisze. auxkeyfunc(glint key, void(*func()); void CALLBACK KeyFunc(void); AUX_ESCAPE AUX_SPACE AUX_LEFT AUX_RIGHT AUX_UP AUX_DOWN Aleksander Dawid 2001-2012 rok 20
Mysz. Biblioteka AUX pozwala nam na interakcje z naszą sceną prze mysz. auxmousefunc(glint button, Glint mode void(* MouseFunc()); PROTOTYP void CALLBACK MouseFunc(AUX_EVENTREC *event); typedef struct _AUX_EVENTREC{ GLint event; Glint data[4]; }AUX_EVENTREC event - AUX_MOUSEUP,AUX_MOUSEDOWN data[aux_mousex]=pozioma współrzędna myszy data[aux_mousey]=pionowa współrzędna myszy data[mouse_status]=przycisk myszy (button param) Aleksander Dawid 2001-2012 rok 21
OpenGL (kod glut) Nagłówki #include <windows.h> #include <gl\gl.h> #include <gl\glut.h> int main(int argc, char **argv) { glutinit(&argc, argv); // GLUT inicjalizacja glutinitdisplaymode(glut_rgb GLUT_DOUBLE GLUT_DEPTH ); // Wyświetlanie glutinitwindowsize(640,480);// rozmiar okna glutcreatewindow("opengl/glut Window.");// utworzenie Okna glutdisplayfunc(display);// Wyświetlenie funkcji glutidlefunc( display );// Wyświetlanie w fazie bezczynności (Animacje) glutkeyboardfunc( keyboard );// Obsługa klawiszy glutmainloop();// główna pętla GLUT return 0; } Aleksander Dawid 2001-2012 rok 22
Prymitywy graficzne. (2) Rysowanie w 3 wymiarach. Układ współrzędnych określa nam bryła obcinania (glortho). (-100,100) 1. Trójwymiarowy punkt: wierzchołek glvertex2f(10.0f, 10.0f); glvertex3f(10.0f, 10.0f, 0.0f); glvertex4f(10.0f, 10.0f, 0.0f, 1.0f); w - współczynnik skalowania. Aleksander Dawid 2001-2012 rok 23
Prymitywy graficzne. Teraz mamy wierzchołek, wystarczy nam teraz określić czy ten wierzchołek będzie punktem, wierzchołkiem odcinka czy też jakiegoś wieloboku. Zadania wierzchołków grupujemy w pętli. glbegin(glenum mode)... glend() Zestaw punktów w 3D. glbegin(gl_points); glvertex3f(10.0f, 10.0f, 0.0f); glvertex3f(10.0f, 1.0f, 0.0f); glend(); Aleksander Dawid 2001-2012 rok 24
Prymitywy graficzne. Pamiętać trzeba o tym że punkt jest rysowany aktualnie wybranym kolorem. W pętli glbegin/glend można zawrzeć dowolną liczbę prymitywów. Ponawianie ustawiania prymitywu powoduje spowolnienie całego procesu tworzenia grafiki. glbegin(gl_points); for(i=0;i<10;i++) { x+=0.1; y+=0.1; glvertex3f(x,y,0.0f); } glend(); Aleksander Dawid 2001-2012 rok 25
Prymitywy graficzne. Ustalenie rozmiaru punktu. Domyślny rozmiar punktu to 1 pixel. Void glpointsize(glfloat size); size -średnica w pixelach rysowanego punktu. MS GL obsługuje wielkości od 0.05 do 10.0 co 0.125 GLfloat sizes[2]; GLfloat step; glgetfloatv(gl_point_size_range,sizes); glgetflotav(gl_point_size_granularity,&step); Wywołania te dotyczą maszyny stanu OpenGL Aleksander Dawid 2001-2012 rok 26
Prymitywy graficzne Rysowanie linii w 3 wymiarach. glbegin(gl_lines) glvertex3f(0.0,0.0,0.0); glvertex3f(50.0,50.0,50.0); glend(); Musimy podawać parzystą liczbę wierzchołków. Inaczej ostatni wierzchołek będzie ignorowany. Łamana GL_LINE_STRIP glbegin(gl_line_strip) glvertex3f(0.0,0.0,0.0); glvertex3f(50.0,50.0,50.0); glvertex3f(50.0,10.0,50.0); glend(); Aleksander Dawid 2001-2012 rok 27
Prymitywy graficzne Łamana zamknięta GL_LINE_LOOP glbegin(gl_line_loop) glvertex3f(0.0,0.0,0.0); glvertex3f(50.0,50.0,50.0); glvertex3f(50.0,10.0,50.0); glend(); Po napotkaniu ostatniego punktu krzywa jest zamykana. Ustalenie grubości linii. gllinewidth(glfloat width) Informacje o szerokości możemy uzyskać z maszyny stanu OpenGL. Aleksander Dawid 2001-2012 rok 28
Prymitywy graficzne glgetfloatv(gl_line_width_range,sizes); glgetfloatv(gl_line_width_ggranularity,&size); Linie przerywane. glenable(gl_line_stipple); gllinestipple(glint factor, Glushort pattern); Wyłączamy za pomocą gldisable(); pattern 16-bit 0000000011111111 = 0x00FF = 255; factor służy jako mnożnik zwiększający szerokość wzoru. Aleksander Dawid 2001-2012 rok 29
Prymitywy graficzne Rysowanie wielokątów w przestrzeni 3D. Trójkąt. glbegin(gl_triangles) glvertex3f(0.0,0.0,0.0); glvertex3f(25.0,25.0,0.0); glvertex3f(50.0,0.0,0.0); glend(); Kolejność określa nam kierunek rysowanego trójkąta. Zgodnie ze wskazówkami zegara lub przeciwnie. OpenGL zakłada, że wielokąty skierowane przeciwnie do wskazówek zegara są do nas zwrócone przodem. Jeśli chcesz to zmienić to glfrontface(gl_cw); GL_CCW Aleksander Dawid 2001-2012 rok 30
Prymitywy graficzne Rysowanie paska trójkątów. GL_TRIANGLE_STRIP Ilość wierzchołków może być większa od 3. Kolejność wierzchołków nie jest zachowana. Anticlockvise - kierunek przeciwny do wskazówek zegara musi być zachowany. Wachlarze trójkątów. GL_TRIANGLE_FAN Opcja ta służy do tworzenia zbioru trójkątów o wspólnym punkcie. Pierwszy wierzchołek wyznacza wspólny punkt dla wachlarza trójkątów. Aleksander Dawid 2001-2012 rok 31
Prymitywy graficzne (jednolite obiekty) Prze tworzeniu złożonych obiektów musimy się zastanowić nad tym jaki jest nasz obiekt. O kolorze wielokąta decyduje pirwszy wierzchołek w wielokącie, przy modelu w którym kolor jest jednolity. Wybór modelu koloru. glshademodel(gl_flat); - jednolity kolor glshademodel(gl_smooth); - interpolacja kolorów pośrednich. glbegin(gl_triangles) glcolor3f(1.0f,0.0f,0.0f); glvertex3f(0.0,0.0,0.0); glvertex3f(25.0,25.0,0.0); glvertex3f(50.0,0.0,0.0); glend(); Aleksander Dawid 2001-2012 rok 32
Prymitywy graficzne (bufor głębokości) W OpenGL obiekt rysowany jako drugi zawsze przesłania obiekt pierwszy. Problem ten można usunąć dzięki technice zwanej buforem głębokości. glenable(gl_depth_test); Testowane są pixele aby wyznaczyć te które są bliżej od tych które są dalej. W celu poprawy wydajności programu stosuje się nie rysowanie tylnych powierzchni. Aleksander Dawid 2001-2012 rok 33
Prymitywy graficzne (usuwanie niewidocznych). Eliminacja wielokątów skierowanych tyłem nazywa się usuwaniem niewidocznych powierzchni. glenable(gl_cull_face); Wielokąty mogą być rysowane jako siatki lub wypełnione. glpolygonmode(gl_front_and_back,gl_line); glpolygonmode(gl_back,gl_fill); Można to ustawiać zarówno dla tyłu jak i przodu. Aleksander Dawid 2001-2012 rok 34
Prymitywy graficzne (usuwanie niewidocznych) Czworokąty. GL_QUADS GL_QUAD_STRIP - pasek wielokątów. Ogólne wielokąty. GL_POLYGON może być używany do rysowania wielokąta o dowolnej liczbie krawędzi. Wypełnianie jednolitych wielokątów. Mapowanie tekstur. Określanie desenia. glenable(gl_polygon_stipple); glpolygonstipple(pbitmap); Aleksander Dawid 2001-2012 rok 35
Prymitywy graficzne (desenie) Wskaźnik do obszaru danych zawierający dane desenia. Glubyte *pbitmap; pbitmap=new Glubyte[16] 32bit x 32bit delete[] pbitmap; Warunki konstruowania wielokątów to 1. Nie wolno produkować wygiętych wielokątów. 2. Tylko wielokąty wypukłe. Aleksander Dawid 2001-2012 rok 36
Prymitywy graficzne (krawędzie). Figury wklęsłe można także konstruować w OpenGl składając je z kilku figur wypukłych. Gdy chcemy zachować krawędzie zewnętrzne jako widoczne to wystarczy podać czy ta krawędź należeć będzie do krawędzi zewnętrznych czy też nie. gledgeflag(true/false); glvertex2f(-20.0f,0.0f); Aleksander Dawid 2001-2012 rok 37
Przekształcenia w 3D Umożliwiają rzutowanie trójwymiarowych współrzędnych na dwuwymiarowy ekran. Najpierw musimy określić położenie obserwatora. Są to bezwzględne współrzędne ekranowe. Przekształcenie punktu obserwacji. Odpowiada ustawieniu i skierowaniu kamery na scenę. Przekształcenie modelu. Aleksander Dawid 2001-2012 rok 38
Przekształcenia w 3D (rzutowanie) Rzutowanie definiuje bryłę widzenia i definiuje bryłę obcinania. Równoległe glortho(..) równoległa bryła rzutowania -------------------------------- Perspektywiczne Ostrosłup widzenia w kierunku oka. glfrustum(gldouble left,right,bottom,top,near,far) - mnoży bieżącą macierz przez macierz rzutowania perspektywicznego. Aleksander Dawid 2001-2012 rok 39
Przekształcenia w 3D (rzutowanie) Znacznie lepszym rozwiązaniem jest funkcja void gluperspective(gldouble fovy, Gldouble aspect, Gldouble znear, Gldouble zfar) fovy - kąt pola widzenia w kierunku pionowym. Aspect - stosunek wysokości do szerokości bryły znear,zfar - odległości od bliższej i dalszej płaszczyzny. Dodatkowo co nam oferuje utility to funkcja glulookat(okox,okoy,okoz,punktx,punkty,punktz, gorax,goray,goraz); Pozwala ona na umieszczenie oka kamery w dowolnym punkcie. Aleksander Dawid 2001-2012 rok 40
Przekształcenia w 3D (rzutowanie) Rzutowanie definiuje bryłę widzenia i definiuje bryłę obcinania. Macierz widoku modelu 4x4 V*M=V Translacje. void gltranslatef(glfloat x, Glfloat y, Glfloat z) gltranslatef(0.0,10.0,0.0); Aleksander Dawid 2001-2012 rok 41
Przekształcenia w 3D (rzutowanie) Obroty. glrotatef(glfloat angle, Glfloat x, Glfloat y, Glfloat z); Kierunek obrotu jest określany w stopniach. Skalowanie. glscalef(glfloat x, Glfloat y, Glfloat z); Ściskanie i rozciąganie. Aleksander Dawid 2001-2012 rok 42
Przekształcenia w 3D (rzutowanie) Macierz tożsamościowa(jednostkowa). glmatrixmode(gl_modelview) Macierz modelu widoku. glloadidentity(); Ładuje macierz tożsamościową do bierzącej macierzy. Stos macierzy. Maksymalna wysokość stosu. glget(gl_max_model_view_stack_depth); glget(gl_max_projection_stack_depth); GL_STACK_OVERFLOW - przepełnienie stosu GL_STACK_UNDERFLOW - zdejmowanie ze stosu pustego. Aleksander Dawid 2001-2012 rok 43
Przekształcenia w 3D (rzutowanie) glpushmatrix(); Rotacje,translacje. glpopmatrix(); Własne macierze transformacji. Glfloat m[]={1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f} glmatrixmode(gl_modelview) glloadmatrix(m) // ładowanie macierzy jako bieżącej. glmatrixmode(gl_modelview) glmultmatrixf(m); // mnożenie macierzy Aleksander Dawid 2001-2012 rok 44
Kolory w OpenGL Dwie metody RGBA i color index. RGBA (red,green,blue,alpha) Color index wybrane kolory z większej palety glcolor4f(1.0f,1.0f,0.0f,1.0f); glcolori(12); Aleksander Dawid 2001-2012 rok 45
Światła w scenie (fotorealizm) (3) Światła: - otoczenia (ambient light) - rozproszone (diffuse) - odbłyski (specular) Światła w naszej scenie obliczamy załączając glenable(gl_lighting); Samo załączenie nic nie daje, trzeba jeszcze określić model oświetlenia. Bez tego nasz obiekt jest 2-wymiarowy. Najpierw określamy światło otoczenia. Glfloat ambient[] = {1.0f,1.0f,1.0f,1.0f} gllightmodelfv(gl_light_model_ambient,ambient); Aleksander Dawid 2001-2012 rok 46
Światła w scenie (fotorealizm) Właściwości materiałów. Nasze wielokąty muszą odbijać światło. Glfloat green[]={0.0f,0.75f,0.0f,1.0f); glmaterialfv(gl_front, GL_AMBIENT_AND_DIFFUSE, green); Przy załączonym oświetleniu tylko w ten sposób można określić kolor naszego trójkąta. glbegin(gl_triangles);... glend(); Aleksander Dawid 2001-2012 rok 47
Światła w scenie (fotorealizm) Generalnie teraz nie widać różnicy w naszej scenie. Faktyczna siła świateł tkwi w rozpraszaniu i odbłyskach. Właściwości materiału można określać dla przedniej lub tylnej ściany. GL_FRONT, GL_BACK, GL_FRONT_AND_BACK Inna metoda to śledzenie kolorów z użyciem glcolor jako funkcji określającej kolor. glenable(gl_color_material); glcolormaterial(gl_front, GL_AMBIENT_AND_DIFFUSE); Aleksander Dawid 2001-2012 rok 48
Światła w scenie (fotorealizm) Do bardziej realistycznych scen potrzebne nam są światła umiejscowione. Źródła te posiadają położenia, intensywności, kolory jak i kierunek padania. Aby biblioteka wiedziała jak mocno rozświetlić daną płaszczyznę potrzebuje aby został określony wektor normalny do płaszczyzny naszego wielokąta. Aleksander Dawid 2001-2012 rok 49
Wektor normalny Mając trzy punkty w przestrzeni możemy obliczyć wektory określające przestrzeń 2D V1 i V2 następnie produkt V1 x V2 da nam wektor prostopadły do naszej płaszczyzny. b a c Aleksander Dawid 2001-2012 rok 50
Wektor normalny void ReduceToUnit(float vector[3]) { float length; // Calculate the length of the vector length = (float)sqrt((vector[0]*vector[0]) + (vector[1]*vector[1]) + (vector[2]*vector[2])); if(length == 0.0f) length = 1.0f; vector[0] /= length; vector[1] /= length; vector[2] /= length; } Aleksander Dawid 2001-2012 rok 51
Wektor normalny void NormV(GLfloat va[3], GLfloat vb[3], GLfloat vc[3], GLfloat out[3]) { float v1[3],v2[3]; static const int x = 0, y=1, z=2; v1[x] = vb[x] - va[x]; v1[y] = vb[y] - va[y]; v1[z] = vb[z] - va[z]; v2[x] = vc[x] - va[x]; v2[y] = vc[y] - va[y]; v2[z] = vc[z] - va[z]; out[x] = v1[y]*v2[z] - v1[z]*v2[y]; out[y] = v1[z]*v2[x] - v1[x]*v2[z]; out[z] = v1[x]*v2[y] - v1[y]*v2[x]; ReduceToUnit(out); } Aleksander Dawid 2001-2012 rok 52
Wektor normalny OpenGL Kąt obserwatora - kąt między wektorem normalnym a promieniem padania światła zrzutowany na płaszczyznę widzenia Kąt obserwatora jest miarą jasności danego wielokąta Glfloat va[3] = {40.0f,0.0f,0.0f}; Glfloat vb[3] = {0.0f,60.0f,0.0f}; Glfloat vc[3] = {-40.0f,0.0f,0.0f}; normlight[3]; NormV(va, vb, vc, normlight); glbegin(gl_trangle); glnormal3fv(&normlight); glvertex3fv(&va); glvertex3fv(&vb); glvertex3fv(&vc); glend(); Aleksander Dawid 2001-2012 rok 53
Światła w scenie (fotorealizm) Przygotowanie źródła światła. Glfloat ambient[]={0.3,0.3,0.3,1.0f} Glfloat diffuse[]={0.7,0.7,0.7,1.0} gllightfv(gl_light0,gl_ambient,ambient); gllightfv(gl_light0,gl_diffuse,diffuse); Glfloat lpos[]={-50.0f,50.0f,100.0f,1.0f} gllightfv(gl_light0,gl_position,lpos); glenable(gl_light0); Do ustalenia koloru możemy także użyć funkcji glrgb(0,255,0); Aleksander Dawid 2001-2012 rok 54
Światła w scenie (fotorealizm) Przygotowanie źródła światła. Glfloat specular[]={1.0,1.0,1.0,1.0f} gllightfv(gl_light0,gl_specular,specular); Ostatnia linia definiuje światło jasno białe dla odbłysków. STOPIEŃ POŁYSKLIWOŚCI. glmateriali(gl_front,gl_shininess,128); Określa jak mała i skupiona będzie plama połysku. Aleksander Dawid 2001-2012 rok 55
Światła w scenie (fotorealizm) Domyślnie światło rozchodzi się w każdym kierunku. W celu przeniesienia światła do nieskończoności trzeba w ostatnim elemencie dać wartość zero. Światło punktowe załączamy przez gllightf(gl_light0,gl_spot_cutof,60.0f); gllightf(gl_light0,gl_spot_exponent,100.0f); glpushattrib(gl_lighting_bit); Instrukcja zachowuje stan oświetlenia. glpopattrib(); Przywraca pierwotny stan oświetlenia. Aleksander Dawid 2001-2012 rok 56
Cienie (fotorealizm) Tworzenie cieni nie jest zaimplementowane w OpenGL bezpośrednio. Cienie można stworzyć programowo na kilka sposobów. Na podstawie równania płaszczyzny i położenia światła tworzy się macierz rzutu cienia. Macierz ta jest zwykłą macierzą rzutowania perspektywicznego, z tą różnicą, że punktem położenia obserwatora jest tutaj położenie źródła światła. Jeśli tę macierz będziemy mnożyć przez macierz widoku modelu, to obiekty będą spłaszczane na tę płaszczyznę Aleksander Dawid 2001-2012 rok 57
Cienie (fotorealizm) // Procedura tworząca macierz rzutu cienia. void MakeShadowMatrix(GLfloat points[3][3], GLfloat lightpos[4], GLfloat destmat[4][4]) { GLfloat planecoeff[4]; GLfloat dot; // Znalezienie współczynników równania płaszczyzny // Wyszukanie trzech pierwszych współczynników tak samo // jak przy znajdowaniu normalnej calcnormal(points,planecoeff); // Znalezienie ostatniego współczynnika przez zastępowanie wstecz planecoeff[3] = - ( (planecoeff[0]*points[2][0]) + (planecoeff[1]*points[2][1]) + (planecoeff[2]*points[2][2])); Aleksander Dawid 2001-2012 rok 58
Cienie (fotorealizm) // Iloczyn skalarny płaszczyzny i położenia światła dot = planecoeff[0] * lightpos[0] + planecoeff[1] * lightpos[1] + planecoeff[2] * lightpos[2] + planecoeff[3] * lightpos[3]; // A teraz rzutowanie // Pierwsza kolumna destmat[0][0] = dot - lightpos[0] * planecoeff[0]; destmat[1][0] = 0.0f - lightpos[0] * planecoeff[1]; destmat[2][0] = 0.0f - lightpos[0] * planecoeff[2]; destmat[3][0] = 0.0f - lightpos[0] * planecoeff[3]; // Druga kolumna destmat[0][1] = 0.0f - lightpos[1] * planecoeff[0]; destmat[1][1] = dot - lightpos[1] * planecoeff[1]; destmat[2][1] = 0.0f - lightpos[1] * planecoeff[2]; destmat[3][1] = 0.0f - lightpos[1] * planecoeff[3]; Aleksander Dawid 2001-2012 rok 59
Cienie (fotorealizm) // Trzecia kolumna destmat[0][2] = 0.0f - lightpos[2] * planecoeff[0]; destmat[1][2] = 0.0f - lightpos[2] * planecoeff[1]; destmat[2][2] = dot - lightpos[2] * planecoeff[2]; destmat[3][2] = 0.0f - lightpos[2] * planecoeff[3]; } // Czwarta kolumna destmat[0][3] = 0.0f - lightpos[3] * planecoeff[0]; destmat[1][3] = 0.0f - lightpos[3] * planecoeff[1]; destmat[2][3] = 0.0f - lightpos[3] * planecoeff[2]; destmat[3][3] = dot - lightpos[3] * planecoeff[3]; Program shadows.c Aleksander Dawid 2001-2012 rok 60
Listy wyświetalania Listy wyświetlania przyspieszają wykonywanie programu OpenGL w przypadku dużej liczby wielokątów. PROCEDURA glnewlist(1, GL_COMPILE);... Kod OpenGL glendlist(); Następnie wywołanie tak przygotowanej listy wygląda następująco glcalllist(1); Zamiast 1 można zasosować dowolny identyfikator Gluint list Aleksander Dawid 2001-2012 rok 61
Grafika rastrowa BITMAPY. Obrazki 2 - kolorowe. Kolor 0 - przezroczysty 1 - bieżący. Do rysowania bitmap służy funkcja glbitmap glbitmap(glsizei width,glsizei height, Glfloat xorig,glfloat yorig,glfloat xmove, Glfloat ymove,const Glubyte *bits) xorig,yorig - położenie środka xmove,ymove - przesunięcie w bitmapie. Do ustalenia pozycji obrazka na naszym oknie służy. glrasterpos2i(x,y); Aleksander Dawid 2001-2012 rok 62
Grafika rastrowa CZCIONKI BITMAPOWE. Aby w OpenGL wyświetlić jakieś teksty na ekranie trzeba przygotować odpowiedni zestaw czcionek. Gluint base; HDC hdc; base=glgenlists(96); wglusefontbitmaps(hdc,32,96,base); Tworzy 96 bitmap znaków poczynając od kodu 32 gllistbase(font-32); glcalllists(strlen(s), GL_UNSIGNED_BYTE, s); Aleksander Dawid 2001-2012 rok 63
Grafika rastrowa Funkcja gllistbase ustawia wartość bazową list wyświetlania. glcalllists - wyświetla nam nasze czcionki wg. zadanego tekstu. Czcionkę możemy ustawić funkcjami Win32 font=createfont(...) SelectObject(hdc,font); Aleksander Dawid 2001-2012 rok 64
Grafika rastrowa. PIXMAPY Obrazy zawierające więcej niż 2 kolory nazywamy pixmapami. Do rysowania pixmap służy funkcja gldrawpixels(glsizei width, Glsizei height, Glenum format, Glenum type, Glvoid *pixels) format GL_COLOR_INDEX GL_RGB GL_LUMINANCE type GL_BYTE GL_UNSIGNED_BYTE GL_BITMAP Aleksander Dawid 2001-2012 rok 65
Grafika rastrowa REMAPOWANIE KOLORÓW glpixeltransfer(gl_red_scale, 1.1); glpixeltransfer(gl_green_scale, 1.1); glpixeltransfer(gl_blue_scale, 1.1); Kod rozjaśnia obraz RGB o 10% SKALOWANIE PIXMAP glpixelzoom(1.0,1.0);brak skalowania glpixelzoom(-1.0,1.0);odbicie lustrzane w poziomie glpixelzoom(0.2,0.2);zmniejszenie obrazka Aleksander Dawid 2001-2012 rok 66
Grafika rastrowa WYKRAWANIE OBSZARÓW glpixelstore(gl_unpack_row_lenght, 640); glpixelstore(gl_unpack_skip_pixels, 100); glpixelstore(gl_unpack_skip_rows, 100); gldrawpixels(300,300,gl_rgb,gl_unsigned_byte,bi tmapbits); ODCZYTYWANIE PIXMAP Z EKRANU glreadpixels(glint x,glint y,glsizei width Glsizei height, Glenum format, Glenum type, const Glvoid *pixels); Aleksander Dawid 2001-2012 rok 67
Mapowanie tekstur Nakładanie obrazów na wielokąty w scenie. Akceleratory 3D same mapują tekstury. Definiowanie textur 1D glteximage1d(glenum target,glint level,glint components,glsizei width, Glint border, Glenum format, Glenum type, const Glvoid *pixels); target - określa jaka tekstura powinna być zdefiniowana (GL_TEXTURE_1D) level - poziom szczegółów obrazu zwykle 0 jak nie ma mipmapy. Components - okresla ilosc wartosci koloru dla jednego pixela RGB=3, RGBA=4 Aleksander Dawid 2001-2012 rok 68
Mapowanie tekstur Width - długość ciągu pixeli musi stanowić potęgę 2. border - pixle ramki format - określa w jakim formacie zapisane są kolory (GL_COLOR_INDEX, GL_RGB, GL_RGBA, GL_LUMINANCE); FILTRY POWIĘKSZENIA I POMNIEJSZENIA. gltexparameteri(gl_texture_1d, GL_TEXTURE_MIN_FILTER,GL_LNEAR); gltexparameteri(gl_texture_1d,gl_texture_mag_filter,gl_lnear); GL_NEAREST,GL_LINEAR, GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST_MIPMAP_LINEAR - liniowo interpolowana mipmapa GL_LINEAR_MIPMAP_LINEAR - liniowo interpolacja interpolowanych mipmap. GL_NEAREST - najlepsza wydajnosc. Aleksander Dawid 2001-2012 rok 69
Mapowanie tekstur Definiowanie textur 2D glteximage2d(glenum target,glint level, Glint components, Glsizei width, Glsizei height, Glint border, Glenum format, Glenum type, const Glvoid *pixels) Dodany jedynie height czyli wysokość mapowanego obrazka. width i height muszą być rozmiaru potęg liczby 2 2,4,8,16,32,64,128,256,512,1024 Aleksander Dawid 2001-2012 rok 70
Mapowanie tekstur Rysowanie wielokątów z nałożoną teksturą. Teksturowanie trzeba załączyć glenable(gl_texture_nd); gltexenvi(gl_texture_env,gl_texture_env_mode, GL_DECAL); Ustawienie teksturowania w tryb kafelków. GL_MODULATE - piksele tekstury filtrują kolory istniejących pikseli na ekranie GL_DECAL GL_BLEND - łączenie ze stałym kolorem. Symulacja chmur. Aleksander Dawid 2001-2012 rok 71
Mapowanie tekstur MIPMAPY Pozwalają zastosować zmienny poziom szczegółów w zależności od odległości od obserwatora. Użycie mniejszych obrazków zwiększa wiarygodność sceny jak i wydajność kodu. Wprowadzamy mipmapy przez funkcje glteximagend podając level i odpowiadającą mu mapę. glteximage2d(gl_texture_2d,0,3,128,128,gl_rgb,gl_unsigned_byte, imagebits0); glteximage2d(gl_texture_2d,1,3,128,128,gl_rgb,gl_unsigned_byte, imagebits1); GL_LINEAR_MIPMAP_LINEAR; Aleksander Dawid 2001-2012 rok 72
Przykładowy Program mapowanie tekstur GLvoid PolygonTex(GLvoid) { GLfloat s=1.0f; glenable(gl_texture_2d); gltexenvi(gl_texture_env, GL_TEXTURE_ENV_MODE, GL_DECAL); glcalllist(walltexture); } glbegin(gl_polygon); gltexcoord2f(0.0, 0.0); glvertex3f(-4.0,-1.0,1.0); gltexcoord2f(s, 0.0); glvertex3f(4.0,-1.0,1.0); gltexcoord2f(s, s); glvertex3f(4.0,-1.0,-5.0); gltexcoord2f(0.0, s); glvertex3f(-4.0,-1.0,-5.0); glend(); Aleksander Dawid 2001-2012 rok 73
Kwadryki (4) GLU32.DLL biblioteka utility OpenGL W niej zdefiniowane są proste kształty 3D takie jak cylindry,sfery,walce,dyski,powierzchnie. GLUquadricObj *quadobj; Struktura danych w której przechowywane są informacje na temat wierzchołków, normalnych, współrzędnych tekstur, sposobu łączenia wierzchołków i wiele innych. Dostęp do tych parametrów zapewniają odpowiednie funkcje. quadobj = glunewquadric(); Instrukcja tworzy nowy obiekt quadobj gludeletequadric (quadobj); Instrukcja niszczy obiekt quadobj i zwalnia pamięć gluquadriccallback (quadobj, GLenum which, void (*fn)()); fn funkcja kontrolna wywoływana w przypadku błędów. Aleksander Dawid 2001-2012 rok 74
Kwadryki gluquadricorientation(quadobj,glu_outside); Kontrola kierunku wektorów normalnych GLU_OUTSIDE na zewnątrz figury GLU_INSIDE do wnętrza figury gluquadricnormals (quadobj, GLU_SMOOTH); Definiuje wektory normalne. GLU_NONE - wartość domyślna, brak wektorów normalnych, stosowana przy braku oświetlenia. GLU_FLAT generowanie wektorów normalnych dla każdej powierzchni, stosowane w przypadku cieniowania. GLU_SMOOTH generowani wektorów normalnych dla każdego wierzchołka, najlepsza jakość przy oświetleniu. Aleksander Dawid 2001-2012 rok 75
Kwadryki gluquadricdrawstyle (quadobj, GLU_LINE); Ustawia styl renderowania obiektów. GLU_POINT wierzchołki przedstawiane jako punkty. GLU_LINE wierzchołki połączone liniami, model szkieletowy. GLU_SILHOUETTE wierzchołki połączone liniami, stosowane w dyskach. GLU_FILL wypełnione wielokąty, rysowane zgodnie z kierunkiem wskazywanym przez wektory normalne. gluquadrictexture (quadobj, GLU_TRUE); Funkcja odpowiedzialna za generowanie współrzędnych tekstury GLU_FALSE Wartość domyślna, brak generowania współrzędnych tekstury. GLU_TRUE Załączone generowanie współrzędnych tekstury, zależne od typu obiekty kwadryki. Aleksander Dawid 2001-2012 rok 76
Kwadryki - prymitywy glusphere(quadobj, radius, gridalfa, gridgama); radius - promień sfery gridalfa - rozdzielczość elementów pozioma gridgama - rozdzielczość elementów pionowa glucylinder(quadobj,rbase,rtop,height,slices,stacks); Rbase - promień podstawy Rtop - promień wierzchołka Height - wyskość slices,stacks - określają z ilu elementów składa się obiekt. gludisk(quadobj,rinner,router,slices,loops); Rinner - promień wewnętrznego dysku. Router - promień zewnętrznego dysku. slices,loops - określają z ilu elementów składa się obiekt. Aleksander Dawid 2001-2012 rok 77
Kwadryki - prymitywy glupartialdisk(quadobj,rinner,router,slices,loops,starta ngle, sweepangle); Rinner - promień wewnętrznego dysku Router - promień zewnętrznego dysku slices,loops - określają z ilu elementów składa się obiekt startangle kąt startowy sweepangle kąt częściowego dysku Aleksander Dawid 2001-2012 rok 78
Kwadryki - program GLvoid RenderQuadrics() { glenable(gl_lighting); glshademodel (GL_SMOOTH); gltranslatef(-1.0, -1.0, 0.0); glcalllist(startlist); glshademodel (GL_FLAT); gltranslatef(0.0, 2.0, 0.0); glpushmatrix(); glrotatef(300.0, 1.0, 0.0, 0.0); glcalllist(startlist+1); glpopmatrix(); gldisable(gl_lighting); glcolor3f(0.0, 1.0, 1.0); gltranslatef(2.0, -2.0, 0.0); glcalllist(startlist+2); } glcolor3f(1.0, 1.0, 0.0); gltranslatef(0.0, 2.0, 0.0); glcalllist(startlist+3); Aleksander Dawid 2001-2012 rok 79
Przezroczystość Przezroczystość (BLENDING). Polega na łączeniu kolorów czyli kontrolowaniu wartości RGBA poszczególnych pixeli. Wartość A odpowiada bezpośrednio za blending. Kolor źródłowy(r s,g s,b s,a s ) Kolor docelowy(r d,g d,b d,a d ) Czynniki przezroczystości źródła (S r,s g,s b,s a ) Czynniki przezroczystości docelowy (D r,d g,d b,d a ) Równanie przezroczystości (R s S r +R d D r, G s S g +G d D g, B s S b +B d D b, A s S a +A d D a ) glenable(gl_blend). Załączenie łączenia kolorów bieżącego z kolorem zeskładowanym w buforze ramki. gldisable(gl_blend) - wyłączenie obliczeń kolorów. Aleksander Dawid 2001-2012 rok 80
Przezroczystość glblendfunc(gl_src_alpha,gl_one_minus_src_alpha); Parametry określają sposoby łączenia kolorów źródłowego i docelowego. Dla tych ustawień kolor alpha będzie określał przezroczystość. GL_ZERO źródło lub przeznaczenie (0, 0, 0, 0) GL_ONE źródło lub przeznaczenie (1, 1, 1, 1) GL_DST_COLOR źródło (Rd, Gd, Bd, Ad) GL_SRC_COLOR przeznaczenie (Rs, Gs, Bs, As) GL_ONE_MINUS_DST_COLOR źródło (1, 1, 1, 1)-(Rd, Gd, Bd, Ad) GL_ONE_MINUS_SRC_COLOR przeznaczenie (1, 1, 1, 1)-(Rs, Gs, Bs, As) GL_SRC_ALPHA źródło lub przeznaczenie (As, As, As, As) GL_ONE_MINUS_SRC_ALPHA źródło lub przeznaczenie (1, 1, 1, 1)-(As, As, As, As) GL_DST_ALPHA źródło lub przeznaczenie (Ad, Ad, Ad, Ad) GL_ONE_MINUS_DST_ALPHA źródło lub przeznaczenie (1, 1, 1, 1)-(Ad, Ad, Ad, Ad) GL_SRC_ALPHA_SATURATE źródło (f, f, f, 1); f=min(as, 1-Ad) Aleksander Dawid 2001-2012 rok 81
Przezroczystość GLvoid drawscene(glvoid) { glclearcolor( 0.0F, 0.0F, 0.0F, 0.0F); glcleardepth( 1.0 ); glclear( GL_COLOR_BUFFER_BIT GL_DEPTH_BUFFER_BIT); if(x>2.0)x=0; x+=0.01; glpushmatrix(); drawrighttriangle(); glpopmatrix(); glpushmatrix(); gltranslatef(x,0.0f,0.0f); drawlefttriangle(); glpopmatrix(); } SWAPBUFFERS; GLvoid initializegl(glsizei width, GLsizei height) { glenable (GL_BLEND); glblendfunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glshademodel (GL_FLAT); glclearcolor( 0.0f, 0.0f, 0.0f, 0.0f); } Aleksander Dawid 2001-2012 rok 82
Antialiasing Wygładzanie krawędzi krzywych Problem pojawia się gdy krzywe rysowane są pod dużym kątem, wtedy pojawiają się na krzywej schodki. Obraz bez antialiasingu Obraz z antialiasingiem Wygładzanie polega na dodaniu dodatkowych krzywych pokrywających. Realizacja tego zadania zależy od sterowników karty graficznej Aleksander Dawid 2001-2012 rok 83
Antialiasing Jakość krzywych glhint(glenum target, GLenum hint) Hint: GL_FASTEST, GL_NICEST, GL_DONT_CARE Parametr GL_POINT_SMOOTH_HINT, GL_LINE_SMOOTH_HINT, GL_POLYGON_SMOOTH_HINT Znaczenie Określa jakość próbkowania dla punktów,linii, lub wielokątów podczas operacji antialiasingu GL_FOG_HINT GL_PERSPECTIVE_CORRECTION_ HINT Określa czy obliczenia dla mgły maja być wykonane dla piksla (GL_NICEST) lub dla wierzchołka (GL_FASTEST) Określa jakość danego koloru i interpolacji współrzędnych tekstury. Aleksander Dawid 2001-2012 rok 84
Mgła Mgła (FOG). Dodanie efektu atmosferycznego czyli zależnego od głębokości cieniowania każdego elementu sceny polega na wymieszaniu pewnego koloru z każdym wierzchołkiem lub obiektem tekstury. glenable(gl_fog); Wybieramy rodzaj mgły. glfogi(gl_fog_mode, GL_LINEAR); GL_EXP,GL_EXP2 Wybieramy kolor mgły. GLfloat fogcolor[4] = {0.7F, 0.8F, 1.0F, 1.0F}; glfogfv (GL_FOG_COLOR, fogcolor); Aleksander Dawid 2001-2012 rok 85
Mgła Mgła (FOG). Symuluje efekty atmosferyczne takie jak mgły, zadymienie, zanieczyszczenie środowiska. Pozwala obiektom dalekim płynnie znikać. Możemy kontrolować gęstość mgły jak i jej kolor. glfogf (GL_FOG_DENSITY, 0.005); glfogi(gl_fog_mode, GL_EXP); F=e -(density.z) (GL_EXP) F=e -(density.z)^2) (GL_EXP2) F=(end-z)/(end-start)(GL_LINEAR) glhint (GL_FOG_HINT, GL_DONT_CARE); Aleksander Dawid 2001-2012 rok 86
Mgła GLfloat fogcolor[4] = {0.5, 0.5, 0.5, 1.0}; glfogi (GL_FOG_MODE, GL_EXP); glfogfv (GL_FOG_COLOR, fogcolor); glfogf (GL_FOG_DENSITY, 0.065f); glhint (GL_FOG_HINT, GL_DONT_CARE); glfogf (GL_FOG_START, 1.0); glfogf (GL_FOG_END, 5.0); Aleksander Dawid 2001-2012 rok 87
Krzywe glmap1f(glenum target,glfloat u1,glfloat u2, GLint stride,glint order,const GLfloat *points) Funkcja rysuje krzywe Beziera na podstawie punktów kontrolnych. Target - typ. współrzędnych GL_MAP1_VERTEX_3 - wierzchołki (x, y, z). GL_MAP1_COLOR_4 - kolory punktów w postaci (r, g, b, a). GL_MAP1_TEXTURE_COORD_2 - współrzędne w obszarze tekstury (s, t). GL_MAP1_NORMAL - współrzędne wektora normalnego (nx, ny, nz). u1,u2 to dziedzina funkcji Stride - oznacza liczbę współrzędnych składających się na każdy punkt kontrolny order - liczba punktów kontrolnych Aleksander Dawid 2001-2012 rok 88
Krzywe glenable(target); void glmapgrid1f(glint n, GLfloat u1, GLfloat u2) N określa ilość punktów krzywej do obiczeń, u1,u2 dziedzina void glevalmesh1(glenum mode, GLint p1, GLint p2) mode - GL_ POINTS, GL_LINE p1 i p2 oznaczają numery próbek, od których zaczynamy i na których kończymy obliczenia. Aleksander Dawid 2001-2012 rok 89
Krzywe float fctrlpointsarray[4][3]= { {(0.0f/3.0f)*4.0f-2.0f,(1.0f)*4.0f-2.0f,0.0f}, {(1.0f/3.0f)*4.0f-2.0f,(3.0f/4.0f)*4.0f-2.0f,0.0f}, {(2.0f/3.0f)*4.0f-2.0f,(3.0f/5.0f)*4.0f-2.0f,0.0f}, {(3.0f/3.0f)*4.0f-2.0f,(1.0f/2.0f)*4.0f-2.0f,0.0f} }; void Init(void) { glclearcolor(0.0,0.0,0.0,0.0); glmap1f(gl_map1_vertex_3,0.0,1.0,3,4,&fctrlpointsarray[0][0]); glenable(gl_map1_vertex_3); glmapgrid1f(100,0.0,1.0); } void CALLBACK Display(void) { glclear(gl_color_buffer_bit); glcolor3f(1.0,1.0,1.0); glevalmesh1(gl_line,0,100); glpointsize(3.0); glcolor3f(1.0,0.0,0.0); glbegin(gl_points); for (i=0;i<4;i++) glvertex3fv(&fctrlpointsarray[i][0]); glend(); glflush(); } Aleksander Dawid 2001-2012 rok 90
Powierzchnie void glmap2f(glenum target,glfloat u1,glfloat u2,glint ustride,glint uorder,glfloat v1, GLfloat v2,glint vstride,glint vorder,const GLfloat *points); MAP1 -> MAP2 void glmapgrid2f(glint nu, Glfloat u1, Glfloat u2, GLint nv, Glfloat v1, Glfloat v2) void glevalmesh2(glenum mode, GLint i1, GLint i2, GLint j1, GLint j2). Aleksander Dawid 2001-2012 rok 91
Powierzchnie i Krzywe Przykłady f(x, y) = 1/[(x + 1) (y + 1)] glmap2f(gl_map2_vertex_3,0.0,1.0,3,4,0.0,1.0,1 2,4,&fCtrlPointsArray[0][0][0]); glmap2f(gl_map2_texture_coord_2,0.0,1.0,2,2,0. 0,1.0,4,2,&fTexCtrlPointsArray[0][0][0]); glenable(gl_map2_vertex_3); glenable(gl_map2_texture_coord_2); glmapgrid2f(100,0.0,1.0,100,0.0,1.0); Aleksander Dawid 2001-2012 rok 92
Bufor głębokości Działanie bufora głębokości polega na przechowywaniu współrzędnej z dla każdego piksela obrazu. Podczas renderingu obliczana jest wartość współrzędnej z piksela obrazu i porównywana jest z wartością bufora głębokości. W ten sposób stwierdzane jest przesłanianie obiektów namalowanych wcześniej. Standardowo OpenGL nie wykonuje operacji na buforze głębokości Włączenie bufora głębokości glenable(gl_depth_test) Wyłączenie zapisu do bufora głębokości gldepthmask(glboolean flag) flag GL_TRUE, GL_FALSE Aleksander Dawid 2001-2012 rok 93
Bufor głębokości Kontrola sposobu sprawdzania bufora głębokości gldepthfunc(glenum func) Wartości func GL_NEVER - wartość testu zawsze negatywna, GL_LESS - wartość testu pozytywna jeżeli testowana wartość współrzędnej z jest mniejsza od wartości znajdującej się w buforze; wartość domyślna, GL_EQUAL - wartość testu pozytywna jeżeli testowana wartość współrzędnej z jest równa wartości znajdującej się w buforze, GL_LEQUAL - wartość testu pozytywna jeżeli testowana wartość współrzędnej z jest mniejsza lub równa wartości znajdującej się w buforze, GL_GREATER - wartość testu pozytywna jeżeli testowana wartość współrzędnej z jest większa od wartości znajdującej się w buforze, GL_NOTEQUAL - wartość testu pozytywna jeżeli testowana wartość współrzędnej z jest różna od wartości znajdującej się w buforze, GL_GEQUAL - wartość testu pozytywna jeżeli testowana wartość współrzędnej z jest większa lub równa wartości znajdującej się w buforze, GL_ALWAYS - wartość testu zawsze pozytywna. Aleksander Dawid 2001-2012 rok 94
Bufor głębokości Czyszczenie bufora głębokości Przez rozpoczęciem rysowania elementów sceny 3D konieczne jest wyczyszczenie zawartości bufora głębokości. Wymaga to dodania stałej GL_DEPTH_BUFFER_BIT przy wywołaniu funkcji glclear. glcleardepth( GLclampd depth ) Standardowo bufor głębokości zawiera liczby z przedziału [0, 1] i jest czyszczony liczbą 1 Biblioteka OpenGL umożliwia zmianę tego przedziału poprzez użycie funkcji: gldepthrange( GLclampd znear, GLclampd zfar ) Aleksander Dawid 2001-2012 rok 95
Bufor głębokości Przesunięcie wartości głębi W wersji 1.1 biblioteki OpenGL, a wcześniej w rozszerzeniu EXT polygon offset, wprowadzono mechanizm pozwalający na przesuwanie wartości głębi pikseli przy rysowaniu wielokątów. Przesunięcie wyliczane jest na podstawie wzoru: (m * factor) + (r * units) którego współczynnik m oznacza maksymalne nachylenie głębokości wielokąta (obliczenia wykonuje OpenGL), a współczynnik r jest zależną od implementacji najmniejszą różnicą wartości przechowywanych w buforze głębokości. Określenie wartości współczynników skalowania factor i units wymaga wywołania funkcji: glpolygonoffset( GLfloat factor, GLfloat units ) Przesuwanie wartości głębi jest domyślnie wyłączone. Włączenie tego mechanizmu wymaga wywołania funkcji glenable z jednym z poniższych parametrów: GL_POLYGON_OFFSET_POINT - przesuwanie wartości głębi, gdy rysowane są tylko wierzchołki wielokątów, GL_POLYGON_OFFSET_LINE - przesuwanie wartości głębi, gdy rysowane są tylko krawędzie wielokątów, GL_POLYGON_OFFSET_FILL - przesuwanie wartości głębi, gdy rysowane są wypełnione wielokąty. Aleksander Dawid 2001-2012 rok 96
Bufor szablonowy (5) Stencil buffer Bufor dodatkowy (konfigurowalny), podobny do bufora głębokości. Składowany w nim jest szablon kolorów jako filtr. Bufor ten określa, które piksele ekranu mają ulegać zmianie, a które nie. Wartości w buforze szablonu przechowywane są dla każdego piksela. Ilość bitów na 1 piksel wacha się między 1 a 8. Przy 8bit rozdzielczości możemy nałożyć 256 warunków na wyświetlanie pikseli. Zastosowania Cienie (shadows) Lustra (mirrors) Filtry Aleksander Dawid 2001-2012 rok 97
Bufor szablonowy Załączenie/Wyłączenie bufora glenable(gl_stencil_test); gldisable(gl_stencil_test); Czyszczenie bufora szablonowego glclear(gl_stencil_buffer_bit); Domyślnie bufor szablonowy wypełniany jest zerami, ale można to zmienić przy pomocy funkcji. glclearstancil(glint s);, gdzie s jest dowolna liczbą całkowitą Aleksander Dawid 2001-2012 rok 98
Bufor szablonowy Sterowanie buforem szablonowym glstencilfunc( GLenum func, GLint ref, GLuint mask ) Dla parametru func mamy te same możliwości co dla bufora głębokości GL_NEVER - wartość testu zawsze negatywna, GL_LESS - wartość testu pozytywna jeżeli testowana wartość współrzędnej z jest mniejsza od wartości znajdującej się w buforze; wartość domyślna, GL_EQUAL - wartość testu pozytywna jeżeli testowana wartość współrzędnej z jest równa wartości znajdującej się w buforze, GL_LEQUAL - wartość testu pozytywna jeżeli testowana wartość współrzędnej z jest mniejsza lub równa wartości znajdującej się w buforze, GL_GREATER - wartość testu pozytywna jeżeli testowana wartość współrzędnej z jest większa od wartości znajdującej się w buforze, GL_NOTEQUAL - wartość testu pozytywna jeżeli testowana wartość współrzędnej z jest różna od wartości znajdującej się w buforze, GL_GEQUAL - wartość testu pozytywna jeżeli testowana wartość współrzędnej z jest większa lub równa wartości znajdującej się w buforze, GL_ALWAYS - wartość testu zawsze pozytywna. Aleksander Dawid 2001-2012 rok 99
Bufor szablonowy Parametr ref Parametr ref określa wartość referencyjną używaną w teście bufora szablonowego. Wartość ta jest zawsze obcinana do przedziału [0, 2n 1], gdzie n jest ilością bitów bufora szablonu. Parametr mask Określa maskę bitową dla których bitów wykonywany jest test porównania wartości referencyjnej z wartościami zeskładowanymi w buforze szablonu. Domyślna wartość maski bitowej dla bufora szablonu wynosi 1. Ustawienie te można zmienić przy pomocy funkcji glstencilmask(uint mask) Aleksander Dawid 2001-2012 rok 100
Funkcja sterująca buforem Bufor szablonowy glstencilop(glenum sfail,glenum dpfail,glenum dppass) sfail, określa reakcję na negatywny wynik testu bufora szablonu dpfail, pozytywny wynik testu bufora szablonu, negatywny bufora głębokości dppass, pozytywny szablonu i głębokości Domyślna wartość dla wszystkich tych przypadków to GL_KEEP GL_KEEP - wartość bufora szablonowego nie jest zmieniana, GL_ZERO - wartość bufora szablonowego jest zerowana, GL_REPLACE - wartość bufora szablonowego jest zamieniana wartością referencyjną określoną w parametrze ref funkcji glstencilfunc, GL_INCR - wartość bufora szablonowego jest zwiększana o 1; w przypadku wystąpienia nadmiaru rezultat przyjmuje maksymalną wartość obsługiwaną przez bufor szablonowy, GL_DECR - wartość bufora szablonowego jest zmniejszana o 1; w przypadku wystąpienia niedomiaru rezultat przyjmuje wartość 0, GL_INVERT - wartość bufora szablonowego jest negowana, GL_DECR_WRAP - wartość bufora szablonowego jest zmniejszana o 1; w przypadku wystąpienia niedomiaru rezultat przyjmuje maksymalną wartość obsługiwaną przez bufor szablonowy, GL_INCR_WRAP - wartość bufora szablonowego jest zwiększana o 1; w przypadku wystąpienia nadmiaru rezultat przyjmuje wartość 0. Aleksander Dawid 2001-2012 rok 101
Bufor szablonowy W OpenGL 2.0 wprowadzono wersje tych funkcji osobne dla przedniej GL_FRONT i tylnej GL_BACK wielokąta. 0 0 1 2 GL_FRONT 2 1 GL_BACK glstencilfuncseparate(enum face,enum func,int ref,uint mask ) glstencilopseparate(enum face,enum sfail,enum dpfail,enum dppass ) glstencilmaskseparate(enum face,uint mask) Aleksander Dawid 2001-2012 rok 102
Bufor szablonowy Odbicie lustrzane gldisable(gl_stencil_test); glenable(gl_stencil_test); Aleksander Dawid 2001-2012 rok 103
Bufor akumulacyjny Przechowuje informacje RGBA dla koloru, w trybie kolor indeks jest niedostępny. Zadania Łączenie kilku obrazów w celu uzyskania pożądanego efektu końcowego. Zastosowanie Efekt rozmycia podczas ruchu (ang. motion blur) Głębia ostrości (ang. depth of field) antyaliasing pełnoekranowy (ang. FSAA - Full Scene Anti Aliasing) miękkie cienie (ang. soft shadows) Aleksander Dawid 2001-2012 rok 104
Sterowanie buforem Bufor akumulacyjny glaccum(glenum op,glfloat value) op określa rodzaj operacji wykonywanej na buforze value parametr operacji (R a,g a,b a,a a ) wektor bufora akumulacji (R c,g c,b c,a c ) wektor bufora kolorów Dostępne operacje op algebraiczne na buforze akumulacji GL_ACCUM R a = R a + value R c G a = G a + value G c B a = B a + value B c A a = A a + value A c Aleksander Dawid 2001-2012 rok 105
Bufor akumulacyjny GL_LOAD GL_RETURN GL_MULT GL_ADD R a = value R c G a = value G c B a = value B c A a = value A c R c = value R a G c = value G a B c = value B a A c = value A a R a = value R a G a = value G a B a = value B a A a = value A a R a = R a + value G a = G a + value B a = B a + value A a = A a + value Aleksander Dawid 2001-2012 rok 106
Bufor akumulacyjny Czyszczenie bufora akumlacyjnego glclear(gl_accum_buffer_bit) Domyślna wartość wypełnienia to wektor zerowy (0,0,0,0) Wartość tę można zmienić przez funkcję glclearaccum( GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha ) Składowe kolorów w razie potrzeby obcinane są do przedziału [ 1, 1] Aleksander Dawid 2001-2012 rok 107
Bufor akumulacyjny Rozmycie w ruchu // dodanie przeskalowanych wartości z bufora kolorów do bufora akumulacynego glaccum( GL_ACCUM, 0.1f ); // kopiowanie wartości z bufora akumulacyjnego do bufora kolorów glaccum( GL_RETURN, 1.0f ); // załadowanie przeskalowanych wartości z bufora kolorów do bufora akumulacyjnego glaccum( GL_LOAD, 0.9f ); Aleksander Dawid 2001-2012 rok 108
GL Shading Language (GLSL) Wprowadzenie do programowania shaderów Aleksander Dawid 2001-2012 rok 109
GL Shading Language (GLSL) Język shaderów wprowadzony został w celu oprogramowania tych elementów OpenGL, które miały ustaloną funkcjonalność. Dotyczy to przetwarzania wierzchołków i fragmentów. Fragment jest wynikiem rasteryzacji prymitywów składających się z wierzchołków kolorów i tekstur. Przetwarzanie fragmentów dotyczy takich operacji jak przycinanie, test alfa, test głębokości, test szablonu, mieszanie kolorów, mapowania tekstur i wiele innych. Shader niezależnie kompilowalna jednostka obliczeniowa Program to zestaw shaderów, skompilowanych i połączonych razem Aleksander Dawid 2001-2012 rok 110
GL Shading Language (GLSL) Połączenia wierzchołków Wierzchołki Transformacja wierzchołków (vertex shader) Przetworzone wierzchołki Składanie prymitywów i rasteryzacja Położenia pikseli Fragmenty Odświeżenie pikseli Rasteryzacja Pokolorowane fragmenty Teksturowanie i kolorowanie fragmentów (pixel shader) Potok przetwarzania grafiki komputerowej Aleksander Dawid 2001-2016 rok 111
GL Shading Language (GLSL) Procesor wierzchołków Na wejściu: położenia, kolor, normalne, współrzędne tekstury Ustalona funkcjonalność Transformacje pozycji wierzchołka Oświetlenie dla wierzchołka Generowanie i przekształcanie współrzędnych tekstur Składanie prymitywów i rasteryzacja Na wejściu: informacja o wierzchołkach i sposobie ich połączenia Na tym etapie wykonywane są również obliczenia związane z obcinanie względem bryły widoku oraz usuwane są niewidoczne powierzchnie Na wyjściu: matryca pikseli określająca prymityw (fragment), dane gotowe do przesłania na bufor ramki Aleksander Dawid 2001-2012 rok 112
GL Shading Language (GLSL) Teksturowanie i kolorowanie fragmentów Na wejściu: fragment prymitywu Ustalona funkcjonalność Interpolowany kolor mieszany jest z wartością teksela (elementu tekstury) Efekt mgły Rasteryzacja Na wejściu: pokolorowany prymityw i położenie piksela Ustalona funkcjonalność Test przycinania Test alfa Test bufora szablonu Test bufora głębokości Na wyjściu: rysowanie w buforze ramki Aleksander Dawid 2001-2012 rok 113
GL Shading Language (GLSL) W nowoczesnych układach graficznych dano możliwość programowania funkcjonalności w dwóch poniższych etapach przetwarzania grafiki Transforamcja wierzchołków programowalna jednostka Vertex Shaders Teksturowanie i kolorowanie fragmentów programowalna jednostka Fragment Shaders (pixel shaders) Vertex Shaders Pozwala pisać własny program na transformacje wierzchołków, transformacje normalnych, transformacje współrzędnych tekstur, obliczanie świateł dla pojedynczych wierzchołków, obliczenia kolorów. W momencie użycia jednostki vertex shaders cała ustalona funkcjonalność musi być obsługiwana przez nasz program Odpowiedzialny za zapis wartości gl_position Program ma dostęp do stanu maszyny OpenGL Aleksander Dawid 2001-2012 rok 114
GL Shading Language (GLSL) Fragment Shaders Zmiana funkcjonalności w zakresie operacji Obliczenia kolorów i współrzędnych tekstur na każdy piksel Nakładanie tekstur Obliczanie mgły Obliczanie normalnych w przypadku oświetlenia na każdy piksel Fragment shaders ma dostęp do położeń poszczególnych pikseli, ale nie może ich zmieniać Na wyjściu: Nie przekazywać nic gl_fragcolor ostateczny kolor dla fragmentu gl_fragdata gdy renderowanie jest dla różnych urządzeń wyświetlających Aleksander Dawid 2001-2012 rok 115
GLSL - programowanie Inicjalizacja Każdy shader jest jak osobny program napisany w języku C i musi być skompilowany. Aplikacja w OpenGL musi mieć minimum dwa shadery (Vertex shader i Fragment Shader) Do programowania shaderów potrzebna jest obsługa OpenGL2.0 lub rozszerzenia ARB (Archtecture Review Board). Dobrym rozwiązaniem zarówno dla jednego i drugiego przypadku jest biblioteka GLEW Aleksander Dawid 2001-2012 rok 116
GLSL - programowanie Test rozszerzenia ARB Sprawdzamy czy nasza karta graficzna/system obsługują rozszerzenia GL_ARB_fragment_shader i GL_ARB_vertex_shader //Incjalizacja OpenGL (glut,wingl,glaux) glewinit(); if (GLEW_ARB_vertex_shader && GLEW_ARB_fragment_shader) printf("glsl OK\n"); else { printf("brak obsługi GLSL\n"); exit(1); } Aleksander Dawid 2001-2012 rok 117
GLSL - programowanie Test OpenGL2.0 Sprawdzamy czy nasza karta graficzna/system obsługują rozszerzenia GL_ARB_fragment_shader i GL_ARB_vertex_shader //Incjalizacja OpenGL (glut,wingl,glaux) glewinit(); if (glewissupported("gl_version_2_0")) printf( Gotowy na OpenGL 2.0\n"); else { printf("opengl 2.0 nie wspierane\n"); exit(1); } Aleksander Dawid 2001-2012 rok 118
GLSL - programowanie Konstrukcja programu Vertex shader glcreateshader glcreateprogram glshadersource glattacheshader glcompileshader glattacheshader FRAGMENT shader glcreateshader gllinkprogram glshadersource gluseprogram glcompileshader Aleksander Dawid 2001-2012 rok 119
GLSL - programowanie Vertex shader GLuint glcreateshader(glenum shadertype); glcreateshader glshadersource glcompileshader FRAGMENT shader glcreateshader glshadersource glcompileshader shadertype GL_VERTEX_SHADER, GL_FRAGMENT_SHADER Gluint shader; shader = glcreateshader(gl_vertex_shader); shader identyfikator shadera void glshadersource(gluint shader, int numofstrings, const char **strings, int *lenofstrings); numofstrings ilość ciągów w tablicy. strings tablica ciągów. lenofstrings tablica rozmiarów ciągów, albo NULL, oznacza ciągi zakończone znakiem zero NULL void glcompileshader(gluint shader); Aleksander Dawid 2001-2012 rok 120
GLSL - programowanie Program glcreateprogram GLuint glcreateprogram(void); Funkcja zwraca identyfikator pojemnika. Programów możemy tworzyć ile chcemy. Możemy przełączać się między tymi programami. glattacheshader void glattachshader(gluint program, GLuint shader); glattacheshader gllinkprogram void gllinkprogram(gluint program); void gluseprogram(gluint prog); prog uchwyt do programu który chcemy użyć, lub zero jako powrót do ustalonej funkcjonalności. gluseprogram Aleksander Dawid 2001-2012 rok 121
GLSL - programowanie Shader program W kodzie GLbyte vshaderstr[] = "attribute vec4 vposition; \n" "void main() \n" "{ \n" " gl_position = vposition; \n" "} \n"; W pliku zewnętrznym char *vs = NULL; vs = File2Text("test.vert"); Aleksander Dawid 2001-2012 rok 122
GLSL - programowanie char *File2Text(char *filename) { FILE *fp; char *content = NULL; int count=0; if (fn!= NULL) { fp = fopen(filename,"rt"); if (fp!= NULL) { fseek(fp, 0, SEEK_END); count = ftell(fp); rewind(fp); } } } if (count > 0) { content = (char *)malloc(sizeof(char) * (count+1)); count = fread(content,sizeof(char),count,fp); content[count] = '\0'; } fclose(fp); return content; Aleksander Dawid 2001-2012 rok 123
void UstawShadery() { char *vs,*fs; Ustawienie shadera- przykład v = glcreateshader(gl_vertex_shader); f = glcreateshader(gl_fragment_shader); vs = File2Text("toon.vert"); //vertex shader fs = File2Text("toon.frag"); //fragment shader const char * vv = vs; const char * ff = fs; glshadersource(v, 1, &vv,null); glshadersource(f, 1, &ff,null); free(vs);free(fs); glcompileshader(v); glcompileshader(f); p = glcreateprogram(); glattachshader(p,v); glattachshader(p,f); } gllinkprogram(p); gluseprogram(p); Aleksander Dawid 2001-2012 rok 124
Sprawdzanie poprawności kodu Dla shaderów nie ma możliwości sprawdzenia poprawności kodu. Narzędzia dostępne w OpenGL 2.0 void glgetshaderiv(gluint object, GLenum type, int *param); object uchwyt do shadera lub programu type GL_COMPILE_STATUS. param zwracana wartość, GL_TRUE kompilacja prawidłowa, GL_FALSE błędy przy kompilacji. void glgetprogramiv(gluint object, GLenum type, int *param); object uchwyt do shadera lub programu type GL_LINK_STATUS. param zwracana wartość, GL_TRUE kompilacja prawidłowa, GL_FALSE błędy przy kompilacji. Aleksander Dawid 2001-2012 rok 125
Poprawności kodu InfoLog W przypadku błędów podczas przetwarzania programu przez kartę graficzną, sterownik generuje dziennik (InfoLog). Format tego dziennika zależny jest od sterownika urządzenia. void glgetshaderinfolog(gluint object, int maxlen, int *len, char *log); void glgetprograminfolog(gluint object, int maxlen, int *len, char *log); object uchwyt do shadera lub programu maxlen maksymalna liczba znaków do pobrania z pliku InfoLog. len zwraca aktualny rozmiar pliku InfoLog. log Nazwa pliku InfoLog. Pobranie rozmiaru pliku InfoLog void glgetshaderiv(gluint object, GLenum type, int *param); void glgetprogramiv(gluint object, GLenum type, int *param); object uchwyt do shadera lub programu type GL_INFO_LOG_LENGTH. param rozmiar pliku InfoLog. Aleksander Dawid 2001-2012 rok 126
Odczyt InfoLog przykład void printshaderinfolog(gluint obj) { int infologlength = 0; int charswritten = 0; char *infolog; //glgetprogramiv(obj, GL_INFO_LOG_LENGTH,&infologLength); glgetshaderiv(obj, GL_INFO_LOG_LENGTH,&infologLength); } if (infologlength > 0) { infolog = (char *)malloc(infologlength); glgetshaderinfolog(obj, infologlength, &charswritten, infolog); printf("%s\n",infolog); free(infolog); } Aleksander Dawid 2001-2012 rok 127
Kasowanie shaderów Przed skasowaniem shadery muszą być odłączone od programu void gldetachshader(gluint program, GLuint shader); program identyfikator programu. shader identyfikator shadera do odłączenia. Kasowanie void gldeleteshader(gluint id); void gldeleteprogram(gluint id); id identyfikator programu lub shadera, który ma zostać skasowany. Aleksander Dawid 2001-2012 rok 128
Komunikacja OpenGL Shader Wynik działania programu shadera przekazywany jest tylko w postaci graficznej do bufora koloru lub głębokości, więc komunikacja jest tylko jednokierunkowa. GLSL pozwala na definiowanie zmiennych do komunikacji z shaderami GLSL obsługuje dwa modyfikatory zmiennych Attribute Uniform Zmienne używające tych modyfikatorów są tylko do odczytu przez shader. Inną metodą przesyłania danych do shaderów są tekstury, które mogą reprezentować tablicę liczb. Aleksander Dawid 2001-2012 rok 129
UNIFORM Zmienne Wartości mogą być zmieniane tylko przez prymitywy. Aby ustawić zmienną UNIFORM trzeba najpierw pobrać jej adres z programu shadera w postaci nazwy. Program shadera musi być zlinkowany i użyty. GLint glgetuniformlocation(gluint program, const char *name); program identyfikator programu. name nazwa zmiennej. Zwracana wartość z tej funkcji to identyfikator położenia, na podstawie którego możemy przypisać wartość do zmiennej. void gluniform1f(glint location, GLfloat v0); void gluniform2f(glint location, GLfloat v0, GLfloat v1); void gluniform3f(glint location, GLfloat v0, GLfloat v1, GLfloat v2); void gluniform4f(glint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); GLint gluniform{1,2,3,4}fv(glint location, GLsizei count, GLfloat *v); Aleksander Dawid 2001-2012 rok 130
Zmienne GLint gluniformmatrix{2,3,4}fv(glint location, GLsizei count, GLboolean transpose, GLfloat *v); location położenie zmiennej. count liczba macierzy. transpose macierz transponowana Anm=Bmn v tablica liczb zmiennoprzecinkowych. Ustawione wartości istnieją tak długo w pamięci dopóki program nie zostanie ponownie zlinkowany. PRZYKŁAD Aleksander Dawid 2001-2012 rok 131
ATTRIBUTE Zmienne Wartości mogą być ustawiane na wierzchołek pomiędzy glbegin glend. Aby ustawić zmienną ATTRIBUTE trzeba najpierw pobrać jej adres z programu shadera w postaci nazwy. Program shadera musi być zlinkowany i użyty. GLint glgetattriblocation(gluint program,char *name); program identyfikator programu. name nazwa zmiennej. Zwracana wartość z tej funkcji to identyfikator położenia, na podstawie którego możemy przypisać wartość do zmiennej. void glvertexattrib1f(glint location, GLfloat v0); void glvertexattrib2f(glint location, GLfloat v0, GLfloat v1); void glvertexattrib3f(glint location, GLfloat v0, GLfloat v1,glfloat v2); void glvertexattrib4f(glint location, GLfloat v0, GLfloat v1,,glfloat v2, GLfloat v3); GLint glvertexattrib{1,2,3,4}fv(glint location, GLfloat *v); Aleksander Dawid 2001-2012 rok 132
ATTRIBUTE przykład Zmienne glbegin(gl_triangle_strip); glvertexattrib1f(loc,5.0); glvertex2f(-1,1); glvertexattrib1f(loc,2.0); glvertex2f(1,1); glvertexattrib1f(loc,-2.0); glvertex2f(-1,-1); Zwracana wartość glvertexattrib1f(loc,-2.0); z tej funkcji to identyfikator położenia, na podstawie którego możemy przypisać glvertex2f(1,-1); wartość do zmiennej. glend(); Aleksander Dawid 2001-2012 rok 133
Typy zmiennych shader program Typy proste int bool float Typy wektorowe vec{2,3,4} (float) bvec{2,3,4} (bool) ivec{2,3,4} (int) Typy macierzowe mat2 macierz 2x2 mat3 - macierz 3x3 mat4 - macierz 4x4 Aleksander Dawid 2001-2012 rok 134
Typy zmiennych shader program Typy teksturowe, dotyczą tekseli sampler1d dla tekstur 1D sampler2d dla tekstur 2D sampler3d dla tekstur 3D Tablice tych zmiennych deklarujemy tak samo jak w języku C vect3 A[10]; mat4 Tab[2]; Struktury struct spotlight { vec3 kierunek; vec3 kolor; }; spotlight A; A.kierunek=vec3(1.0,1.0,1.0); Aleksander Dawid 2001-2012 rok 135
Instrukcje sterujące IF-ELSE if (bool warunek)... else... FOR for (inicjalizacja; warunek; zmiana wartości)... WHILE while (warunek)... DO-WHILE do... while (warunek) Aleksander Dawid 2001-2012 rok 136
Funkcje Funkcje deklaruje się podobnie jak w języku C void main() vec4 ChangeColor(in float intensity){ vec4 color; color = vec4(intensity, intensity, intensity,1.0); return(color); } Modyfikatory: in,out,inout Domyślny in Aleksander Dawid 2001-2012 rok 137
Zmienna varying Zmienna przenoszona pomiędzy programem Vertex Shader a Fragment Shader varying float intensity; Aleksander Dawid 2001-2012 rok 138
Przykład Vertex Shader void main(){ gl_position = gl_modelviewprojectionmatrix * gl_vertex; } Fragment Shader void main(){ gl_fragcolor = gl_color; } Aleksander Dawid 2001-2012 rok 139
Przykład Windows API GLSL Omówienie interfejsu OpenGL dla Windows Aleksander Dawid 2001-2016 rok 140
Powiązanie technologii GLSL z WinApi Czynności wstępne case WM_CREATE: /* Tworzenie kontekstu renderowania OpenGL */ ghdc = GetDC(hWnd); setuppixelformat(ghdc); ghrc = wglcreatecontext(ghdc); wglmakecurrent(ghdc, ghrc); GetClientRect(hWnd, &rect); initializegl(rect.right, rect.bottom); SetTimer(hWnd, 101, 5, NULL); break; Aleksander Dawid 2001-2012 rok 141
Powiązanie technologii GLSL z WinApi Pobranie kontekstu urządzenia wyświetlającego ghdc = GetDC(hWnd); Ustalenie formatu Pikseli setuppixelformat(ghdc); Utworzenie kontekstu OpenGL ghrc = wglcreatecontext(ghdc); Ustawienie kontekstu OpenGL jako bierzącego wglmakecurrent(ghdc, ghrc); Aleksander Dawid 2001-2012 rok 142
Powiązanie technologii GLSL z WinApi Pobranie rozmiaru okna roboczego GetClientRect(hWnd, &rect); Inicjalizacja parametrów OpenGL i GLSL initializegl(rect.right, rect.bottom); Ustawienie timera jako dodatkowego wątku kontrolującego animację SetTimer(hWnd, 101, 5, NULL); Aleksander Dawid 2001-2012 rok 143
Inicjalizacja grafiki OpenGL GLvoid initializegl(glsizei width, GLsizei height) { glclearcolor( 0.0f, 0.0f, 0.0f, 0.0f); glcleardepth( 1.0 ); glshademodel(gl_smooth); glenable(gl_depth_test); InitGLSL(); InitShaders(); } GLSL InitGLSL(); InitShaders(); Aleksander Dawid 2001-2012 rok 144
Inicjalizacja biblioteki Shaderów Do inicjalizacji shaderów służy biblioteka GLEW: The OpenGL Extension Wrangler Library #include <GL/glew.h> W celu wykorzystania tej biblioteki w systemie Windows trzeba wykonać kompilację jej kodu źródłowego glew32d.dll biblioteka dynamiczna glew32d.lib biblioteka statyczna Biblioteka wykorzystuje zarówno kartę graficzną jak i emuluje bibliotekę shaderów w przypadku ich braku. Aleksander Dawid 2001-2012 rok 145
Inicjalizacja biblioteki Shaderów Instrukcja glewinit(); inicjalizuje bibliotekę GLEW GLvoid InitGLSL(){ glewinit(); if (GLEW_VERSION_2_0){ MessageBox(ghWnd, "INFO: OpenGL 2.0 wspierany", Informacja",MB_OK); }else{ MessageBox(ghWnd, "INFO: OpenGL 2.0 nie wspierany", " Informacja",MB_OK); } } glewinit(); musi być wywołane po inicjalizacji biblioteki OpenGL Jeżeli zmienna boolowska GLEW_VERSION_2_0=prawda to możemy skorzystać z funkcjonalności jaką oferuje standard OpenGL2.0 Aleksander Dawid 2001-2012 rok 146
GLvoid InitShaders(){ char shaderfn[]="wave.vert"; char fragmentfn[]="wave.frag"; char Info[64]; Program Shaderów char *vssource = textfileread(shaderfn); if(vssource==null){ sprintf(info,"plik: %s nie znaleziony",shaderfn); MessageBox(ghWnd, Info, "Informacja",MB_OK); exit(0); } char *fssource = textfileread(fragmentfn); if(fssource==null){ sprintf(info,"plik: %s nie znaleziony",fragmentfn); MessageBox(ghWnd, Info, "Informacja",MB_OK); exit(0); } Aleksander Dawid 2001-2012 rok 147
Program Shaderów const char * vv = vssource; const char * ff = fssource; vs = glcreateshader(gl_vertex_shader); fs = glcreateshader(gl_fragment_shader); glshadersource(vs, 1, &vv, NULL); glshadersource(fs, 1, &ff, NULL); free(vssource); free(fssource); glcompileshader(vs); glcompileshader(fs); printlog(vs); printlog(fs); Aleksander Dawid 2001-2012 rok 148
Program Shaderów sp = glcreateprogram(); glattachshader(sp, vs); glattachshader(sp, fs); gllinkprogram(sp); printlog(sp); gluseprogram(sp); } Aleksander Dawid 2001-2012 rok 149
Falująca powierzchnia Efekt falującej powierzchni jest często stosowany w grafice komputerowej; woda, flaga, trawa itd. Do czasu zanim zostały wprowadzone shadery wykonywany był przez procesor główny komputera. Dla wielkie ilości wierzchołków był praktycznie niemożliwy do wykonania w grach komputerowych. Aleksander Dawid 2001-2012 rok 150
Falująca powierzchnia Algorytm Start Inicjalizacja OpenGL Wierzchołki Vertex Shader Pixel Shader i<n i=i+1 Aleksander Dawid 2001-2012 rok 151
Vertex shader Fala uniform float wavetime; uniform float wavewidth; uniform float waveheight; void main(void) { vec4 gv = vec4(gl_vertex); gv.z = sin(wavewidth * gv.x + wavetime) * cos(wavewidth * gv.y + wavetime) * waveheight; } gl_position = gl_modelviewprojectionmatrix * gv; Aleksander Dawid 2001-2012 rok 152
Vertex shader Fala uniform float wavetime; uniform float wavewidth; uniform float waveheight; Zmienne uniform to zmienne dostępne dla naszego programu. Przy ich pomocy możemy w czasie rzeczywistym modyfikować zachowanie fali. Aby zmodyfikować te zmienne musi nasz program shadera być już uruchomiony. GLvoid InitWave(){ wavetimeloc = glgetuniformlocation(sp, "wavetime"); wavewidthloc = glgetuniformlocation(sp, "wavewidth"); waveheightloc = glgetuniformlocation(sp, "waveheight"); printlog(sp); } Aleksander Dawid 2001-2012 rok 153
Vertex shader Fala GLvoid initializegl(glsizei width, GLsizei height) {... InitShaders(); InitWave(); } Adresy w pamięci karty graficznej GLint wavetimeloc; GLint wavewidthloc; GLint waveheightloc; Inicjalizacja zmiennych w CPU GLfloat wavetime = 0.0; Glfloat wavewidth = 0.2; Glfloat waveheight = 5.0; Glfloat wavefreq = 0.1; Aleksander Dawid 2001-2012 rok 154
Vertex shader Fala gl_vertex - wierzchołki, które będą poddane obróbce przez nasz program Równanie fali płaskiej. z f ( x, y) Asin( Wx t)cos( Wy t) Modyfikacji podlega tylko składowa z gv.z = sin(wavewidth * gv.x + wavetime) * cos(wavewidth * gv.y + wavetime) * waveheight; Zmodyfikowane pozycje wierzchołków gl_position = gl_modelviewprojectionmatrix * gv; Aleksander Dawid 2001-2012 rok 155
Fragment shader Fala gl_fragcolor - Ostateczny kolor fragmentów void main() { gl_fragcolor[0] = gl_fragcoord[0] / 400.0; gl_fragcolor[1] = gl_fragcoord[1] / 400.0; gl_fragcolor[2] = 1.0; } gl_fragcoord - Współrzędne fragmentów Aleksander Dawid 2001-2012 rok 156
Płaszczyzna wielokatów Fala GLvoid PlainSurface() { int i,j; glbegin(gl_quads); for (i = -50; i < 50; i++) for (j = -50; j < 50; j++) { glvertex2f(i, j); glvertex2f(i + 1, j); glvertex2f(i + 1, j + 1); glvertex2f(i, j + 1); } glend(); } Aleksander Dawid 2001-2012 rok 157
Pętla animacji Fala GLvoid drawscene(glvoid) { glclearcolor( 0.0f, 0.0f, 0.4f, 0.0f); glclear(gl_color_buffer_bit GL_DEPTH_BUFFER_BIT); gluniform1f(wavetimeloc, wavetime); gluniform1f(wavewidthloc, wavewidth); gluniform1f(waveheightloc, waveheight); } PlainSurface(); wavetime += wavefreq; SWAPBUFFERS; Animacja wykonywana jest w osobnym wątku ustawionym przez timer wavewidth, waveheight - Można modyfikować w głównym wątku Aleksander Dawid 2001-2012 rok 158
Cieniowanie Phonga Stosowane bardzo często w grafice wektorowej w celu reprezentacji rozbłysków Vertex Shader varying vec3 N; varying vec3 v; void main(void) { v = vec3(gl_modelviewmatrix * gl_vertex); N = normalize(gl_normalmatrix * gl_normal); gl_position = gl_modelviewprojectionmatrix * gl_vertex; } Aleksander Dawid 2001-2012 rok 159
Fragment Shader varying vec3 N; varying vec3 v; Cieniowanie Phonga void main (void) { vec3 L = normalize(gl_lightsource[0].position.xyz - v); vec3 E = normalize(-v); vec3 R = normalize(-reflect(l,n)); L wektor światła E odwrotny wektor modelu R wektor odbicia Aleksander Dawid 2001-2012 rok 160
Fragment Shader Cieniowanie Phonga //Kolor otoczenia (Ambient): vec4 Iamb = gl_frontlightproduct[0].ambient; //Kolor rozpraszania (Diffuse): vec4 Idiff = gl_frontlightproduct[0].diffuse * max(dot(n,l), 0.0); Idiff = clamp(idiff, 0.0, 1.0); // Kolor rozbłysków (Specular): vec4 Ispec = gl_frontlightproduct[0].specular *pow(max(dot(r,e),0.0),0.3*gl_frontmaterial.shininess); Ispec = clamp(ispec, 0.0, 1.0); // Całkowity Kolor: gl_fragcolor = gl_frontlightmodelproduct.scenecolor + Iamb + Idiff + Ispec; } Aleksander Dawid 2001-2012 rok 161
Cieniowanie Phonga Przekazywanie zmiennych Zmienne typu varying mogą być przekazywane między vertex shader a fragment shader Cały algorytm bazuje na wektorach normalnych, które liczone są w jednostce vertex shader. Aleksander Dawid 2001-2012 rok 162
Cieniowanie Phonga Porównanie standardowego cieniowania wielokątów z cieniowaniem Phonga przy użyciu shaderów. Aleksander Dawid 2001-2012 rok 163
WebGL Standard OpenGL ES Aleksander Dawid 2001-2016 rok 164
WebGL Standard stworzony do obróbki grafiki 3D w przeglądarce internetowej. WebGL bazuje na bibliotekach OpenGL for Embeded Systems. Grafika tworzona jest w całości przez kartę graficzną, która obsługuje minimalnie OpenGL 2.0 lub OpenGL ES 2.0. Główni dostawcy przeglądarek Apple (Safari), Google (Chrome), Mozilla (Firefox), i Opera (Opera) są członkami WebGL Working Group. Aleksander Dawid 2001-2016 rok 165
WebGL WebGL korzysta z osadzenia w znaczniku canvas z HTML5. Programowanie API WebGL odbywa się przy pomocy języka JavaScript. WebGL jest w 100% kompatybilny z OpenGL ES. Do transformacji wierzchołków i renderowania fragmentów wykorzystuje programy shaderów. WebGL nie wymaga instalowania dodatkowych bibliotek. Aleksander Dawid 2001-2016 rok 166
WebGL Inicjalizacja okna WebGL Kod HTML5 <HTML> <HEAD> <SCRIPT type="text/javascript"> // Kod JavaScript </SCRIPT> </HEAD> <BODY onload="startgl()" bgcolor="white"> <canvas id="glid" width="640" height="480"> Brak wsparcia dla technologii HTML5 </canvas> </BODY> </HTML> Aleksander Dawid 2001-2016 rok 167
Inicjalizacja okna WebGL Kod JavaScript WebGL var gl; function startgl(){ var canvas=document.getelementbyid("glid"); gl = null; try{gl=canvas.getcontext("experimental-webgl");} catch(e){} } if(!gl){ alert("brak wsparcia sprzętowego dla OpenGL (WebGL)"); return; }else{ gl.clearcolor(0.2,0.2,0.6,1.0); gl.clear(gl.color_buffer_bit gl.depth_buffer_bit); } Aleksander Dawid 2001-2016 rok 168
Rysowanie WebGL W celu wyświetlenia wierzchołka w oknie WebGL potrzeba wykonać następujące czynności. 1. Utworzyć Vertex Shader 2. Utworzyć FragmentShader 3. Skompilować i zlinkować program shaderów 4. Wpisać wierzchołki do tablicy 5. Uruchomić program shaderów 6. Pobrać atrybut położenia z vertex shadera 7. Przekazać położenia z tablicy do vertex shadera 8. Wydać komendą wyświetlania tablicy Dla wielu różnych obiektów czynności te trzeba powtórzyć. Aleksander Dawid 2001-2016 rok 169
Deklaracja tablicy wierzchołków A. Przypisanie w trakcie deklaracji tablicy Punkty3D = [ 0.0, 0.5, 0.0, 0.5, -0.5, 0.0, -0.5, -0.5, 0.0]; B. Wypełnianie tablicy algorytmicznie WebGL Punkty3D = []; skok=0.5; iter=-0.5; for(i=0;i<9;i++){ if(i%3==0){ Punkty3D.push(iter); iter=iter+skok; }else{ Punkty3D.push(0.0); } } Aleksander Dawid 2001-2016 rok 170
Deklaracja Vertex Shadera WebGL A. Wewnątrz ciągu znaków var VShader="attribute vec4 pozycja; "+ " void main() " + "{" + "gl_position = pozycja;"+ "gl_pointsize = 30.0;"+ "}"; B. Wewnątrz dodatkowego znacznika <SCRIPT> <script id="vertex-shader" type="x-shader/x-vertex"> attribute vec4 pozycja; void main() { gl_position = pozycja; gl_pointsize = 30.0; } </script> Aleksander Dawid 2001-2016 rok 171
Przekazywanie wierzchołków A. Przez zmienne attribute Zmienna gl_position przekazuje wierzchołki do dalszego renderowania. attribute vec4 pozycja; void main() { gl_position = pozycja; gl_pointsize = 30.0; } WebGL var coor = gl.getattriblocation(shaderprogram, "pozycja"); gl.vertexattrib4f(coor, g_points[0], g_points[1], g_points[2], 1.0); gl.drawarrays(gl.points, 0, 1); //Przekazanie 1 wierzchołka Wada: transfer z CPU do GPU każdego wierzchołka. Aleksander Dawid 2001-2016 rok 172
Przekazywanie wierzchołków B. Przez bufor GPU WebGL Punkty3D = [ 0.0, 0.5, 0.0, 0.5, -0.5, 0.0, -0.5, -0.5, 0.0]; var vertex_buffer = gl.createbuffer(); gl.bindbuffer(gl.array_buffer, vertex_buffer); gl.bufferdata(gl.array_buffer, new Float32Array(Punkty3D), gl.static_draw); // kopiowanie danych wierzchołków //Połaczenie bufora z Vertex Shaderem var coord = gl.getattriblocation(shaderprogram, "pozycja"); gl.vertexattribpointer(coord, 3, gl.float, false, 0, 0); gl.enablevertexattribarray(coord); //Przekazanie 3 wierzchołków z bufora GPU gl.drawarrays(gl.points, 0, Punkty3D.length/3); Aleksander Dawid 2001-2016 rok 173
Fragment Shader WebGL <script id="fragment-shader" type="x-shader/x-fragment"> precision mediump float; uniform vec4 kolor; void main() { gl_fragcolor = kolor; } </script> highp, mediump, lowp precyzja obliczeń Do fragment shadera parametry można przesyłać tylko w zmiennych uniform. Aleksander Dawid 2001-2016 rok 174
Fragment Shader Zmiana koloru przez zmienną var nk = gl.getuniformlocation(shaderprogram, "kolor"); gl.uniform4f( nk, 1.0, 0.0, 0.0, 1.0 ); gl.drawarrays(gl.points, 0, 1); gl.uniform4f( nk, 0.0, 1.0, 0.0, 1.0 ); gl.drawarrays(gl.points, 1, 1); gl.uniform4f( nk, 0.0, 0.0, 1.0, 1.0 ); gl.drawarrays(gl.points, 2, 1); WebGL gl.drawarrays(gl.points, start, length); start offset w buforze GPU lenght rozmiar liczony w rozmiarze wektor 3-elementowego. Aleksander Dawid 2001-2016 rok 175
Fragment Shader WebGL Zmiana koloru ze względu na dane w Vertex Shader attribute vec4 pozycja; varying vec4 N; //zmienna dostępna we Fragment Shader void main() { N = pozycja; gl_position = pozycja; gl_pointsize = 30.0; } Przekazujemy w zmiennej N pozycje każdego z wierzchołków Aleksander Dawid 2001-2016 rok 176
Fragment Shader Zmiana koloru ze względu na dane w Vertex Shader precision mediump float; varying vec4 N; WebGL void main() { vec4 kolor; if(n.x<0.0) kolor=vec4(1.0,0.0,0.0,1.0); if(n.x==0.0) kolor=vec4(0.0,1.0,0.0,1.0); if(n.x>0.0) kolor=vec4(0.0,0.0,1.0,1.0); } gl_fragcolor = kolor; gl.drawarrays(gl.points, 0, Punkt3D.length/3); Aleksander Dawid 2001-2016 rok 177
Kompilacja Shaderów WebGL var vertelem = document.getelementbyid(vertexshaderid); //Pobranie lokalizacji znacznika <SCRIPT id=vertexshaderid> vertshdr = gl.createshader(gl.vertex_shader); gl.shadersource(vertshdr, vertelem.text); // vertelem.text tekst wewnątrz znacznika gl.compileshader(vertshdr); if (!gl.getshaderparameter(vertshdr, gl.compile_status)) { var msg = "Vertex shader nie można skompilowć:" + "<pre>" + gl.getshaderinfolog(vertshdr) + "</pre>"; alert(msg); console.log(msg); return -1; } Aleksander Dawid 2001-2016 rok 178
Kompilacja Shaderów WebGL if(n.x<0) kolor=vec4(1.0,0.0,0.0,1.0); Aleksander Dawid 2001-2016 rok 179
Kompilacja Shaderów WebGL fragshdr = gl.createshader(gl.fragment_shader); gl.shadersource(fragshdr, fragelem.text); gl.compileshader(fragshdr); var program = gl.createprogram(); gl.attachshader(program, vertshdr); gl.attachshader(program, fragshdr); gl.linkprogram(program); if (!gl.getprogramparameter(program, gl.link_status)) { var msg = "Shader program nie można zlinkować:" + "<pre>" + gl.getprograminfolog(program) + "</pre>"; alert(msg); console.log(msg); return -1; } Aleksander Dawid 2001-2016 rok 180
Użycie Shaderów WebGL var vertex_buffer = gl.createbuffer(); gl.bindbuffer(gl.array_buffer, vertex_buffer); gl.bufferdata(gl.array_buffer, new Float32Array(g_points), gl.static_draw); var shaderprogram = initshaders( gl, "vertex-shader", "fragment-shader" ); //Program shaderów musi być uruchomiony gl.useprogram(shaderprogram); var coord = gl.getattriblocation(shaderprogram, "pozycja"); gl.vertexattribpointer(coord, 3, gl.float, false, 0, 0); gl.enablevertexattribarray(coord); gl.clearcolor(0.6,0.6,1.0,1.0); //Ustawienie koloru tła gl.clear(gl.color_buffer_bit gl.depth_buffer_bit); gl.drawarrays(gl.points, 0, g_points.length/3); Aleksander Dawid 2001-2016 rok 181
Rysowanie trójkątów Położenia wierzchołków g_points = [ 0.0, 0.5, 0.0, 0.5, -0.5, 0.0, -0.5, -0.5, 0.0]; Kolory wierzchołków color_points = [ 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0,]; Vertex shader attribute vec4 pozycja; attribute vec4 pozycjacolor; varying vec4 N; WebGL Wypełnianie gradientowe void main() { gl_position = pozycja; N = pozycjacolor; } Aleksander Dawid 2001-2016 rok 182
Rysowanie trójkątów Fragment shader precision mediump float; varying mediump vec4 N; void main() { gl_fragcolor = N; } WebGL Wypełnianie gradientowe Inicjalizacja buforów var vertex_buffer = gl.createbuffer(); gl.bindbuffer(gl.array_buffer, vertex_buffer); gl.bufferdata(gl.array_buffer, new Float32Array(g_points), gl.static_draw); var VerticesColorBuffer = gl.createbuffer(); gl.bindbuffer(gl.array_buffer, VerticesColorBuffer); gl.bufferdata(gl.array_buffer, new Float32Array(color_points), gl.static_draw); Aleksander Dawid 2001-2016 rok 183
Rysowanie trójkątów WebGL Przed samym wyświetleniem gl.bindbuffer(gl.array_buffer, vertex_buffer); gl.vertexattribpointer(coord, 3, gl.float, false, 0, 0); gl.bindbuffer(gl.array_buffer, VerticesColorBuffer); gl.vertexattribpointer(coordcolor, 4, gl.float, false, 0, 0); gl.drawarrays(gl.triangles, 0, 3); Aleksander Dawid 2001-2016 rok 184
Oświetlenie WebGL Wektory normalne normal_points = [ 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0]; Aleksander Dawid 2001-2016 rok 185
Oświetlenie Vertex Shader attribute vec3 pozycja; attribute vec3 pozycjanorm; varying vec3 N; varying vec3 Pos; WebGL void main() { gl_position = vec4(pozycja,1.0); N = pozycjanorm; //Przekazanie normalnych do Fragment shadera Pos = pozycja; //Przekazanie położenia do Fragment shadera } Aleksander Dawid 2001-2016 rok 186
Oświetlenie Fragment Shader precision mediump float; varying vec3 N; varying vec3 Pos; WebGL void main() { vec4 Ambient = vec4(0.6,0.0,0.0,1.0); // Ambient Color vec4 Diffuse = vec4(1.0,1.0,0.0,1.0); // Diffuse Color vec3 Light_pos = vec3(0.0,-0.2,0.3); // Wektor Promienia od źródła światła do wierzchołka vec3 Ray = normalize(light_pos - Pos); // Iloczyn skalarny wektora Normalnego i wektora promienia float DiffAmp = max(dot(n,ray), 0.0); vec4 DiffV = Diffuse*DiffAmp; DiffV = clamp(diffv, 0.0, 1.0); // Normalizacja do [0.0,1.0] vec4 Suma = Ambient + DiffV; gl_fragcolor = Suma; } Aleksander Dawid 2001-2016 rok 187
Teksturowanie attribute vec3 pozycja; attribute vec2 atexturecoord; varying mediump vec2 vtexturecoord; void main() { gl_position = vec4(pozycja,1.0); vtexturecoord = atexturecoord; } WebGL W procesie nakładania tekstur na trójkąty bardzo ważne są współrzędne tekstury. Przesyłana one są z Vertex Shadera do Fragment Shadera Vertex Shader Fragment Shader varying mediump vec2 vtexturecoord; uniform sampler2d usampler; } void main() { gl_fragcolor = texture2d(usampler, vtexturecoord); Aleksander Dawid 2001-2016 rok 188
Teksturowanie WebGL Ustalenie współrzędnych tekstury dla kwadratu=2 trójkąty Wierzchołki var si=0.5; wall_points = [ -si, -si, 0.0, si, -si, 0.0, -si, si, 0.0, -si, si, 0.0, si, -si, 0.0, si, si, 0.0 ]; 0.0, 1.0 Współrzędne tekstury wall_texcoor = [ 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 ]; 1.0, 1.0 0.0, 0.0 1.0, 0.0 Aleksander Dawid 2001-2016 rok 189
Teksturowanie WebGL Ładowanie Obrazka InitTextures=function() { walltexture = gl.createtexture(); wallimage = new Image(); wallimage.src = "jatex.jpg"; } Sprawdzenie czy rozmiary obrazka są potęgą liczby 2 function ispowerof2(value) { return (value & (value - 1)) == 0; }; Aleksander Dawid 2001-2016 rok 190
Teksturowanie WebGL Parametry tekstury TextureParams=function(texture,image) { gl.bindtexture(gl.texture_2d, texture); gl.teximage2d(gl.texture_2d, 0, gl.rgba, gl.rgba, gl.unsigned_byte, image); if (ispowerof2(image.width) && ispowerof2(image.height)) { gl.texparameteri(gl.texture_2d, gl.texture_mag_filter, gl.linear); gl.texparameteri(gl.texture_2d, gl.texture_min_filter, gl.linear_mipmap_linear); gl.generatemipmap(gl.texture_2d); } else { gl.texparameteri(gl.texture_2d, gl.texture_wrap_s, gl.clamp_to_edge); gl.texparameteri(gl.texture_2d, gl.texture_wrap_t, gl.clamp_to_edge); gl.texparameteri(gl.texture_2d, gl.texture_min_filter, gl.linear); } } Aleksander Dawid 2001-2016 rok 191
Teksturowanie WebGL Problemy przy teksturowaniu WebGL Asynchroniczne wczytywanie plików graficznych. Problem dotyczy JavaScript i polega na wcześniejszym wywołaniu instrukcji renderujących teksturę niż wczytanie samego pliku który ma być teksturą. Zabezpieczenia przeglądarek internetowych. Pliki zewnętrzne (obrazy tekstur) nie mogą być pobierane podczas uruchamiania strony internetowej (plik HTML) z lokalnego folderu. Obraz taki można tylko pobrać z serwera WWW (HTTP). Aleksander Dawid 2001-2016 rok 192
Teksturowanie WebGL Renderowanie tekstury na trójkątach. wallimage.onload = function() { gl.clearcolor(0.9,0.9,1.0,1.0); //Ustawienie koloru tła gl.clear(gl.color_buffer_bit gl.depth_buffer_bit); gl.bindbuffer(gl.array_buffer, vertex_buffer); gl.vertexattribpointer(coord, 3, gl.float, false, 0, 0); gl.bindbuffer(gl.array_buffer, texcoor_buffer); gl.vertexattribpointer(texturecoordattribute, 2, gl.float, false, 0, 0); var textureunit = 1; TextureParams(wallTexture,wallImage); } gl.activetexture(gl.texture0+textureunit); gl.bindtexture(gl.texture_2d, walltexture); gl.uniform1i(samp, textureunit); gl.drawarrays(gl.triangles, 0, 6); Aleksander Dawid 2001-2016 rok 193
Teksturowanie WebGL Ustalenie współrzędnych tekstury dla kwadratu=2 trójkąty 0.0, 1.0 1.0, 1.0 0.0, 0.0 1.0, 0.0 0.0, 1.0 1.0, 1.0 0.0, 0.0 1.0, 0.0 Aleksander Dawid 2001-2016 rok 194
Rzutowanie perspektywiczne WebGL Aleksander Dawid 2001-2016 rok 195
WebGL Aleksander Dawid 2001-2016 rok 196 Rzutowanie perspektywiczne Macierz perspektywy P v v far near far near far near far near ar P * 0 * 2* 0 0 1 0 0 0 0 2 tan 0 0 0 0 / 2 tan
WebGL Aleksander Dawid 2001-2016 rok 197 Rzutowanie perspektywiczne Macierz Widoku M MW P v v MW * * 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 Macierz Translacji x x z y x z y x T x T z y x x T T T z y x z y x T T T MT 1* *0 *0 *1 1 0 1 0 0 0 0 1 0 0 0 0 1,1,,,1,, 1 0 1 0 0 0 0 1 0 0 0 0 1 Macierz Skalowania 1 0 0 0 0 0 0 0 0 0 0 0 0 z y x S S S MS
WebGL Aleksander Dawid 2001-2016 rok 198 Rzutowanie perspektywiczne Macierze Obrotu wokół osi x 1 0 0 0 0 ) cos( ) sin( 0 0 ) sin( ) cos( 0 0 0 0 1 O x Macierze Obrotu wokół osi y 1 0 0 0 0 ) cos( 0 ) sin( 0 0 1 0 0 ) sin( 0 ) cos( O y Macierze Obrotu wokół osi z 1 0 0 0 0 1 0 0 0 0 ) cos( ) sin( 0 0 ) sin( ) cos( O z
Rzutowanie perspektywiczne WebGL Macierz perspektywy (JavaScript) makeperspective=function(fieldofviewinradians, aspect, near, far) { var f = Math.tan(Math.PI * 0.5-0.5 * fieldofviewinradians); var rangeinv = 1.0 / (near - far); return [ f / aspect, 0, 0, 0, 0, f, 0, 0, 0, 0, (near + far) * rangeinv, -1, 0, 0, near * far * rangeinv * 2, 0 ]; }; Aleksander Dawid 2001-2016 rok 199
Rzutowanie perspektywiczne WebGL makeident=function() { return [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ]; }; perspectivematrix = makeperspective(45.0*math.pi/180.0, 400.0/400.0, 0.1, 100.0); MMatrix = makeident(); Przekazanie macierzy perspektywy i modelu do Vertex Shadera var PM = gl.getuniformlocation(shaderprogram, "ProjMatrix"); gl.uniformmatrix4fv(pm, false, new Float32Array(perspectiveMatrix)); var MM = gl.getuniformlocation(shaderprogram, "ModelMatrix"); gl.uniformmatrix4fv(mm, false, new Float32Array(MMatrix)); Aleksander Dawid 2001-2016 rok 200
Rzutowanie perspektywiczne WebGL Perspektywa (C, Vertex Shader) attribute vec3 pozycja; attribute vec3 pozycjanorm; uniform mat4 ProjMatrix; uniform mat4 ModelMatrix; varying vec3 N; varying vec3 Pos; void main() { gl_position = ProjMatrix*ModelMatrix*vec4(pozycja,1.0); N = pozycjanorm; Pos = pozycja; } Aleksander Dawid 2001-2016 rok 201
Translacje WebGL Wektor przesunięcia trans = [1.0, -1.0, -4.0]; Przekazanie do Vertex Shadera var trans = gl.getattriblocation(shaderprogram, "TransW"); gl.vertexattrib4f(trans, trans[0], trans[1], trans[2], 1.0); Translacja Vertex Shadera void main() { mat4 TrMat = mat4( vec4(1.0, 0.0, 0.0, 0.0), vec4(0.0, 1.0, 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(transw.x, TransW.y, TransW.z, 1.0) ); mat4 ModMat = ModelMatrix*TrMat; gl_position = ProjMatrix*ModMat*vec4(pozycja,1.0); } Aleksander Dawid 2001-2016 rok 202
Translacje WebGL Przykład. Przesuwanie trójkąta w kierunku Z Aleksander Dawid 2001-2016 rok 203
Animacja WebGL Animacja wywoływana jest z poziomu JavaScript window.requestanimationframe(render); Metoda z klasy Window wywołuje funkcję Render render=function() { gl.clear(gl.color_buffer_bit); if(xcor>0.8) step=-step; if(xcor<-0.8) step=-step; Xcor+=step; } gl.uniform1f( Xpos, Xcor ); gl.uniform1f( Scale, 8.0 ); gl.drawarrays(gl.triangle_fan, 0, vertices.length/3); window.requestanimationframe(render); Aleksander Dawid 2001-2016 rok 204
Najważniejsze funkcje języka Shaderów Konwersja radianów do stopni float radians(float degrees) vec2 radians(vec2 degrees) vec3 radians(vec3 degrees) vec4 radians(vec4 degrees) Konwersja stopni do radianów float degrees(float radians) vec2 degrees(vec2 radians) vec3 degrees(vec3 radians) vec4 degrees(vec4 radians) Aleksander Dawid 2001-2016 rok 205
Najważniejsze funkcje języka Shaderów Funkcje trygonometryczne Funkcja sinus float sin(float angle) vec2 sin(vec2 angle) vec3 sin(vec3 angle) vec4 sin(vec4 angle) Funkcja cosinus float cos(float angle) vec2 cos(vec2 angle) vec3 cos(vec3 angle) vec4 cos(vec4 angle) Aleksander Dawid 2001-2016 rok 206
Najważniejsze funkcje języka Shaderów Funkcje trygonometryczne Funkcja tangens float tan(float angle) vec2 tan(vec2 angle) vec3 tan(vec3 angle) vec4 tan(vec4 angle) Funkcja arcus sinus float asin(float x) vec2 asin(vec2 x) vec3 asin(vec3 x) vec4 asin(vec4 x) Aleksander Dawid 2001-2016 rok 207
Najważniejsze funkcje języka Shaderów Funkcje trygonometryczne Funkcja arcus cosinus float acos(float x) vec2 acos(vec2 x) vec3 acos(vec3 x) vec4 acos(vec4 x) Funkcja arcus tangens float atan(float y_over_x) vec2 atan(vec2 y_over_x) vec3 atan(vec3 y_over_x) vec4 atan(vec4 y_over_x) Aleksander Dawid 2001-2016 rok 208
Najważniejsze funkcje języka Shaderów Funkcje exponencjalne Funkcja potęgowa float pow(float x, float y) vec2 pow(vec2 x, vec2 y) vec3 pow(vec3 x, vec3 y) vec4 pow(vec4 x, vec4 y) Funkcja exponent e x float exp(float x) vec2 exp(vec2 x) vec3 exp(vec3 x) vec4 exp(vec4 x) Aleksander Dawid 2001-2016 rok 209
Najważniejsze funkcje języka Shaderów Funkcje exponencjalne Funkcja logarytm naturalny log e x float log(float x) vec2 log(vec2 x) vec3 log(vec3 x) vec4 log(vec4 x) Funkcja exponent 2 x float exp2(float x) vec2 exp2(vec2 x) vec3 exp2(vec3 x) vec4 exp2(vec4 x) Aleksander Dawid 2001-2016 rok 210
Najważniejsze funkcje języka Shaderów Funkcje exponencjalne Funkcja logarytm log 2 x float log2(float x) vec2 log2(vec2 x) vec3 log2(vec3 x) vec4 log2(vec4 x) Funkcja pierwiastkowania kwadratowego x float sqrt(float x) vec2 sqrt(vec2 x) vec3 sqrt(vec3 x) vec4 sqrt(vec4 x) Aleksander Dawid 2001-2016 rok 211
Najważniejsze funkcje języka Shaderów Funkcje exponencjalne Funkcja odwrotnego pierwiastka 1 x float inversesqrt(float x) vec2 inversesqrt(vec2 x) vec3 inversesqrt(vec3 x) vec4 inversesqrt(vec4 x) Aleksander Dawid 2001-2016 rok 212
Najważniejsze funkcje języka Shaderów Funkcje wspólne (zaokrągleń) Funkcja wartość bezwzględna float abs(float x) vec2 abs(vec2 x) vec3 abs(vec3 x) vec4 abs(vec4 x) Funkcja znakowa float sign(float x) vec2 sign(vec2 x) vec3 sign(vec3 x) vec4 sign(vec4 x) sign x = 1. 0 gdy x > 0 0. 0 gdy x = 0 1. 0 gdy x < 0 Aleksander Dawid 2001-2016 rok 213
Najważniejsze funkcje języka Shaderów Funkcje wspólne (zaokrągleń) Zaokrąglenie w dół do liczby całkowitej float floor(float x) vec2 floor(vec2 x) vec3 floor(vec3 x) vec4 floor(vec4 x) Zaokrąglenie w górę do liczby całkowitej float ceil(float x) vec2 ceil(vec2 x) vec3 ceil(vec3 x) vec4 ceil(vec4 x) Aleksander Dawid 2001-2016 rok 214
Najważniejsze funkcje języka Shaderów Funkcje wspólne (zaokrągleń) Część ułamkowa float fract(float x) vec2 fract(vec2 x) vec3 fract(vec3 x) vec4 fract(vec4 x) y = x floor(x) Modulo float mod(float x, float y) vec2 mod(vec2 x, vec2 y) vec3 mod(vec3 x, vec3 y) vec4 mod(vec4 x, vec4 y) Aleksander Dawid 2001-2016 rok 215
Najważniejsze funkcje języka Shaderów Funkcje wspólne (zaokrągleń) Minimum float min(float x, float y) vec2 min(vec2 x, vec2 y) vec3 min(vec3 x, vec3 y) vec4 min(vec4 x, vec4 y) Maximum float max(float x, float y) vec2 max(vec2 x, vec2 y) vec3 max(vec3 x, vec3 y) vec4 max(vec4 x, vec4 y) Aleksander Dawid 2001-2016 rok 216
Najważniejsze funkcje języka Shaderów Funkcje wspólne (zaokrągleń) Clamp (liczba z przedziału) float clamp(float x, float minval, float maxval) vec2 clamp(vec2 x, vec2 minval, vec2 maxval) vec3 clamp(vec3 x, vec3 minval, vec3 maxval) vec4 clamp(vec4 x, vec4 minval, vec4 maxval) Mieszanie liniowe float mix(float x, float y, float a) vec2 mix(vec2 x, vec2 y, float a) vec3 mix(vec3 x, vec3 y, float a) vec4 mix(vec4 x, vec4 y, float a) Aleksander Dawid 2001-2016 rok 217
Najważniejsze funkcje języka Shaderów Funkcje wspólne (zaokrągleń) Funkcja progowa float step(float edge, float x) vec2 step(vec2 edge, vec2 x) vec3 step(vec3 edge, vec3 x) vec4 step(vec4 edge, vec4 x) Funkcja gładka dla 0.0(edge0,edge1)1.0 float smoothstep(float edge0, float edge1, float x) vec2 smoothstep(vec2 edge0, vec2 edge1, vec2 x) vec3 smoothstep(vec3 edge0, vec3 edge1, vec3 x) vec4 smoothstep(vec4 edge0, vec4 edge1, vec4 x) Aleksander Dawid 2001-2016 rok 218
Najważniejsze funkcje języka Shaderów Funkcje geometryczne Funkcja długość wektora float length(float x) float length(vec2 x) float length(vec3 x) float length(vec4 x) L = x 2 + y 2 + z 2 + w 2 Funkcja odległości między dwoma punktami float distance(float p0, float p1) float distance(vec2 p0, vec2 p1) float distance(vec3 p0, vec3 p1) float distance(vec4 p0, vec4 p1) Aleksander Dawid 2001-2016 rok 219
Najważniejsze funkcje języka Shaderów Funkcje geometryczne Iloczyn skalarny wektorów float dot(float x, float y) float dot(vec2 x, vec2 y) float dot(vec3 x, vec3 y) float dot(vec4 x, vec4 y) v w = v w cos (α) Iloczyn wektorowy vec3 cross(vec3 x, vec3 y) v w = e x e y e z v x w x v y w y v z w z = (e x, e y, e z ) Aleksander Dawid 2001-2016 rok 220
Najważniejsze funkcje języka Shaderów Funkcje geometryczne Normalizacja wektora float normalize(float x) vec2 normalize(vec2 x) vec3 normalize(vec3 x) vec4 normalize(vec4 x) Rozpraszanie N x = 1 y 2 + z 2 + w 2 float faceforward(float N, float I, float Nref) vec2 faceforward(vec2 N, vec2 I, vec2 Nref) vec3 faceforward(vec3 N, vec3 I, vec3 Nref) vec4 faceforward(vec4 N, vec4 I, vec4 Nref) Aleksander Dawid 2001-2016 rok 221
Najważniejsze funkcje języka Shaderów Funkcje geometryczne Odbicie float reflect(float I, float N) vec2 reflect(vec2 I, vec2 N) vec3 reflect(vec3 I, vec3 N) vec4 reflect(vec4 I, vec4 N) Załamanie float refract(float I, float N, float eta) vec2 refract(vec2 I, vec2 N, float eta) vec3 refract(vec3 I, vec3 N, float eta) vec4 refract(vec4 I, vec4 N, float eta) Aleksander Dawid 2001-2016 rok 222
Najważniejsze funkcje języka Shaderów Funkcje macierzowe Mnożenie komponentów mat2 matrixcompmult(mat2 x, mat2 y) mat3 matrixcompmult(mat3 x, mat3 y) mat4 matrixcompmult(mat4 x, mat4 y) Aleksander Dawid 2001-2016 rok 223
Najważniejsze funkcje języka Shaderów Funkcje relacji wektorów Porównanie składowych wektora x[i]<y[i] bvec2 lessthan(vec2 x, vec2 y) bvec3 lessthan(vec3 x, vec3 y) bvec4 lessthan(vec4 x, vec4 y) Porównanie składowych wektora x[i]<=y[i] bvec2 lessthanequal(vec2 x, vec2 y) bvec3 lessthanequal(vec3 x, vec3 y) bvec4 lessthanequal(vec4 x, vec4 y) Aleksander Dawid 2001-2016 rok 224
Najważniejsze funkcje języka Shaderów Funkcje relacji wektorów Porównanie składowych wektora x[i]>y[i] bvec2 greaterthan(vec2 x, vec2 y) bvec3 greaterthan(vec3 x, vec3 y) bvec4 greaterthan(vec4 x, vec4 y) Porównanie składowych wektora x[i]>=y[i] bvec2 greaterthanequal(vec2 x, vec2 y) bvec3 greaterthanequal(vec3 x, vec3 y) bvec4 greaterthanequal(vec4 x, vec4 y) Aleksander Dawid 2001-2016 rok 225
Najważniejsze funkcje języka Shaderów Funkcje relacji wektorów Porównanie składowych wektora x[i]==y[i] bvec2 equal(vec2 x, vec2 y) bvec3 equal(vec3 x, vec3 y) bvec4 equal(vec4 x, vec4 y) Porównanie składowych wektora x[i]!=y[i] bvec2 notequal(vec2 x, vec2 y) bvec3 notequal(vec3 x, vec3 y) bvec4 notequal(vec4 x, vec4 y) Aleksander Dawid 2001-2016 rok 226
Najważniejsze funkcje języka Shaderów Funkcje relacji wektorów Prawda gdy którakolwiek ze składowych jest True bool any(bvec2 x) bool any(bvec3 x) bool any(bvec4 x) Prawda gdy wszystkie składowe zwracają prawdę bool all(bvec2 x) bool all(bvec3 x) bool all(bvec4 x) Aleksander Dawid 2001-2016 rok 227
Najważniejsze funkcje języka Shaderów Funkcja przeglądanie tekstur vec4 texture2d(sampler2d sampler, vec2 coord) vec4 texture2d(sampler2d sampler, vec2 coord, float bias) Funkcja zwraca kolor texela dla danej współrzędnej tekstury. Parametr bias dotyczy wybranej MIPMAPY Aleksander Dawid 2001-2016 rok 228
OpenCL Otwarty standard programowania multiprocesorów Aleksander Dawid programowanie procesorów graficznych
OpenCL Język tej biblioteki podobnie jak wszystkie systemy otwarte operuje na własnych typach zmiennych. cl_int, cl_float, cl_uint, cl_double, cl_long Aleksander Dawid programowanie procesorów graficznych
clgetplatformids clgetdeviceids clcreatecontext Strumień przetwarzania potoku OpenCL clcreatecommandqueue clcreateprogramwithsource Zwolnienie zasobów clbuildprogram clenqueuereadbuffer clcreatebuffer clenqueuendrangekernel clcreatekernel clsetkernelarg Aleksander Dawid programowanie procesorów graficznych
OpenCL - przygotowanie przetwarzania informacji na GPU 1. Informacja o platformie i urządzaniach cl_int clgetplatformids(cl_uint nentries, cl_platform_id *platforms, cl_uint *nplatforms) nentries spodziewana ilość plaform platforms zwraca listę identyfikatorów platform OpenCL nplatforms zwraca ilość platform Sukces: CL_SUCCESS Porażka: CL_INVALID_VALUE cl_int clgetdeviceids(cl_platform_id platform, cl_device_type device_type, cl_uint nentries, cl_device_id *devices, cl_uint *ndevices) platform identyfikator platformy device_type CL_DEVICE_TYPE_CPU, CL_DEVICE_TYPE_GPU, CL_DEVICE_TYPE_ALL nentries spodziwana ilość urządzeń devices zwraca listę identyfikatorów urządzeń. ndevices zwraca ilość urządzeń OpenCL Sukces: CL_SUCCESS Porażka: CL_INVALID_PLATFORM, CL_INVALID_DEVICE_TYPE, CL_INVALID_VALUE, CL_DEVICE_NOT_FOUND Aleksander Dawid programowanie procesorów graficznych
OpenCL - przygotowanie przetwarzania informacji na GPU cl_int clgetdeviceinfo(cl_device_id device, cl_device_info param_name, size_t param_value_size, void *param_value, size_t *param_value_size_ret) Device identyfikator urządzania Param_name nazwa parametru informacji Param_value_size rozmiar w bajtach parametru inforamcji Param_value wskaźnik do obszaru przechowującego informacje Param_value_size_ret zwrócony rozmiar Param_name CL_DEVICE_NAME CL_DEVICE_VENDOR CL_DEVICE_VERSION CL_DEVICE_MAX_CLOCK_FREQUENCY Aleksander Dawid programowanie procesorów graficznych
OpenCL - przygotowanie przetwarzania informacji na GPU 2. Utworzenie kontekstu urządzenia cl_context clcreatecontext(cl_context_properties *properties, cl_uint num_devices, const cl_device_id *devices, void *pfn_notify ( const char *errinfo, const void *private_info, size_t cb, void *user_data), void *user_data, cl_int *errcode_ret) Zbiornik grupujący dane. properties właściwości platformy, NULL = domyślne num_devices zadeklarowana ilość urządzeń devices wskźnik do list urządzeń pfn_notify funkcja zwrotna (callback function) user_data związany z funkcja zwrotną errcode_ret zwraca kod błędu Sukces: CL_SUCCESS Porażka: CL_INVALID_PLATFORM, CL_INVALID_DEVICE, CL_INVALID_VALUE, Aleksander Dawid programowanie procesorów graficznych
OpenCL - przygotowanie przetwarzania informacji na GPU 3. Utworzenie kolejkę poleceń na wybranym urządzeniu cl_command_queue clcreatecommandqueue(cl_context context, cl_device_id device, cl_command_queue_properties properties, cl_int *errcode_ret) context OpenCL kontext z poprzedniego kroku device identyfikator urządzenia properties właściwości kolejki poleceń errcode_ret zwraca kod błędu Sukces: CL_SUCCESS Porażka: CL_INVALID_CONTEXT, CL_INVALID_DEVICE, CL_INVALID_VALUE, CL_INVALID_QUEUE_PROPERTIES, CL_OUT_OF_HOST_MEMORY Aleksander Dawid programowanie procesorów graficznych
OpenCL - przygotowanie przetwarzania informacji na GPU 4. Tworzenie obiektu programu dla kontekstu cl_program clcreateprogramwithsource (cl_context context, cl_uint count, const char **strings, const size_t *lengths, cl_int *errcode_ret) Context utworzony kontekst OpenCL Count ilość kontekstów Strings Ciąg z programem źródłowym kernela Lengths Długości każdego z ciągów errcode_ret zwracany kod błędu Sukces: CL_SUCCESS Porażka: CL_INVALID_CONTEXT, CL_INVALID_VALUE, CL_OUT_OF_HOST_MEMORY Aleksander Dawid programowanie procesorów graficznych
OpenCL - przygotowanie przetwarzania informacji na GPU 5. Kompilacja programu cl_int clbuildprogram ( cl_program program, cl_uint num_devices, const cl_device_id *device_list, const char *options, void (*pfn_notify)(cl_program, void *user_data), void *user_data) program identyfikator programu num_devices ilość urządzeń device_list lista urządzeń Options wskaźnik do ciągu z opcjami (Optymalizacja) pfn_notify- funkcja zwrotna (callback function) user_data - związany z funkcja zwrotną Sukces: CL_SUCCESS Porażka: CL_INVALID_PROGRAM, CL_INVALID_VALUE, CL_INVALID_DEVICE, CL_COMPILER_NOT_AVAILABLE Aleksander Dawid programowanie procesorów graficznych
OpenCL - przygotowanie przetwarzania informacji na GPU 6. Alokacja pamięci cl_mem clcreatebuffer ( cl_context context, cl_mem_flags flags, size_t size, void *host_ptr, cl_int *errcode_ret) context OpenCL kontekst flags pole bitowe specyfikujące sposób użycia pamięci CL_MEM_READ_WRITE, CL_MEM_WRITE_ONLY, CL_MEM_READ_ONLY, CL_MEM_USE_HOST_PTR CL_MEM_ALLOC_HOST_PTR, CL_MEM_COPY_HOST_PTR size rozmiar bufora do zaalokowania host_ptr wskaźnik(adres) tego bufora errcode_ret kod błędu Sukces: CL_SUCCESS Porażka: CL_INVALID_CONTEXT, CL_INVALID_BUFFER_SIZE, CL_INVALID_HOST_PTR, CL_MEM_OBJECT_ALLOCATION_FAILURE Aleksander Dawid programowanie procesorów graficznych
OpenCL - przygotowanie przetwarzania informacji na GPU 7. Tworzenie kernela cl_kernel clcreatekernel ( cl_program program, const char *kernel_name, cl_int *errcode_ret) Program identyfikator programu kernel_name nazwa kernela errcode_ret zwracany kod błędu Sukces: CL_SUCCESS Porażka: CL_INVALID_PROGRAM, CL_INVALID_PROGRAM_EXECUTABLE, CL_INVALID_KERNEL_NAME, CL_INVALID_KERNEL_DEFINITION, CL_INVALID_VALUE Aleksander Dawid programowanie procesorów graficznych
OpenCL - przygotowanie przetwarzania informacji na GPU 8. Ustawienie argumentów cl_int clsetkernelarg ( cl_kernel kernel, cl_uint arg_index, size_t arg_size, const void *arg_value) Kernel identyfikator kernela arg_index indeks argumentu arg_size rozmiar argumentu arg_value wskaźnik do bufora pamięci Sukces: CL_SUCCESS Porażka: CL_INVALID_KERNEL, CL_INVALID_ARG_INDEX, CL_INVALID_ARG_VALUE, CL_INVALID_MEM_OBJECT, CL_INVALID_ARG_SIZE Aleksander Dawid programowanie procesorów graficznych
OpenCL - przygotowanie przetwarzania informacji na GPU 9. Uruchomienie kernela cl_int clenqueuendrangekernel ( cl_command_queue command_queue, cl_kernel kernel, cl_uint work_dim, const size_t *global_work_offset, const size_t *global_work_size, const size_t *local_work_size, cl_uint num_events_in_wait_list, const cl_event *event_wait_list, cl_event *event) command_queue kolejka poleceń Kernel kernel identyfikator work_dim ilość wymiarów określających zadanie global_work_offset na razie NULL, wprowadzony dla przyszłych wersji global_work_size lista określająca rozmiar dla każdego wymiaru local_work_size określa rozmiar grup roboczych num_events_in_wait_list określa zdarzenie na które musi czekać kernel event_wait_list - określa zdarzenie na które musi czekać kernel event identyfikator zdarzenia Aleksander Dawid programowanie procesorów graficznych
OpenCL - przygotowanie przetwarzania informacji na GPU 9. Uruchomienie kernela cd Sukces: CL_SUCCESS Porażka: CL_INVALID_PROGRAM_EXECUTABLE, CL_INVALID_COMMAND_QUEUE, CL_INVALID_KERNEL, CL_INVALID_CONTEXT, CL_INVALID_KERNEL_ARGS, CL_INVALID_WORK_DIMENSION, CL_INVALID_WORK_GROUP_SIZE CL_INVALID_WORK_ITEM_SIZE, CL_INVALID_GLOBAL_OFFSET CL_OUT_OF_RESOURCES, CL_MEM_OBJECT_ALLOCATION_FAILURE, CL_INVALID_EVENT_WAIT_LIST, CL_OUT_OF_HOST_MEMORY Aleksander Dawid programowanie procesorów graficznych
OpenCL - przygotowanie przetwarzania informacji na GPU 10. Odczytanie danych z urządzenia cl_int clenqueuereadbuffer ( cl_command_queue command_queue, cl_mem buffer, cl_bool blocking_read, size_t offset, size_t cb, void *ptr, cl_uint num_events_in_wait_list, const cl_event *event_wait_list, cl_event *event) command_queue kolejka poleceń buffer identyfikator bufora blocking_read odczyt blokujący Offset przesunięcie w buforze cb ilość danych do odczytu ptr wskaźnik do bufora w pamięci gospodarza num_events_in_wait_list lista zdarzeń event_wait_list lista zdarzeń event - zdarzenie Aleksander Dawid programowanie procesorów graficznych
OpenCL - przygotowanie przetwarzania informacji na GPU 10. Odczytanie danych z urządzenia cd Sukces: CL_SUCCESS Porażka: CL_INVALID_CONTEXT, CL_INVALID_COMMAND_QUEUE, CL_INVALID_MEM_OBJECT, CL_INVALID_VALUE, CL_INVALID_EVENT_WAIT_LIST, CL_MEM_OBJECT_ALLOCATION_FAILURE, CL_OUT_OF_HOST_MEMORY Aleksander Dawid programowanie procesorów graficznych
OpenCL - przygotowanie przetwarzania informacji na GPU 11. Zwolnienie zasobów status = clreleasekernel(kernel); status = clreleaseprogram(program); status = clreleasememobject(inputbuffer); status = clreleasememobject(outputbuffer); status = clreleasecommandqueue(commandqueue); status = clreleasecontext(context); Sukces: CL_SUCCESS Porażka: zależna od zwalnianego zasobów Aleksander Dawid programowanie procesorów graficznych
OpenCL - Kernel GPU kernel void helloworld( global char* in, global char* out) { int num = get_global_id(0); out[num] = in[num] + 1; } Aleksander Dawid programowanie procesorów graficznych
Platformy OpenCL AMD APP SDK 3.0 Karty AMD wspierane w OpenCL od wersji Radeon HD 4000 w górę AMD kompilacja kernel void helloworld( global char* in, global char* out) { int num = get_global_id(0); out[num] = in[num] + 1; } Aleksander Dawid programowanie procesorów graficznych
Platformy OpenCL CUDA TOOLKIT do wersji 4.0 Wspierane karty z rdzeniami CUDA od GF 8600GTX NVIDIA kompilacja kernel void helloworld( global char* in, global char* out) { int num = get_global_id(0); out[num] = in[num] + 1; } Aleksander Dawid programowanie procesorów graficznych
Przykład OpenCL na AMD i NVIDIA Kod CPU kernel void helloworld( global char* in, global char* out) { int num = get_global_id(0); out[num] = in[num] + 1; } Aleksander Dawid programowanie procesorów graficznych
Przykład OpenCL na AMD i NVIDIA Kod GPU kernel void helloworld( global char* in, global char* out) { int num = get_global_id(0); out[num] = in[num] + 1; } Aleksander Dawid programowanie procesorów graficznych
Programowanie procesorów graficznych NVIDIA (rdzenie CUDA)
Programowanie procesorów graficznych Wprowadzenie Procesory graficzne GPU (Graphics Processing Units) stosowane są w kartach graficznych do przetwarzania grafiki komputerowej i wyświetlania jej na ekranie monitora Motorem rozwoju GPU jest rynek gier komputerowych Fotorealizm w czasie rzeczywistym Cechy GPU Przetwarzanie równoległe Ilość rdzeni > 100 (1 CPU = 8 rdzeni) Przyspieszone operacje na macierzach. Wydajność rzędu Tfps Przetwarzanie wierzchołków i pixeli Przetwarzania światła Obsługa efektów fizycznych Obsługa biblioteki OpenGL i DirectX Aleksander Dawid 2010-2016
Programowanie procesorów graficznych Naukowe obliczenia numeryczne 2 najszybsze komputery świata korzystają z kart graficznych do zwiększenia swojej mocy obliczeniowej. 1 Titan supercomputer Oak Ridge National Laboratory Układ Kepler GK110 2688 - rdzeni CUDA 6 GB pamięci GDDR5 384-bitowy interfejs 8,972 - GPU Tesla K20X (Architektura Kepler) Maksymalna moc obliczeniowa to 27 petaflops czyli 10 15 operacji zmiennoprzecinkowych na sekundę Aleksander Dawid 2010-2016
Programowanie procesorów graficznych Naukowe obliczenia numeryczne 2 Tianhe 1a - Chiny TESLA (Fermi core) 448 CUDA Cores Tianhe 1a - Chiny 515 Gigaflops (podwójna precyzja) 14,336 procesorów Xeon X5670 1 Teraflop (pojedyncza precyzja) 7,168 GPU Nvidia Tesla M2050 Maksymalna wydajność 2.507 petaflops 10 15 operacji zmiennoprzecinkowych na sekundę Aleksander Dawid 2010-2016
Programowanie procesorów graficznych Światowe zasoby Aleksander Dawid 2010-2016
Programowanie procesorów graficznych Wzrost wydajności Aleksander Dawid 2010-2016
Programowanie procesorów graficznych Wzrost wydajności Aleksander Dawid 2010-2016
Programowanie procesorów graficznych Obliczenia ogólnego przeznaczenia na GPU Model Cg ( C for graphics) Obliczenia wykonywane były w ramach jednostek obliczeniowych pixel shader i vertex shader. Wynik obliczeń nie dało się odczytać bezpośrednio w postaci numerycznej tylko jako zestaw pixeli na ekranie monitora. Model CUDA (Compute Unified Device Architecture) Obliczenia wykonywane są na wszystkich dostępnych rdzeniach. Wynik obliczeń można odebrać w postaci numerycznej (terminal) Cechy CUDA Wielowątkowość Wielozadaniowość Programowanie w językach wysokiego poziomu Aleksander Dawid 2010-2016
Programowanie procesorów graficznych Architektura CUDA Model pamięci Pamięć lokalna dostępna tylko dla wątku (bardzo szybka) Pamięć dzielona dostępna tylko dla wszystkich wątków w bloku (bardzo szybka) Pamięć globalna dostępna dla wszystkich wątków (raczej wolna). Aleksander Dawid 2010-2016
Programowanie procesorów graficznych Architektura CUDA RAM CPU >= GPU Większa ilość pamięci na karcie zwiększa prędkość obliczeń Wspierane języki programowania. Dodatkowo istniej możliwość programowania CUDA w językach JAVA i Python Aleksander Dawid 2010-2016
Programowanie procesorów graficznych Programowanie CUDA C Kompilator: nvcc Dostęþny jest w pakiecie CUDA toolkit dla różnych systemów operacyjnych takich jak Windows, Linux, Mac. Pełne wsparcie dla standardu ANSI C z elementami C++ CUDA w wersji 1.0 dostępne jest już dla kart NVIDA GeForce 8600 Kod programu Kod CPU Kod GPU Aleksander Dawid 2010-2016
Programowanie procesorów graficznych Programowanie CUDA C Zadania Kod CPU Informacja o sprzęcie Inicjalizacja pamięci Operacje I/O CPU->GPU, GPU->CPU Zwalnianie pamięci Zadania Kod GPU Sterowanie programem Pamięci lokalne i dzielone Obliczenia numeryczne Synchronizacja wątków Program oddaje sterowanie do GPU i czeka na wynik obliczeń. Wykonane może to być w sposób synchroniczny lub asynchroniczny. GPU rozwiązuje zadanie na wszystkich dostępnych rdzeniach równolegle. Kod programu musi być specjalnie urównoleglony. Aleksander Dawid 2010-2016
Programowanie procesorów graficznych Programowanie CUDA C Wymagania systemowe Windows XP/VISTA/7/8/10 CUDA developer driver, CUDA toolkit, MS Visual Studio C++ Linux: nowsze dystrybucje. CUDA developer driver, CUDA toolkit, gcc4.4 Dodatkowo dla wszystkich systemów GPUComputingSDK, w którym są przykłady programów CUDA. Działanie tych programów jest gwarancją prawidłowej instalacji sterowników CUDA w systemie. Uwaga!!! WINDOWS VISTA/7 resetuje karte po braku odpowiedzi w przeciągu 90 s. Warto ten czas przedłużyć gdy nie będziemy korzystać z grafiki. Aleksander Dawid 2010-2016
Programowanie procesorów graficznych Kod CPU (informacja o zainstalowanej karcie) #include <stdio.h> #include <cutil.h> W pliku nagłówkowym cutil.h zawarte są informacje o wszystkich nagłówkach CUDA. Aby zastosować tą funkcje w systemi musi być dostępna biblioteka libcutil_x86_64.a (Linux64), która znajduje się w GPUComputingSDK. void PrintDevicesInformation() { int devicecount,nrdev,nmulproc; cudagetdevicecount(&devicecount); printf("number of CUDA devices: %d\n",devicecount); for(nrdev = 0; nrdev < devicecount; nrdev++) { cudadeviceprop deviceprop; cudagetdeviceproperties(&deviceprop, nrdev); printf("device %d: %s\n", nrdev, deviceprop.name); printf("maxthreadsperblock: %d\n", deviceprop.maxthreadsperblock); nmulproc=deviceprop.multiprocessorcount; printf("multiprocessorcount: %d\n", nmulproc); printf("computemode: %d\n", deviceprop.computemode); printf("sharedmemperblock: %ld\n", deviceprop.sharedmemperblock); } } Aleksander Dawid 2010-2016
Programowanie procesorów graficznych Pola struktury cudadeviceprop int canmaphostmemory // Urządzenie pozwala na mapowanie pamięci RAM int clockrate // Częstotliwość zegara w khz int computemode // cudacomputemodedefault - przetwarzanie wielowątkowe załączone // cudacomputemodeexclusive tylko jeden wątek // cudacomputemodeprohibited żaden wątek (CUDA wyłaczone) int concurrentkernels // Urządzenie uruchamia wiele jąder (kernel) konkurencyjnie int deviceoverlap // Urządzenie konkurencyjnie kopiuje i wykonuje jądra. int ECCEnabled // Urządzenie wspiera ECC int integrated // Czy urządzenie jest zintegrowane int kernelexectimeoutenabled // Czy są ogranicznia czasowe na wykonanie kernela int major // Główna wspierana wersja CUDA Aleksander Dawid 2010-2016
Programowanie procesorów graficznych Pola struktury cudadeviceprop int maxgridsize [3] // Maksymalny rozmiar macierzy obliczeniowej w każdym kierunku dim1 x dim2 x dim3 int maxtexture1d // Maksymalny rozmiar tekstury jednowymiarowej int maxtexture2d [2] // Maksymalny rozmiar tekstury dwuwymiarowej int maxtexture2darray [3] // Maksymalny rozmiar macierzy tekstury dwuwymiarowej int maxtexture3d [3] // Maksymalny rozmiar tekstury trójwymiarowej int maxthreadsdim [3] // Maksymalny rozmiar każdego wymiaru w bloku wątków int maxthreadsperblock // Maksymalna ilość wątków w bloku size_t mempitch // Maksymalny rozmiar pakietu w bajtach dozwolony przy kopiowaniu int minor // Numer 1.x wersji CUDA wspieranej Aleksander Dawid 2010-2016
Programowanie procesorów graficznych Pola struktury cudadeviceprop int multiprocessorcount // Ilość multiprocesorów w urządzeniu char name [256] // Ciąg ASCI identyfikujący urządzenie int pcibusid // Identyfikator PCI Bus urządzenia int pcideviceid // PCI ID urządzenia int regsperblock // ilość rejestrów 32-bit na blok size_t sharedmemperblock // Pamięć dzielona dostępna na blok [bajty] size_t surfacealignment // Wymagania dotyczące wyrównania powierzchni int tccdriver // 1 Jeżeli TESLA używa sterownika TCC; w przeciwnym razie 0 size_t texturealignment // Wymagania dotyczące wyrównania tekstury size_t totalconstmem // Constan memory dostępna na urządzeniu w bajtach size_t totalglobalmem // Globalna pamięć dostępna na urządzeniu int warpsize // Wielkość Warp w wątkach Aleksander Dawid 2010-2016
Programowanie procesorów graficznych Kod CPU (informacja o zainstalowanej karcie) int main(int argc, char* argv[]) { PrintDevicesInformation(); return 0; } Kompilacja gcc4.4 UBUNTU > nvcc program.cu -lcudart pathtolib/libcutil_x86_64.a -o program Wynik działania Number of CUDA devices: 1 Device 0: Quadro FX 5800 maxthreadsperblock: 512 multiprocessorcount: 30 computemode: 0 sharedmemperblock: 16384 Często stosowane rozszerzenie.cu zarówno w Linux jak i w Windows Aleksander Dawid 2010-2016
Kwalifikatory Typy funkcji host - oznacza funkcję która będzie wykonywana na CPU device - oznacza że funkcja będzie wykonywana na GPU global -funkcja globalna, wywoływana z CPU(host) i GPU(device) CUDA 3.x host device host device func() { #if CUDA_ARCH >= 500 // Device code path for compute capability 5.x #elif CUDA_ARCH >= 300 // Device code path for compute capability 3.x #elif CUDA_ARCH >= 200 // Device code path for compute capability 2.x #elif!defined( CUDA_ARCH ) // Host code path #endif } Aleksander Dawid 2010-2016
Kwalifikatory Typy zmiennych constant - oznacza stałą zadeklarowaną w GPU device - oznacza zmienną wewnątrz GPU shared - razem z kwalifikatorem device oznacza zmienną która rezyduje w pamięci dzielonej bloku i istnieje tak długo jak istnieje blok. Dostępna jest tylko dla wątków z bloku. Aleksander Dawid 2010-2016
Zarządzanie urządzeniami Wybór urządzenia najlepiej odpowiadającego wymaganiom obliczeniowym host cudaerror_t cudachoosedevice ( int* device, const cudadeviceprop* prop ) device urządzenie wybrane do obliczeń prop wymagania względem urządzenia. Returns cudasuccess, cudaerrorinvalidvalue Liczba dostępnych urządzeń CUDA host device cudaerror_t cudagetdevicecount ( int* count ) count liczba dostępnych urządzeń CUDA Aleksander Dawid 2010-2016
Zarządzanie urządzeniami Funkcja zwraca urządzenie id urządzenia na którym trwają obliczenia. host device cudaerror_t cudagetdevice ( int* device ) device urządzenie wybrane do obliczeń Ustawienie urządzenia na którym będą wykonywane obliczenia. host cudaerror_t cudasetdevice (int device) device urządzenie wybrane do obliczeń Resetowanie wszystkich ustawień w urządzeniu, zamykanie wątków obliczeniowych. host cudaerror_t cudadevicereset (void) Aleksander Dawid 2010-2016
Zarządzanie urządzeniami Czekaj aż wszystkie urządzenia przestaną liczyć. host device cudaerror_t cudadevicesynchronize ( void ) Ustaw flagę urządzenia host cudaerror_t cudasetdeviceflags ( unsigned int flags ) flags wskaźnik do ustawionej flagi na komputerze. Pobierz flagę urządzenia host cudaerror_t cudagetdeviceflags ( unsigned int* flags ) flags wskaźnik do ustawionej flagi na komputerze. Aleksander Dawid 2010-2016
Obsługa błędów Zwracanie nazwy błędu w postaci ciągu znaków. host device const char* cudageterrorname ( cudaerror_t error ) error identyfikator błędu. Zwracanie opisu błędu w postaci ciągu znaków. host device const char* cudageterrorstring ( cudaerror_t error ) error identyfikator błędu. Funkcja zwraca numer ostatniego błędu host device cudaerror_t cudagetlasterror ( void ) Aleksander Dawid 2010-2016
Obsługa zdarzeń (Event Management) Utwórz obiekt zdarzenie host cudaerror_t cudaeventcreate ( cudaevent_t* event ) event obiekt zdarzenie. Utwórz obiekt zdarzenie i ustaw dla niego flagę. host device cudaerror_t cudaeventcreatewithflags ( cudaevent_t* event, unsigned int flags ) Usuń obiekt zdarzenie host device cudaerror_t cudaeventdestroy ( cudaevent_t event ) Aleksander Dawid 2010-2016
Obsługa zdarzeń (Event Management) Oblicz czas pozostały pomiędzy zdarzeniami host cudaerror_t cudaeventelapsedtime ( float* ms, cudaevent_t start, cudaevent_t end ) Prześlij status zdarzenia host cudaerror_t cudaeventquery ( cudaevent_t event ) Nagraj zdarzenie host device cudaerror_t cudaeventrecord ( cudaevent_t event, cudastream_t stream = 0 ) Czekaj dopuki jakieś zdarzenie się wydarzy host cudaerror_t cudaeventsynchronize ( cudaevent_t event ) Aleksander Dawid 2010-2016
Programowanie procesorów graficznych Kod CPU (CPU->GPU) #define real float real* R; size_t size; void CPUMemAlloc() { size = 16*sizeof(real); // 16 liczb typu real R = (real*)malloc(size); memset(r,0,size); } Funkcja CPUMemAlloc alokuje pamięć dla 16 liczb typu real czyli float real* d_r; void GPUMemAlloc() { cudamalloc((void**)&d_r, size); } Funkcja GPUMemAlloc alokuje pamięć na karcie graficznej dla 16 liczb typu real Aleksander Dawid 2010-2016
Programowanie procesorów graficznych Kod CPU (CPU->GPU) void CopyCPUToGPU() { cudamemcpy(d_r, R, size, cudamemcpyhosttodevice); } Funkcja kopiuje size bloków pamięci z komputera na kartę graficzną Host komputer z CPU Device karta graficzna void CopyGPUToCPU() { cudamemcpy(r, d_r, size, cudamemcpydevicetohost); } Odwrotna operacja W operacjach tych brakuje obsługi wyjątków, które mogą wystąpić z różnych przyczyn. Funkcja cudagetlasterror()podaje numer ostatniego błędu. Aleksander Dawid 2010-2016
Programowanie procesorów graficznych Kod CPU (CPU->GPU) int main(int argc, char* argv[]) { CPUMemAlloc(); GPUMemAlloc(); R[0]=5; CopyCPUToGPU(); CopyGPUToCPU(); printf("r[0]=%f\n",r[0]); return 0; } Brakuje operacji wykonywanych na karcie graficznej Musimy stworzyć tzw. Kernel, który będzie wykonywany na GPU. Aleksander Dawid 2010-2016
Programowanie procesorów graficznych Kod CPU (Inicjalizacja Kernela GPU) int threadsperblock, blockspergrid, sharedsize; void InitKernel() { threadsperblock = 16; //Tyle samo wątków w bloku ile liczb mamy do //przeliczenia blockspergrid = 1; sharedsize = size; //Szybka pamięć dzielona na 16 liczb real } Każda karta graficzna ma inną maksymalną ilość wątków w jednym bloku. Wartość ta waha się między 128 a 1024. Tutaj blok został ustalony na 16 wątków. Ilość bloków w macierzy obliczeniowej też zależy od karty, tutaj ustalamy 1 blok. Teraz możemy już pisać program dla GPU Aleksander Dawid 2010-2016
Programowanie procesorów graficznych Kod GPU (Przemnożenie macierzy przez dwa) global void MultByTwo(real* R){ extern shared real rs[]; unsigned int id = threadidx.x; R[id]=R[id]*2; } Główna procedura w GPU tworzona jest przez dyrektywę global. shared oznacza pamięć dostępną dla całego bloku. int main(int argc, char* argv[]) { CPUMemAlloc(); GPUMemAlloc(); R[0]=5; CopyCPUToGPU(); InitKernel(); MultByTwo<<<blocksPerGrid, threadsperblock, sharedsize>>>(d_r); CopyGPUToCPU(); printf( R[0]=%f\n,R[0]); return 0; } Aleksander Dawid 2010-2016
Programowanie procesorów graficznych Przetwarzanie Kod sekwencyjny Wielokrotne wywoływanie kodu równoległego dla tego samego zestawu danych Kod równoległy kernel0<<<>>>() Kod sekwencyjny Kod równoległy kernel1<<<>>>() Aleksander Dawid 2010-2016
Programowanie procesorów graficznych Kod GPU (Sumowanie elementów macierzy) global void SumM(real* R){ extern shared real rs[]; unsigned int id = threadidx.x; rs[id]=r[id]; syncthreads(); if(id==0){ real SUM=0; for(int i=0;i<16;i++){ SUM+=rS[i]; } R[0]=SUM; } } int main(int argc, char* argv[]) { CPUMemAlloc(); GPUMemAlloc(); R[0]=5;R[1]=2;R[2]=4; CopyCPUToGPU(); InitKernel(); SumM<<<blocksPerGrid, threadsperblock, sharedsize>>>(d_r); CopyGPUToCPU(); printf( R[0]=%f\n,R[0]); return 0; } Aleksander Dawid 2010-2016
Programowanie procesorów graficznych Kod GPU (Redukcja 1) W poprzednim programie do sumowania liczb z każdego wątku użyte został tylko jeden wątek o identyfikatorze 0 global void SumReducto(real* R){ extern shared real rs[]; unsigned int id = threadidx.x; rs[id]=r[id]; syncthreads(); for(unsigned int s=1; s < blockdim.x; s *= 2) { if (id % (2*s) == 0) { rs[id] += rs[id + s]; } syncthreads(); } if(id == 0) R[0] = rs[0]; } Aleksander Dawid 2010-2016
Programowanie procesorów graficznych Kod GPU (Redukcja 1) Aleksander Dawid 2010-2016
Programowanie procesorów graficznych Kod GPU (Redukcja 2) Operacja modulo (%) jest bardzo wolna i wymaga zmiany. global void SumReducto2(real* R){ extern shared real rs[]; unsigned int id = threadidx.x; rs[id]=r[id]; syncthreads(); for(unsigned int s=1; s < blockdim.x; s *= 2) { int index = 2 * s * id; if (index < blockdim.x) { rs[index] += rs[index + s]; } syncthreads(); } if(id == 0) R[0] = rs[0]; } Aleksander Dawid 2010-2016
Programowanie procesorów graficznych Kod GPU (Obliczanie numeryczne całki metoda trapezów) Polega na sumowaniu pól trapezów pod krzywą Aleksander Dawid 2010-2016
Programowanie procesorów graficznych Kod GPU (Obliczanie numeryczne całki metoda trapezów) global void Trapez(real* Y, real* R){ extern shared real rs[]; unsigned int id = threadidx.x; rs[id]=y[id]; syncthreads(); if(id<blockdim.x-1){ real field; field=(rs[id] + 0.5* abs(rs[id]-rs[id+1]))*dxgpu; syncthreads(); rs[id]=field; } for(unsigned int s=1; s < blockdim.x; s *= 2) { int index = 2 * s * id; if (index < blockdim.x) { rs[index] += rs[index + s]; } syncthreads(); } if(id == 0) R[0] = rs[0]; } Aleksander Dawid 2010-2016
Programowanie procesorów graficznych Kod GPU (Obliczanie numeryczne całki metoda trapezów) constant real dxgpu=0; int main(int argc, char* argv[]) { CPUMemAlloc(); GPUMemAlloc(); InitKernel(); // threadsperblock=128 dx=0.0078125; //1/128 cudamemcpytosymbol(dxgpu, &dx, sizeof(real)); for(int i=0;i<threadsperblock;i++){ Y[i]=sqrt(1-(i*dx)*(i*dx)); } CopyCPUToGPU(); Trapez<<<blocksPerGrid, threadsperblock, sharedsize>>>(d_y, d_r); CopyGPUToCPU(); printf( R[0]=%f\n,R[0]); return 0; } Aleksander Dawid 2010-2016
Aleksander Dawid 290 CUDA-Układ wielu cząstek Numeryczne rozwiązywanie równań ruchu bazuje na rozwinięciu szeregu Taylora wokół pewnej chwili czasowej. Postać ogólna szeregu Taylora i j
Aleksander Dawid 291 Układ wielu cząstek Śledzenie trajektorii cząstki w odpowiednich przedziałach czasowych Algorytm velocity Verlet
V Ar-Ar [10-21 J] Układ wielu cząstek Potencjał Lennarda-Jonesa 2 1 0-1 Parametry zależne od typu atomu -2 2 4 6 8 10 12 14 16 r [A] Siły - potencjł symetryczny Aleksander Dawid 292
Aleksander Dawid 293 Siłę liczymy jako gradient potencjału. Siła jest wektorem o 3 składowych F(x,y,z) Obliczanie siły - Gradient potencjału Lennarda-Jonesa
Aleksander Dawid 294 Obliczanie siły kod sekwencyj for(i=0;i<n-1;i++) //F[i],R[i] struktury przechowujące { // siły i położenia poszczególnych for(j=i+1;j<n;j++) // atomów { Rxij=R[i].x - R[j].x; Ryij=R[i].y - R[j].y; Rzij=R[i].z - R[j].z; Rijsqr2 = Rxij*Rxij + Ryij*Ryij + Rzij*Rzij; Rij = sqrt(rijsqr2); Rijs2 = (Sigma*Sigma)/Rijsqr2; Rijap = Rijs2*Rijs2*Rijs2; Rijrp = 2*Rijs2*Rijs2*Rijs2*Rijs2*Rijs2*Rijs2; FXij = (ALJ*Rxij*(Rijrp-Rijap))/Rijsqr2; FYij = (ALJ*Ryij*(Rijrp-Rijap))/Rijsqr2; FZij = (ALJ*Rzij*(Rijrp-Rijap))/Rijsqr2; FXji = -FXij; FYji = -FYij; FZji = -FZij; F[i].x += FXij; F[i].y += FYij; F[i].z += FZij; F[j].x += FXji; F[j].y += FYji; F[j].z += FZji; } }
Aleksander Dawid 295 Obliczanie siły kod CUDA global void Force(real4* Rvect,real4* Fvect) { extern shared real4 rpos[]; //Pamięć dzielona unsigned int gid = mul24(blockdim.x,blockidx.x) + threadidx.x; if(gid>gn) return; int i,tile; real4 mpos; real3 f=make_real3(0.0f,0.0f,0.0f); mpos=rvect[gid]; for (i = 0, tile = 0; i < gn; i += gp, tile++) { int bli = tile * blockdim.x; int idx = bli + threadidx.x; //kopiowania porcji położeń do pamięci dzielonej rpos[threadidx.x] = Rvect[idx]; syncthreads(); f=calcforcetail(bli,gid,mpos,f); syncthreads(); } // Zapis siły w zmiennej globalnej Fvect[gid]=make_real4(f.x,f.y,f.z,0.0f); }
Aleksander Dawid 296 Obliczanie siły kod CUDA Obliczanie siły na i-te centrum odziaływania 256 wątków 256 wątków 256 wątków Kopiuj położenia Pamięć dzielona Przesuń do następnego bloku Oblicz w pojedynczym wątku odległość między i-tym atomem a położeniemi atomów zapisanym w pamięci dzielonej bloku.
Aleksander Dawid 297 Obliczanie siły- sumowanie par w pamięci dzielonej device real3 CalcForceTail(int bli,unsigned int gbli,real4 r,real3 f) { int i; extern shared real4 rpos[]; for(i=0;i<blockdim.x;i++){ } return f; } if( bli+i!= gbli){ f=calcpairs(r, rpos[i], f); }
Aleksander Dawid 298 Obliczanie siły między i-tym a j-tym atomem device real3 CalcPairs(real4 ri, real4 rj, real3 f) { real R2S,InvR2, Rijap,Rijrp,RP; real4 Rij; Rij.x = ri.x - rj.x; Rij.y = ri.y - rj.y; Rij.z = ri.z - rj.z; Rij.w = Rij.x*Rij.x + Rij.y*Rij.y + Rij.z*Rij.z; InvR2=1.0f/Rij.w; R2S=SGM2*InvR2; Rijap=R2S*R2S*R2S; Rijrp=2*Rijap*Rijap; RP=EPS24*(Rijrp-Rijap)*InvR2; f.x += RP*Rij.x; f.y += RP*Rij.y; f.z += RP*Rij.z; return f; }
Aleksander Dawid 299 Rozwiązywanie równań ruch (algorytm Velocity Verlet) Aby nie składowąć starych przyspieszeń, algorytm dzieli się na dwa kroki global void IntegrateHalf(real4* Rvect,real4* Vvect,real4* Fvect) { int idx = mul24(blockdim.x,blockidx.x) + threadidx.x; if(idx>gn) return; real4 dr; real3 f=make_real3(fvect[idx].x,fvect[idx].y,fvect[idx].z); real3 v=make_real3(vvect[idx].x,vvect[idx].y,vvect[idx].z); real3 r=make_real3(rvect[idx].x,rvect[idx].y,rvect[idx].z); dr.x = v.x*gdt + f.x*gimass*gdt; dr.y = v.y*gdt + f.y*gimass*gdt; dr.z = v.z*gdt + f.z*gimass*gdt; r.x += dr.x; r.y += dr.y; r.z += dr.z; v.x += f.x*gimass; v.y += f.y*gimass; v.z += f.z*gimass; Rvect[idx]=make_real4(r.x,r.y,r.z,0.0f); Vvect[idx]=make_real4(v.x,v.y,v.z,0.0f); syncthreads(); }
Aleksander Dawid 300 Rozwiązywanie równań ruch (algorytm Velocity Verlet) Aby nie składowąć starych przyspieszeń, algorytm dzieli się na dwa kroki global void IntegrateFull(real4* Vvect,real4* Fvect) { unsigned int idx = mul24(blockdim.x,blockidx.x) + threadidx.x; if(idx>gn) return; real3 f=make_real3(fvect[idx].x,fvect[idx].y,fvect[idx].z); real3 v=make_real3(vvect[idx].x,vvect[idx].y,vvect[idx].z); v.x += f.x*gimass; v.y += f.y*gimass; v.z += f.z*gimass; Vvect[idx]=make_real4(v.x,v.y,v.z,1.0f); }
Aleksander Dawid 301 Rozwiązywanie równań ruch (algorytm Velocity Verlet) t Położenia początkowe t+δt Nowe położenia Każdy atom skojarzony jest z jednym wątkiem Cząstka jest jednostką obliczeniową
Aleksander Dawid 302 Rozwiązywanie równań ruch (algorytm Velocity Verlet) //Inicjalizacja for(t=0;t<time;t++) { IntegrateHalf<<<blocksPerGrid,threadsPerBlock,sharedSize>>>(d_R,d_V,d_F); Force<<<blocksPerGrid, threadsperblock, sharedsize>>>(d_r,d_f); IntegrateFull<<<blocksPerGrid, threadsperblock, sharedsize>>>(d_v,d_f); ReadTrajectory<<<blocksPerGrid, threadsperblock>>>(d_r,d_traj,item); item+=n; }
Aleksander Dawid 303 Zapis trajektorii do bufora w pamięci globalnej global void ReadTrajectory(real4* Rvect,real4* Traj, int item) { unsigned int idx = mul24(blockdim.x,blockidx.x) + threadidx.x; if(idx>gn) return; real3 r=make_real3(rvect[idx].x,rvect[idx].y,rvect[idx].z); } Traj[item+idx]=make_real4(r.x,r.y,r.z,idx);
Stabilność numeryczna Aleksander Dawid 304
Przyśpieszenie w stosunku do CPU dla liczb podwójnej precyzji Aleksander Dawid 305
Niektóre wyniki Aleksander Dawid 306
Programowanie procesorów graficznych NEXT TECHNOLOGY Aleksander Dawid programowanie procesorów graficznych