„Számítógépes grafika házi feladat tutorial” változatai közötti eltérés
| 38. sor: | 38. sor: | ||
=== Rajzolás az OpenGL segítségével === | === Rajzolás az OpenGL segítségével === | ||
Az OpenGL néhány csak néhány típusú primitívet tud rajzolni, ezekből kell építkeznünk. A típusok: | |||
* Pontok: <code>GL_POINTS</code> | |||
* Vonalak: <code>GL_LINES, GL_LINE_STRIP, GL_LINE_LOOP</code> | |||
* Háromszögek: <code>GL_TRIANGLES, GL_TRIANGLE_STRIP, GL_TRIANGLE_LOOP</code> | |||
* Háromszögekből összetett alakzatok: | |||
** Négyszögek (igazándiból 2 háromszög): <code>GL_QUADS, GL_QUAD_STRIP</code> | |||
** Sokszög (ez is háromszögenként rajzolódik ki): <code>GL_POLYGON</code> | |||
<div style="text-align:center;margin:0px auto;"> | <div style="text-align:center;margin:0px auto;"> | ||
| 51. sor: | 50. sor: | ||
</div> | </div> | ||
A rajzolás az alábbi módon történik: | |||
<pre> | <pre> | ||
glBegin("Primitív típus"); | glBegin("Primitív típus"); | ||
| 59. sor: | 58. sor: | ||
glEnd(); | glEnd(); | ||
</pre> | </pre> | ||
A pontok megadásához glVertex{2,3}f függvények valamelyikét kell használnod, az alapján, hogy hány dimenzióban dolgozol. Tehát 2 dimenzióban a glVertex2f-et, 3 dimenzióban a glVertex3f-et kell használnod. | |||
A pontok sorrendje nagyon fontos, már egy quad esetében sem lehet "csak úgy" felsorolni a négy pontot, ha rossz sorrendben adjuk meg őket, akkor két egymásba csúszott háromszöget fogunk látni. | |||
=== 2D rajzolás === | === 2D rajzolás === | ||
A koordináták amiket átadsz azok a normalizált eszköz koordináta-rendszerben vannak értelmezve, ahol a (0,0) a képernyő közepe, a (-1, -1) pedig a bal alsó sarok. | |||
Példaprogram: [[Média:Grafpp_haromszogek.cpp|Háromszögek]] | |||
<br/> <syntaxhighlight lang="c"> | <br/> <syntaxhighlight lang="c"> | ||
| 87. sor: | 87. sor: | ||
</div> | </div> | ||
<br/> | <br/> | ||
Minden egyes ponthoz külön színt is meg tudunk megadni. A glColor3f()-el lehet állítani a rajzolószínt, ami utána az összes glVertex hívásra érvényes lesz. Az összetettebb alakzatoknál az egyes pontok színei interpolálódnak, és szép színátmenetet kapunk. | |||
Példaprogram: [[Média:Grafpp_smiley.cpp|Smiley]] | |||
<br/> <syntaxhighlight lang="c"> | <br/> <syntaxhighlight lang="c"> | ||
| 141. sor: | 142. sor: | ||
=== Eseménykezelés === | === Eseménykezelés === | ||
A grafikus programok általában eseményvezéreltek, azaz a felhasználó által generált események (pl. egérkattintás) irányítják a programot. A GLUT ehhez nagyon sok segítséget ad, nekünk csak be kell regisztrálnunk egy-egy függvényt, hogy melyik esemény hatására mi történjen, pl az egérkattintásokat az onMouse() függvényben kezeljük. | |||
A három legfontosabb eseménytípus: | |||
* Billentyűzet esemény: | |||
** Billentyű lenyomás - onKeyboard | |||
** Billentyű felengedés - onKeyboardUp | |||
* Idő múlása (lényegében ez is egy esemény) - onIdle | |||
* Egér esemény: | |||
** Egér mozgatás - onMouseMotion | |||
** Egér gombbal kattintás - onMouse | |||
** Az egér eseményekkel kapcsolatban egy apró kellemetlenség, hogy a GLUT a kattintások helyét az oprendszer koordináta rendszerében adja át nekünk (ablak bal fölső sarka az origó, x jobbra, y lefelé nő, az egység pedig a pixel), míg mi normalizált eszközkoordinátákkal dolgozunk (az ablak közepe az origó, a x jobbra, az y felfele nő, és mindkét dimenzióban az ablak méretének a fele az egység). Ezért kénytelenek vagyunk átszámolni azokat az értékeket, amiket a GLUT ad nekünk. Erre egy lehetséges megoldás: | |||
<br/> <syntaxhighlight lang="c"> | <br/> <syntaxhighlight lang="c"> | ||
| 167. sor: | 169. sor: | ||
</syntaxhighlight> <br/> | </syntaxhighlight> <br/> | ||
Példa: [[Média:Grafpp_rajzoloprogram.cpp|Egyszerű rajzolóprogram]] | |||
<br/> <syntaxhighlight lang="c"> | <br/> <syntaxhighlight lang="c"> | ||
void onMouse(int button, int state, int x, int y) { | void onMouse(int button, int state, int x, int y) { | ||
if(button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN) { | if(button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN) { | ||
glClear(GL_COLOR_BUFFER_BIT); // Jobb klikkre | glClear(GL_COLOR_BUFFER_BIT); // Jobb klikkre töröljuk a képernyőt. | ||
glutPostRedisplay(); // | glutPostRedisplay(); // Szólunk, hogy az ablak tartalma megváltozott, kérjuk a GLUT-ot, hogy hívja meg az onDisplay-t. | ||
} else if(button == GLUT_LEFT_BUTTON) { // Ha a bal gomb | } else if(button == GLUT_LEFT_BUTTON) { // Ha a bal gomb állapota megváltozott. | ||
if(state == GLUT_DOWN) { | if(state == GLUT_DOWN) { | ||
drawing = true; // Ha lenyomtuk akkor rajzolni akarunk. | drawing = true; // Ha lenyomtuk akkor rajzolni akarunk. | ||
Vector pos = convertToNdc(x, y); // | Vector pos = convertToNdc(x, y); // Átváltjuk a pontot. | ||
glBegin(GL_POINTS); { // Kirajzoljuk. | glBegin(GL_POINTS); { // Kirajzoljuk. | ||
glVertex2f(pos.x, pos.y); | glVertex2f(pos.x, pos.y); | ||
} glEnd(); | } glEnd(); | ||
last_mouse_pos = pos; // | last_mouse_pos = pos; // Elmentjük, hogy az első szakasz, majd ebből a pontból indul. | ||
glutPostRedisplay(); // Szolunk, hogy az ablak | glutPostRedisplay(); // Szolunk, hogy az ablak megváltozott, kérjük az újrarajzolását. | ||
} else if(state == GLUT_UP) { | } else if(state == GLUT_UP) { | ||
drawing = false; // Ha most | drawing = false; // Ha most engedtük fel, akkor mar nem akarunk rajzolni. | ||
} | } | ||
} | } | ||
| 191. sor: | 193. sor: | ||
void onMouseMotion(int x, int y) { | void onMouseMotion(int x, int y) { | ||
if(drawing) { | if(drawing) { | ||
Vector pos = convertToNdc(x, y); // | Vector pos = convertToNdc(x, y); // Kiszámoljuk az egér jelenlegi helyzetet NDC-ben. | ||
glBegin(GL_LINES); { // Kirajzolunk egy vonalat az | glBegin(GL_LINES); { // Kirajzolunk egy vonalat az előző és a mostani helyzete közé. | ||
glVertex2f(last_mouse_pos.x, last_mouse_pos.y); | glVertex2f(last_mouse_pos.x, last_mouse_pos.y); | ||
glVertex2f(pos.x, pos.y); | glVertex2f(pos.x, pos.y); | ||
} glEnd(); | } glEnd(); | ||
glutPostRedisplay(); // | glutPostRedisplay(); // Szólunk, hogy az ablak megváltozott, kérjük az újrarajzolását. | ||
last_mouse_pos = pos; // | last_mouse_pos = pos; // Frissítjük a előző helyzetet. | ||
} | } | ||
} | } | ||
| 208. sor: | 210. sor: | ||
=== Animáció === | === Animáció === | ||
Az animáció annyit jelent, hogy az egyes objektumok állapota az időnek is a függvénye. A pillanatnyi időt a <code> glutGet(GLUT_ELAPSED_TIME); </code> függvényhívással tudjuk lekérdezni, célszerűen az onIdle függvényben. Az animáció alatt leggyakrabban testek mozgását, néha testek deformálódását értjük. Egy mozgó testet legjobban a fizika törvényeivel tudunk leírni, egy egyenes vonalú egyenletes mozgás leírásához mindössze a <code> v = s / t </code> képletre van szükségünk. Az animáció onnantól kezd bonyolulttá válni, amikor több mozgó test állapota egymástól függ (például ütköznek egymással). Ilyenkor ugyanis a korrekt szimuláció egy differenciálegyenlet megoldását jelentené. Numerikus módszerekkel viszont nem szeretünk diffegyenletet megoldani. Ennek a problémának egy egyszerű közelítése a diszkrét idő-szimuláció, ahol az ötlet az, hogy válasszunk egy időegységet, amennyi idő alatt a testek állapota csak minimálisan változik meg, ez tipikusan pár milliszekundum, és legfeljebb ilyen időközönként kiválasztott statikus pillanatokban vizsgáljuk csak az egymásra hatásokat. Így a képletek nagyon leegyszerűsödnek, és semmi szükség nem lesz differenciálegyenletekre. Manapság a számítógépes játékok nagy része is ezt a módszert használja. | |||
* Egyszerű példaprogram: [[Média:Grafpp_pattogo_labda.cpp|Pattogó labda]] | * Egyszerű példaprogram: [[Média:Grafpp_pattogo_labda.cpp|Pattogó labda]] | ||