Számítógépes grafika OpenGL 1. gyakorlat
Tartalom OpenGL röviden Első program: üres képernyő Második program: rajzolás
OpenGL SGI által elkezdett API, grafikus alkalmazások programozására Gyakorlatilag is cross-platform Eredetileg az SGI IRIS GL-jéből fejlődött ki OpenGL Architecture Review Board kezelte kezdetekben 2006 óta a Khronos Groupé az irányítás OpenGL specifikáció: www.opengl.org
OpenGL Állapotgép, a Khronos által kezelt specifikációknak megfelelő driverek valósítják meg az utasításokat Kliens-szerver jellegű, ahol a szerver a GL, a kliens az alkalmazás Lehetőséget nyújt a szabványon túli kiegészítések elkészítésére is
OpenGL Verziók: Forrás: http://www.opengl.org/documentation/specs/ OpenGL 1.0: 1992. július 1. OpenGL 2.0: 2004. október 22. OpenGL 3.0: 2008. augusztus 11. OpenGL 4.0: 2010. március 11. Forrás: http://www.opengl.org/documentation/specs/
OpenGL Ezekre lesz szükségünk a CG-n kívül: GLEW: http://glew.sourceforge.net/index.html GLM (matematikai könyvtár): http://glm.g-truc.net/download.html Freeglut: http://freeglut.sourceforge.net/index.php#download
Visual Studio beállítása OpenGL-hez Include könyvtárak közé: glm-0.9.B.1\ glew-1.5.3\include freeglut-2.6.0\include Library könyvtárak közé: glew-1.5.3\lib Szükséges lib fájlok: #pragma comment(lib, "cg.lib") #pragma comment(lib, "cgGL.lib") #pragma comment(lib, "glew32s.lib")
Konkrétan graflabban beállítandó Tools/Options/Projects and Solutions/VC++ directories/ Include files: C:\Program Files\freeglut-2.4.0\include T:\glew-1.5.3\include Library files: C:\Program Files\freeglut-2.4.0\ReleaseStatic T:\glew-1.5.3\lib
Konkrétan graflabban letöltendő GLEW: https://sourceforge.net/projects/glew/files/glew/1.5.3/glew-1.5.3.zip/download https://sourceforge.net/projects/glew/files/glew/1.5.3/glew-1.5.3-win32.zip/download GLM: https://sourceforge.net/projects/glf/files/glm/glm-0.9.B.1/glm-0.9.B.1.zip/download
Visual Studio beállítása OpenGL-hez DLL fájlok amikre szükség lesz: CG-hez cg.dll és cgGL.dll glew.dll freeglut.dll (hacsak nem statikusan linkeljük utóbbi kettőt)
GLUT Segédkönyvtár, ami elfedi előlünk a Windows-os dolgokat Mi a freeglut-ot fogjuk használni
Extension-ök Az alap OpenGL specifikáció lehetőséget nyújt bővítésre Ezt ezeken a kiterjesztéseken keresztül lehet elérni Tipikusan gyártó specifikus indíttatású egy-egy extension Ha mindenkinek tetszik, akkor végül a szabvány része lesz (pl. vbo-k)
OpenGL elnevezési konvenciók
Tartalom OpenGL röviden Első program: üres képernyő Második program: rajzolás
Első OpenGL program Készítsünk egy fekete képernyőt! Program letölthető innen: http://people.inf.elte.hu/valasek/bevgraf/08/01_Create.zip
main.cpp #define FREEGLUT_STATIC #include <GL/glew.h> #include <GL/freeglut.h> #include <windows.h> #include <iostream> #pragma comment(lib, "glew32.lib") #pragma comment(lib, "freeglut_static.lib")
main.cpp int main(int argc, char* argv[]) { glutInit(&argc, argv); glutInitWindowSize(640, 480); glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH); glutCreateWindow("OpenGL program"); ...
glutInit glutInit( int *argcp, char **argv) A GLUT segédkönyvtár inicializálása argcp: a programunk parancssorának számát tartalmazó módosítatlan változóra
glutInit glutInit( int *argcp, char **argv) A GLUT segédkönyvtár inicializálása argv: a tényleges parancssor
glutInitWindowSize glutInitWindowSize( int width, int height) Létrehozandó ablak szélessége és magassága
glutInitDisplayMode glutInitDisplayMode( unsigned int mode) A kezdeti megjelenítési tulajdonságok beállítása: GLUT_RGBA: RGBA színmodell használata GLUT_DOUBLE: dupla pufferelés használata GLUT_DEPTH: mélységi puffer használata További információk: http://www.opengl.org/documentation/specs/glut/spec3/node12.html
glutCreateWindow glutCreateWindow( char *name) A paraméterben megadott feliratú ablak létrehozása
main.cpp ... glutDisplayFunc(Render); glutIdleFunc(Idle); if (glewInit() != GLEW_OK) { std::cout << "Hiba!" << std::endl; return -1; } Init(); glutMainLoop(); return 0; }
glutDisplayFunc glutDisplayFunc( void (*func)(void)) Egy callback függvényt adunk át a GLUT-nak, ami akkor hívódik meg, ha a kliensterületet újra kell rajzolni A függvénynek így kell kinéznie: void név() { … }
glutIdleFunc glutIdleFunc( void (*func)(void)) Egy callback függvényt adunk át a GLUT-nak, ami akkor hívódik meg, ha nincs feldolgozásra váró üzenete az ablakunknak A függvénynek így kell kinéznie itt is: void név() { … }
glewInit() Inicializálja a glew-t (ez fogja betölteni az extension-öket)
glutMainLoop() Elindul a fő ciklusa a GLUT-nak Ez csak akkor hívja a rajzoló callback-et, ha az ablakozó szerint újra kell rajzolni Ezért mi az idle callback-ben mindig kiadunk egy render parancsot (glutPostRedisplay-t):
main.cpp void Idle() { glutPostRedisplay(); }
main.cpp void Init() { glClearColor(0,0,0,1); }
glClearColor glClearColor( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); Beállítja a törlési színt Az egyes színkomponensek 0 és 1 közötti lebegőpontos számok kellenek, hogy legyenek
OpenGL adattípus typedef-ek
main.cpp void Render() { glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glutSwapBuffers(); }
glClear glClear(GLbitfield mask) Mit töröljünk: GL_COLOR_BUFFER_BIT: a frame puffert (OpenGL-ül color buffer) GL_DEPTH_BUFFER_BIT: mélységi puffert GL_STENCIL_BUFFER_BIT: stencil puffert
glutSwapBuffers glutSwapBuffers() A back és a front buffer megcserélése
Feladat 3 másodperc alatt feketéből váltson át a képernyő színe zöldre és vissza, szép folyamatosan
Tartalom OpenGL röviden Első program: üres képernyő Második program: rajzolás
Második program Rajzoljunk ki egy háromszöget!
main.cpp A main() és Idle() függvényeink nem változnak Van egy új globális változónk, ez a Vertex Buffer Object-ünk (VBO) azonosítója lesz: GLuint g_vb;
main.cpp/void Init() void Init() { glClearColor( 0, 0, 0.5f, 1); float geom[] = -1, -1, 0.5f, 0, 1, 0.5f, 1, -1, 0.5f, }; ...
OpenGL
main.cpp/void Init() ... glGenBuffers(1, &g_vb); glBindBuffer(GL_ARRAY_BUFFER, g_vb); glBufferData( GL_ARRAY_BUFFER, sizeof(geom), geom, GL_STREAM_DRAW); }
glGenBuffers glGenBuffers( GLsizei n, GLuint * buffers) Puffer objektumokat hoz létre n darab puffert hoz létre A buffers egy tömb, ami tárolni fogja a létrehozott pufferek azonosítóit
glBindBuffer glBindBuffer( GLenum target, GLuint buffer); A második paraméterben megadott puffert hozza létre (rendeli a contexthez), vagy veszi használatba: GL_ARRAY_BUFFER GL_ELEMENT_ARRAY_BUFFER GL_PIXEL_PACK_BUFFER GL_PIXEL_UNPACK_BUFFER
glBufferData glBufferData( enum target, sizeiptr size, const void *data, enum usage) A tényleges memóriafoglalás itt történik meg Ha már létező pufferre hívjuk meg, akkor újrafoglalódik neki memóriaterület Meglévő memória átírására: glBufferSubData
glBufferData glBufferData( enum target, sizeiptr size, const void *data, enum usage) Milyen puffert hozunk létre: GL_ARRAY_BUFFER GL_ELEMENT_ARRAY_BUFFER GL_PIXEL_PACK_BUFFER GL_PIXEL_UNPACK_BUFFER
glBufferData glBufferData( enum target, sizeiptr size, const void *data, enum usage) A létrehozandó puffer mérete bájtban
glBufferData glBufferData( enum target, sizeiptr size, const void *data, enum usage) Memóriaterület, ahonnan feltöltődik a puffer a méretének megfelelő bájtnyi adattal
glBufferData glBufferData( enum target, sizeiptr size, const void *data, enum usage) A puffer felhasználási módja, adatfeltöltés gyakoriságának szempontjából: STATIC: csak egyszer lesz adat feltöltve rá STREAM: használat után változó tartalom DYNAMIC: többszöri változtatások, de egy-egy változtatás után többszöri felhasználás
glBufferData glBufferData( enum target, sizeiptr size, const void *data, enum usage) A puffer felhasználási módja, az adatfelhasználás módjának függvényében: DRAW: az adatokat az alkalmazás hozza létre, kirajzoláshoz szükséges adatok tárolója COPY: az adatokat a GL hozza létre, kirajzoláshoz is használja READ: az adatokat a GL hozza létre, de nem használja fel inputként
glBufferData Usage lehetséges értékei:
main.cpp/Render() void Render() { glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnableClientState(GL_VERTEX_ARRAY); glBindBuffer(GL_ARRAY_BUFFER, g_vb); glVertexPointer(3, GL_FLOAT, 3*sizeof(float), 0); ...
glEnableClientState glEnableClientState(GLenum cap) Engedélyezünk egy kliens (alkalmazás) oldali dolgot: GL_VERTEX_ARRAY GL_TEXTURE_COORD_ARRAY GL_COLOR_ARRAY És a többi: http://www.opengl.org/sdk/docs/man/xhtml/glEnableClientState.xml Alapból minden le van tiltva Letiltani glDisableClientState-tel lehet
glVertexPointer glVertexPointer( GLint size, GLenum type, GLsizei stride, const GLvoid * pointer) Vertexek egy tömbjét definiáljuk
glVertexPointer glVertexPointer( GLint size, GLenum type, GLsizei stride, const GLvoid * pointer) size: a vertexek adattagjainak száma Itt a vertex csak pozíciókat jelent, így ennek lehetséges értéke 2, 3 illetve 4 (utóbbi az alapértelmezett)
glVertexPointer glVertexPointer( GLint size, GLenum type, GLsizei stride, const GLvoid * pointer) A koordináták megadásához használt adattípus: GL_FLOAT (alapértelmezett) GL_DOUBLE GL_SHORT GL_INT
glVertexPointer glVertexPointer( GLint size, GLenum type, GLsizei stride, const GLvoid * pointer) Egymást követő vertexek közti távolság nagysága, bájtban mérve
glVertexPointer glVertexPointer( GLint size, GLenum type, GLsizei stride, const GLvoid * pointer) Mutató az első koordináta memóriacímére (a kezdeti eltolást így adhatjuk meg)
main.cpp/Render() ... glDrawArrays(GL_TRIANGLES, 0, 3); glBindBuffer(GL_ARRAY_BUFFER, 0); glDisableClientState( GL_VERTEX_ARRAY); glutSwapBuffers(); }
glDrawArrays glDrawArrays( GLenum mode, GLint first, GLsizei count); Mode: kirajzolandó primitívek típusa:
glDrawArrays glDrawArrays( GLenum mode, GLint first, GLsizei count); first: kezdőindex a felhasznált vertex tömbben (vbo-ban)
glDrawArrays glDrawArrays( GLenum mode, GLint first, GLsizei count); A kirajzolás során felhasznált csúcspontok száma