Doðru
Parçalarýný Çizimi
Daha önce OpenGL altýnda basit bazý poligonlarýn çizimini görmüþtük.
OpenGL sadece birkaç basit geometrik þeklin çizimini destekliyor: nokta,
doðru, poligon ve küçük dörtgensel veya üçgensel yaylarla tanýmlanmýþ
yüzeyler gibi.
OpenGL'in basitliðinin ardýndaki ana fikir bu basit nesnelerden,
karýþýk nesnelere doðru geliþtirimin geliþtiriciye býrakýlmýþ
olmasýdýr. OpenGL noktalarýn, doðrularýn ve poligonlarýn
detaylarýný kontrol etmek için komutlar içerir.
Örnek olarak noktanýn büyüklüðü piksel olarak glPointSize
ile aþaðýdaki kullaným þekliyle belirlenir:
void glPointSize(GLfloat size)
Noktanýn benimsenmiþ deðer olarak büyüklüðü 1 dir ve size
daima 0'dan büyük olmalýdýr. Özet olarak noktanýn büyüklüðü ondalýklý
sayýlarla ifade edilir. Nokta ve doðru büyüklüklerinde oransal (fractional)
deðerlere izin verilir. OpenGL oransal piksel büyüklükleri görüntüleþtirim
içeriðine (rendering context) göre yorumlar. Eðer basamak görüntü giderici
(anti-aliasing) mod etkinse, OpenGL komþu pikselleri ilgilenilen doðruya
uyacak þekilde düzeltir ve oransal geniþlik görünümünü vermeye çalýþýr.
Basamak görüntü giderimi (anti-aliasing), doðrularýn düþük ekran
çözünürlüðünde gösterdiði çirkin yýldýzlarý ortadan kaldýrmak için
geliþtirilen bir tekniktir. Eðer bu yöntem uygulanamýyorsa
glPointSize size'ý en yakýn tamsayýya yuvarlatacaktýr.
Fiziksel olarak bir pikselin büyüklüðü aygýta baðlý bir þeydir. Örnek
olarak düþük ekran çözünürlüðünde piksel daha geniþ olarak çözülür. Benzer
biçimde, çizici gibi çok yüksek çözünürlükte de, benimsenmiþ olan 1
piksellik çizgi hemen hemen görünmez hale gelir. Çizgilerinizin gerçek
geniþliðini kestirmek istiyorsanýz pikselin çýktý aygýtýnýzdaki gerçek
fiziksel ölçü deðerini bilmeniz gerekmektedir.
Çizgilerin geniþliði glLineWidth fonksiyonu ile belirlenir,
bu komutun glBegin() - glEnd() çifti arasýnda daha önceden
çaðrýlmýþ olmasý gerekir. Komutun tam sözdizimi aþaðýdadýr.
void glLineWidth(GLfloat width)
OpenGL'de basamak görüntü giderimsiz (nonantialiased) çizgilerin geniþliði
basamak görüntü giderimli (antialiased) çizgilerin geniþliðinin en yakýn
tamsayýya yuvarlanmýþ en büyük deðeriyle sýnýrlanmýþtýr. Þunu aklýnýzda tutun:
çizgi geniþlikleri çizgiye dik olarak ölçülmezler; eðimin mutlak deðerinin
1 den, küçük olmasý durumunda y doðrultusunda, büyük olmasý durumunda x
doðrultusunda ölçülürler.
Bu ay diðer bir basit fakat yararlý 2D animasyonlarý hazýrlamýþ
bulunuyoruz. Bunlar size çeþitli tür çizgi kalýnlýklarýnýn OpenGL'de
nasýl kullanýlacaðýný gösterecektir.(../../common/March1998/example2.c,
../../common/March1998/Makefile). Kuvantum fiziðinden bir örnek, bir kuyu
potansiyel içinde tutulu kalmýþ bir kuvantum parçacýk seçtim. Niye? Hýmmm,
gerçekte unuttum. Her neyse, bunun fizik ve mühendislik öðrencilerine
zamana baðýmlý Schroedinger denkleminin nasýl çözülebileceðini görmekte
yardýmcý olacaðýný düþündüm. Diðer bireyler kuvantum mekaniðinin önceden
kestirilemez doðasýný gözleyerek eðlenebilirler. Kuvantum Mekaniði'nde
bir parçacýk, pozisyonu ve hýzý ile deðil bir "dalga" ile, mutlak deðer
karesi, parçacýðýn verilen bir konumda (parçalý beyaz doðru) bulunma
olasýlýðýný veren dalga ya da dalga fonksiyonu (bizim animasyonumuzda mor
kalýn çizgi olan) ile temsil edilir:
Figure 1. Quantum Simulation Snapshot
Sýradan diferansiyel denklemler hakkýnda bazý kurs çalýþmalarýnda
bulunanlara söylediðim gibi dalga denklemi FFT (Hýzlý Fourier Dönüþümü)
ayrýk operatör (split operator) yöntemi ile integre edilir. Bu metod
diðer sonlu farklar metodlarýndan daha hýzlý ve doðrudur. Bu yöntem
doðrusal olmayan dalga yayýlýmýnda da kullanýlabilir. Zamansal evrim
operatörü ikinci ya da daha yüksek mertebeden olan ve sadece ya konuma
ya da momentuma baðlý operatörlere ayrýþtýrýlýr. Daha sonra dalga
fonksiyonunun evrimi, bu operatörlerin ardýþýk olarak uygulanmalarý ve
bunun için de konum ve momentum uzaylarý arasýnda gidiþ geliþlerle
saðlanýr.
Kaynak kodu diðer birçok uygulama için kullanýlabilir. Benim kuvantum
simulasyonumu kendi zamana baðýmlý fonksiyonunuzla deðiþtokuþ edebilir
ve sisteminizin güzel animasyonlarýný elde edebilirsiniz. Kendiniz de,
fonksiyon ve veri dosyalarýnýn grafiklerinin çizimi için basitleþtirilmiþ
bir OpenGL tabanlý gnuplot yazmayý deneyebilirsiniz.
Eðer okuyucu daha önceki makaleleri takip ettiyse Glut ve OpenGL
üzerindeki kaynak kodlarýný çok basit görüp kolay anlayacaktýr.
(Tabii ki kuvantum mekaniði bir kenarda tutularak). Burada olaðanüstü
giden birþey bulunmamaktadýr. main()'de çift emicibellekli
(buffer) bir modda pencere açtýk. Daha sonra, sýrasýyla, dalga
fonksiyonunun grafiðinin çizimini ve denkleminin çözümünden elde
edilmesini saðlayan display() ve idle() geriçaðýrým
(callback) fonksiyonlarýna geçtik. Her ne kadar bu yazýnýn içeriðini
kavramak için çok güzel bir aldatmaca olan idle() fonksiyonunda ne olduðunu
bilmek ille de gerekmiyorsa da siz yine de önemseyin.
void
display (void)
{
static char label[100];
float xtmp;
/* Clean drawing board */
glClear (GL_COLOR_BUFFER_BIT);
/* Write Footnote */
glColor3f (0.0F, 1.0F, 1.0F);
sprintf (label, "(c)Miguel Angel Sepulveda 1998");
glRasterPos2f (-1.1, -1.1);
drawString (label);
/* Draw fine grid */
glLineWidth (0.5);
glColor3f (0.5F, 0.5F, 0.5F);
glBegin (GL_LINES);
for (xtmp = -1.0F; xtmp < 1.0F; xtmp += 0.05)
{
glVertex2f (xtmp, -1.0);
glVertex2f (xtmp, 1.0);
glVertex2f (-1.0, xtmp);
glVertex2f (1.0, xtmp);
};
glEnd ();
/* Draw Outsite box */
glColor3f (0.1F, 0.80F, 0.1F);
glLineWidth (3);
glBegin (GL_LINE_LOOP);
glVertex2f (-1.0F, -1.0F);
glVertex2f (1.0F, -1.0F);
glVertex2f (1.0F, 1.0F);
glVertex2f (-1.0F, 1.0F);
glEnd ();
/* Draw Grid */
glLineWidth (1);
glColor3f (1.0F, 1.0F, 1.0F);
glBegin (GL_LINES);
for (xtmp = -0.5; xtmp < 1.0; xtmp += 0.50)
{
glVertex2f (xtmp, -1.0);
glVertex2f (xtmp, 1.0);
glVertex2f (-1.0, xtmp);
glVertex2f (1.0, xtmp);
};
glEnd ();
/* Draw Coordinate Axis */
glLineWidth (2);
glBegin (GL_LINES);
glVertex2f (-1.0, 0.0);
glVertex2f (1.0, 0.0);
glVertex2f (0.0, -1.0);
glVertex2f (0.0, 1.0);
glEnd ();
/* Axis Labels */
glColor3f (1.0F, 1.0F, 1.0F);
sprintf (label, "Position");
glRasterPos2f (0.80F, 0.025F);
drawString (label);
glColor3f (1.0F, 0.0F, 1.0F);
sprintf (label, " Quantum Probability ");
glRasterPos2f (0.025F, 0.90F);
drawString (label);
glColor3f (1.0F, 1.0F, 1.0F);
sprintf (label, " Real(Psi) ");
glRasterPos2f (0.025F, 0.85F);
drawString (label);
/* Draw Wavefunction */
psiDraw (NR_POINTS, psi, x);
/* Draw potential Function */
potentialDraw (NR_POINTS, potential, x);
glutSwapBuffers ();
};
Ýlk olarak renk emicibellek biti (color buffer bit) temizleniyor.
Bu bize temiz (siyah) bir çizim düzlemi oluþturuyor. glRasterPos ve
glutBitmapCharacter (çizimkatarý renk bakýpseçme [clut=color look
up table] ) olanaðý için bir sarmalayýcýdan [wrapper] baþka birþey deðil)
kullanýlarak dipnot ekleniyor. Gelecek derslerde glRasterPos
dokularýn görüntüleþtiriminde yine yardýmcý fonksiyon olarak gözükecektir.
Ne OpenGL ne de GLUT grafik penceresi üzerinde metin görüntüleþtiriminde
kolay ve güçlü bir yol saðlayabilmektedir. glutBitmapCharacter, temelde,
bir font ikilitabangösterilimini (bitmap) renk emicibelleði üzerine
düþürür.
Dipnotu bir takým ãizgiler izler: dýþ kutu, arka plan çizgisi,
koordinat eksenleri ve tabii ki psiDraw ve potentialDraw
ile oluþturulan eðriler. Her çizgi görüntüleþtirilmeden önce
glLineWidth komutu doðrunun kalýnlýðýný piksel sayýlarý ile
belirtir. 1. þekil bir Xwindow sistemindeki (Linux Alpha) çýktýyý
göstermektedir. Bazý bilinmeyen nedenlerden dolayý bana göre windows95
çýktýsý anlamsýy bir yapýda gibi gözüküyor, sanki antialiasing özelliði
SGI OpenGL sürücüsü tarafýndan desteklenmiyor görünümü veriyor; farklý
geniþlikteki doðrularý ayýrdedilebilir biçimde görüntülemek mümkün olamýyor,
arka plan kare örgü (grid) çok fazla düzgün gözüküyor. Bu bozukluklar
düþük çözünürlüklerde olma yerine yüksek çözünürlüklerde oluþuyor.
Linux X pencere sisteminin büyük win95/NT sistemini bir kez daha yenilgiye
uðratmasýndan dolayý mutluyum.
display() fonksiyonunda iki tür doðru görüntüleþtirimi
bulunmaktadýr. Düðüm noktalarýný sürekli bir açýk doðru ile birleþtiren
GL_LINES modu ve sonunda çevrimi kapatan GL_LINE_LOOP modu.
Doðru
Parçalarýnda Basamak Görüntü Giderimi
Burada reshape() geriçaðýrým fonksiyonunda doðrular
için basamak görüntü giderimini etkinleþtirmiþ bulunmaktayým.
void
reshape (int w, int h)
{
glMatrixMode (GL_MODELVIEW);
glLoadIdentity ();
glViewport (0, 0, w, h);
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
gluOrtho2D (-1.2, 1.2, -1.2, 1.2);
glEnable (GL_LINE_SMOOTH); /* Enable Antialiased lines */
glEnable (GL_LINE_STIPPLE);
};
GL_LINE_STIPPLE ne için kullanýlýyor? OpenGL bize sadece çizgi
geniþliðini deðil ayný zamanda örüntüyü de (pattern) kontrol etmeyi saðlýyor.
GL_LINE_STIPPLE etkinleþtirilmesi bize tirelerle veya diðer örüntülerle
doðrular çizmemizi saðlar. Animasyondaki tek kesikli çizgi (stippled line)
psiDraw() fonksiyonunun çiziminde gözükmektedir.
glLineWidth (1);
glPushAttrib (GL_LINE_BIT);
glLineStipple (3, 0xAAAA);
glBegin (GL_LINE_STRIP);
for (i = 0; i < nx; i++)
{
xs = ratio1 * (x[i] - XMIN) - 1.0;
ys = ratio2 * (psi[2 * i] - YMIN) - 1.0;
glVertex2d (xs, ys);
};
glEnd ();
glPopAttrib ();
Çizgi
Kesiklileþtirimi
glLineStipple kesikli çizgi çiziminde kullanýlacak
örüntüyü belirler. Bizim örneðimizde kullanýlan örüntü 0xAAAA dýr. 2'li
düzende bu mod 0000100010001000 þeklindedir. OpenGL bu çizimi 3 bit boþ,
1 bit dolu, 3 bit boþ, 1 bit dolu, 3 bit boþ, 1 bit dolu ve son olarak
4 bit boþ biçiminde yorumlar. Evet, örüntü geriye doðru okunur, çünkü
ilk önce düþük mertebeden bit'ler okunur. Þimdi glLineStipple
iki parametre çaðýracaktýr, onaltýlýk düzende bir sayý olmasý gereken
kesikli örüntü ve bu örüntüyü ölçeklemek için bir tamsayý çarpan.
Dolayýsýyla, bir 3 çarpanýyla, bizim kesikli doðrumuz 9 bit boþ,
3 bit dolu, 9 bit boþ, 3 bit dolu, 9 bit boþ, 3 bit dolu ve son
olarak da 12 bit boþ biÇiminde bir görüntü verecektir. Bu çarpanla ve
ikilitaban örüntülerle oynayarak karmaþýk yapýdaki olasý tüm doðrularý
çizmek mümkündür.
Bir ayrýntý daha: Burada kesikli çizgi görüntüleþtirimini push ve pop
deyimleri arasýna aldým. Birinci yazýmýzda OpenGL'in bir durum makinasý
olduðunu belirttiðimizi anýmsayýn. Gelecek yazýlarýmýzda bu push ve pop
iþlemleri üzerinde daha ayrýntýlý duracaðýz, ama kýsaca yaptýðýmýz þeyin
ilk olarak glPushAttrib (GL_LINE_BIT) komutuyla GL_LINE_BIT
durum deðiþkeninin (bu deðiþken kesiklileme örüntüsünü tanýmlar ya da
seçer) o andaki deðerini bir yýðýt (stack) içine yerleþtirmek, daha sonra da
GL_LINE_BIT deðerini glLineStipple komutuyla deðiþtirmek ve
iþimizi bitirdiðimizde GL_LINE_BIT'in ilk deðerini geri getiren
glPopAttrib fonksiyonunu çaðýrmak olduðunu söyleyebiliriz.
Bu düzenek (mechanism) OpenGL durum deðiþkenlerinin deðerlerinin
yerel olarak deðiþtirilmesinin etkin bir yoludur. Eðer bunu yapmamýþ
olsaydýk, glLineStipple komutundan sonra çizilen tüm
öizgiler ayný kesiklileme örüntüsüne sahip olacak ve kendi uygulamamýzdaki
her görüntüleþtirimi yapýlan çizgi için bir glLineStipple komutu
kullanmak zorunda kalacaktýk. Push ve Pop bizi bu can sýkýcý duruma
düþmekten korur.
Ýlerki Zamanda....
OpenGL, 3 Boyutlu API arayüzü nedeniyle çok ünlüdür. Buradaki
kadarýyla, biz OpenGL ile 2 Boyutlu bazý temel görüntüleþtirim olanaklarýný
incelemiþ bulunuyoruz. Gelecek kez, 3 Boyutlu OpenGL görünümünü, bir
perspektifin nasýl yaratýlacaðýný, koordinat sistemlerini, kesmeyle alma
düzlemlerini (clipping plane) ve izdüþüm matrislerini inceleyeceðiz.
O güne dek OGL......ile iyi eðlenceler.
|