OpenGL tutorial za Lazarus (multiplatform)

OpenGL tutorial za Lazarus (multiplatform)

offline
  • Srđan Tot
  • Am I evil? I am man, yes I am.
  • Pridružio: 12 Jul 2005
  • Poruke: 2483
  • Gde živiš: Ljubljana

Pre koji dan sam Linux i prvo sto sam pokusao da uradim je da napravim OpenGL aplikaciju... instalirao sam Lazarus i drajvere za graficku karticu i dok si rek'o keks... uradio sam prvi primer koji sam pisao u tutorialu za OpenGL pod Windowsom. Posto OpenGL nije vezan za neku odredjenu platformu kao DirectX, odlucio sam da tutorial pisem za Lazarus koristeci GLUT za rad sa prozorima tako da kod moze da se kompajlira na skoro svakoj platformi (za platforme na kojima rade Lazarus i GLUT).

Vise o Lazarusu mozete naci ovde:
http://www.mycity.rs/phpbb/viewforum.php?f=183
http://www.lazarus.freepascal.org/

Vise o OpenGL:
http://www.opengl.org/about/overview/

Vise o GLUT:
http://www.opengl.org//documentation/specs/glut/index.html#1

Linux distribucije uglavnom imaju instaliran GLUT, ali Windows dolazi bez njega... Windows korisnici mogu skinuti GLUT odavde:
http://www.xmission.com/~nate/glut.html

Ako vas OS nema instaliran GLUT, potrazite na google i naci ce te instalacioni paket vrlo lako.

Pre nego sto pocnemo, moram da napomenem jednu "sitnicu" u vezi sa GLUT bibliotekom. Ona ima svoj mehanizam za obradu poruka prozora koji, kada se pokrene, nikad ne prestaje da se izvrsava i time onemogucava zaustavljanje programa kada se prozor zatvori. Aplikaciju je moguce zatvoriti reagujuci na dogadjaje kao sto su klik misa, pritisak na taster tastature i slicno pozivanjem procedure Halt. Nazalost, u standardnoj verziji GLUT biblioteke nije moguce detektovati kada se prozor zatvorio i da se onda pozove Halt.

Funkcije koje sam vec objasnio u tutorijalu za Windows necu ponovo objasnjavati... mozete ih pogledati ovde:
http://www.mycity.rs/phpbb/viewtopic.php?t=40657

Sad kada znamo prednosti (pogledajte link o GLUT) i mane GLUT biblioteke u odnosu na pisanje svog mehanizma za rad sa prozorima i ulaznim uredjajima, mozemo poceti sa pisanjem.

Da bi inicijalizovali GLUT moramo prvo pozvati proceduru glutInit. Ova funkcija moze na osnovu komandne linije da odredi kakav prozor treba da se kreira, koji displaymanager da se koristi (pod Linuxom) i slicno. Komandnu liniju ocekuje u formatu koji se koristi u main funkciji u C/C++ programima. Pointer na Integer vrednost koja pokazuje koliko parametara ima i pointer na niz PChar promenljivih od kojih svaka predstavlja jedan parametar. Posto u Lazarus/Delphi ne postoji nista sto bi nam pomoglo da ParamCount i ParamStr prevedemo u oblik koji odgovara glutInit funkciji, prinudjeni smo da sami uradimo konverzaciju:
procedure glutInitPascal(ParseCmdLine: Boolean); var   Cmd: array of PChar;   CmdCount, I: Integer; begin   if ParseCmdLine then     CmdCount := ParamCount + 1   else     CmdCount := 1;   SetLength(Cmd, CmdCount);   for I := 0 to CmdCount - 1 do     Cmd[I] := PChar(ParamStr(I));   glutInit(@CmdCount, @Cmd); end;
Kreiramo niz koji punimo stringovima iz ParamStr. Parametar ParseCmdLine oznacava da li da se glutInit funkciji prosledjuje komandnja linija ili ne... tako mozemo kontrolisati da li ce korisnik biti u mogucnosti da preko komandnje linije bira nacin rada.

Vise o glutInit: http://www.opengl.org/resources/libraries/glut/spec3/node10.html

Sledece sto nam treba je kreiranje prozora. Da bi mogli da ga kreiramo, moramo da definisemo nacin na koji ce OpenGL da radi u prozoru i da definisemo poziciju i dimenzije prozora.

Definisanje nacina rada OpenGLa koristimo proceduru glutInitDisplayMode. Ova procedura uzima samo jedan parametar koji je ustvari kombinacija flagova. Mi cemo koristiti GLUT_DOUBLE or GLUT_RGB or GLUT_DEPTH.

