Home Index Search Links About Us
[LinuxFocus Image]
[Navegation Bar]
  Duyumlar   Belgelikler   Kuruluþlar  Öðütler  

OpenGL Programlama: Doðru Parçalarý Üzerine Ekbilgiler

Yazar: Miguel Miguel Angel Sepúlveda

Çeviri:Filiz Topal


../../common/March1998/example2.c

../../common/March1998/Makefile

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:

[Click here to see the image]
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.


Daha Çok Bilgi Ýçin:
© 1998 Miguel Angel Sepulveda
Bu sanal yörenin bakýmý Miguel A Sepulveda tarafýndan yapýlmaktadýr..