30. září 2013, Brno Připravil: David Procházka Vertex Buffer Objects Počítačová grafika 2
Obsah přednášky Strana 2 / 22 Obsah přednášky 1 Obsah přednášky 2 Vertex Buffer Objects 3 Příklady 4 Shrnutí
Obsah přednášky Strana 3 / 22 Obsah přednášky Ukládání informací o vrcholech a jejich vlastnostech do paměti grafické karty za účelem efektivního vykreslování.
Vertex Buffer Objects Strana 4 / 22 Obsah přednášky 1 Obsah přednášky 2 Vertex Buffer Objects 3 Příklady 4 Shrnutí
Vertex Buffer Objects Strana 5 / 22 Další grafická primitiva Vertex Buffer Objects (VBO) lze volně překládat jako objekty pro buffery vrcholů. Zásadní rozdíl oproti předchozím metodám vykreslování spočívá v tom, že v tomto případě ukládáme data pro vykreslování přímo paměti grafické karty. Tam k nim obvykle opakovaně přistupujeme. Při překreslování scény tedy není nutné přenášet data neustále z operační paměti do paměti grafické karty. Využívání VBO je doporučovaná metoda pro vykreslování podle nových verzí specifikace OpenGL (3.0+).
Vertex Buffer Objects Strana 6 / 22 Vykreslování do VBO se skládá z pěti kroků 1 Vygenerování jména pro buffer, 2 aktivace bufferu (bind), 3 uložení dat do bufferu, 4 využití bufferu pro vykreslování, 5 zrušení bufferu z paměti.
Vertex Buffer Objects Strana 7 / 22 Vygenerování jména bufferu glgenbuffers(glsizei n, GLuint *buffers). Funkci předáme v parametru n kolik názvů pro buffery potřebujeme vygenerovat. Vygenerované názvy se uloží do pole buffers. Pole bude obsahovat sekvenci celočíselných názvů. Funkce zaručuje, že tyto názvy nebyly dříve použity a proto mohou sloužit jako jednoznačný identifikátor bufferu. Příklad ilustruje vygenerování jména pro jeden buffer. 1 GLuint bufferid ; 2 glgenbuffers (1, & bufferid ); Uvolnění bufferu s daným jménem provedeme pomocí funkce gldeletebuffers(): 1 gldeletebuffers (1, & bufferid );
Vertex Buffer Objects Strana 8 / 22 Vytvoření bufferu Vytvoříme fyzicky buffer v paměti grafické karty. void glbindbuffer(glenum target, GLuint buffer). buffer název bufferu, který jsme vygenerovali v předchozím kroku. target identifikuje typ bufferu (co se do něj bude ukládat za hodnoty). Může nabývat hodnot: GL ARRAY BUFFER slouží pro ukládání vrcholů objektů, GL ELEMENT ARRAY BUFFER slouží pro ukládání indexů na vrcholy, GL PIXEL PACK BUFFER, GL PIXEL UNPACK BUFFER slouží pro ukládání pixelů rastrů (nyní nás nezajímá). Příklad: 1 glbindbuffer ( GL_ ARRAY_ BUFFER, bufferid )
Vertex Buffer Objects Strana 9 / 22 Naplnění bufferu void glbufferdata(glenum target, GLsizeiptr size, const GLvoid data, GLenum usage) target opět identifikuje typ bufferu, size obsahuje velikost dat kopírovaných do bufferu, data obsahuje ukazatel na pole vrcholů, které má být do bufferu kopírováno, usage popisuje způsob použití bufferu. Lze používat libovolně. Jen za účelem optimalizace výkonu. Pokud parametr zvolíte nevhodně, nebude to mít vliv na funkčnost aplikace, ale bude ovlivněn její výkon. Parametr nabývá následujících hodnot, které lze rozdělit do tří skupin: 1 GL STREAM DRAW, GL STREAM READ, GL STREAM COPY, 2 GL STATIC DRAW, GL STATIC READ, GL STATIC COPY, 3 GL DYNAMIC DRAW, GL DYNAMIC READ, GL DYNAMIC COPY.
Vertex Buffer Objects Strana 10 / 22 Naplnění bufferu významy parametrů Parametry pro četnost přístupu do bufferu Parametr Význam STREAM data budou zapsána jednou a čtena jen několikrát STATIC data budou zapsána jednou a čtena mnohokrát DYNAMIC data budou čtena i zapisována mnohokrát Parametry pro způsob přístupu do bufferu Parametr Význam DRAW obsah bufferu bude zapsán aplikací a používán pro renderování pomocí OpenGL READ obsah bude vytvořen OpenGL a využíván aplikací COPY obsah bude vytvořen OpenGL a následně OpenGL využíván pro renderování
Vertex Buffer Objects Strana 11 / 22 Naplnění bufferu příklad Příklad naplnění bufferu souřadnicemi vrcholů z pole trinagles: 1 glbufferdata ( 2 GL_ ARRAY_ BUFFER, // typ bufferu 3 sizeof ( triangles ), // kolik dat ukladam 4 triangles, // odkud 5 GL_ STATIC_ DRAW ); // pouziti bufferu Pokud zavoláte příkaz glbufferdata() na buffer, který již data obsahuje budou předchozí data smazány. Pokud se pokusíte uložit větší množství dat, než je aktuálně volné místo v paměti grafické karty, bude vyhozena chyba GL OUT OF MEMORY.
Vertex Buffer Objects Strana 12 / 22 Naplnění bufferu oddělená inicializace Druhou variantou je inicializovat buffer jako prázdný. Data pak přepsat požadovanými hodnotami. Některé zdroje tento způsob doporučují jako efektivnější. K doplnění dat použijeme např. příkaz void glbuffersubdata(glenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data). První parametr opět udává typ bufferu, druhý offset odkud se má do bufferu provádět zápis (nula znamená od počátku bufferu), třetí velikost zapisovaných dat a poslední je odkaz na data. Příklad přepsání celého bufferu: 1 glbufferdata(gl ARRAY BUFFER, sizeof(triangles), NULL, GL STATIC DRAW); 2 glbuffersubdata(gl ARRAY BUFFER, 0, sizeof(triangles), triangles);
Vertex Buffer Objects Strana 13 / 22 Definice ukazatele Nyní je nutné definovat ukazatel do pole vrcholů, abychom mohli vykreslovat. Toto je krok ve které se velmi snadno udělá chyba. Definice je prakticky totožná s definicí, kterou jsme používali u polí vrcholů. Rodíl je pouze posledním parametru odkaz na pole je roven nule! OpenGL automaticky použije právě vytvořený buffer a ukazatel nasměruje do něj. Příklad: glvertexpointer(2, GL INT, 0, 0); Z tohoto důvodu je nezbytné, aby příkaz glvertexpointer byl volán bezprostředně po vytvoření bufferu.
Vertex Buffer Objects Strana 14 / 22 Aktualizace dat v bufferu Již zmíněným glbuffersubdata(). V případě nekorektních parametrů (size je menší než nula, size+offset je větší, než původní velikost) generuje chybu GL INVALID VALUE. GLvoid* glmapbuffer(glenum target, GLenum acess) target GL ARRAY BUFFER nebo GL ELEMENT ARRAY BUFFER. acess GL READ ONLY, GL WRITE nebo GL READ WRITE. Pokud buffer nelze namapovat, je vrácena chyba GL OUT OF MEMORY. Při snaze o namapování již namapovaného bufferu je vrácena chyba GL INVALID OPERATION. V obou případech navíc příkaz glmapbuffer() vrátí hodnotu NULL. Uvolnění bufferu: glunmapbuffer(glenum target).
Příklady Strana 15 / 22 Obsah přednášky 1 Obsah přednášky 2 Vertex Buffer Objects 3 Příklady 4 Shrnutí
Příklady Strana 16 / 22 VBO příklad inicializace 1 GLuint vertexid ; // identifikatory bufferu 2 GLuint colorid ; 3 4 void init ( void ) 5 { 6 glclearcolor (0.0, 0.0, 0.0, 0. 0); 7 glmatrixmode ( GL_ PROJECTION ); 8 glloadidentity (); 9 gluortho2d (0, 640, 0, 480); 10 11 // vygenerovani cisel pro ID bufferu 12 glgenbuffers (1, & vertexid ); 13 glgenbuffers (1, & colorid ); 14 }
Příklady Strana 17 / 22 VBO příklad definice vrcholu 1 void display ( void ){ 2 glclear ( GL_COLOR_BUFFER_BIT ); 3 4 // definice vrcholu a barev 5 GLint triangles [] = { 6 10, 10, 7 320, 470, 8 630, 10, 9 }; 10 11 GLfloat colors [] = { 12 1.0, 0.0, 0.0, 13 0.0, 1.0, 0.0, 14 0.0, 0.0, 1.0 15 }; 16 // pokracovani funkce na dalsim slidu
Příklady Strana 18 / 22 VBO příklad vytvoření bufferů 1 // propojeni jmena bufferu a jeho typu 2 glbindbuffer ( GL_ ARRAY_ BUFFER, vertexid ); 3 // vytvoreni bufferu a naplneni polem vrcholu 4 glbufferdata ( GL_ ARRAY_ BUFFER, sizeof ( triangles ), 5 triangles, GL_ STATIC_ DRAW ); 6 7 // nastaveni ukazatele na barvy do bufferu 8 // musi byt volano bezprostredne po vytvoreni 9 glvertexpointer (2, GL_INT, 0, 0); 10 11 glbindbuffer ( GL_ ARRAY_ BUFFER, colorid ); 12 glbufferdata ( GL_ ARRAY_ BUFFER, 3* sizeof ( colors ), 13 colors, GL_ STATIC_ DRAW ); 14 glcolorpointer (3, GL_ FLOAT, 0, 0); 15 16 // pokracovani funkce na dalsim slidu
Příklady Strana 19 / 22 VBO příklad aktivace a vykreslení 1 // aktivace pole vrcholu a barev 2 glenableclientstate ( GL_ VERTEX_ ARRAY ); 3 glenableclientstate ( GL_ COLOR_ ARRAY ); 4 5 // vykresleni 3 vrcholu trojuhelniku 6 gldrawarrays ( GL_ TRIANGLES, 0, 3); 7 8 // zruseni poli 9 gldisableclientstate ( GL_ COLOR_ ARRAY ); 10 gldisableclientstate ( GL_ VERTEX_ ARRAY ); 11 glflush (); 12 }
Shrnutí Strana 20 / 22 Obsah přednášky 1 Obsah přednášky 2 Vertex Buffer Objects 3 Příklady 4 Shrnutí
Shrnutí Strana 21 / 22 Shrnutí VBO jsou metodou ukládání dat, která je doporučována jako hlavní metoda v OpenGL od verze 3. Jedná se o ukládání dat přímo do paměti grafické karty. Použití vrcholů se skládá z následujících kroků, které je nutné znát: 1 Vygenerování jména pro buffer, 2 aktivace bufferu (bind), 3 uložení dat do bufferu, 4 využití bufferu pro vykreslování, 5 zrušení bufferu z paměti.
Shrnutí Strana 22 / 22 Kontrolní otázky/úkoly Vytvořte příklad, který umožní vykreslení jednoduchého auta za pomoci VBO. Dbejte na korektní objektový návrh aplikace. Aplikaci rozdělte na hlavičkové a implementační soubory v souladu s prezentovanými principy objektového návrhu.