| Doğru
Parçalarını ÇizimiDaha ö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]](../../common/March1998/ogl-thumb.gif)  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ü GiderimiBurada 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. |