OpenGL.Hu – IV. rész

Hozzuk mozgásba a dolgokat!

A III. Rész végén tettem egy kis utalást az animációkra, de példát már hely hiányában nem tudtam rá mutatni. Nos, ezek után – mint ahogy a cím is sejteti – az animációkkal fogunk foglalkozni. Sokak legnagyobb örömére, másoknak pedig bánatára, ezt a részt előbbre vettem, mint a legtöbb hasonló cikkben, ahol a vertexek bemutatása után a színek, anyagok, fények jönnek. Nekünk ez most a későbbi cikkekre fog maradni. A dolgot úgy kezdeném, hogy elmondom, milyen lehetőségek állnak rendelkezésre az animációhoz, utána egy példaprogram, majd pedig annak magyarázata következik.

Vágjunk is bele! A következő program a cikk mellékleteként forráskódban és Windows alá lefordítva is megtalálható. (A továbbiakban az összes példaprogram is hasonlóan.)

A programunk tehát:

#define GLUT_DISABLE_ATEXIT_HACK

#include <windows.h>

 

#include <GL/gl.h>

#include <GL/glu.h>

#include <GL/glut.h>

 

float x=0;

float y=0;

float xm=0.01;

float ym=0.01;

 

void SceneIdle(void)

{

      if ( (x>=.5)||(x<=-.5) )

            { xm=-xm; }

      if ( (y>=.4)||(y<=-.4) )

            { ym=-ym; }

      x=x+xm;

      y=y+ym;

      glutPostRedisplay();

}

 

void RenderScene(void)

{

      glClear(GL_COLOR_BUFFER_BIT);

      glClearColor(0.0f, 0.0f, 0.0f, 1.0f );

      glColor3f(1.0f, 1.0f, 1.0f);

      glBegin(GL_QUADS);

            glVertex3f(-0.5f+x, -0.5f+y, 0.0f);

            glVertex3f(-0.5f+x,  0.5f+y, 0.0f);

            glVertex3f( 0.5f+x,  0.5f+y, 0.0f);

            glVertex3f( 0.5f+x, -0.5f+y, 0.0f);

      glEnd();

      glutSwapBuffers();

}

 

int main(int argc, char* argv[])

{

      glutInit(&argc, argv);

      glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);

      glutCreateWindow("Pelda01");

      glutDisplayFunc(RenderScene);

      glutIdleFunc(SceneIdle);

      glutMainLoop();

      return 0;

}

Ez a program a II. Részben bemutatott első példaprogramunk (Példa 01 – Fehér Négyzet) továbbfejlesztett változata. Ebben már a korábban megrajzolt négyzetünket pattogtatjuk oda-vissza az ablak határain belül. Most még megtehetem, hogy az egész programot bemutatom, de később már csak a megváltozott részeket, illetve azok helyét fogom itt leírni, hely hiányában. (Egy jó darabig még úgyis ugyanazt a programot fogjuk továbbfejlesztgetni.)

Hogy hogyan is történik az animáció? Nos, a GLUT úgynevezett CallBack függvényekkel rendelkezik – pontosabban mi hozzuk létre őket a számára – melyek bizonyos feltételek mellett, akár periodikusan is meghívódnak. A legfontosabb CallBack függvény, amit már használtunk, bár nem neveztünk nevén, a RenderScene(), amely periodikusan hívódik meg, amikor az OpenGL az aktuális frame (képkocka, de a továbbiakban az angol – és zsargonban jobban elfogadott nevét használom) tartalmát rendereli. Amit most használtunk, az SceneIdle() nevű CallBack függvény, amelynek a RenderScene()-hez hasonlóan nem kell semmilyen paramétert definiálni, a haszna pedig annyi, hogy meghívódik minden olyan alkalommal, amikor a grafikus vezérlő dolgozik – pl. éppen renderel – viszont a processzor „ráér”. Itt elvégezhetők olyan számítások például, mint jelen esetben a négyzet eltolásának kiszámítása.

