-
Szovtver architektúra: (legalábbis amit mi használunk)

- Az eseménykezeléshez glutot használunk, a lényeg, hogy a main-ben regisztrálunk event handlereket pl. onDisplay és az OS eseményeire a glut callback-ként hívja a mi függvényünk
-
- VAO: vertex array object - ebben több VBO-t tárolhatunk, a műveletek (transzformációk, vágás) ezen történnek
- VBO: vertex buffer object - ebben tárolunk pontokat és a hozzá tartozó alakzatokat
- VBO/VAO megértést segítő videó
- Az OpenGL egy állapotgép = amit beállítok úgy marad
- Kirajzolás:
- GL_POINTS
- GL_LINE_STRIP, GL_LINE_LOOP (bezárja a strip-et)
- GL_TRIANGLES (mindig 3 egymás utáni pont egy háromszog) GL_TRIANGLESTRIP (az utolsó pontot veszi hozzá az előző kettőhöz: (abc), (bcd), (cde)...) GL_TRIANGLE_FAN: (az első ponthoz veszi a legutóbbi kettőt: (abc), (acd), (ade) ...)
glDrawArrays(MODE, first, count);
-
Input kezelés:
- az operációs rendszernél a koordináta rendszer origója a bal felső sarokban található, az y tegnely fejjel lefelé van!
- az glViewport viszont a bal alsó sarkot tekinti origónak, tehát valahogy így néz ki a dolog:

