Professional Documents
Culture Documents
OpenGL dediimiz ey, grafiksel donanma arayz olan bir yazlmdr.Bu arayz, imdiki aratrmalarma gre yaklak olarak 250 tane birbirinden farkl olan OpenGL komutlar ierir ( bu komutlarn yaklak 200 tanesi OpenGLe has olan ve kalan 50 tanesi ise OpenGL Utility Lbrary dediimiz ktphaneye aittir.) Bu komutlar kullanarak objeleri yaratabilir ve interaktif bir ekilde boyutlu uygulamalar salayan ilemleri gerekletirebilirsiniz. OpenGL, fakl donanm zelliklerine sahip platformlarda alabilen bir arayz olarak tasarlanan, yani donanmdan bamsz bir aratr. OpenGLin bu niteliini geekletirebilmek iin OpenGLde kullancnn dardan bilgi girmesini salayan aralar ve iletim sistemlerinde pencere ynetimini salayan komutlar yoktur. Bu yzden programc bulunduu platformu iyi tanmal ve kulland iletim sistemi komutlarn iyi bilmelidir. Ayn ey boyutlu nesneler iin de geerlidir.Yani sylemek istediim ey, OpenGLin boyutlu nesneler iin salayaca yksek seviyeli komutlar yoktur. Sizin yapmanz gereken ey OpenGLin salad ilkel ( primitive) geometrik nesneleri kullanarak istediiniz modelde iki veya boyutlu nesneleri yaratmanzdr. lkel nesneler olarak bahsettiim eyler nokta, izgi, poligon gibi objelerdir. Bu zellikleri salayabilen gelimi bir ktphane OpenGLin stne ina edilmitir. OpenGL Utility Library ( GLU ) quadric yzeyleri, NURBS erileri ve yzeyleri gibi bir ok zzellii salamaktadr. GLU, her OpenGL implementasyonunun bir gerekletirim standarddr.
reder ileminde kontrol grevini salayan belirli durumlar ilklemek ve render edilecek olan nesneleri ise belirlemek OpenGLin grevleri arasnda yer alr. OpenGL koduna bakmadan nce, birka terimi incelemekte fayda var. Mesela biraz nce kullandm render kelimesinin anlam bilgisayarn modellerden yaratt resimleri ileme anlamna gelir. Bu modeller ve nesneler geometrik ilkel elemanlardan yaratlrlar ( poligonlar, izgiler ve noktalar). Sonu olarak retilen resim yani render edilmi olan resim ekrannzda izilmi olan pikselleri ierir. Pikselin anlam, donanm tarafndan ekrana koyulan en kk grnr elementtir. Piksellerle ilgili bilgiler, memorideki bitplaneler iinde dzenlenmitir. Bitplane bir memori blgesidir. Bu blge ekran zerindeki her bir piksel ile ilgili tek bitlik bilgi tutmaktadr.rnek olarak, bit herhangi bir pikselin nasl krmz renkte olup olamayaca ile ilgili bilgiyi tutar.Bitplanelerin kendileri ise bir framebuffer ierisinde organize olmutur.Bu framebuffer, ekran zerindeki piksellerin renk kontollerini ve younlukar ile ilgili ihtiya duyduu bilgileri tutmaktadr. Bir OpenGL kodunu genel yapsn incelersek, rnek 2-1, arka plan siyah olan beyaz renkli bir karenin render ediini Resim 2-1 de gstermektedir.
Resim 2-1
rnek 2-1
#include <istenile balk dosyalar> int main(int argc, char** argv) { Pencerelklemelemleri(); glClearColor(0.0, 0.0, 0.0, 0.0); glClear(GL_COLOR_BUFFER_BIT); glColor3f(1.0, 1.0, 1.0); glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0); glBegin(GL_POLYGON); glVertex3f(0.25, 0.25, 0.0); glVertex3f(0.75, 0.25, 0.0); glVertex3f(0.75, 0.75, 0.0); glVertex3f(0.25, 0.75, 0.0); glEnd(); glFlush(); PencereyiGncelleVeKontrolleriYap(); return 0; }
main() fonksiyonun ilk satr, ekranda gzkecek olan pencere ile ilgili hazrlk ilemleri yapmaktadr. Pencerelklemelemleri() fonksiyonu, OpenGLe ait olamayan iletim sistemine has pencere sistemi ile ilgili rutinleri ieren bir yer tutucudur. Sonraki iki satr ise pencerenin arka plann siyah olarak temizleyen OpenGL komutlardr: glClearColor(), pencerenin hangi renk ile temizleneceini belirler ve glClear() komutu ise pencereyi temizler. glColor3f() komutu izilecek olan nesnenin rengini belirtir. Bu
rnek ierisinde izilmi olan karenin rengi beyaz olarak belirlenmitir.Bu noktadan itibaren tm nesneler bu komut tarafndan yeni bir renk ayarlamas olana kadar bu rengi kullanrlar. Sonraki OpenGL komutu glOrtho() dur. Bu komut pencerede nesne izilmeden nce, koordinat sistemini belirtir. glBegin() ve glEnd() komutlar tarafndan sarlm olan komutlar, izilecek nesneyi tanmlamaktadr. rnek ierisinde greceiniz gibi drt keli bir poligon izilmitir. Poligonu keleri, glVertex3f() komutlar tarafndan tanmlanmaktadr. glVertex3f() komutu koordinat sistemi ile alakal tane parametre almaktadr. Bu parametreler x, y ve z dir. Bu rnek ierisinde znin deeri 0 olarak belirlenmitir. Son olarak glFlush() komutu izim komutlarn altrr. PencereyiGncelleVeKontrolleriYap() rutini ise pencere ile ilgili gncellemeri yapmaktadr ve dier processler arasndaki mesaj al-veriini dinlemektedir. Aslnda rnek 2-1, basit olarak OpenGL komut yapsn vermektedir. Ayrntlara raporumun sonraki sayfalarnda deineceim.
Baz OpenGL komutlar, sekiz farkl tipte argman almaktadr. Bir sonraki sayfadaki tablo, OpenGL in ISO C gerekletirimi iin belirlenmi veri tiplerini nek olarak tanmlamalar ile beraber kullanmn gstermektedir. Bu veri tiplerini programlama dilinde kullanmakta fayda var, nk kullanlacak olan komutlarn argman tipleri, programla dilinde kullanlan veri tipleri ile uyumayabilir. Bu yzden, OpenGL komutlarnn tanabilirlii sz konusu ise bu komutlar kullanmakta fayda var. Tablo 2-1 Komut nekleri ve Argman Veri Tipleri
ne Veri Tipi k B 8-bit integer 16-bit integer 32-bit integer 32-bit floating-point 64-bit floating point 8-bit unsigned integer 16-bit unsigned integer 32-bit unsigned integer C programlama dilinde Kullanlan Tipler signed char Short int veya long Float Double unsigned char unsigned short unsigned int veya unsigned long OpenGL Tip Tanm GLbyte GLshort GLint, GLsizei GLfloat, GLclampf GLdouble, GLclampf GLubyte, GLboolean GLushort GLuint, GLenum, GLbitfield
S F D Ub Us Ui
her iki komut ta ayn ileve sahiptir. Fakat ilki, vertexin koordinatlar argman olarak 32-bit integerlar ve die komut ise argman olarak float tipindedir.
Baz OpenGL komutlar, son ek olarak v karakterini alr. Bu karakter, programcya parametre olarak alnacak eyin bir vectr veya bir diziyi iaret eden bir iareti olduunu bildirir.Birok komutun parametre olarak vector alan veya almayan versiyonlar bulunmaktadr. Aadaki satrlar glColor*() komutunun vektrl ve vektrsz olarak parametre almn gstermektedir.
glColor3f(1.0, 0.0, 0.0); GLfloat color_array[] = {1.0, 0.0, 0.0}; glColor3fv(color_array);
Son olarak, OpenGL veri tipi olarak GLvoidi tanmlar. Bu veri tipi dizileri iaret eden pointerlar, argman olarak alan OpenGL komutlar iin kullanlmaktadr.
gsterileceine ihtiya duyduunu belirlerse, glutDisplayFunc() tarafndan altrlacak fonksiyon arlr. Anlalaca gibi, glutDispalyFunc() a parametre olarak aktarlan bir pointer to function tipinde bir iaretidir. Bu nedenden tr, pencerenizi yeniden izmeniz iin gerekli grdnz rutinleri aracanz fonksiyon ierisine yani void (*func)(void) poiner to function ierisine koyun.
glColor3f(1.0, 0.0, 0.0); glVertex2f(0.25, 0.25); glColor3f(0.0, 1.0, 0.0); glVertex2f(0.75, 0.25); glColor3f(0.0, 0.0, 1.0); glVertex2f(0.50, 0.75); glEnd(); glFlush(); return; } // end of void display(void) void init(void) { /* arka plan rengini belirle */ glClearColor(0.0, 0.0, 0.0, 0.0); glShadeModel(GL_SMOOTH); /* bakis degerlerini ilkle */ glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); return; } // end of void init(void) int main(int argc, char* argv[]) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); glutInitWindowSize(250, 250); glutInitWindowPosition(100, 100); glutCreateWindow(argv[0]); init(); glutDisplayFunc(display); glutMainLoop();
Resim 2-2
10
glutIdleFunc(void (*func)(void)) , eyer arka planda bir olay olmuyorsa yani dardan bir bilgi girii yok ise, kendisine parametre olarak aktarlan fonksiyon ismini altrr.Eyer glutIdleFunc() fonksiyonun inaktif yapmak istiyorsanz fonksiyona NULL deerini aktarn.
11
GL_POINTS
nceki sayfada grdnz gibi, OpenGLin izecei mode glBegin tarafndan poligon olarak belirtilmitir. Bunun iin glBegin() fonksiyonuna parametre olarak aktarlan parametre GL_POLYGON dur. sayfada grdnz resim 2-3 n sol tarafnda poligon modu geerli olarak bir ken izilmitir. Eer glBegin()e aktarlacak olan mod GL_POINTS olsayd, ayn resmin sanda bulunan tane nokta gzkecekti. Resim 2-4, izim modlarn gstermektedir.
12
V1 V0 V4 V1 V2 V3 V6 V7 V0 V4 V2 V5 V3
GL_POINTS
V0 V2 V3 V4 V1 V5 V4 V0
GL_LINE
V1 V2 V3
GL_LINE_STRIP
V3
GL_LINE_LOOP
V7 V0 V4 V1 V2 V1 V5 V2 V3 V5 V4 V0 V6
GL_TRIANGLES
V2 V1 V3 V1 V0 V4
GL_TRIANGLE_STRIP
V0 V4 V3 V2 V7 V6 V5
GL_TRIANGLE_FAN
GL_QUADS
V0 V1
V1 V0 V2 V3 V4
V2 V7 V6 V5 V4 V3
GL_QUAD_STRIP
GL_POLYGON
Resim 2-4 rnekte, grdnz gibi, glEnd() fonksiyonunun parametresi yoktur. OpenGLe belirttiimiz modda, izdiimiz ilkel geometrik nesnenin izimini birtirmesi gerektiini haber vermekten baka, bir zel ilevi yoktur.
13
unu belirtmek gerekirse, glBegin() / glEnd() blou ierisinde, baka bir glBegin() / glEnd() blou bulunamaz. Ayrca, tm OpenGL fonksiyonlar, bu bloun ierisinde kullanlamayabilirler. Gerekte, sadece glVertex(), glColor(), glIndex(), glNormal(), glTextCoord(), glEvalCoord(), glEvalPoint(), glMaterial(), glEdgeFlag(), glCallList() ve glCallLists() fonksiyonlarnn eitli varyasyonlar glBegin() / glEnd() blou ierisinde kullanlabilirler.
Bu fonksiyon, nesnenin zel bir koordinat bilgisine gre en fazla drt parametre ( parametre bilgisi olarak (x, y, z ,w) olabilir ) ve en az iki parametre parametre (parametre bilgisi olarak (x, y)) alabilir.Eyer z veya w gibi parametreleri kullanmadnz bir glVertex*() fonksiyonu kullanyorsanz, znin deeri 0 ve wnun deeri 1 olarak varsaylacaktr. glVertex*() fonksiyon ars sadece glBegin() / glEnd() blou ierisinde verimlidir. Aadaki rnek glVertex*() kullanmn basite gstermektedir.
glVertex2s(2, 3); glVertex3d(0.0, 0.0, 3.1415926535898); glVertex4f(2.3, 1.0, -2.2, 2.0); Gldouble dVect[] = {5.0, 9.0, 1992.0}; glVertex3dv(dVect);
14
lk satrdaki komut, boyutlu koordinat sistemine gre koordinat bilgisi (2, 3, 0) olan bir vertexi gstermektedir.Bildiiniz gibi bu komut, sadece iki parametre almaktadr. Yani koordinat biligileri olarak x = 2, y = 3 tr. Kullanmadmz znin deeri 0 ve wnun deeri 1 dir. kinci komut koordinat bilgileri (0.0, 0.0, 3.1415926535898) deerlerine sahip olan bir vertexi gsterir. nc satrdaki komut ise parametre olarak (2.3, 1.0, -2.2, 2.0) alr. Dikkat ederseniz wnun deeri 2.0 dr ve bu yzden demin belirttiim parametre bilgilerini yeniden incelersek w deeri x, y ve z deerlerini blecektir. Yani parametre aktarm (x/w, y/w, z/w) olarak aktarlr. Sonu olarak OpenGLin grd koordinat bilgiler (2.3, 1.0, -2.2) deilde (1.15, 0.5, -1.1) olacaktr. Son satrda ise, fonksiyona bir dizi parametre olarak atanmtr. Baz donanmlarda glVertex*() fonksiyonunun vektr formlarn kullanmak daha etklidir nk sadece tek bir parametre, grafik alt sistemine geirilmeye ihtiya duyar. zel bir donanm, tek bir seri halinde, tm koordinat bilgilerini gnderme yeteneine sahip olabilir. Buda size iyi bir performans salar.
Varsayl olan nokta byklnn deeri yani size 1.0a eittir. Farkl nokta byklkleri iin ekrana izilecek olan piksel topluluklar antialiasing durumunun aktif veya pasif olamasna baldr.(Antialiasing izilecek olan nokta veya izgileri prssz bir ekilde izmek iin kullanlacak olan bir tekniktir.) Eyer antialiasing aktif deil ise ve verilen byklk deerleri virgll bir say ise bu say, tam sayya dntrlr ve ekranda izilecek olan noktalar kare eklinde izilirler. Mesela bykl 1.0 olan bir nokta, 1e 1 geniliinde bir piksel olarak izilir.Eer bykl 2.0 olan bir nokta enine vo boyuna 2 piksel olarak kare eklinde izilecektir
15
Antialiasingin aktif olduu durumlarda, izilecek plan noktalarn pikselleri dairesel bir ekilde izilir buda nesnenin keskin kelerinde yumuak geiler salayacaktr yani izilecek olan nesne prssz olacaktr. Bu modda bykl tamsay olmayan bir say yuvarlanmayacaktr. Programn almas esnasnda seilmi olan nokta bykln glGet() fonksiyonuyla eldeedersiniz. Bu fonsiyona GL_PONIT_SIZE parametresini aktardnzda noktann bykl bulunur.
width yani genilik 0.0 dan byk olmaldr ve varsayl olan deeri 1.0 dr. Noktalarn iziminde antialiasing etkili olduu gibi ayn ey izgiler iin de geerlidir. Antialiasing olmadan, izilecek olan izgilerin kalnlklar, srasyla 1, 2 ve 3 ise, piksel genilikleri, yine ayn srada, 1, 2 ve piksel geniliinde olacaktr. nemle belirtmem gerekirse, ekrannz dk znrlkte alyorsa piksel genilii 1.0 olan izgiler geni olarak gzkecektir eer znrlk yksek ise izilecek olan izgi gzkmemeye yakn olabilir.
16
Bilmemiz gereken ey, bitplane olarak biline grafiksel donanmda her pikselin renginin nasl tutulduudur. Renklerin tutulmasna dair iki ynten mevcut.Birinci yntem, bir pikselin krmz, yeil, mavi ve alfa deerlerinin direk olarak bitplane ierisinde korunmas ve dier bir yntem ise renk index modudur. Aadaki komut satrlar RGBA modunda pencereyi siyaha temizlemektedir.
glClearColor(0.0, 0.0, 0.0, 0.0); glClear(GL_COLOR_BUFFER_BIT);
lk satrdaki komut temizleme rengini siyah yapmaktadr ve ardndan gelen komut ise seilmi olan temizleme rengini dikkate alarak pencereyi temizler. glClear() komutuna aktarlm olan tek parametre hangi buffern temizleneceini OpenGLe bildirmektedir. Bu durumda resmin sakl tutulduu renk buffer program tarafndan temizlenecektir. Aada glClear() ile glClearColor() fonksiyonlarnn prototipleri ve komutlarn ilevleri aklanmaktadr. void glClear(Glbitfield mask) fonksiyonu mask olarak belirtilmi parametreye gre bufferlar temizler. void glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) fonksiyonu RGBA modda temizlemek iin kullanlacak olan rengi belirler. Varsaylan temizleme deerleri (0.0, 0.0, 0.0, 0.0) olduundan dolay siyahtr.
17
Yukardaki rnekte A ve B nesneleri krmz olarak ve C nesnesi ise mavi olarak izilecektir. Drdnc satrdaki SetCurrenColor(GREEN) komutu gereksiz yere kullanlmtr. Bir rengi belirlemek iin, glColor3f() komutunu kullann. Bu fonksiyon 0.0 ile 1.0 arasnda tane argman almaktadr. Parametreleri srasyla red, green ve blue dur. Bu parametrelerin deerlerinin karmndan yeni renkler yaratabilirsiniz. 0.0 deeri bileeni yani rengi kullanmayacamz anlamna gelmektedir. 1.0 ise tam tersidir. Mesela glColor3f(1.0, 0.0, 0.0); fonksiyonunu kulandmzda sistemin bir nesneyi parlak krmz bir renkte izecei anlamna gelmektedir yeil ve mavi renkler kullanlmaz. Tm sfrlar rengi siyah, tm birler ise rengi beyaz yapar. Tm renk deerle-
18
rini 0.5 olarak ayarlarsak rengimiz griye kaacaktr. Bir sonraki sayfada sekiz tane renk ayarlamas gsterilmektedir.
glColor3f(0.0, 0.0, 0.0); glColor3f(1.0, 0.0, 0.0); glColor3f(0.0, 1.0, 0.0); glColor3f(1.0, 1.0, 0.0); glColor3f(0.0, 0.0, 1.0); glColor3f(1.0, 0.0, 1.0); glColor3f(0.0, 1.0, 1.0); glColor3f(1.0, 1.0, 1.0); siyah krmz yeil sar mavi magenta iyan beyaz
19
Viewing transformation, yazdnz kod ierisinde modelling transformationdan nce gelmelidir fakat izim yapmadan nce projection ve viewport transformationlar yani dnmlerini belirleyebilirsiniz. Aadaki ekil resim 2-5 bilgisayarnzda hangi ilemlerin srayla olduunu gstermektedir.
Vertex
Modelview Matris
Kesme Koordinatlar Perspektiv Blm Normalletirilmi Ara Koordinatlar Perspective Blm Viewport Transformation Pencere Koordinatlar
Resim 2-5
Viewing, modeling ve projection transformationlarn belirlemek iin, 4X4 lk bir M matris tanmlamas yapmanz gerekir.Bu matris, istenilen transformasyonlar gerekletirebilmek iin ekrandaki her bir v verteksinin koordinatlaryla arplr. v = Mv
20
(Not: vertexlerin drt tane koordinat olduunu nemle vurgulamam gerekir. Fakat bir ok durumda w, 1e eit ve iki boyutlu koordinat sistemi iin z deeri 0a eittir.)Viewing ve modeling transformasyonlar otomatik olarak yzey normal vektrlerine ve ek olarak vertexlere uygulanmaktadr.( Normal vektrleri sadece gz koordinatlarnda kullanlr.Bu, normal vektrnn vertex verisi ile olan ilikisini uygun bir ekilde saladn temin etmektedir. Belirttiiniz viewing ve modelling transformasyonlar, modelview matrisini oluturmak iin bir araya getirilirler. Gz koordinatlarn vermek iin, gelen nesnenin koordinat bilgilerine bu matris uygulanmaktadr.Eer nesnenin ekranda gzkmeyen ksmlarn silmek gerekiyorsa, kesme yzeyleri uygulanr. Bundan sonra, OpenGL, projection matrisini kesme koordinatlarn verebilmek iin uygulayacaktr. Bu sayede kamerann nesneyi gsteremedii ksmlar kesilecektir, yani gzkmeyecektir. Bu noktadan sonra perspektif blm, normallemi ara koordinatlarn retebilmek iin koordinat deerlerini w ile blerek yerine getirilir. Son olarak ise, viewport transformasyonu uygulanarak, dntrlm koordinatlar pencere koordinatlarna evrilir. Bylece viewport boyutlar zerinde, resim ile oynamak iin, eitli manipulasyonlar uygulayabilirsiniz.
21
#include <windows.h> #include <GL/glut.h> void init(void) { glClearColor(0.0, 0.0, 0.0, 0.0); glShadeModel(GL_FLAT); } // end of void init(void) void display(void) { glClear(GL_COLOR_BUFFER_BIT); glColor3f(1.0, 1.0, 1.0); glLoadIdentity(); /* viewing transformation */ gluLookAt(0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); //glTranslatef(0.0, 0.0, -5.0); glScalef(1.0, 2.0, 1.0); glutWireCube(1.0); glFlush(); } // end of void display(void) void reshape(int w, int h) { glViewport(0, 0, (GLsizei) w, (GLsizei) h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(-1.0, 1.0, -1.0, 1.0, 1.5, 20.0); // gluPerspective(60.0, 1.0, 1.5, 20.0); glMatrixMode(GL_MODELVIEW); } // end of void reshape(int, int) int main(int argc, char** argv) {
22
glutInit(&argc, argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); glutInitWindowSize(500, 500); glutInitWindowPosition(100, 100); glutCreateWindow(argv[0]); init(); glutDisplayFunc(display); glutReshapeFunc(reshape); glutMainLoop(); return 0; } // end of int main(int, char**)
Resim 2-6
23
Bu aama gereklidir, nk belirtilen bir matris current matris ile arplp tekrar current matrise atanr. Dolays ile yapacamz ilemlere dikkat etmemiz gerekir. Eer current matrisini identity olarak ilklemezseniz yani temizlemezseniz, baz istenmeyen sonular elde edersiniz. rnekte, matris ilklendikten sonra, gluLookAt() fonksiyonu ile viewing transformasyonu belirlenmektedir. Fonksiyona aktarlan argmanlar, kamerann( gz koordinatlar) nereye yerletirileceini, nereye ynlendirileceini ve nasl bir ekilde modeli gstereceini belirtirler. Kodda kullanlan argmanlar kamerann (0, 0, 5) noktasnda olduunu, kamerann lensinin (0, 0, 0) noktasna ynlendirildiini ve up-vectr olarak (0, 1, 0) ekim yaptn anlatmaktadr. gluLookAt() fonksiyonunu kullanmam olsaydk, kamerann varsayl olan deerleri kullanlm olurdu. Varsayl olarak, kamera koordinat sistemini merkezinde, lensi negatif z eksenine evrilmi ve up vektr olarak (0, 1, 0) noktasna gre ayarlanm olurdu. rnekte ise kameray 5 birim, pozitif z ekseni dorultusunda kaydrlmtr.
void gluLookAt(GLdouble eyex, GLdouble eyey, GLdouble eyez, GLdouble centerx, GLdouble centery, GLdouble centerz, GLdouble upx, GLdouble upy, GLdouble upz);
(eyex, eyey, eyez) koordinatlar kamerann yerini ayarlar. (centerx, centery, centerz) koordinatlar kamerann hangi noktaya bakacan tanmlamaktadr. Son olan koordinat parametreleri ise (upx, upy, upz) kamerann up-vektrn belirtmektedir. Resim 2-7 bu parametrelerin, kamera zerindeki kullanmn gstermektedir.
24
Kamera
Resim 2-7
25
//gluLookAt(0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); glTranslatef(0.0, 0.0, -5.0); glScalef(1.0, 2.0, 1.0); glutWireCube(1.0); glFlush(); } // end of void display(void)
Ekrannzda izeceiniz nesne iin belirlemi olduunuz modeling transformasyon fonksiyonlarnn sras nemlidir. rnek vermek gerekirse, Resim 2-8, translation ileminden sonra rotation ilemini ve rotation ileminden sonra translation ilemini gstermektedir. ki farkl ilemin etkileri birbirlerinden farkldr. Farz edelim ki, koordinat sisteminin merkezine yerlemi olan bir ok olsun. Uygulayacamz ilk transformasyon
26
ilemi bu oku z eksenine gre 30 derece dndrmektir yani rotation ilemidir. Ardndan x ekseni dorultusunda koordinat sistemini 5 birim tama yapalm. Eer bu ilemi tersini yaparsak elde edeceimiz sonu ilkinden farkl olacaktr.
+y -x +x -x
+y +x -x
+y +x
-y
-y
-y
+y -x +x -x
+y
+y +x -x
+y
+x
-y
-y
-y
-y
Resim 2-8
27
Herhangi bir transformation ilemini armadan nce, hangi matris modu zerinde Modifikasyonlar uygulayacanz belirtmeniz gerekir. Modelview modunda ilem yapmak istiyorsanz parametre olarak GL_MODELVIEW parametresini aktarn. glMatrixMode() iin aktarlacak dier parametreler ise GL_PROJECTION ve GL_TEXTURE argmanlardr. Projection matrisini belirtmek iin GL_PROJECTION kullanlr ve texture matrisi iin ise GL_TEXTURE bunu belirtmektedir. Bir ok durumda, bu matrisi current matris olarak ayarladktan sonra modelview matrisini identity matris olarak ilkleyin. Bunu yapabilmek iin glLoadIdentity() fonksiyonu kullann.
2.21 Translation
boyutlu bir dnyada, nesneyi bir yerden baka bir yere tamak iin bu ilem kullanlmaktadr. Bunu yapabilmek iin glTanslatef() ve glTranslated() fonksiyonlar bu ilemi gerekletirir.
void glTranslatef(GLfloat x, GLfloat y, GLfloat z); void glTranslated(GLdouble x, GLdouble y, GLdouble z);
Bu iki fonksiyon arasndaki tek fark aldklar parametre tiplerinin birbirlerinden farkl olmaldr. glTranslatef(), float tipinde ve glTranslated() fonksiyonu double tipinde parametre alr. Farzedin ki, bir kb koordinat sisteminin merkezinden (5, 5, 5) noktasna tamak istiyorsunuz. lk olarak modelview matrisini ykleyin ve sonra ilkleyin. Aadaki kod yapacamz ilemi gerekletirir ve resim 2-9 bunun sonucunu gsterir.
28
+y -z
(5, 5, 5)
-x
+x
+z
-y
Resim 2-9
2.22 Rotating
OpenGLde rotating, glRotate*() fonksiyonu ile gerekletirilmektedir.
void glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z); void glRotated(GLdouble angle, GLdouble x, GLdouble y, GLdouble z);
Tekrar sylemek gerekirse, glTranslate*() fonksiyonunda olduu gibi bu iki fonksiyon arasndaki tek fark aldklar parametre tiplerinin birbirlerinden farkl olmalardr. x, y ve z parametrelerine gre, nesneyi belirli bir a lsnde bu koordinat eksenleri etrafnda dndrebilirsiniz. Mesela izmi olduunuz bir modeli y ekseni etrafnda yelkovan ynne, 135 derece dndrmek istiyoruz. Bunun iin aadaki bu ilemi bizim iin yapmaktadr.
29
y argmann ald 1.0 deeri, y ekseni yndeki birim vektr belirtmektedir. stediiniz eksene gre, rotate ilemini yapabilmeniz iin sadece birim vektrn belirtmeniz gerekir. Resim 2-10 glRotate*() fonksiyonunun nasl altn gstermektedir.
+y -z
-x
+x
+z -y
Resim 2-10 Eer ekli saat ynnn tersine evirmek istiyorsanz, ay negatif olarak ayarlamanz gerekir. Bahsettiimiz ayn rotating rnei iin nesneyi saat ynnn tersinde 135 derece y ekseni evresinde dndrmek istiyorsak aadaki komutu yazmamz gerekmektedir.
glRotatef(-135.0, 0.0, 1.0, 0.0);
x, y, z parametrelerini kullanarak modeli istediimiz yne evirebiliriz. Unutmayn ki koordinat ekseni bu dnten etkilenecektir.
30
2.23 Scaling
Modelin boyutundaki ayarlamalar yapmak iin scaling ilemi kullanlmaktadr. Nesnenin boyutlar eksenlere gre uzatlabilip ksaltlabilir. Bunu OpenGLin salad glScale*() fonksiyonu ile yapabiliriz.
void glScalef(GLfloat x, GLfloat y, GLfloat z); void glScaled(GLdouble x, GLdouble y, GLdouble z);
x, y, z parametrelerine geirilen deerler her bir eksenin scale faktrn belirler. rnek olarak aadaki satr nesnenin her boyutunu 2 katna kartmaktadr.
glScalef(2.0, 2.0, 2.0);
Mesela, izdiimiz bir kbn derinlik ve yksekliini deitirmeden x ekseni zerindeki genilini 2 katna kartmak istiyoruz.
glScalef(2.0, 1.0, 1.0);
-x
+x
-x
+x
+z
+z
-y
-y
31
Matrislerin ytlar hiyerarik olarak nesneleri meydana getirmek iin kullanldrkar. Bu karmak modeller basit olan modellerden yaratlrlar. rnein, kutulardan nasl bir robot oluturulduunu dnn. Eer robotu bileenlerine ayrrsanz, robotun bir gvdesinin, kollarnn, bann ve bunun gibi bileenlerinin olduunu grrsnz. Bu ana kadar yaptmz matris ilemleri hep current matris ile ilgiliydi. Aslnda bu matris ytn en st elemandr.Yt ilemlerini yerine getiren komutlar ile, ytn stnde bulunan matrisi kontrol edebiliriz. Bildiiniz gibi yt ilemelerinde en sklkla kullanlan iki komut vardr. Bu komutlar push() ve pop() komutlardr. Yta bilgi gndermek iin ytn en stne bu bilgi kopyalanr. Bu ilem push() ilemidir. Yttn en stnden bilginin atlabilmesi iin pop() ilemi kullanlmaktadr. OpenGL bu gibi komutlar bize salamtr. glPushMatrix() ve glPopMatrix() glPushMatrix()
32
current matrisi kopyalar ve ytn en stne bu kopyalanm bilgiyi yerletirir. glPopMatrix() ise ytn en stndeki bilgiyi ekip kartr. Hatrlayn: ytn en st current matristir. Resim 2-11 yt matrisini gsterir.
glPushMatrix()
glPopMatrix()
Matris Yt Resim 2-11 glPushMatrix() ve glPopMatrix() iin yapacamz en uygun rnek, bir robot kolu olacaktr. Bu rnek sayesinde bu iki fonksiyonun ne ie yaradn bu rnek sayesinde anlayacaksnz. Bu blmde robot kolunun ikiden fazla segmenti vardr. Aadaki resim 2-12 izilecek olan robot kolunu gstermektedir.
33
Resim 2-12 Kolun segmentlerini izebilmek iin ncelikle boyutlarn deitirebileceiniz bir kbe ihtiyacnz olmal, fakat ilk olarak her segmentin kendi koordinat eksenlerine yerletirmek iin uygun modelleme transformasyonlarn armak gerekir. lk olarak yerel koordinat sisteminin merkezi izilen kbn merkezinde olacandan dolay, kbn bir kenarna yerel koordinat sistemini tamaya ihtiyacnz olacak. Dier bir koulda, kp pivot noktasna gre deil de merkezine gre dnecektir. Pivot noktasn yaratmak iin glTranslate*() fonksiyonunu ve bu pivot noktasna gre glRotate*() fonksiyonunu ardktan sonra, kbn merkezine doru evrimi yapn. Daha sonra kp izilmeden nce, kbn boyutlarn deitirin. glScale*() fonksiyonu dier segmentleri etkileyebilir ve bunu engellemek iin glPushMatrix ve glPopMatrix fonksiyonlarn kullanmak faydal olacaktr. Aada robot kolunun ilk segmenti iin, program kodunun nasl bir eye benzediini grn.
glTranslatef(-1.0, 0.0, 0.0); glRotatef((GLfloat) shoulder, 0.0, 0.0, 1.0); glTranslatef(1.0, 0.0, 0.0);
34
kinci segmenti yaratabilmek iin, lokal koordinat sistemini bir sonraki pivot noktaSna hareket ettirmemiz gerekiyor. Koordinat sistemi nceden dndne gre, x ekseni, dnm olan kolun uzunluu dorultusunda oktan yerlemi olacaktr. Bu sebepten dolaydr ki, x ekseni dorultusunda transformasyon yapmak lokal koordinat sistemini bir sonraki pivot noktasna hareket ettirecektir. Bu noktaya koordinat sistemin tandktan sonra, ilk olarak kullanm olduunuz kod blounu yeniden kullanarak, ikinci segmenti izebilirsiniz. Bu ilem sonsuz sayda segmentler iin geerlidir. rnek 2-4 deki program kodunun tm gsterilmektedir.
rnek 2-4
#include <stdlib.h> #include <GL/glut.h> static GLfloat shoulder = 0.0, elbow = 0.0, wrist1 = 0.0, finger1 = 0.0, b_wrist = 0.0, b_finger = 0.0; void init(void) { glClearColor(0.0, 0.0, 0.0, 0.0); glShadeModel(GL_FLAT); return; } // end of void init(void) void reshape(int w, int h) {
35
glViewport(0, 0, (GLsizei) w, (GLsizei) h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(65.0, (GLfloat) w / (GLfloat) h, 1.0, 20.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(-2.0, 0.0, -5.0); return; } // end of reshape(int, int) void display(void) { glClear(GL_COLOR_BUFFER_BIT); glColor3f(1.0, 1.0, 1.0); glPushMatrix(); glTranslatef(-1.0, 0.0, 0.0); glRotatef((GLfloat) shoulder, 0.0, 0.0, 1.0); glTranslatef(1.0, 0.0, 0.0); glPushMatrix(); glScalef(2.0, 0.4, 1.0); glutWireCube(1.0); glPopMatrix(); glTranslatef(1.0, 0.0, 0.0); glRotatef((GLfloat) elbow, 0.0, 0.0, 1.0); glTranslatef(1.0, 0.0, 0.0); glPushMatrix(); glScalef(2.0, 0.4, 1.0); glutWireCube(1.0); glPopMatrix();
glPushMatrix();
36
glTranslatef(1.0, 0.125, 0.25); glRotatef((GLfloat)wrist1, 0.0, 0.0, 1.0); glTranslatef(0.25, 0.0, 0.0); glPushMatrix(); glScalef(0.5, 0.1 , 0.25); glutWireCube(1.0); glPopMatrix(); glTranslatef(0.25, 0.0, 0.0); glRotatef((GLfloat) finger1, 0.0, 0.0, 1.0); glTranslatef(0.25, 0.0, 0.0); glPushMatrix(); glScalef(0.5, 0.1 , 0.25); glutWireCube(1.0); glPopMatrix(); glPopMatrix(); glPushMatrix(); glTranslatef(1.0, 0.125, -0.25); glRotatef((GLfloat)wrist1, 0.0, 0.0, 1.0); glTranslatef(0.25, 0.0, 0.0); glPushMatrix(); glScalef(0.5, 0.1, 0.25); glutWireCube(1.0); glPopMatrix(); glTranslatef(0.25, 0.0, 0.0); glRotatef((GLfloat) finger1, 0.0, 0.0, 1.0); glTranslatef(0.25, 0.0, 0.0); glPushMatrix(); glScalef(0.5, 0.1, 0.25); glutWireCube(1.0); glPopMatrix(); glPopMatrix();
37
glPushMatrix(); glTranslatef(1.0, -0.125, 0.0); glRotatef((GLfloat)b_wrist, 0.0, 0.0, 1.0); glTranslatef(0.25, 0.0, 0.0); glPushMatrix(); glScalef(0.5, 0.1, 0.25); glutWireCube(1.0); glPopMatrix(); glTranslatef(0.25, 0.0, 0.0); glRotatef((GLfloat) b_finger, 0.0, 0.0, 1.0); glTranslatef(0.25, 0.0, 0.0); glPushMatrix(); glScalef(0.5, 0.1, 0.25); glutWireCube(1.0); glPopMatrix(); glPopMatrix(); glPopMatrix(); glutSwapBuffers(); return; } // end of void display(void) void keyboard(unsigned char key, int x, int y) { switch (key) { case 's': shoulder += 5; if (shoulder > 360.0) shoulder -= 360.0; glutPostRedisplay(); break; case 'S': shoulder -= 5;
38
if (shoulder < 360.0) shoulder += 360.0; glutPostRedisplay(); break; case 'e': elbow += 5; if (elbow > 360.0) elbow -= 360.0; glutPostRedisplay(); break; case 'E': elbow -= 5; if (elbow < 360.0) elbow += 360.0; glutPostRedisplay(); break; case 'd': wrist1 += 5; if (wrist1 > 360.0) wrist1 -= 360.0; glutPostRedisplay(); break; case 'D': wrist1 -= 5; if (wrist1 < 360.0) wrist1 += 360.0; glutPostRedisplay(); break; case 'f': finger1 += 5; if (finger1 > 360.0) finger1 -= 360.0; glutPostRedisplay(); break; case 'F': finger1 -= 5; if (finger1 < 360.0) finger1 += 360.0; glutPostRedisplay(); break; case 'v': b_finger += 5; if (b_finger > 360.0) b_finger -= 360.0; glutPostRedisplay();
39
break; case 'V': b_finger -= 5; if (b_finger < 360.0) b_finger += 360.0; glutPostRedisplay(); break; case 'c': b_wrist += 5; if (b_wrist > 360.0) b_wrist -= 360.0; glutPostRedisplay(); break; case 'C': b_wrist -= 5; if (b_wrist < 360.0) b_wrist += 360.0; glutPostRedisplay(); break; case 27: exit(0); break; default: break; } // end of switch (key) } // end of void keyboard(unsigned char, int , int) int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB); glutInitWindowSize(640, 480); glutInitWindowPosition(100, 100); glutCreateWindow(argv[0]); init(); glutDisplayFunc(display); glutReshapeFunc(reshape); glutKeyboardFunc(keyboard); glutMainLoop(); return 0;
40
41
Specular Iklandrma, belirli bit ynden gelerek yzeye arpar ve nceden belirlenmi bir yne doru yansmaktadr yani eit olarak yansma yoktur. Emissive Iklandrma, nesneden kan k anlamna gelmektedir. OpenGL klandrma ynteminde, nesnenin yzeyinden yansyan renk, nesneye daha ok younluk katar, fakat bu dier k kaynaklarn etkilemez.
42
Iklar iin belirlenmi olan renk bileenleri, materyaller iin, daha farkl bir anlama gelmektedir. Bir ele alrsak, her renk iin, saylar tam younluk yzdesine uygun dmektedir. In krmz, yeil ve mavi bileenlerinin deerinin hepsi 1.0 a eit ise, k parlak bir beyaz k kayna olmaktadr. Eer tm deerler 0.5 e eit olduunda, k kayna yine beyaz olur fakat younlu %50 orannda azalcaktr. Ik bileenlerinden krmz ve yeilin deeri !.0 a, mavinin deeri ise 0.0 a eit ise, k yeil olarak grnr. Materyaller iin, saylar yansmakta n bileenler deeri ile arplmaktadr. Mesela materyalin kmz deeri 1.0 a, yeil deeri 0.5 e ve mavi deeri 0.0 a eit oluyorsa, materyal gelen klardan krmz n %100 n, yeil n %50sini ve mavi n %0 n yanstmakta olduunu belirtmektedir. Dier bir anlatm ekli ile anlatmaya alrsak, elimizde bir k kaynaklarnn deerleri olsun. Bu deerler ( IK, IY, IM ) ve materyalin deerleri ise ( MK, MY, MM ) olsun. Dier yansma etkilerini gze almasak, gzn grecei deerler yani cismin yanstaca k deerleri ( IK * MK, IY * MY, IM * MM ) olmaktadr. Benzer olarak, iki k kayna kullanyorsanz, yani gze gnderilecek deerler ( K1, Y1, M1 ) ve ( K2, Y2, M2 ), OpenGL bu bileenleri toplayacaktr ( K1 + K2, Y1 + Y2, M1 + M2 ). Bu toplama ilemlerinden herhangi biri 1 den byk karsa toplama ilemi 1 olarak alnr.
43
3. Bir klandrma modelin yaratn. 4. Nesnenin materyal zelliklerini tanmlayn. Aadaki rnek 2-5 bu ilemleri gerekletirmektedir. Bu rnekte tek bir k kayna altnda izilmi olan krmz bir aydanlk izilmektedir. rnek 2-5 Krmz aydanlk
#include <GL/glut.h> #include <GL/glu.h> GLfloat rotate_y = 0.0;
void draw_net(GLfloat size, GLint LinesX, GLint LinesZ) { int xc, zc; glBegin(GL_LINES); for (xc = 0; xc < LinesX; xc++) { glVertex3f( -size / 2.0 + xc / (GLfloat)(LinesX-1)*size, 0.0, size / 2.0); glVertex3f( -size / 2.0 + xc / (GLfloat)(LinesX-1)*size, 0.0, size / -2.0); } // end of for (xc = 0; xc < LinesX; xc++) for (zc = 0; zc < LinesZ; zc++) {
44
glVertex3f( size / 2.0, 0.0, -size / 2.0 + zc / (GLfloat)(LinesZ-1)*size); glVertex3f( size / -2.0, 0.0, -size / 2.0 + zc / (GLfloat)(LinesZ-1)*size); } // end of for (zc = 0; zc < LinesZ; zc++) glEnd(); return; } // end of void draw_net(GLfloat, GLint, GLint) void init(void) { GLfloat light_position[] = {1.0, 1.0, 1.0, 0.0}; GLfloat light_ambient[] = {1.0, 1.0, 1.0, 1.0}; GLfloat light_diffuse[] = {1.0, 1.0, 1.0, 1.0}; GLfloat light_specular[] = {1.0, 1.0, 1.0, 1.0}; GLfloat material_ambient[] = {0.23, 0.0, 0.0, 1.0}; GLfloat material_diffuse[] = {0.44, 0.0, 0.0, 1.0}; GLfloat material_specular[] = {0.33, 0.33, 0.52, 1.0}; GLfloat material_emission[] = {0.0, 0.0, 0.0, 0.0}; GLfloat material_shininess = 10; glClearColor(0.0, 0.0, 0.0, 0.0); glShadeModel(GL_SMOOTH); glLightfv(GL_LIGHT0, GL_POSITION, light_position); glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient); glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular); glMaterialfv(GL_FRONT, GL_AMBIENT, material_ambient);
45
glMaterialfv(GL_FRONT, GL_DIFFUSE, material_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, material_specular); glMaterialfv(GL_FRONT, GL_EMISSION, material_emission); glMaterialfv(GL_FRONT, GL_SHININESS, &material_shininess); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_DEPTH_TEST); glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); return; } // end of init(void) void display(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); glRotatef(rotate_y, 0.0, 1.0, 0.0); glPushMatrix(); glTranslatef(0.0, 0.55, 0.0); glutSolidTeapot(0.75); glPopMatrix(); glDisable(GL_LIGHTING); glColor3f(1.0, 1.0, 1.0); draw_net(5, 11, 11); glEnable(GL_LIGHTING); glPopMatrix(); glutSwapBuffers(); return; } // end of void display(void)
46
void reshape(int w, int h) { glViewport(0, 0, (GLsizei)w, (GLsizei)h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(60.0, (GLfloat)w/(GLfloat)h, 1.0, 20.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(0.0, 2.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); return; } // end of void reshape(GLfloat, GLfloat) void rotate_teapot(void) { rotate_y += 0.5; if (rotate_y > 360.0) rotate_y -= 360.0; glutPostRedisplay(); return; } // end of rotate_teapot(void) int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(500, 500); glutInitWindowPosition(100, 100); glutCreateWindow("Teapot"); init(); glutDisplayFunc(display); glutReshapeFunc(reshape); glutIdleFunc(rotate_teapot); glutMainLoop();
47
rnei incelemeye balayalm. Ik kaynaklarnn bir ok zellikleri vardr, bunlar renk, pozisyon ve n yndr. Bu tm zellikleri belirlemek iin kullanlan komut glLight*() fonksiyonudur. Fonksiyon argman almaktadr. Fonksiyonun prototipi aada belirtilmitir.
void glLight[if]v( GLenum light, GLenum pname, Type *param );
lk parametre olan light parametresi zellii belirlenecek olan k kaynan belirtir. Bu kaynaklar GL_LIGHT0, GL_LIGHT1, GL_LIGH7 olan sekiz tane k kayna mevcuttur. In karakteristiini belirleyen parametre pname parametresidir ve tablo 2-2 bu parametrenin alaca deerleri listelemektedir. pname parametresine gre param parametresinin alaca deerler vardr. Bu parametre bir vektr gsteren bir iaretidir. Tablo 2-2 glLight*() Parametreleri
48
Parametre
GL_AMBIENT GL_DIFFUSE
Varsayl Deerler
(0.0, 0.0, 0.0, 0.0) (1.0, 1.0, 1.0, 1.0) (0.0, 0.0, 0.0, 0.0)
Anlam
Ambient younluu Diffuse younluu (light 0 iin) (Dier klar iin) specular younluu (light 0 iin) (Dier klar iin) (x, y, z, w) pozisyon
GL_SPECULAR
GL_POSITION
Gsterilecek daha bir ok parametre var fakat u anda bizim ilgileneceimiz parametreler uygulamalarmz iin yeterli. rnei dikkatlice incelerseniz init() fonksiyonu iinde n ambient, diffuse, specular ve pozisyon bilgileri tanmlanmtr.
GLfloat light_position[] = {1.0, 1.0, 1.0, 0.0}; GLfloat light_ambient[] = {1.0, 1.0, 1.0, 1.0}; GLfloat light_diffuse[] = {1.0, 1.0, 1.0, 1.0}; GLfloat light_specular[] = {1.0, 1.0, 1.0, 1.0}; glLightfv(GL_LIGHT0, GL_POSITION, light_position); glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient); glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
Greceiniz gibi, parametre deerleri iin diziler tanmlanm ve glLightfv() fonksiyonu n zelliklerini belirlemek iin tekrar tekrar arlmtr. Bu zellikler ayarlandktan sonra, klandrma olayn ve k kaynan aktifletirmeye geldi. Temel olarak klandrmann aktif hale gelebilmesi iin glEnable() fonksiyonunu kullanmak gerekir.
49
glEnable(GL_LIGHTING);
Bu ilemin ardndan hangi k kaynan aktif hale getirmek istediimizi OpenGL e anlatmak ii yine ayn fonksiyonu yani glEnable() fonksiyonunu kullanmamz gerekir. zelliklerini ayarladmz k kayna light 0 olduuna gre aadaki kod bu k kaynan aktif hale getirecektir.
glEnable(GL_LIGHT0);
I aktif ettikten sonra ksaca anlatmak istediimiz ey n bulunduu konum, yani n pozisyonu ile ilgili nemli bir konuyu dile getirmek istiyoruz. Ik pozisyonu ayarlanrken kullanlan drt farkl deerler var ( x, y, z, w ). Bu deerleri ilk yani x, y, z tahmin edeceiniz gibi k kaynann koordinatlarn belirtmektedir. Peki ya drdnc parametre ne anlama gelmektedir ? Drdnc parametreyi 0.0 a eit olduunda k kaynann sonsuz uzaklktan bir yerden geldii anlamna gelmektedir ve bu sebepten dolay k kaynandan yaylan nlar parelel olarak yaylrlar. Bu akla ilk somut olarak gelen rnein gne olduudur. Gne dnyadan ok uzak olduundan dolay bu uzakl sonsuz olarak alabiliriz. Uzaklk sonsuz olunca gneten kan nlar dnya yzeyine parelel olarak gelmektedir. Bu tip k kaynaklarna directional light source denmektedir. Light 0 iin bu rnei komut olarak yazarsak aadaki gibi kod blounu gsterebiliriz.
GLfloat light_position[] = {0.0, 0.0, 1.0, 0.0} glLightfv(GL_LIGHT0, GL_POSITION, light_position);
Bu yukardaki rnekte z ekseninden gelen k kayna tanmlanmtr. Drdnc parametreyi sfrdan farkl bir deere sahip olduunda bu tip k kayna positional light source olarak adlandrlr. Bunun anlam ( x, y, z ) noktasnda konumlandrlm olan bir k kaynann bulunmas anlamna gelmektedir. Bu sanki masann stne konmu olan bir lambann bulunmas gibidir.
50
Ik kaynann karakteristiklerini grdkten sonra materyallerin karakteristiklerini inceleyerek ikisi arasndaki benzerlikleri veya farkllklar anlayacaz. En ok bilinen materyal zellikleri nceden grm olduunuz k kayna zelliklerine benzemektedir. Bu zellikleri belirlemek iin kullanlan mekanizma kta kullanlan mekanizma ile benzerlik tamaktadr. Fakat bu sefer materyaller iin kullanlan komut glMaterial*() fonksiyonudur.
void glMaterial[if]v( GLenum face, GLenum pname, Type *param );
Fonksiyon sayesinde, klandrmada kullanm iin, materyalin zelliini belirler. face parametresi, GL_FRONT, GL_BACK veya GL_FRONT_AND_BACK deerlerini alarak nesnenin yz materyaline, materyaller iin tanmlanm olan zelliklerin uygulanmas anlamna gelmektedir. Bu parametreye uygulanacak deerler ise param parametresi tarafndan belirlenir. param parametresi, bir vektr veya diziyi iaret eden bir iaretidir. Bu pname parametresi iin deerler tablo 2-3 te gsterilmektedir. Tablo 2-3 glMaterial*() pname Parametresi
Parametre
GL_AMBIENT GL_DIFFUSE GL_SPECULAR GL_SHININESS GL_EMISSION
Varsayl Deerler
(0.2, 0.2, 0.2, 1.0) (0.8, 0.8, 0.8, 1.0) (0.0, 0.0, 0.0, 1.0) (0.0) (0.0, 0.0, 0.0, 1.0)
Anlam
Ambient renk Diffuse renk specular renk specular exponent emissive renk
face parametresi iin GL_FRONT olarak tanmlanm ise, GL_FRONT deeri OpenGL e poligonun sadece n ksmnda materyal zelliklerini kullanlaca anlatlmaktadr GL_BACK olduunda ise poligonun arka ksmnda materyal zelliklerinin kullanlaca veya GL_FRONT_AND_BACK kullanldnda ise poligonun her iki
51
yzeyinde bu materyal zelliklerinin geerli olaca bildirilmektedir. Program altrldnda resim 2-13 te izim yaplmaktadr.
Resim 2-13
2.28 Blending
OpenGL de renk karm ( color blending ) izeceiniz nesnelere saydamlk katlmasna izin vermektedir. Bu saydamlk sayesinde, gerek hayatta grmekte olduunuz
52
su, am, pencereler ve dier nesneleri simule edebilirsiniz. u ana kadar nesneler zerinde kullandmz renk verme fonksiyonu glColor3*() fonksiyonuydu. Fonksiyon sadece parametre almaktadr. Bu parametrelerin ne olduklarn biliyorsunuz. Nesnelere saydamlk katabilmek iin baka bir renk fonksiyonu kullanacaz. Bu fonksiyon imdiye kadar kullanlan parametreye ek olarak drdnc bir parametre almaktadr. Bu parametreye alfa parametresi denmektedir. Kullanacamz fonksiyon ise glColor4*() fonksiyonudur. Peki ya alfa deeri ne yapar ? Alfa deeri nesnenin yeni rengini, frame buffer nda bulunan renk ile birletirmektedir. Frame buffer olarak sylenen ey sistemde kullanlan tm buffer larn btndr. Yani color buffer, depth buffer, stencil buffer ve accumulation buffer size tek bir frame buffer n verebilmek iin birleirler. Buffer lar konusuyla pek ilgimiz olamayacak. Blending ileminde, RGB bileenleri fragmann rengini ve alfa bileeni ise o fragmann katlk derecesini yani effaf olmama derecesini syler. Saydam veya effaf olan cisimlerin effaf olmama derecesi saydam olmayan kilere gre daha dktr bu da demek oluyor ki bu cisimlerin alfa deerleri daha dktr.
53
( Rs * Sr + Rd * Dr, Gs * Sg + Gd * Dg, Bs * Sb + Bd * Db, As * Sa + Ad * Da ) Kaynak ve hedef RGBA deerleri srasyla s ve d alt simge karakteri ile belirtilmektedir. imdi kullanacamz fonksiyon, kaynak ve hedef blending faktrlerini oluturmaktadr. Kullanacamz fonksiyonun ad glBlendFunc() tur ve bu fonksiyon iki sabiti destekler. lki hesaplanmas gereken kaynak faktr ve dieri ise hedef faltrdr. Ek olarak blending ilemini aktif hale getirmek iin her zaman aadaki tek satrlk kodu yazmalsnz.
glEnable(GL_BLEND);
Blending ilemini inaktif yapmak istiyorsanz bildiiniz gibi glDisable() fonksiyonuna GL_BLEND parametresini aktarabilirsiniz. glBlendFunc() fonksiyonun prototipi aadaki gibidir.
void glBlendFunc( GLenum sfactor, GLenum dfactor );
sfactor parametresi kaynak blending faktrnn, dfactor parametresi ise hedef blending faktrnn nasl hesaplanacan belirtirler. Bu parametreler iin mmkn deerler tablo 2-4 gsterilmektedir. Blending faktrleri 0 ile 1 aralnda deerler alr. Tabloda source, destination ve constant ( sabit ) renklerin RGBA deerleri altsimge karakteri olan s, d, c harfleri ile gsterilmektedir.
54
Sabit
GL_ZERO GL_ONE GL_DST_COLOR GL_SRC_COLOR GL_ONE_MINUS_DST_COLOR GL_ONE_MINUS_SRC_COLOR GL_SRC_ALPHA
lgili Faktr
source veya destination source veya destination source destination source destination source veya destination source veya destination source veya destination source veya destination source source veya destination
GL_ONE_MINUS_SRC_ALPHA
GL_DST_ALPHA
GL_ONE_MINUS_DST_ALPHA
GL_SRC_ALPHA_SATURATE GL_CONSTANT_COLOR
55
Yapacamz rnek bir Windows uygulamasdr. Bu uygulamay GLUT yardm ile de yapabilirdik, fakat biraz deiiklik olsun istedik ve biraz da Windows uygulamalarnda altrma yapmaya altk. rnek 2-6da alfa deeri 0.75 olan ve birbirinden farkl ve kesimi iki keni gstermektedir. Blending aktif durumdadr, kaynak blending faktr GL_SRC_ALPHA olarak ve hedef blending faktr ise GL_ONE_MINUS_SRC_ALPHA olarak ayarlanmtr. Program altnda, ilk olarak sar ken pencerenin sol tarafnda izilir ve daha sonra iyan renkli ken ekrann sa tarafna izilerek kenler kesiirler. Pencerede izilecek olan ilk keni l veya r tularna basarak belirleyebilirsiniz. l tuuna bastnzda izilecek ilk ken sar renkte olan ve ekrann sol tarafna bulunan ken olacaktr, r tuuna basarsanz ekrann sa tarafna izilecek olan iyan renkli ken ilk olarak izilir. rnek 2-6
#include <windows.h> #include <gl/gl.h> #include <gl/glu.h> #include <gl/glaux.h> float angle = 0.0; HDC g_HDC; BOOL fullScreen = FALSE; BOOL keyPressed[256]; int left_first = GL_TRUE; void init(void) { glClearColor(0.0, 0.0, 0.0, 0.0); glShadeModel(GL_FLAT); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
56
glEnable(GL_BLEND); return; } // end of void initialize(void) void resize(int width, int height) { glViewport(0, 0, (GLsizei) width, (GLsizei) height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (width <= height) gluOrtho2D(0.0,1.0, 0.0, (GLfloat)height / (GLfloat)width); else gluOrtho2D(0.0, (GLfloat)width / (GLfloat)height, 0.0, 1.0); // // glMatrixMode(GL_MODELVIEW); glLoadIdentity(); return; } // end of void resize(int, int) void draw_leftTriangle(void) { glBegin(GL_TRIANGLES); glColor4f(1.0, 1.0, 0.0, 0.75); glVertex3f(0.1, 0.9, 0.0); glVertex3f(0.1, 0.1, 0.0); glVertex3f(0.7, 0.5, 0.0); glEnd(); return; } // end of void draw_leftTrianfle(void) void draw_rightTriangle(void) { glBegin(GL_TRIANGLES); glColor4f(0.0, 1.0, 1.0, 0.75); glVertex3f(0.9, 0.9, 0.0);
57
glVertex3f(0.3, 0.5, 0.0); glVertex3f(0.9, 0.1, 0.0); glEnd(); return; } // end of void draw_rightTriangle(void) void display(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); if (left_first) { draw_leftTriangle(); draw_rightTriangle(); }else { draw_rightTriangle(); draw_leftTriangle(); } SwapBuffers(g_HDC); return; } // end of void display(void) void SetupPixelFormat(HDC hDC) { int nPixelFormat; static PIXELFORMATDESCRIPTOR pfd = { sizeof(PIXELFORMATDESCRIPTOR), 1, PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, PFD_TYPE_RGBA, 32, 0, 0, 0, 0, 0, 0, 0,
58
0, 0, 0, 0, 0, 0, 16, 0, 0, PFD_MAIN_PLANE, 0, 0, 0, 0 }; nPixelFormat = ChoosePixelFormat(hDC, &pfd); SetPixelFormat(hDC, nPixelFormat, &pfd); return; } // end of void SetupPixelFormat(HDC) LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { static HGLRC hRC; static HDC hDC; char string[] = "Simple Windows Application"; int width, height; switch(message) { case WM_CREATE: hDC = GetDC(hWnd); g_HDC = hDC; SetupPixelFormat(hDC); hRC = wglCreateContext(hDC); wglMakeCurrent(hDC, hRC);
59
init(); return 0; break; case WM_CLOSE: wglMakeCurrent(hDC, NULL); wglDeleteContext(hRC); PostQuitMessage(0); return 0; break; case WM_SIZE: height = HIWORD(lParam); width = LOWORD(lParam); if (height == 0) height = 1; resize(width, height); return 0; break; case WM_KEYDOWN: keyPressed[wParam] = TRUE; return 0; break; case WM_KEYUP: keyPressed[wParam] = FALSE; return 0; break; default: break; } // end of switch(message) return DefWindowProc(hWnd, message, wParam, lParam); } // end of WndProc(HWND, UINT, WPARAM, LPARAM) int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) {
60
WNDCLASSEX windowClass; HWND hWnd = NULL; MSG msg; BOOL done = FALSE; DWORD dwExStyle; DWORD dwStyle; RECT windowRect; int width = 200; int height = 200; int bits = 32; windowRect.left = 0; windowRect.right = width; windowRect.top = 0; windowRect.bottom = height; windowClass.cbSize = sizeof(WNDCLASSEX); windowClass.style = CS_HREDRAW | CS_VREDRAW; windowClass.lpfnWndProc = WndProc; windowClass.cbClsExtra = 0; windowClass.cbWndExtra = 0; windowClass.hInstance = hInstance; windowClass.hIcon = LoadIcon(NULL, IDI_APPLICATION); windowClass.hCursor = LoadCursor(NULL, IDC_ARROW); windowClass.hbrBackground = NULL; windowClass.lpszMenuName = NULL; windowClass.lpszClassName = "MyClass"; windowClass.hIconSm = LoadIcon(NULL, IDI_WINLOGO); if (!RegisterClassEx(&windowClass)) return 0; if (MessageBox(NULL, "Would You Like To Run In Fullscreen Mode?", "Start FullScreen?",MB_YESNO|MB_ICONQUESTION)==IDYES) fullScreen = TRUE;
61
if (fullScreen) { DEVMODE dmScreenSettings; memset(&dmScreenSettings, 0, sizeof(DEVMODE)); dmScreenSettings.dmSize = sizeof(dmScreenSettings); dmScreenSettings.dmPelsWidth = width; dmScreenSettings.dmPelsHeight = height; dmScreenSettings.dmBitsPerPel = bits; dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; if (ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) { MessageBox(NULL, "Display mode failed", NULL, MB_OK); fullScreen = FALSE; } } // end of if (fullScreen) if (fullScreen) { dwExStyle = WS_EX_APPWINDOW; dwStyle = WS_POPUP; ShowCursor(FALSE); } else { dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; dwStyle = WS_OVERLAPPEDWINDOW; } AdjustWindowRectEx(&windowRect, dwStyle, FALSE, dwExStyle);
hWnd = CreateWindowEx(0,
62
"MyClass", "The OpenGL Window Application", dwStyle | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0, 0, windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, NULL, NULL, hInstance, NULL); if (!hWnd) return 0; ShowWindow(hWnd, SW_SHOW); UpdateWindow(hWnd); while(!done) { PeekMessage(&msg, hWnd, 0, 0, PM_REMOVE); if (msg.message == WM_QUIT) done = TRUE; else { if (keyPressed[VK_ESCAPE]) done = TRUE; if(keyPressed['l'] || keyPressed['L']) left_first = TRUE; if (keyPressed['r'] || keyPressed['R']) left_first = FALSE; display(); TranslateMessage(&msg); DispatchMessage(&msg);
63
} } // end of while(!done) return (int) msg.wParam; } // end of WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
izilecek olan kenlerin sras, kesitikleri blgenin rengini etkiler. Soldaki ken izildiinde, iyan fragman ( kaynak veya source ) sar fragman ile kartrlr. Tabi bu sar fragman nceden frame buffern ( hedef veya destination) iinde bulunmaktadr. Sa taraftaki ken ilk izilirse, sar iya ile kartrlcaktr. Alfa faktrnn 0.75 olmasndan dolay, kaynak iin blending faktr 0.75, hedef iin ise 1.0 0.75 = 0.25 olacaktr.
64
olucaktr. Fakat saydam bir cisim bak noktasna daha yakn olduunda, bu cismi dier saydam olmayan cisimler ile blend etmek zorundasnz. Bunu yapabilmek iin depth buffer n read-only mofunda kullanmak gerekir. izilecek boyutlu nesnelerin izim srasda nemlidir. O zaman ilk olarak izilecek olan nesneler saydam olmayan cisimlerdir tabi bu srada depth buffer normal olarak ilemektedir. Bu depth buffer n read-only moduna getirerek, derinlik deerlerini saklayn. Saydam nesneler izildiinde, onlarn derinlik deerleri saydam olamayan nesneler tarafndan retilen deerler ile kyaslanr ve bylece saydam olan nesneler izilmez tabi bu nesneler saydam olmayan nesnelerin arkasnda iseEer saydam nesneler bak noktasna yakn olduunda, saydam olmayan nesneleri saklamazlar, nk depth buffer deerleri deimemitir. Bunun yerine bu nesneler saydam olmayan nesneler ile blend edilmitir. Depth buffer n yazlabilir olup olmadn kontrol edebilmek iin, glDepthMask() fonksiyonu kullanlr.
void glDepthMask(GLboolean flag);
flag parametresine, GL_FALSE deerini atarsanz, buffer read-only modunda olacaktr, fakat GL_TRUE olarak atarsanz yazlabilir bir buffer olacaktr. rnek 2-7, bize bu anlattklarmzn kk bir uygulamasn gsterecek bir program kodunu anlatmaktadr. Ekran ierisinde bir grid zerinde bulunan saydam ve krmz renkli bir kp ile onun biraz tesinde bulunan mavi renkli bir kre izilmitir ve bu izilen nesneler y ekseni etrafnda dnmektedir. rnek 2-7
#include <stdlib.h> #include <GL/glut.h> #include <GL/glu.h> GLfloat cube_ambient[] = {0.23, 0.0, 0.0, 1.0}; GLfloat cube_diffuse[] = {0.44, 0.0, 0.0, 1.0};
65
GLfloat cube_specular[] = {0.33, 0.33, 0.52, 1.0}; GLfloat cube_emission[] = {0.0, 0.0, 0.0, 0.0}; GLfloat cube_shininess = 50; GLfloat sphere_ambient[] = {0.0, 0.0, 0.39, 1.0}; GLfloat sphere_diffuse[] = {0.0, 0.47, 0.5, 1.0}; GLfloat sphere_specular[] = {0.0, 0.64, 0.34, 1.0}; GLfloat sphere_emission[] = {0.0, 0.0, 0.2, 0.0}; GLfloat sphere_shininess = 38; GLfloat rotate_y = 0.0; void draw_net(GLfloat size, GLint LinesX, GLint LinesZ) { int xc, zc; glBegin(GL_LINES); for (xc = 0; xc < LinesX; xc++) { glVertex3f( -size / 2.0 + xc / (GLfloat)(LinesX-1)*size, 0.0, size / 2.0); glVertex3f( -size / 2.0 + xc / (GLfloat)(LinesX-1)*size, 0.0, size / -2.0); } // end of for (xc = 0; xc < LinesX; xc++) for (zc = 0; zc < LinesZ; zc++) { glVertex3f( size / 2.0, 0.0, -size / 2.0 + zc / (GLfloat)(LinesZ-1)*size); glVertex3f( size / -2.0,
66
0.0, -size / 2.0 + zc / (GLfloat)(LinesZ-1)*size); } // end of for (zc = 0; zc < LinesZ; zc++) glEnd(); return; } // end of void draw_net(GLfloat, GLint, GLint) void init(void) { GLfloat light_position[] = {1.0, 1.0, 1.0, 0.0}; GLfloat light_ambient[] = {1.0, 1.0, 1.0, 1.0}; GLfloat light_diffuse[] = {1.0, 1.0, 1.0, 1.0}; GLfloat light_specular[] = {1.0, 1.0, 1.0, 1.0}; glClearColor(0.0, 0.0, 0.0, 0.0); glShadeModel(GL_SMOOTH); glLightfv(GL_LIGHT0, GL_POSITION, light_position); glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient); glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_DEPTH_TEST); glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); return; } // end of init(void) void reshape(int w, int h) { glViewport(0, 0, (GLsizei)w, (GLsizei)h); glMatrixMode(GL_PROJECTION);
67
glLoadIdentity(); gluPerspective(60.0, (GLfloat)w/(GLfloat)h, 1.0, 20.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(0.0, 2.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); return; } // end of void reshape(GLfloat, GLfloat) void display(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); glRotatef(rotate_y, 0.0, 1.0, 0.0); glPushMatrix(); glTranslatef(1.0, 0.5, 0.0); glMaterialfv(GL_FRONT, GL_AMBIENT, sphere_ambient); glMaterialfv(GL_FRONT, GL_DIFFUSE, sphere_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, sphere_specular); glMaterialfv(GL_FRONT, GL_EMISSION, sphere_emission); glMaterialfv(GL_FRONT, GL_SHININESS, &sphere_shininess); glutSolidSphere(0.5, 16, 16); glPopMatrix();
68
cube_ambient); glMaterialfv(GL_FRONT, GL_DIFFUSE, cube_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, cube_specular); glMaterialfv(GL_FRONT, GL_EMISSION, cube_emission); glMaterialfv(GL_FRONT, GL_SHININESS, &cube_shininess); glEnable(GL_BLEND); glDepthMask(GL_FALSE); glBlendFunc(GL_SRC_ALPHA, GL_ONE); glutSolidCube(1.0); glDepthMask(GL_TRUE); glDisable(GL_BLEND); glPopMatrix();
glDisable(GL_LIGHTING); glColor3f(1.0, 1.0, 1.0); draw_net(5, 11, 11); glEnable(GL_LIGHTING); glPopMatrix(); glutSwapBuffers(); return; } // end of void display(void) void rotate(void) { rotate_y += 0.5; if (rotate_y > 360.0) rotate_y -= 360.0;
69
glutPostRedisplay(); return; } // end of rotate_teapot(void) void keyboard(unsigned char key, int x, int y) { switch(key) { case 'R': case 'r': rotate_y = 0; glutPostRedisplay(); break; case 27: exit(0); } return; } // end of void keyboard(unsigned char, int, int) int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(600, 400); glutInitWindowPosition(100, 100); glutCreateWindow("Teapot"); init(); glutDisplayFunc(display); glutReshapeFunc(reshape); glutKeyboardFunc(keyboard); glutIdleFunc(rotate); glutMainLoop(); return 0; } // end of int main(int, char**)
70
Aadaki resim 2-14, rnek 2-7 deki kodu altrdnzda ortaya kacak sonucu gstermektedir.
Resim 2-14
71
Resim 2-15 bir BMP dosyasnn yapsn gstermektedir. Bitmap file header, Bitmap information header ve bitmap data
Bitmap Data
Resim 2-15 Bitmap dosya Bitmap File Header dosyasn yklemek iin kullanlan veri yaps BITMAPFILEHEADER dr ve bu yap aada gsterilmektedir.
typedef struct tagBITMAPFILEHEADER { WORD WORD WORD bfType; // specifies the file type; must be BM (0x4D42) // specifies the size in bytes of BMP file // reserved; must be zero // reserved; must be zero DWORD bfSize;
bfReserved1; bfReserved2;
Bu yap ile ilgili olarak, bir bmp dosyas ykleyeceiniz zaman dosyann uzants-
72
na dikkat etmeniz gerektiidir. Bunu, dosyann BITMAPFILEHEADER yapsnn bir yesine bakarak yani bfType e bakarak dosyann uzantsnn bmp olup olmadn anlayabilirsiniz. Bu ye bitmap dosyalar iin her zaman 0x4D42 deerine eittir. Bu sayy nceden Windows proglamlamas esnasnda grmtnz. Bir bmp uzantl dosyay aarken bu say ile kontrol yaplmaktadr. bfSize, bize dosyann boyutunu, bOffBits ise bize dosyann bandan itibaren Bitmap Datann nereden baladn ieren bir ofset bilgisini gsterir. Bir sonraki inceleyeceimiz veri blgesi, her BMP dosyasna zg olan bilgileri ierir. Bu blge, BMP dosyasnn 8-bitlik ve bir palet verisine sahip olmasna gre bir veya iki paraya ayrlmaktadr. Biz palet verisi ile ilgilenmeyeceimiz iin sadece BITMAPINFOHEADER yapsn okuyacaz.
typedef struct tagBITMAPINFOHEADER { DWORD biSize; LONG LONG WORD WORD // number of bytes required by the structure biWidth; // width of the bitmap, in pixels biHeight; // height of the bitmap, in pixels biPlanes; // number of color planes, must be 1 biBitCount; // number of bits per pixel must be 1, 4, 8, // 16, 24, 32 DWORD biCompression; // type of compression DWORD biSizeImage; // size of image in bytes LONG LONG biXPelsPerMeter; // number of pixels perm eter in x-axis biYPelsPerMeter; // number of pixels perm eter in y-axis
DWORD biClrUsed; // number of colors used by the bitmap DWORD biClrImportant; // number of colors that are important } BITMAPINFOHEADER;
Bu yapnn yanndaki aklamalar okumak kendini aklayacak kadar yeterlidir. Burada nemli olan bir BMP dosyasn nasl bellee ykleyeceimizdir. BMP dosyasnn Bitmap Data ksmnda krmz ve mavi renk deerlerinin yerleri deimitir yani dosya bildiiniz gibi krmz, yeil ve mavi olarak sral deilde mavi, yeil krmz ola-
73
rak okunmal ve krmz ile mavi deerlerin yerlerinin deimesi gerekmektedir. Bu ilem, dosya okunurken yaplmadr. Bir bitmap dosyas yaratlacaksa bu ilemi tersinden yapmak yani ncelikle mavi sonra yeil ve en son olarak krmz renk deeri dosyaya yazlmaldr nk bitmap dosya yapsna uymamz gerekir. rnek 2-8 de 24-bitlik bir bitmap dosyasn ykleye ve bitmap dosyasn oluturan program kodu ve onun balk dosyas bulunmaktadr. rnek 2-8 Bitmap.h ve Bitmap.c
// Bitmap.h #ifndef _BITMAP_H #define _BITMAP_H #include <windows.h> typedef unsigned char *BITMAPIMAGE; #define BITMAP_ID 0x4D42 #define FILE_NOT_OPENED_TO_WRITE -12 extern BITMAPIMAGE Bitmap_LoadBitmapFile(const char*, const BITMAPINFOHEADER*); extern int Bitmap_WriteBitmapFile(const char*, LONG, LONG, BITMAPIMAGE); #endif // Bitmap.c #include <windows.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include "Bitmap.h"
BITMAPIMAGE
74
Bitmap_LoadBitmapFile(const char* filename, const BITMAPINFOHEADER* bitmapInfoHeader) { FILE *filePtr; BITMAPFILEHEADER bitmapFileHeader; BITMAPIMAGE bitmapImage; DWORD imageIdx; unsigned char tempRGB; if ((filePtr = fopen(filename, "rb")) == NULL) { MessageBox(NULL, "File not found.", "Error", MB_OK); return NULL; } fread(&bitmapFileHeader, sizeof(BITMAPFILEHEADER), 1, filePtr); if (bitmapFileHeader.bfType != BITMAP_ID) { MessageBox(NULL, "Invalid file extention.", "Error", MB_OK); fclose(filePtr); return NULL; } fread((BITMAPINFOHEADER*)bitmapInfoHeader, sizeof(BITMAPINFOHEADER), 1, filePtr); fseek(filePtr, bitmapFileHeader.bfOffBits, SEEK_SET); bitmapImage = (BITMAPIMAGE) malloc(bitmapInfoHeader->biSizeImage); if (!bitmapImage) { MessageBox(NULL, "Out of memory", "Error", MB_OK); fclose(filePtr);
75
return NULL; } fread((BITMAPIMAGE)bitmapImage, sizeof(*bitmapImage), bitmapInfoHeader->biSizeImage, filePtr); if (!bitmapImage) { MessageBox(NULL, "File not read.", "Error", MB_OK); free(bitmapImage); fclose(filePtr); return NULL; } for(imageIdx = 0; imageIdx < bitmapInfoHeader->biSizeImage; imageIdx+=3) { tempRGB = bitmapImage[imageIdx]; bitmapImage[imageIdx] = bitmapImage[imageIdx + 2]; bitmapImage[imageIdx + 2] = tempRGB; } fclose(filePtr); return bitmapImage; } int Bitmap_WriteBitmapFile(const char* filename, LONG width, LONG height, BITMAPIMAGE imageData) { FILE *filePtr; BITMAPFILEHEADER bitmapFileHeader; BITMAPINFOHEADER bitmapInfoHeader;
76
DWORD imageIdx; unsigned char tempRGB; if ((filePtr = fopen(filename, "wb")) == NULL) return FILE_NOT_OPENED_TO_WRITE; bitmapFileHeader.bfSize = sizeof(BITMAPFILEHEADER); bitmapFileHeader.bfType = BITMAP_ID; bitmapFileHeader.bfReserved1 = 0; bitmapFileHeader.bfReserved2 = 0; bitmapFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); bitmapInfoHeader.biSize = sizeof(BITMAPINFOHEADER); bitmapInfoHeader.biPlanes = 1; bitmapInfoHeader.biBitCount = 24; bitmapInfoHeader.biCompression = BI_RGB; bitmapInfoHeader.biSizeImage = width * height * 3; bitmapInfoHeader.biXPelsPerMeter = 0; bitmapInfoHeader.biYPelsPerMeter = 0; bitmapInfoHeader.biClrImportant = 0; bitmapInfoHeader.biWidth = width; bitmapInfoHeader.biHeight = height; for(imageIdx = 0; imageIdx < bitmapInfoHeader.biSizeImage; imageIdx += 3) { tempRGB = imageData[imageIdx]; imageData[imageIdx] = imageData[imageIdx + 2]; imageData[imageIdx + 2] = tempRGB; } fwrite((BITMAPFILEHEADER*)&bitmapFileHeader, 1, sizeof(BITMAPFILEHEADER), filePtr); fwrite((BITMAPINFOHEADER*)&bitmapInfoHeader, 1, sizeof(BITMAPINFOHEADER), filePtr);
77
78
yutlu bir texture map ilemi yapmak istiyorsanz glTexImage2D() fonksiyonunu kullann. Bir boyutlu texture map ilemi yapmak istiyorsanz glTexImage1D() fonksiyonunu, boyutlu olarak ilem yapmak istiyorsanz glTexImage3D() fonksiyonunu kullanabilirsiniz.
void glTexImage2D(GLenum target, GLint level, GLint intenalFormat, GLsizei width, GLsizei height, GLint border, GLenum type, const GLvoid* texels);
target parametresi GL_TEXTURE_2D veya GL_PROXY_TEXTURE_2D olarak ayarlanabilir. Fakat bizim iin bu parametreyi GL_TEXTURE_2D yapmak daha uygundur. level parametresi texture map in znrln belirler. Sadece tek bir znrlk kullanmak istiyorsanz bu parametreyi 0 yapn. u an iin bir ok znrlk modunun kullanmn tartmayacaz. internalFormat paramtresi 1 den 4 e kadar veya size gsteremiyeceimiz 38 sabit deerden birini kullanan sayya eittir. Bizim sadece kullanabileceklerimiz GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_RGB ve GL_RGBA olmaktadr. width ve height parametreleri texture map in genilik ve boyutunu belirlerler. Bu deerler 2 nin ss bir deer olmaldrlar. border parametresi texture evresinde bir snrn olup olmadn bildirmektedir. Snr var ise bu deer 1, yok ise deer 0 olmaldr. format parametresi, texture mapin verisinin formatn tanmlar ve bu format GL_COLOR_INDEX, GL_RGB, GL_RGBA, GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA, GL_LUMINANCE veya GL_LUMINANCE_ALPHA olabilir. type parametresi ise bu verinin tipini belirtir ve GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_INT, GL_UNSIGNED_INT, GL_FLOAT veya GL_UNSIGNED_FLOAT olabilir. Son parametre olan texel parametresi bir iaretidir. Bu iareti texture mapping iin kullanacanz resmi iaret eder. Mesela bir RGBA resmi yklediniz ve onu gsteren iareti ise textureData olsun. Bu dizinin boyutu textureWidth ve textureHeight olsun. glTexImage2D() fonksiyonu ise aadaki gibi kullanlabilir.
79
parametre n, ka tane texture ismi yaratlacan bildirmektedir ve bu isimle bir dizinin iine yerletirilecek olan bir textureNames parametresinin gsterdii dizi olacaktr. rnek olarak vermek gerkirse, texture isimlerini saklayacanz bir 3 elemanl diziniz mevcutsa, fonksiyon aadaki gibi kullanlacaktr.
unsigned int textureNames[3]; ... glGenTextures(3, textureNames);
Texture isimlerini yarattktan sonra bu isimlerin texture verilerine verilmesi veya balanmas gerekmektedir. Bunu glBindTexture() fonksiyonu ile gerekletirebilir.
void glBindTexture(GLenum target, GLuint textureName);
Bu fonksiyonu ilk olarak kullandnzda, yeni bir texture nesnesi varsayl deerlere sahip olarak yaratlr. OpenGL bu isim balama ileminden sonra texture nesnesinde-
80
ki varsayl deerleri yeniden tanmlayacaktr. target parametresi bu fonksiyon iin GL_TEXTURE_1D, GL_TEXTURE_2D veya GL_TEXTURE_3D olabilir. Bu isim balama ileminden sonra texture nesnesini o an kullanlabilecek texture durumuna getirmek iin glBindTexture() fonksiyonunu kullann. Mesela birka texture nesnesi yarattnz dnelim ve bu nesnelerin texture verilerini ve texture zelliklerini bu nesnelere baladnz. Ekranda poligonlar izeceiniz zaman, glBindTexture() ile texture belirleyerek, OpenGL e belirlemi olduunuz texture syleyebilirsiniz. Aadaki kod paras, texture zellikleri ayarlandktan sonra, ikinci texture nesnesini current texture olacan, OpenGL e anlatmaktadr.
unsigned int textureNames[3]; ... glGenTextures(3, textureNames); ... glBindTexture(GL_TEXTURE_2D, textureNames[1]); // texture verisi ve zelliklerini ayarla glBindTexture(GL_TEXTURE_2D, textureNames[1]); // nesneyi iz
81
target parametresi kullandnz texture boyutuna baldr ve GL_TEXTURE_1D, GL_TEXTURE_2D veya GL_TEXTURE_3D deerleri alabilir. Magnification filitrelemede pname parametresi GL_TEXTURE_MAG_FILTER deerini ve minification filitrelemede pname parametresi GL_TEXTURE_MIN_FILTER deerini almaktadr. param parametresinin alaca deerler tablo 2-5 te gsterilmektedir. Tablo 2-5 Texture Filitre Deerleri
Filitre
GL_NEAREST
Aklama
Texture edilecek olan pikselin merkezine en yakn olan texel i kullanr. izilecek olan pikselin ne en yakn olan texellerin arlkl ortalamasn kullanr.
GL_LINEAR merkezi-
GL_NEAREST_MIPMAP_NEAREST
GL_NEAREST filitrelemeyi ve poligon znrlne en yakn imaj kullanr. GL_LINEAR filitrelemeyi ve poligon znrlne en yakn imaj kullanr. GL_NEAREST filitrelemeyi ve poligon znrlne en yakn olan iki mipmap ler arasdaki arlkl ortalamay kullanr. GL_LINEAR filitrelemeyi ve poligon znrlne en yakn olan iki mipmap ler arasdaki arlkl ortalamay kullanr.
GL_NEAREST_MIPMAP_LINEAR
GL_LINEAR_MIPMAP_NEAREST
GL_LINEAR_MIPMAP_LINEAR
82
target parametresi GL_TEXTURE_ENV deerine eit olmaldr. pname parametresine ise GL_TEXTURE_ENV_MODE deerini aktararak, frame buffer ndaki renkler ile texture lerin nasl birletirileceini belirleyebilirsiniz. param parametresi iin kullanlacak deerler tablo 2-6 da belirtilmitir. Tablo 2-6
Mod
GL_BLEND GL_DECAL GL_MODULATE
Aklama
Texture rengi piksel rengi ile arplr ve sabit bir renk ile birletirilir. Texture, mevcut olan pikseller ile yer deitirir. Texture rengi piksel rengi ile arplr.
glTexEnvi() ini varsayl deeri GL_MODULATE tir. Aadaki tek satrlk kod texture fonksiyonunu GL_DECAL e ayarlamaktadr.
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
83
Texture koordinatlar, bir nesneye ait olan texture map in her bir texel i nereye konumlanacan belirtmek iin kullanlr. Bir texture koordinat olan ( 0, 0 ) texture un sol alt kesini, ( 1, 1 ) ise sa st kesini belirtir. ki boyutlu texture lerde bu koordinatlar ( s, f ) formundadr.Burada s ve f deerleri 0 dan 1 e doru deiir. Resim 2-16 poligonun her verteksi iin texture koordinatlarn gstermitir. Bu koordinatlar her verteks render edilmeden nce, kendileri ile ilikilendirilmi olan texture koordinatlar belirlenmelidir.
( 0.0, 1.0 )
( 1.0, 1.0 )
( 0.0, 0.0 )
( 1.0, 0.0 )
Resim 2-16 Texture koordinatlarn glTexCoord*() fonksiyonu ile belirlersiniz. Biz konu ierisinde iki boyutlu texture mapping yapacamzdan dolay bu fonksiyonun aadaki iki boyutlu olann kullanacaz.
void glTexCoord2f(GLfloat s, GLfloat t);
84
Texture mapping konusu bu kadar rnek ise Windows platformunda geekletirilmi olan dnen kpn bir benzeri vardr fakat bu rnek GLUT ktphanesi fonksiyonlar kullanlarak yaplmtr. Bu kbn her bir yzeyine bir bitmap dosyasndan yklenmi resim yaptrlmtr. Resim ise satran tahtasna benzeyen bir resim kbn her yzeyi texture kaplama yaplmtr. Kb, farenizin sol tuuna bask tutarak dndrebilirsiniz. Fareyi hareket halinde iken serbest braktnzda kb sabit bir hzda dnmeye devam edecektir. rnek 2-9' u inceleyiniz. rnek 2-9
#include <windows.h> #include <stdlib.h> #include <GL/glut.h> #include "Bitmap.h" #include "HiResTimer.h" #define BITMAP_ID 0x4D42 BITMAPINFOHEADER bitmapInfoHeader; BITMAPIMAGE bitmapData = NULL; unsigned int texture; int last_x, last_y; rotationY = 0.0, timeElapsed = 0.0; GLfloat dx = 0.0, dy = 0.0; HiResTimer timer = NULL;
85
void DrawTextureCube(GLfloat xPos, GLfloat yPos, GLfloat zPos) { glPushMatrix(); glTranslatef(xPos, yPos, zPos); glBegin(GL_QUADS); // top face glTexCoord2f(0.0, 0.0); glVertex3f(-0.5, 0.5, 0.5); glTexCoord2f(1.0, 0.0); glVertex3f(0.5, 0.5, 0.5); glTexCoord2f(1.0, 1.0); glVertex3f(0.5, 0.5, -0.5); glTexCoord2f(0.0, 1.0); glVertex3f(-0.5, 0.5, -0.5); glEnd(); glBegin(GL_QUADS); // front face
glTexCoord2f(0.0, 0.0); glVertex3f(0.5, -0.5, 0.5); glTexCoord2f(1.0, 0.0); glVertex3f(0.5, 0.5, 0.5); glTexCoord2f(1.0, 1.0); glVertex3f(-0.5, 0.5, 0.5); glTexCoord2f(0.0, 1.0); glVertex3f(-0.5, -0.5, 0.5); glEnd(); glBegin(GL_QUADS); // right face
glTexCoord2f(0.0, 0.0); glVertex3f(0.5, 0.5, -0.5); glTexCoord2f(1.0, 0.0); glVertex3f(0.5, 0.5, 0.5); glTexCoord2f(1.0, 1.0); glVertex3f(0.5, -0.5, 0.5);
86
glTexCoord2f(0.0, 0.0); glVertex3f(-0.5, -0.5, 0.5); glTexCoord2f(1.0, 0.0); glVertex3f(-0.5, 0.5, 0.5); glTexCoord2f(1.0, 1.0); glVertex3f(-0.5, 0.5, -0.5); glTexCoord2f(0.0, 1.0); glVertex3f(-0.5, -0.5, -0.5); glEnd(); glBegin(GL_QUADS); // bottom face
glTexCoord2f(0.0, 0.0); glVertex3f(0.5, -0.5, 0.5); glTexCoord2f(1.0, 0.0); glVertex3f(-0.5,-0.5, 0.5); glTexCoord2f(1.0, 1.0); glVertex3f(-0.5, -0.5, -0.5); glTexCoord2f(0.0, 1.0); glVertex3f(0.5, -0.5, -0.5); glEnd(); glBegin(GL_QUADS); // back face
glTexCoord2f(0.0, 0.0); glVertex3f(0.5, 0.5, -0.5); glTexCoord2f(1.0, 0.0); glVertex3f(0.5, -0.5, -0.5); glTexCoord2f(1.0, 1.0); glVertex3f(-0.5, -0.5, -0.5); glTexCoord2f(0.0, 1.0); glVertex3f(-0.5, 0.5, -0.5); glEnd(); glPopMatrix();
87
return; } // end of void DrawTextureCube(GLfloat, GLfloat, GLfloat) void init(void) { glClearColor(0.0, 0.0, 0.0, 0.0); glShadeModel(GL_SMOOTH); glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); glFrontFace(GL_CCW); glEnable(GL_TEXTURE_2D); bitmapData = Bitmap_LoadBitmapFile("Checkerboard_64.bmp", &bitmapInfoHeader); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, bitmapInfoHeader.biWidth, bitmapInfoHeader.biHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, bitmapData); return; } // end of void initialize(void) void reshape(int width, int height) {
88
glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(60.0, (GLfloat)width/(GLfloat)height, 1.0, 20.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); return; } // end of void resize(int, int) void display(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); glEnable(GL_TEXTURE_2D); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glBindTexture(GL_TEXTURE_2D, texture); glTranslatef(0.0, 0.0, -3.0); glRotatef(rotationY, 0.0, 1.0, 0.0); glRotatef(rotationX, 1.0, 0.0, 0.0); DrawTextureCube(0.0, 0.0, 0.0); glDisable(GL_TEXTURE_2D); glPopMatrix(); glFlush(); glutSwapBuffers(); return; } // end of void display(void) void spin(void) { rotationX += dx; rotationY += dy;
89
if (rotationX > 360.0) rotationX -= 360.0; if (rotationY > 360.0) rotationY -= 360.0; glutPostRedisplay(); return; } // end of void spin(void) void mouse(int button, int button_state, int x, int y ) { if ( button == GLUT_LEFT_BUTTON && button_state == GLUT_DOWN ) { glutIdleFunc(NULL); if (last_x == x) dx = 0.0; if (last_y == y) dy = 0.0; last_x = x; last_y = y; } // end of if statement else glutIdleFunc(spin);
void motion(int x, int y ) { timeElapsed = HiResTimer_GetElapsed_Seconds(timer); rotationX += (float) (y - last_y); rotationY += (float) (x - last_x);
90
dx = (float)(y - last_y)/(1000*timeElapsed); dy = (float)(x - last_x)/(1000*timeElapsed); if (rotationX > 360.0) rotationX -= 360.0; if (rotationY > 360.0) rotationY -= 360.0; last_x = x; last_y = y; glutPostRedisplay(); return; } // end of void motion(int, int) void keyboard(unsigned char key, int x, int y) { switch(key) { case 27: case 'q': exit(0); default: break; } // end of switch(key) return; } // end of void keyboard(unsigned char, int, int) int on_exit(void) { free(bitmapData); bitmapData = NULL; free(timer); timer = NULL;
91
return 0; } // end of void on_exit(void) int main(int argc, char** argv) { timer = HiResTimer_Create(); if (!HiResTime_Init(timer)) { MessageBox(NULL, "Timer initialization failed", 0, 0); free(timer); timer = NULL; exit(-1); } // end of if (!HiResTime_Init(timer)) glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB); glutInitWindowSize(500, 500); glutInitWindowPosition(100, 100); glutCreateWindow("Texture Mapping Application"); init(); glutDisplayFunc(display); glutReshapeFunc(reshape); glutKeyboardFunc(keyboard); glutMotionFunc( motion ); glutMouseFunc( mouse ); _onexit(on_exit); glutMainLoop(); return 0; } // end of int main(int, char**)
Resim 2-17, bu kodu altracanz zaman, texture mapping ile kaplanm olan kb gstermektedir.
92
Resim 2-17 Kodu inceledikten sonra, kod ierisinde birka bilinmedik fonksiyon grceksiniz. Bunlardan biri glPixelStorei() fonksiyonudur. Bu fonksiyonu aklamadan nce birka sylenecek ey var. Gelitirmi olduunuz bir projeyi bir makineden dier bir makineye tayorken, projeniz daha yava alr. Bununla ilgili bir ok faktr olmasna ramen, bu faktrlerden ilgineceimiz sadece biri olan hafzadaki alignment' tr. Baz makinelerde veri aktarm daha hzl yaplsn diye, veri 2, 4 veya 8 byte'lk snrlar erevesinde memoride doru bir pozisyonda konumlanr. Bu durumda, glPixelStorei() fonksiyonunu kullanarak, veri pozisyonunu (data alignment) kontrol edebilirsiniz.
void glPixelStorei(GLenum pname, Type param);
Fonksiyonu kullanmak iin, pname parametresi GL_PACK_ALIGNMENT veya GL_UNPACK_ALIGNMENT olabilir. param parametresi 1, 2, 4 veya 8 olabilir. pname parametresini GL_PACK_ALIGNMENT olarak belirlediinizde, OpenGL' e ve-
93
rinin nasl paketleneceini anlatrsnz. GL_UNPACK_ALIGNMENT parametresini kullandmzda, OpenGL' e verinin hafzada nasl paketlenmeyecei anlatlr. lk olarak grdnz dier fonksiyonlar zaman ile ilgili olan fonksiyonlardr. HiResTimer.h balk dosyas bu fonksiyonlarn tanmlamasn yapmaktadr. Zaman ile ilgili fonksiyonlar niin kullandmz ve bu fonksiyonlarn ne ie yaradn anlatalm. Zaman, dnyada bir niteliktir, kendi oyun dnyanzda ise bu zaman kavram bir nem tamaktadr. Zaman dikkatli bir ekilde izleyebilmek iin bir timer kullnrsnz. Bu timer fiziksel hesaplamalara daha ok gereklik kazandrr ve hesaplamalar, izim esnasndaki her izilen ereveden ( frame ) bamsz bir ekilde takipedebilirsiniz. ki tip timer kullanabilirsiniz: Yksek performansa sahip olan bir timer veya Windows' un mesaj olarak gnderdii timer, WM_TIMER. Bu ikisi arasndaki en nemli fark hz ve doruluktur. Biz yksek performansa sahip olan timer' kullancaz nk hza ve dorulua sahiptir. Eer bilgisayarnz bunu desteklemiyorsa, bunun yerine WM_TIMER' kullann. Yksek perfomanstaki timer' kullanabilmek iin makinenizde bir saniyede ka clock atldn belirlemeniz gerekmektedir. Bundan sonra o anki zaman renip, uygulamanzn ne zaman baladn gsteren bir deikenin iine bu zaman saklamanz gerekir. Bu her bir tasla gerekletirmek iin QueryPerformanceFrequency() ve QueryPerformanceCounter() fonksiyonlarn kullanmalsnz.
BOOL QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency); BOOL QueryPerformanceCounter(LARGE_INTEGER *lpPerformanceCount);
QueryPerformanceFrequency() fonksiyonu bir saniyede ka clock atldn gstermektedir. Clock saysn lpFrequency iaretisi aracl ile elde ederiz. Donanmnz bu fonksiyonu desteklemiyorsa, bu iaretinin gsterecei deer sfr olabilir ve fonksiyondan dnen deer sfr' dr. Eer donanmnz bu fonksiyonu destekliyorsa fonksiyondan dnen deer sfrdan farkl olacaktr. QueryPerformanceCounter() ise o anki
94
timer' n current deerini dnderir ve dnen deer lpPerformanceCount iaretisi tarafndan gsterilmektedir. Bu fonksiyonun donanm tarafnda desteklenip desteklenmemesi gibi durumunda fonksiyonun izledii tutum, QueryPerformanceFrequency() fonksiyonunun izledii durumdan farksz olacaktr. Her iki fonksiyon da ayn paramere tiplerini almaktadrlar. Bu parametre tipi 64-bitlik integer olarak ifade edilir ve ismi LARGE_INTEGER' dr.
typedef union _LARGE_INTEGER { struct { DWORD LowPart; LONG HighPart; }; LONGLONG QuadPart; } LARGE_INTEGER;
LowPart alan 32-bitlik low-order parasn ve HighPart ise 32-bitlik high-order parasn belirtmektedir. QuadPart ise 64-bitlik iaretli bir tam sayy gsterir. Dikkat edeceiniz gibi bu veri yaps bir union' dur. rnek 2-10, HiResTimer.h balk dosyasn ve HiResTimer.c ise bu balk dosyasndaki fonksiyonlarn gerekletirimlerini gstermektedir. rnek 2-10
// HiResTimer.h #ifndef _HIRESTIMER_H #define _HIRESTIMER_H #define WIN32_LEAN_MEAN #include <windows.h> struct _HIRESTIMER; typedef struct _HIRESTIMER* HiResTimer;
95
extern HiResTimer HiResTimer_Create(void); extern void HiResTimer_Destroy(HiResTimer*); extern BOOL HiResTime_Init(HiResTimer); extern float HiResTimer_GetElapsed_Seconds(HiResTimer); extern float HiResTimer_GetFPS(HiResTimer, unsigned int); extern float HiresTimer_LockFPS(HiResTimer, unsigned char); #endif // HiResTimer.c #include <windows.h> #include <stdio.h> #include <stdlib.h> #include "HiResTimer.h" struct _HIRESTIMER { LARGE_INTEGER m_StartTime; LARGE_INTEGER m_ticksPerSecond; LARGE_INTEGER s_lastTime_GetElapsed_Seconds ; LARGE_INTEGER s_lastTime_GetFPS; LARGE_INTEGER s_lastTime_LockFPS; }; HiResTimer HiResTimer_Create(void) { HiResTimer _this; _this = (HiResTimer) malloc(sizeof(struct _HIRESTIMER)); if (!_this) { MessageBox(NULL, "\tOut of memory", "Error", 0); return NULL; } // end of if (!_this) return _this; } /* end of HiResTimer HiResTimer_Create(LARGE_INTEGER, LARGE_INTEGER)
96
*/ void HiResTimer_Destroy(HiResTimer *_this) { free(*_this); *_this = NULL; return; } // end of void HiResTimer_Destroy(HiResTimer*) BOOL HiResTime_Init(HiResTimer _this) { if (!QueryPerformanceFrequency( &(_this->m_ticksPerSecond))) return FALSE; else { QueryPerformanceCounter(&(_this->m_StartTime)); _this->s_lastTime_GetElapsed_Seconds = _this->m_StartTime; _this->s_lastTime_GetFPS = _this->m_StartTime; _this->s_lastTime_LockFPS = _this->m_StartTime; return TRUE; } } // end of BOOL HiResTime_Init(HiResTimer) float HiResTimer_GetElapsed_Seconds(HiResTimer _this) { LARGE_INTEGER currentTime; float seconds; QueryPerformanceCounter(¤tTime); seconds = ((float)currentTime.QuadPart (float)_this->s_lastTime_GetElapsed_Seconds.QuadPart) / (float)_this->m_ticksPerSecond.QuadPart; _this->s_lastTime_GetElapsed_Seconds = currentTime; return seconds;
97
} // end of float HiResTimer_GetElapsed_Seconds(HiResTimer) float HiResTimer_GetFPS(HiResTimer _this, unsigned int elapsedFrames) { LARGE_INTEGER currentTime; float fps; QueryPerformanceCounter(¤tTime); fps = (float)elapsedFrames* (float)_this->m_ticksPerSecond.QuadPart / ((float)currentTime.QuadPart (float)_this->s_lastTime_GetFPS.QuadPart); _this->s_lastTime_GetFPS = currentTime; return fps; } /* end of float HiResTimer_GetFPS(HiResTimer, unsigned int) */ float HiresTimer_LockFPS(HiResTimer _this, unsigned char targetFPS) { LARGE_INTEGER currentTime; float fps; if (targetFPS == 0) targetFPS = 1; do { QueryPerformanceCounter(¤tTime); fps = (float) _this->m_ticksPerSecond.QuadPart /
98
((float)(currentTime.QuadPart _this->s_lastTime_LockFPS.QuadPart)); }while(fps > (float)targetFPS); _this->s_lastTime_LockFPS = currentTime; return fps; } /* end of float HiresTimer_LockFPS(HiResTimer, unsigned char) */
HiResTimer_Create() fonksiyonu sizin iin bir timer yaratr ve dndrecei deer HiResTimer olan bir iareti dnderecektir. Bu iareti yaratlan timer' gstermektedir. HiResTimer_Destroy() ise yarattnz timer' yok eder, alaca parametre ise bu yok edilecek olan timer' n iaretisidir. Bu iaretinin gsterdii timer' n ii boaltlp iaretiye NULL deeri atanmaktadr. HiResTime_Init() fonksiyonu timer' ilklemektedir. Bu ilkleme ileminde, bir saniyede atlan clock says ve o anki balang clock deeri bulunur. HiResTimer_GetElapsed_Seconds() fonksiyonu, bize fonksiyonun arlmasndan bu yana nekadar saniyenin getiini dndrmektedir. Dn deeri float tipindedir. HiResTimer_GetFPS(), elapsedFrames parametresi zerinden ortalama nekadar frame' in gsterildiini sylemektedir. HiresTimer_LockFPS() fonksiyonu ise istenilen frame says kadar frame orann kilitleyerek bekletir. Bu istenilen frame says targetFPS parametresi ile fonksiyona aktarlmaktadr.
99