Megjegyezném, hogy az M.J. Kilgard (Silicon Graphics Inc.) által összeállított GLUT API v3 referencia szerint nem túl ajánlott dolog az SceneIdle() függvényben túl sok számítást végezni, mert előfordulhat, hogy a ló túloldalára esünk át azáltal, hogy már nem a processzor fog szabad lenni, hanem más alkalmazások futtatása akad meg, miközben a videovezérlő már készen áll az új renderfolyamat indításához. (Személyes tapasztalat: nekem ezt még – ésszerű kereteken belül - szándékosan sem sikerült így elérnem, tehát nem igazán tudom elmondani, mennyi az a „nem túl sok” számítás.)

Miután a SceneIdle() függvényt jobban szemügyre vesszük, láthatjuk, hogy van egy sor a végén, amelyik a glutPostRedisplay() függvényhívást tartalmazza. Ez a függvény arra szolgál, hogy meghívásakor felveszi az aktuális ablakot az újrarajzolandó ablakok listájába. A számításokat végző néhány sort és a módosított glVertex3f() sorokat nem szándékozom részletezni, az olvasóra bízom a velük való kísérletezést. A főprogram csak egyetlen sorral bővült az eredetihez képest, ez pedig:

      glutIdleFunc(SceneIdle);

Ebben a sorban beállítjuk, melyik legyen az a függvény, amely meghívódik az Idle (üresjárati) CallBack esetén.

CallBack – Mit tudunk elérni vele?

Ha már felhoztuk a CallBack függvényeket, nem ártana, ha néhányat bemutatnék közülük, lévén később jó hasznukat vesszük. Igazából nem túl sok áll belőlük rendelkezésünkre, viszont azokkal nagyjából mindent meg tudunk csinálni. Láttuk már a DisplayFunc() ill. IdleFunc() függvényeket, melyekkel a renderelő, illetve az Idle (üresjárati) CallBack-eket tudtuk lekezelni, illetve kihasználni. Erről a kettőről tehát itt nem ejtünk szót.

A fennmaradó néhány közül elsőnek venném a glutTimerFunc() függvényt, amellyel beállíthatunk egy adott időközönként meghívott függvényt. Ez főleg akkor lesz majd, hasznos, mikor adott sebességű animációkat akarunk előállítani. Ugyanis az Idle CallBack-es megoldás nagyban függ a processzor órajelétől és gyorsabb számítógépen így az animáció (játék) is gyorsabbá válik, ami nem biztos, hogy jó.

A glutTimerFunc paraméterezése:

                glutTimerFunc(unsigned int msecs, void (*func) (int value), value);

A paraméterek közül a (*func) az átadott függvény, melynek egyetlen integer paramétere lehet, ez pedig a value. Ez a híváskor értékül azt kapja, amit a glutTimerFunc() value-jának adunk meghíváskor. Egyszerre több ilyen időzített hívás is beállítható, viszont egyiket sem lehet visszavonni. Helyette – érdekes megoldás! – a value paraméter alapján figyelmen kívül lehet hagyni szükség esetén az időzített hívást.

Következő CallBack függvény a glutReshapeFunc(void (*func) (int w, int h)) mely akkor hívódik meg, amikor az aktuális ablak mérete megváltozik. A (h,w) páros értelemszerűen az új méretet hordozza.

Jó néhány CallBack foglalkozik egér- és billentyű-események lekezelésével, így ezekre, mivel később nagy szükség lesz rájuk, a teljes következő cikket szándékozom szentelni.

Erre az alkalomra körülbelül ennyit terveztem, bízom benne, hogy érthető volt. A GLUT CallBack-ekről bőséges anyag található a már fent említett Kilgard-féle referencia-könyvben (angol nyelvű!), amely .PDF változatban jó néhány hivatalos OpenGL oldalról elérhető.

Továbbra is várom leveleiteket, kérdéseiteket a témával kapcsolatban!

Merczel László - da_maniac_@yahoo.com