- tehát ha a normalizált eszközkoordinátákat szeretnénk megmondani az ablak koordinátái alapján akkor
$ndcX = \cfrac{2(x − offsetX)}{viewWidth} − 1$ $ndcY = 1 − \cfrac{2(y − offsetY)}{viewHeight}$
-
Adatok feldolgozása:
glEnableVertexAttribArray(0); // engedélyezi az írást ezekbe a regiszterekbe // beállítja a regiszter tulajdonságait glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL); // Paraméterek: id, hány darab számot tárol, milyen típusú, isFixedPoint, stride, offset // adatok feltöltése glBufferData(GL_ARRAY_BUFFER, size_in_bytes, &startOfArray[0], GL_STATIC_DRAW); // a mód lehet dinamikus is attól függően állítjuk, hogy gyakran cserélődik-e az adat
-
gl_Position: egy kötelező kimeneti regiszter (változó), ebbe várunk össze a rajzoláshoz megfelelő számú csúcspontot (pl. háromszögnél 3 darabot)- Figyelem: ez mindig 4 dimenziós lesz és a 3D-s projektív geometriai szabályok szerint lesz értelmezve (mivel a 3. dimenziót egészítjük ki +1-gyel)
- Uniform változók: olyan változók, amik állíthatók a hader programban. Nem a pontok adatai közé tartoznak (pl. az MVP)
- Mi a megvalósításnál dupla bufferelést használtunk (a háttér buffert rajzoljuk, a előteret mutatjuk a usernek és ezt a kettőt cserélgetjük). Ezt a
glutSwapBuffers();függvényhívással értük el.
-
Ezen a programon lett bemutatva az OpenGL használata
(ez nem az optimális algoritmus, de egészen használható)
1. Hány háromszöget próbál kirajzoltatni az alábbi programsor:
glDrawArrays(GL_TRIANGLE_FAN, 5, 7);
- glDrawArrays(MODE, start, count)
$\Rightarrow$ az 5-ös rész csak azt jelenti, hogy az 5. től kezdve szeretnénk kirajzolni 7 pontnyit - A GL_TRIANGLE_FAN az első 2 pontból még nem tud háromszöget rajzolni, úgyhogy csak a 3.-tól kezdve, viszont akkor minden új ponttal rajzol egy darab háromszöget
- Vagyis 7-2 = 5 darabot tud rajzolni
(Másik számokkal szemléltető kép)
2. Az onMouse eseménykezelő egy eseményt kapott, amelyben az átadott koordináták 884,600 volt. Mi ennek a pontnak a normalizált eszközkoordinátarendszerbeli y koordinátája, ha az alkalmazásablak felbontása 1000x1000 az utolsó nézeti beállítás a glViewport(100, 200, 800, 700) volt.
- Kis segítség:
glViewport(x, y, width, height), és a bal alsó sarokból veszi az offsetet, az egér viszont bal felülről számol. - Képletek és ábra fent, de nem garantálom hogy jók
3. Egészítsük ki egész számokkal az alábbi programot úgy, hogy a 10 elemeű vtxData tömb teljes egészéba a vbo-ba másolódjon. A pos adattag a csúcspont árnyaló 0. regiszterébe A norm adattag az 1. regiszterébe A tex adattag a 2. regiszterébe
- Magyrázat:
- az elején a struktúrát megnézzük, akkor látjuk, hogy: 1 db vec3 az 3 float-ból 1 db VertexData az 3 vec3-ból áll
- 360 azért annyi, mert byte-okban kell megadni és egy float az 4 byte, vagyis
$4 \cdot 3 \cdot 3 \cdot 10$ byte lesz feltöltve - A 3 azért annyi, mert egy vec3 valójában 3 floatból áll, a 36 az a VertexData mérete, az offset pedig szintén byte-ban az adat pozíciójának offset-je
4. Mik igazak a gl_Position regiszterre?
- Ha 3D euklideszi geometriában dolgozik a vertex shader, akkor ide a Descartes koordinátákat kell írni kiegészítve a w=1-gyel
(Magyarázat picit korábban volt, de a lényeg annyi, hogy perspektív térábrázolásra van kitalálva a GPU, ezért érdemes úgy használni $\Rightarrow$
gl_Position = (vp.x, vp.y, vp.z, 1))
- Az ebbe pakolt pont koordinátáit a GPU a 3D projektív geometria szabályai szerint értelmezi, azzal a megkötéssel, hogy a nemnegatív w koordinátájú pontokat tartja meg csak a vágás. (Ezt csak későbbi előadáson részleteztük, de érdemes megjegyezni, hogy ami nem látszik az le lesz vágva)
5. Az alábbiak közül melyik OpenGL programokkal befolyásolhatjuk a pixel shader program működését
- A glUniform - ez volt az egyetlen felsorolva, amire igaz volt, a többi az vagy független pl. viewport vagy már fragment shading
6. Válasszuk ki az igaz állításokat. Feltételezzük, hogy a GPU háromszögeket dolgoz fel aés a glDrawArrays(GL_TRIANGLES, 0, 30) OpenGL hívás hatására.
- Egy helyes válasz volt:
- Lehet olyan csúcspontárnyalót írni, amely esetén a GPU nem rajzol ki semmit a vbo tartalmától függetlenül
/* magyarázat: */ void main() { gl_Position = vec4(0, 0, 0, 0); }
- A többi válasz miért helytelen:
- A GPU csúcspont árnyaló programjában ki tudjuk számítani egy háromszög súlypontját. (Nem tudjuk, egyszerre mindig csak egy csúcsponttal foglalkozunk egy számítási egységen)
- A csúcspontárnyaló dönthet arról, hogy a pontokat a háromszög csúcspontjaiként vagy háromszög legyezőként (GL_TRIANGLE_FAN) értelmezze. (Nem, ezt mi állítjuk be. Az OpenGL állapotgép)
- Ha a háromszög súlypontját a pixel árnyalóban számoljuk ki, akkor azt elég egyetlen pixelre, és az eredményt át lehet adni a többi pixel árnyalójának. (... no comment)
- A vágás során a primitív típusa (GL_TRIANGLES) lényegtelen. (Nem lényegtelen, mert ettől függ mit rajzolunk ki $\Rightarrow$ különböző alakzatokat különböző módon kell vágni)
- A GPU pixel árnyaló programja eldönti, hogy melyik pixelt színezze ki a kért színre. (ElDöNTi - nem, majd én döntöm el. Az OpenGL állapotgép)
7. Válassza ki a helyes állításokat az OpenGL körrajzoló képességével kapcsolatban.
- A helyes válaszok:
- Az OpenGL nem tud kört rajzolni, mert projektív geometriában nincs távolság, ezért nincs kör sem, helyette kúpszeletek lehetnek, azok viszont túl bonyolultak lennének a vágás és raszterizáció hw. implementációjához.
- Az OpenGL nem tud kört rajzolni, mert a művelet felesleges, hiszen a kör közelíthető szabályos sokszöggel.
8. Jelöljük be az alábbi programra vonatkozó igaz állításokat:
#include <windows.h>
#include <GL/glew.h>
#include <GL/freeglut.h>
void onDisplay(), onInitialization();
int main(int argc, char * argv[]) {
glutInit(&argc, argv);
glutInitContextVersion(3, 3);
glutInitWindowSize(600, 600);
glutInitWindowPosition(100, 100);
glutInitDisplayMode(GLUT_RGBA|GLUT_DOUBLE);
glutCreateWindow(“Hi Graphics");
glewExperimental = true;
glewInit();
glViewport(0, 0, 600, 600);
onInitialization();
glutDisplayFunc(onDisplay);
glutMainLoop();
return 1;
}-
Helyes állítások:
- Csak Microsoft Windows operációs rendszer alatt fordul le.
(
#include <windows.h>) - A rajzolás célterülete a teljes alkalmazó ablak. (a viewportot teljesen kitöltjük, nincs offset)
- Egy pixelt 64 biten fog a hardver tárolni a rasztertárban.
(
glutInitDisplayMode(GLUT_RGBA|GLUT_DOUBLE);emiatt - 2 buffer, 4 channel, 8 bit / szín $\Rightarrow 2 \cdot 4 \cdot 8 = 64$) - Egyetlen sor törlésével a program Unix alatt is fordíthatóvá válik.
(
#include <windows.h>)
- Csak Microsoft Windows operációs rendszer alatt fordul le.
(
-
Hamis állítások
- Ha Visual Studiót használunk, akkor semmit sem kell installálni és a Web-ről letölteni, hogy leforduljon.
- A nézeti téglalap 100x100 pixelből áll.
- A glutCreateWindow után hívhatunk OpenGL függvényeket. (nem, csak akkor hívhatók, ha inicializáltuk az OpenGL-t, ami az onInitialization-ban történik a framework-ben)
- Hibás, hogy az opengl.h nincs beinklúdolva. (nem hibás, mert ezért van nekünk a glew könyvtár - ez segít eldönteni, hogy az OpenGL melyik verzióját vagunk képesek használni)
- Ez OpenGL 3.0-ás verzióra készül fel. (a glew eldönti)
- Ez OpenGL 1.0-ás verzióra készül fel. (a glew eldönti)
9. Az alábbi program szándéka szerint egy zöld háromszöget rajzolna ki phi radiánnal elforgatva, de nem működik. Mely sorokban van hiba?
void onDisplay( ) {
glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT);
int location = glGetUniformLocation(shaderProgram, "color");
glUniform3f(location, vec3(0.0f, 1.0f, 0.0f)); // hiba: 3 float változót vár paraméternek
float MVPtransf[4][4] = {
cos(phi), sin(phi), 0, 0,
-sin(phi), cos(phi), 0, 0,
0, 0, 0, 0,
0, 0, 0, 1
};
location = glGetUniformLocation(shaderProgram, "MVP");
glUniformMatrix4fv(location, 1, GL_FALSE, &MVPtransf[0][0]); // hiba: 1 dimenziós array-t vár az utolsó paraméternek
glBindVertexArray(vao);
glDrawArrays(GL_TRIANGLES, 1, 3 ); // hiba: nem 1 darab háromszöget, hanem 3 darabot akar kirajzolni
glutSwapBuffers( );
}10. Mely könyvtárak szükségesek feltétlenül, azaz nem csupán opcionálisak, az GPU OpenGL könyvtáron keresztüli programozásához.
- Válasz: OpenGL (nincs további helyes opció)
11. Hány csúcspontot fog tartalmazni az alábbi vbo?
unsigned int vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
double vertices[] = {1,2,3,4,5,6,7,8};
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0); // AttribArray 0
glVertexAttribPointer(0, 1, GL_FLOAT, GL_FALSE, 0, NULL);- Válasz: 16
- Mert nagyon trükkösen double arraybe lettek pakolva a pontok, de float-ként lesznek feltöltve. Mivel a Double kétszer annyi helyet használ fel, mint a float, ezért 16 float-nyi helyet fognak elfoglalni