Vise o glutInitDisplayMode i flagovima: http://www.opengl.org/resources/libraries/glut/spec3/node12.html

Poziciju i velcinu prozora definisemo procedurama glutInitWindowPosition i glutInitWindowSize i svaka od njih uzima po 2 prametra... X i Y koordinatu i sirinu i visinu prozora. U programu cemo koristiti i glutGet funkciju kojom cemo moci da pronadjemo visinu i sirinu ekrana i tako postaviti prozor na sredinu.

Vise o ovim procedurama: http://www.opengl.org/resources/libraries/glut/spec3/node11.html
http://www.opengl.org/documentation/specs/glut/spec3/node70.html

Kada smo dali sve podatke za kreiranje prozora mozemo pozvati funkciju glutCreateWindow koja kreira prozor i daje mu ime koje se nalazi u parametru koji prosledjujemo. Kao rezultat vraca broj koji oznacava trenutno kreiran prozor.

Viseo o glutCreateWindow: http://www.opengl.org/resources/libraries/glut/spec3/node16.html

Pre nego sto se pocne sa izvrsavanjem glavne petlje treba da postavimo i nase procedure koje zelimo da GLUT poziva u odredjenim situacijama. U ovom primeru cemo instalirati procedure za iscrtavanje prozora, za promenu velicine prozora i za detektovanje pritiska tastera na tastaturi. To cemo postici pozivanjem procedura glutDisplayFunc,glutReshapeFunc i glutKeyboardFunc.

Vise o postavljanju callback procedura: http://www.opengl.org/resources/libraries/glut/spe.....0000000000

Procedura za prikaz ce izgledati ovako:
procedure DrawGLScene; cdecl; begin   glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);   glutSwapBuffers; end;
Ovim cemo sad obrisati pozadinu i ZBuffer i zatim to prikazati na prozoru.

Procedura koja ce reagovati na promenu velicine prozora ce izgledati ovako:
procedure ReSizeGLScene(Width, Height: Integer); cdecl; begin   if Height = 0 then     Height := 1;   glViewport(0, 0, Width, Height);   glMatrixMode(GL_PROJECTION);   glLoadIdentity;   gluPerspective(45, Width / Height, 0.1, 1000);   glMatrixMode(GL_MODELVIEW);   glLoadIdentity; end;
Ovde cemo podesiti na kom delu ce OpenGL moci da crta i definisati matrice.

Na, kraju, funkcija koja ce detektovati pritisnute tastere ce izgledati ovako:
procedure GLKeyboard(Key: Byte; X, Y: Longint); cdecl; begin   if Key = 27 then     Halt(0); end;
Pritiskom na tester ESCAPE prekidamo izvrsavanje programa (ako prozor zatvorite na drugi nacin, program ce i dalje nastaviti da se izvrsava iako ce se prozor zatvoriti).

Da bi sve pocelo da se izvrsava pozivamo proceduru glutMainLoop koja ulazi u beskonacnu petlju i poziva sve nase callback procedure.

Kod glavnog dela programa izgleda ovako:
const   AppWidth = 640;   AppHeight = 480; procedure InitializeGL; begin   glClearColor(0.18, 0.20, 0.66, 0); end; var   ScreenWidth, ScreenHeight: Integer; begin   glutInitPascal(True);   glutInitDisplayMode(GLUT_DOUBLE or GLUT_RGB or GLUT_DEPTH);   glutInitWindowSize(AppWidth, AppHeight);   ScreenWidth := glutGet(GLUT_SCREEN_WIDTH);   ScreenHeight := glutGet(GLUT_SCREEN_HEIGHT);   glutInitWindowPosition((ScreenWidth - AppWidth) div 2, (ScreenHeight - AppHeight) div 2);   glutCreateWindow('OpenGL Tutorial 1');   InitializeGL;   glutDisplayFunc(@DrawGLScene);   glutReshapeFunc(@ReSizeGLScene);   glutKeyboardFunc(@GLKeyboard);   glutMainLoop; end.

U, narednom tutorialu cemo pokazati kako se vrsi iscrtavanje (ako ste pogledali pocetak OpenGL tutoriala za Windows, onda cete vec znati da uradite to i sami Smile ).

Source code: [url=https://www.mycity.rs/must-login.png | [url=https://www.mycity.rs/must-login.png
Executable: [url=https://www.mycity.rs/must-login.png | [url=https://www.mycity.rs/must-login.png
Delphi Units (ovi uniti su potrebni da bi kod u Delphiu bio kompatibilan sa kodom u Lazarusu): https://www.mycity.rs/must-login.png

P.S. Ako neko ima instaliran Lazarus na nekoj trecoj platformi, mogao bi da iskompajlira kod i posalje izvrsni fajl. Takodje bih molio nekog ko ima Linux da proba da pokrene izvrsni fajl jer jos uvek nisam potpuno shvatio Linux pa ne znam da li sam poslao sve potrebne fajlove.

Dopuna: 21 Jul 2006 22:53

U ovom primeru cemo dodati samo malo koda u kojem cemo pokazati kako se iscrtavaju vertexi i nesto malo o postavljanju matrica koje uticu na konacnu poziciju objekata koje crtamo.

Prvo cemo analizirati kod koji smo vec napisali. U ReSizeGLScene proceduri, izmedju ostalog, izvrsava se sledeci kod:
  .   .   .   glMatrixMode(GL_PROJECTION);   glLoadIdentity;   gluPerspective(45, Width / Height, 0.1, 1000);   glMatrixMode(GL_MODELVIEW);   glLoadIdentity; end;

glMatrixMode funkcijom odredjujemo koju cemo matricu da podesavamo. U OpenGL postoje 3 matrice koje mozemo menjati:
GL_MODELVIEW: matrica kojom se mnoze koordinate vertexa da bi se postavili na pravu poziciju u sceni.
GL_PROJECTION: matrica koja 3D koordinate prevodi u 2D koordinatu za prikaz na ekranu.
GL_TEXTURE: matrica kojom se mnoze koordinate textura i time odredjuje koji deo texture se prikazuje.

Kada izaberemo matricu koju zelimo da menjamo (prvo smo izabrali projekciju), mozemo pozivati funkcije koje vrse izmene. glLoadIdentity funkcija resetuje matricu tako da ona ne utice na poziciju vertexa. Posto skoro sve funkcije za menjanje matrice mnoze trenutnu matricu podacima koje prosledimo, prvo sto moramo je da matricu resetujemo. Da bismo lakse podesili matricu projekcije imamo funkciju gluPerspective. Parametre koje uzima su sirina vidika u stepenima, odos izmedju sirine i visine, minimalna i maximalna udaljenost vidljivih objekata.

Kada smo podesili matricu projekcije biramo GL_MODELVIEW matricu tako da svaki sledeci poziv funkcijama za menjanje matrice utice na nju.

Ok... sada cemo dodati kod za crtanje:
procedure DrawGLScene; cdecl; begin   glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);   glLoadIdentity;   glTranslatef(0, 0, -5);   glBegin(GL_TRIANGLES);     glColor3f(1, 0, 0);     glVertex3f(-1, -1, 0);     glColor3f(0, 1, 0);     glVertex3f(1, -1, 0);     glColor3f(0, 0, 1);     glVertex3f(0, 1, 0);   glEnd;     glutSwapBuffers; end;

glClear funkciju smo vec spominjali u proslom primeru. Ona sluzi da resetuje buffere. Preskocicemo sledece dve funkcije i preci na glBegin.

glBegin funkcija oznacava da cemo da pocnemo sa unosenjem podataka o vertexima koje zelimo da nacrtamo. Parametar koji uzima odredjuje nacin na koji ce se vertexi obraditi:
GL_POINTS: svaki vertex definise posebnu tacku koja ce se iscrtati.

GL_LINES: dva vertexa odredjuju liniju koja ce biti nacrtana... broj vertexa mora biti paran.

GL_LINE_STRIP: crta se linija koja polazi iz prvog vertexa i prolazi kroz svaki naredni.

GL_LINE_LOOP: isto kao i GL_LINE_STRIP samo sto se crta i linija od zadnjeg do prvog vertexa i tako dobija zatvoren oblik.

GL_TRIANGLES: svaka 3 vertexa definisu trougao... broj vertexa mora biti deljiv sa 3.

GL_TRIANGLE_STRIP: trougao se iscrtava za svaki vertex posle drugog... za svako neparno n crta se trougao na koordinatama n, n + 1 i n + 2, a za svako parno n se crta na koordinatama n + 1, n, n + 2... broj vertexa mora biti veci od 2.

GL_TRIANGLE_FAN: zadaje se centralni vertex i zatim vertexi oko njega... trougao pod rednim brojem n je definisan vertexima 1, n + 1, n + 2... broj vertexa mora biti veci od 2.

GL_QUADS: svaka 4 vertexa definisu cetvorougao... broj vertexa mora biti deljiv sa 4.

GL_QUAD_STRIP: crta se cetvorougao za svaki par vertexa definisan posle prvog para... cetvorougao pod rednim brojem n je definisan vertexima 2n - 1, 2n, 2n + 2, 2n + 1... broj vertexa mora biti paran i veci od 2.

GL_POLYGON: isto kao GL_LINE_LOOP samo sto je unutrasnjost objekta popunjena.

U primeru smo izabrali GL_TRIANGLES tako i funkcijom glVertex3f smo definisali 3 vertexa. Postoje vise funkcija koje pocinju sa glVertex... razlike su u broju i tipu parametara koje uzimaju. Nastavak 3f znaci da uzima 3 float (single) parametra... 2i bi znacilo 2 parametra tipa integer. Parametri su uvek x, y, z i w. glVertex3f odgovara u skoro svim situacijama.

Pre nego sto se postavi vertex, moguce mu je postaviti boju, materijal, texturu,... U ovom primeru cemo postaviti samo boju. To se radi pozivanje funkcije glColor. Ona takodje moze primati vese ili manje paramtera koji mogu biti jednog ili drugog tipa sto zavisi od nastavka. Uglavnom cemo koristiti glColor3f (postavlja samo r,g i b) i glColor4f (postavlja r, g, b i a). Kada se boja postavi pozivom ove funkcije ona vazi za svaki naredni vertex.

Posto smo Z koordinatu vertexa postavili na 0, a minimalnu udaljenos prilikom postavljanja perspektiva na 0.1 (minimalna vrednost mora biti veca od 0) objekat se nece videti... za to nam sluze one dve funkcije koje smo preskocili u objasnjavanju. Posto smo u ReSizeGLScene proceduri na kraju izabrali GL_MODELVIEW matricu, sada mozemo raditi s njom. Prvo sto radimo je resetovanje, a zatim pozivamo funkciju glTranslatef koja pravi matricu translacije. Posto smo Z parametar postavili na -5, trougao koji crtamo se nece nalaziti na udaljenosti 0, vec na udaljenosti 5 (u OpenGL smer Z ose je negativan) i time ce pasti u dozvoljeni opseg.

Na kraju pozivamo glEnd funkciju koja oznacava da smo zavrsili sa crtanjem odredjenog tipa objekata. Da smo hteli da crtamo neki kvadrat, posle ovog bi ponovo pozvali glBegin i izabrali GL_QUADS.

U sledecem primeru cemo pokazati kako se kreiraju display liste koje ubrzavaju iscrtavanje objekata.



Source code: [url=https://www.mycity.rs/must-login.png | [url=https://www.mycity.rs/must-login.png
Executable: [url=https://www.mycity.rs/must-login.png | [url=https://www.mycity.rs/must-login.png

Dopuna: 22 Jul 2006 23:34

Uploadovao sam noviju verziju unita za Delphi. U ovoj verziji postoje procedure i funkcije koje u mnogome olaksavaju rad sa OpenGL, dodacima i GLUTom. Postojeci kod je kompatibilan i sa novim unitima tako da nista ne mora da se menja, mada ce kod koji budemo pisali u sledecim verzijama vec zahtevati nove unite.

Link je ispravan i u prvom postu, ali evo ga i ovde: https://www.mycity.rs/must-login.png

Dopuna: 23 Jul 2006 1:30

Cesto ce se pojaviti potreba da iscrtavamo vise istih objekata na sceni. OpenGL ima mogucnost da pravi display liste koje ubrzavaju taj proces. Display lista se kreira kao kad nesto stvarno zelimo da iscrtamo... podatke koje dajemo kada zelimo da se kreiraju vertexi se cuvaju u memoriji i izvrsavaju se kada ih pozovemo. U ovom primeru cemo kreirati jednu listu koja ce sadrzati podatke o piramidi i iskoristiti je da iscrtamo 3 poramide na razlicitim mestima u 3d sceni.

Pocecemo kreiranjem liste:
const   LIST_OBJECT = 1; procedure CreateList; begin   glNewList(LIST_OBJECT, GL_COMPILE);     glBegin(GL_TRIANGLE_FAN);       glColor3f(1, 0, 0);       glVertex3f(0, 0.5, 0);       glColor3f(1, 1, 0);       glVertex3f(-0.5, -0.5, 0.5);       glColor3f(1, 1, 1);       glVertex3f(0.5, -0.5, 0.5);       glColor3f(0, 1, 1);       glVertex3f(0.5, -0.5, -0.5);       glColor3f(0, 0, 1);       glVertex3f(-0.5, -0.5, -0.5);       glColor3f(0, 1, 0);       glVertex3f(-0.5, -0.5, 0.5);     glEnd;     glBegin(GL_QUADS);       glColor3f(1, 1, 0);       glVertex3f(-0.5, -0.5, 0.5);       glColor3f(1, 1, 1);       glVertex3f(0.5, -0.5, 0.5);       glColor3f(0, 1, 1);       glVertex3f(0.5, -0.5, -0.5);       glColor3f(0, 0, 1);       glVertex3f(-0.5, -0.5, -0.5);       glColor3f(0, 1, 0);       glVertex3f(-0.5, -0.5, 0.5);     glEnd;   glEndList; end;
Kao sto vidite, kreiranje liste je isto kao i crtanje... jedina razlika je sto je kod za crtanje stavljen izmedju glNewList i glEndList procedura. glNewList uzima 2 parametra. Prvi je broj (ID) liste koju zelimo da kreiramo. Ako vec postoji neka lista sa tim brojem, bice izbrisana i nova ce je zamenuti. Drugi parametar je flag koji kaze da li zelimo da samo pripremimo listu (kao sto sad stoji) ili da je odmah i iscrtamo (GL_COMPILE_AND_EXECUTE).
glIsList funkcija nam moze pomoci da saznamo da li je lista vec kreirana za neki odredjen index. Jedini parametar koji joj se prosledjuje je ID liste i ako lista postoji vraca GL_TRUE, a ako ne postoji GL_FALSE.
Ako dinamicki zelimo da kreiramo liste (nemamo konstantu za listu kao u nasem programu), ne moramo sami da pamtimo koje smo ID iskoristili ili da pozivamo glIsList kako bismo saznali da li lista postoji ili ne. Pozivanjem funkcije glGenLists mozemo zatraziti od OpenGL da nam kreira prazne display liste. Jedini parametar koji ova lista uzima je broj lista koje zelimo da dobijemo. Rezultat je ID prve liste tako da lako mozemo da odredimo i ostale. Ako smo zatrazili x listi, a glGenLists je vratio rezultat r, liste koje su nam na raspolaganju su r, r + 1, r + 2,..., r + x - 1.

Sve liste koje kreiramo, moramo i da unistimo. U nasem programu cemo to raditi na izlasku:
procedure GLKeyboard(Key: Byte; X, Y: Longint); cdecl; begin   if Key = 27 then   begin     glDeleteLists(LIST_OBJECT, 1);     Halt(0);   end; end;
glDeleteLists uzima 2 parametra, ID i raspon za brisanje. Ona je napravljena da lepo radi sa funckijom glGenLists. Ako je prvi parametar n, a drugi x, bice obrisane sledece liste: n, n + 1, n + 2,..., n + x - 1.

Ok... sada kada znamo kako da kreiramo i da brisemo liste, red je da naucimo kako da ih pozivamo:
procedure DrawGLScene; cdecl; begin   glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);   glLoadIdentity;   glTranslatef(-2, 0, -5);   glRotatef(40, 1, 0, 1);   glCallList(LIST_OBJECT);   glLoadIdentity;   glTranslatef(1, -2, -10);   glRotatef(62, 0, 1, 0);   glCallList(LIST_OBJECT);   glLoadIdentity;   glTranslatef(-4, 0.5, -15);   glRotatef(200, 1, 0, 0);   glCallList(LIST_OBJECT);   glutSwapBuffers; end;
Koriscenjem glCallList mozemo pozvati jednu listu. U ovom primeru, pre pozivanja liste, podesavamo model matricu tako da objekti budu na razlicitim pozicijama i u razlicitim polozajima u 3d sceni.
Postoji i procedura glCallLists koja ima mogucnost pozivanja vise listi odjednom. Ona uzima 3 parametra. Prvi je broj listi koje zelimo da pozovemo, drugi parametar oznacava tip podataka koji odredjuju koje ce se liste iscrtati, a treci je taj niz podataka.
Drugi parametar moze biti:
GL_BYTE: svaki clan niza se tumaci kao GLbyte.

GL_UNSIGNED_BYTE: svaki clan niza se tumaci kao GLubyte.

GL_SHORT: svaki clan niza se tumaci kao GLshort.

GL_UNSIGNED_SHORT: svaki clan niza se tumaci kao GLushort.

GL_INT: svaki clan niza se tumaci kao GLint.

GL_UNSIGNED_INT: svaki clan niza se tumaci kao GLuint.

GL_FLOAT: svaki clan niza se tumaci kao GLfloat.

GL_2_BYTES: svaka dva clana (GLubyte) definisu jedan ID i to: 256 * prvi clan + drugi clan.

GL_3_BYTES: svaka tri clana (GLubyte) definisu jedan ID i to: 65536 * prvi clan + 256 * drugi clan + treci clan.

GL_4_BYTES: svaka cetiri clana (GLubyte) definisu jedan ID i to: 16777216 * prvi clan + 65536 * drugi clan + 256 * treci clan + cetvrti clan.

To je to za sada... sledeci put cemo mali planetarni sistem i pokazati malo bolje kako se koriste matrice i kako se pravi animirana scena koja ce raditi istom brzinom bez obzira na broj frejmova u sekundi (naravno... ako je broj frejmova manji animacija ce izgledati kao da secka, a na vecem frame rateu ce izgledati potpuno glatko).



Source code: [url=https://www.mycity.rs/must-login.png | [url=https://www.mycity.rs/must-login.png
Executable: [url=https://www.mycity.rs/must-login.png | [url=https://www.mycity.rs/must-login.png

Dopuna: 23 Jul 2006 2:21

U ovom primeru cemo nauciti kako da program radi u fullscrene modu, kako da napravimo animaciju koja ne zavisi od broja frejmova u sekundi i naucicemo jos komandi za rad sa matricama.

Prvo cemo da promenimo kod za inicijalizaciju programa:
const   FSMode = '800x600:32@75'; begin   glutInitPascal(False);   glutInitDisplayMode(GLUT_DOUBLE or GLUT_RGB or GLUT_DEPTH);   glutGameModeString(FSMode);   glutEnterGameMode;   glutSetCursor(GLUT_CURSOR_NONE);   InitializeGL;   glutDisplayFunc(@DrawGLScene);   glutReshapeFunc(@ReSizeGLScene);   glutKeyboardFunc(@GLKeyboard);   glutIdleFunc(@DrawGLScene);   glutMainLoop; end.
Ovog puta ne zelimo da GLUT parsira komandnu liniju i stavljamo false kao parametar za glutInitPascal proceduru. Kao sto vidite, sada nema koda za kreiranje prozora. To je zato sto GLUT ima specijalni mod (game mode) kada ulazi u fullscreen.
Procedura glutGameModeString postavlja mod koji zelimo. U konstanti FSMode smo naveli da zelimo 800x600 rezoluciju, 32bitnu paletu boja i 75Hz osvezavanje. Znaci string se zadaje u obliku:
[SIRINA "x" VISINA][":" PALETA]["@" OSVEZAVANJE]
Moguce je navesto samo rezoluciju, samo deo informacije... npr 800x600 ili 800x600@60 ili :32...
Postoji jos jedan nacin formiranja string. Ako zelimo rezoluciju koja ima sirinu bar 800, 16bitnu paletu i osvezavanje od bar 60Hz mozemo string napisati ovako:
FSMode = 'width>=800 bpp=16 hertz>=60';
Nazivi podataka koje mozemo da menjamo su: bpp (paleta), height (sirina), hertz (osvezavanje), width (sirina).
Moguce poredjenja su:
=: jednako
!=: razlicito
<: manje (postavlja najmanju mogucu vrednost)
>: vece (postavlja najvecu mogucu vrednost)
<=: manje ili jednako (postavlja najmanju mogucu vrednost)
>=: vece ili jednako (postavlja najvecu mogucu vrednost)
~: vece ili jendako (postavlja najmanju mogucu vrednost)

Kada smo podesili mod koji zelimo, pokrecemo ga funkcijom glutEnterGameMode.

U ostatku ovog dela kod se pojavljuju jos 2 nove procedure.
glutSetCursor procedura postavlja zeljeni oblik kursora za program. S obzorim da nam u fullscreen modu ne treba kursor, sakricemo ga postavljajuci parametar na GLUT_CURSOR_NONE.
Moguce vrednosti za ovaj parametar su:
GLUT_CURSOR_RIGHT_ARROW
GLUT_CURSOR_LEFT_ARROW
GLUT_CURSOR_INFO
GLUT_CURSOR_DESTROY
GLUT_CURSOR_HELP
GLUT_CURSOR_CYCLE
GLUT_CURSOR_SPRAY
GLUT_CURSOR_WAIT
GLUT_CURSOR_TEXT
GLUT_CURSOR_CROSSHAIR
GLUT_CURSOR_UP_DOWN
GLUT_CURSOR_LEFT_RIGHT
GLUT_CURSOR_TOP_SIDE
GLUT_CURSOR_BOTTOM_SIDE
GLUT_CURSOR_LEFT_SIDE
GLUT_CURSOR_RIGHT_SIDE
GLUT_CURSOR_TOP_LEFT_CORNER
GLUT_CURSOR_TOP_RIGHT_CORNER
GLUT_CURSOR_BOTTOM_RIGHT_CORNER
GLUT_CURSOR_BOTTOM_LEFT_CORNER
GLUT_CURSOR_FULL_CROSSHAIR
GLUT_CURSOR_NONE
GLUT_CURSOR_INHERIT

glutIdleFunc postavlja callback proceduru koja se poziva kad god program nema poruka za obradu. Ovo je savrseno mesto da radimo iscrtavanje nase 3d scene kada zelimo da se ona konstantno osvezava. Jednostavno cemo samo postaviti istu proceduru kao i za display callback.

Pogledajmo i deo za izlazak iz programa u kojem moramo da izadjemo iz fullscrene moda:
procedure GLKeyboard(Key: Byte; X, Y: Longint); cdecl; begin   if Key = 27 then   begin     glutLeaveGameMode;     Halt(0);   end; end;
Jedino sto treba da pozovemo pre izlaska iz programa je glutLeaveGameMode procedura koja ce vratiti stanje koje je bilo pre poziva funkcije glutEnterGameMode.

Sad da se malo bacimo na matrice i racunanje pozicija objekata koje ne zavisi od brzine iscrtavanja.
U proslim primerima smo u ReSizeGLScene proceduri model matricu resetovali tako da ne utice na poziciju objekata. U ovom primeru cemo u njoj postaviti matricu koja odredjuje odakle gledamo na scenu tj. polozaj kamere.
procedure ReSizeGLScene(Width, Height: Integer); cdecl; begin   .   .   .   glMatrixMode(GL_MODELVIEW);   glLoadIdentity;   gluLookAt(0, 20, 25, 0, 0, 0, 0, 1, 0); end;
gluLookAt procedura definise matricu koja ce objekte postaviti tako da izgledaju kao da se gledaju iz ekog odredjenom mesta na sceni. Prva 3 parametra definisu koordinatu pozicije iz koje se gleda. Druga tri parametra definisu tacku u koju zelimo da gledamo. Treca tri parametra opdredjuju gde nam je "gore". U normalnim slucajevima, gore nam je u pozitivnom smeru Y ose, a npr. da zelimo da postavimo kameru da lezi na nekoj strani, onda bi nam "gore" bio pozitivan ili negativan smer X ose.
Postavili smo matricu za kameru i sad ne bi bilo dobro ako pri crtanju matricu resetujemo jer cemo izgubiti sve promene koje smo ovde postavili... sada cemo videti kako je moguce sacuvati prethodno stanje matrice i zatim ga posle vratiti:
procedure DrawGLScene; cdecl; var   T: Single; begin   T := glutGet(GLUT_ELAPSED_TIME) / 1000;   glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);     glPushMatrix;     glRotatef(5 * T, 0, 1, 0);     glColor3f(1, 1, 0);     glutWireSphere(2, 20, 20);   glPopMatrix;     glPushMatrix;     glRotatef(90 * T, 0, 1, 0);     glTranslatef(5, 0, 0);     glRotatef(40 * T, 0, 1, 0);     glColor3f(1, 0, 0);     glutWireSphere(0.6, 10, 10);   glPopMatrix;   glPushMatrix;     glRotatef(60 * T, 0, 1, 0);     glTranslatef(-3, 0, 9);     glRotatef(50 * T, 0, 1, 0);     glColor3f(0, 1, 0);     glutWireSphere(1, 16, 16);         glPushMatrix;       glRotatef(360 * T, 0, 1, 0);       glTranslatef(-1.7, 0, 0);       glRotatef(50 * T, 0, 1, 0);       glColor3f(0, 0, 1);       glutWireSphere(0.4, 10, 10);     glPopMatrix;       glPopMatrix;   glutSwapBuffers; end;
glPushMatrix i glPopMatrix sluze za cuvanje i povrat trenutne matrice. Na ovaj nacin pre promene matrice mozesmo da sacuvamo trenutno stanje, zatim da promenimo matricu (dodamo matrice koje su potrebne za trenutni objekat) i zatim vratimo matricu kakva je bila za upotrebu sa sledecim objektom.
Treba imati u vidu da se matrice u OpenGL mnoze s desna na levo pa ako prvo navedemo matricu rotacije pa onda matricu translacije, objekat ce biti prvo pomeren pa tek onda rotiran.

Da se objekti ne bi pokretali brze kada je frame rate veci, a sporije kada je manji, koristicemo glutGet funkciju i GLUT_ELAPSED_TIME parametar. Tako cemo dobiti vreme u mili sekundama od kad je glutInit procedura pozvana. Vidite da u matricama translacije mnozimo uglove vremenom u sekundama (vreme u milisekundama delimo sa 1000). Na ovaj nacin objekat ce se rotirati za ugao koji smo naveli za tacno jednu sekundu bez obzira na frame rate.

To je to za sad.



Source code: [url=https://www.mycity.rs/must-login.png | [url=https://www.mycity.rs/must-login.png
Executable: [url=https://www.mycity.rs/must-login.png | [url=https://www.mycity.rs/must-login.png

Dopuna: 23 Jul 2006 23:18

Sledeci tutorial ce pokazati kako se koriste svetla i materijali u OpenGL. Takodje cemo uvesti jos jedan unit koji ce imati pomocne funkcije za dobijanje trenutnog vremena u sekundama, vremena koje je proslo od prethodnog renderovanja i funkcije za racunanje broja frejmova u sekundi.

Objasnjenje ce uskoro stici, za sad su tu slika i fajlovi.



Source code: [url=https://www.mycity.rs/must-login.png | [url=https://www.mycity.rs/must-login.png
Executable: [url=https://www.mycity.rs/must-login.png | [url=https://www.mycity.rs/must-login.png

Dopuna: 23 Jul 2006 23:29

BTW da li neko ovo uopste cita... moze neki feedback? Smile



Registruj se da bi učestvovao u diskusiji. Registrovanim korisnicima se NE prikazuju reklame unutar poruka.
offline
  • Pridružio: 04 Sep 2003
  • Poruke: 24130
  • Gde živiš: Wien

Razmisljas li o prevodu na Engleski, pa da objavis na Lazarus Wiki-ju?



offline
  • Srđan Tot
  • Am I evil? I am man, yes I am.
  • Pridružio: 12 Jul 2005
  • Poruke: 2483
  • Gde živiš: Ljubljana

Nije losa ideja... mada bi ovo verovatno trebao prvo da pogleda nako ko se bolje od mene razume u terminologiju.

Trebala bi mi i pomoc za prevod na engleski.

offline
  • Pridružio: 04 Sep 2003
  • Poruke: 24130
  • Gde živiš: Wien

Ja mogu malo oko Engleskog da pomognem (ili malo vise, kako vreme dozvoli), ali oko terminologije... duduk sam za 3D pojmove i izraze.

offline
  • Srđan Tot
  • Am I evil? I am man, yes I am.
  • Pridružio: 12 Jul 2005
  • Poruke: 2483
  • Gde živiš: Ljubljana

Usled nedostatka vremena, ne mogu da pisem text i na Lazarus Wiki na engleskom i ovde na srpskom. Tutoriali ce se nastaviti samo na engleskom jeziku na Lazarus Wiki.

http://wiki.lazarus.freepascal.org/index.php/OpenGL_Tutorial

Ovde sam uvek da objasnim ako nekom nesto nije jasno.

Ko je trenutno na forumu
 

Ukupno su 517 korisnika na forumu :: 41 registrovanih, 7 sakrivenih i 469 gosta   ::   [ Administrator ] [ Supermoderator ] [ Moderator ] :: Detaljnije

Najviše korisnika na forumu ikad bilo je 2413 - dana 03 Okt 2019 05:07

Korisnici koji su trenutno na forumu:
Korisnici trenutno na forumu: _Rade, A.R.Chafee.Jr., aljosa7, Atomski čoban, bulovic, darkangel, Davor Kondic, DENA2, Djokkinen, doktor1964, Dorcolac2, dule10savic, Ehinacea, galijot, ivan979, ivance95, Kubovac, kybonacci, ladro, ljuba.b, Marko Marković, Mihajlo, milandlc84.wow, MrNo, radionica1, rovac, Sall, Shomy, stalker2, StefanNBG90, Toni, trajkoni018, Trpe Grozni, uruk, voja64, YU-UKI, yufighter, Zikka, Zmaj 99, zoidbergs, |_MeD_|