COM337 Bilgisayar Grafiği OpenGL ile Grafik Programlama Dr. Erkan Bostancı
İçerik OpenGL OpenGL bileşenleri ve mimarisi Basit etkileşim ve çizimler Koordinat sistemi Kamera tanımı Ön tanımlı nesneler Kamera hareketi
OpenGL Endüstride kullanılan grafik standardı OpenGL dir. İlk olarak Silicon Graphics şirketi (SGI) tarafından çalıştıkları bilgisayarlarda programlama yapmaları amacıyla geliştirilen Graphics Library (GL) olarak ortaya çıkmıştır. Daha çok ilgi görünce diğer platformlarda da çalışabilecek şekilde port edilmiş ve OpenGL ortaya çıkmıştır. GL Silicon Graphics bilgisayarları içindi. OpenGL çalışılan platformdan bağımsız olarak çalışır.
OpenGL de neler var? 3B geometrik nesneler: çizgiler, poligonlar, polimesh ler, küreler, küpler, yüzeyler ve eğriler 3B modelleme ve gösterim dönüşümleri Render özellikleri: hidden surface removal, ışıklandırma, texture, sis efektleri Görüntü listeleri (Display lists): Bir modeli çizdikten sonra cache de tutarak hızlı çizim yapmayı sağlayan özellik. Hiyerarşik modelleme. Piksel boyutunda görüntülerin işlenmesi: anti-aliasing, vb.
OpenGL bileşenleri ve mimarisi GLUT Uygulama Programı OpenGL Pencere Sistemi (X, Win32) GLU Genelde bu kısımdan OpenGL olarak bahsedilir. OpenGL kütüphanesi: Rendering den sorumlu Fonksiyon isimleri gl ile başlar. GLU (the OpenGL Utility Library) Daha karmaşık işlevleri sağlar Fonksiyon isimleri glu ile başlar. GLUT (the OpenGL Utility Toolkit) Etkileşim ile ilgili işlevleri sağlar. Fonksiyon isimleri glut ile başlar. İşletim sistemi
İlk OpenGL programımız #include <stdlib.h> #include <glut.h> void display (void) { glclear(gl_color_buffer_bit); } int main (int argc, char *argv[]) { glutinit (&argc, argv); glutcreatewindow ( Hello, OpenGL! ); glutdisplayfunc (display); glutmainloop (); return EXIT_SUCCESS; }
İlk OpenGL programımız Bir önceki sunuda gösterilen program basit bir pencere oluşturur ve temizler. İlk olarak glut.h kütüphanesini ekliyoruz. Bu kütüphanenin içinde OpenGL ve GLU zaten çağrılmaktadır. glutinit, GLUT ı başlatır ve çağrılması gereken ilk GLUT fonksiyonudur. Bazı komut satırı parametrelerini işleyebilir. glutcreatewindow bir OpenGL penceresi oluşturur. Pencere adnı parametre olarak alır ve default olarak pencere boyutları 300x300 pikseldir. Son olarak glutmainloop sürekli olarak çalışacak olan OpenGL döngüsüne girer ve hiç çıkmaz.
Olay-tabanlı mimari (1/3) Etkileşim özellikleri sunan neredeyse her toolkit benzer şekilde çalışır: Programcı belirli fonksiyonları belirler ve bunu toolkit e bildirir ve program toolkit in ana döngüsüne girer. OpenGL (ya da GLUT) ta gördüğümüz gibi program sürekli olarak çalışacak olan glutmainloop fonksiyonunu çağırır. Bu sayede kullanıcı etkileşiminin sürekli bir biçimde cevap vermesi sağlanır. Herhangi bir olay (event) olduğunda gerekli fonksiyon (callback olarak adlandırılır) çağrılarak olayın handle edilmesi sağlanır. Bu tür bir mimariye alışmak biraz zaman alabilir!
Olay-tabanlı mimari (2/3) glutmainloop aşağıdaki gibi bir döngü yapısı olarak düşünülebilir: while True: if Grafikler değişti then display fonksiyonunu çağır. if Pencere hareket etti veya boyutu değişti then reshape fonksiyonunu çağır. if Klavye veya fare olayı oluştu then klavye vaya fare fonksiyonunu çağır.
Olay-tabanlı mimari (3/3) glutdisplayfunc ile OpenGL in çizim yapması gerektiğinde çağıracağı fonksiyon kaydedilir. display: tanımlanması zorunlu bir fonksiyondur, parametre almaz ve dönüş değeri yoktur. İlk örneğimizde display fonksiyonumuz yalnızca glclear ı çağırarak ekranı temizler. Temizleme işlemi ile birden fazla buffer temizlenebilir. Bunlar aralarında OR işlemi kullanılarak belirlenebilir: (GL_COLOR_BUFFER_BIT GL_DEPTH_BUFFER_BIT) Burada OpenGL e frame buffer ını temizlemesini söylüyoruz. Bu buffer daki her pikselin değeri default renk olan siyah olarak atanıyor.
Basit etkileşim ve çizim (1/3) Örnek 2 glutinitwindowposition ve glutinitwindowsize pencere konumunu ve boyutlarını belirler. glutkeyboardfunc ile klavye olaylarını handle edecek fonksiyon kaydedilir. Örnekte kullanıcı ESC tuşuna bastığında programdan çıkılması sağlanıyor. Bu kullanımı OpenGL programları için bir gelenek olarak düşünebilirsiniz.
Basit etkileşim ve çizim (2/3) Örnek 3 display fonksiyonu 4 beyaz çizgiden oluşan bir dikdörtgen çiziyor. glcolor3f çizim yapılırken kullanılacak rengi beyaz olarak belirlememizi sağlıyor. Fonksiyon adındaki 3f fonksiyonun 3 tane floating point parametre aldığını gösterir. Bu kullanımı diğer OpenGL fonksiyonlarında da görebilirsiniz. OpenGL sağ-el koordinat sistemini kullanır: x pencerede yatay olarak uzanır. y pencerede dikey olarak uzanır. z ekranda bize doğru uzanır.
Basit etkileşim ve çizim (3/3) Dikdörtgen 4 adet köşe noktası ile tanımlanır. Yine bunlar floating point olarak tanımlanmıştır. Aynı fonksiyonların tamsayı (integer) parametre alanları da vardır. glvertex3f fonksiyon çağrısında, z=0 olduğundan glvertex2f(0.25, 0.75) olarak da kullanabilirdik.
Diğer geometrik temel şekiller (1/4) GL_POINTS Bağımsız noktalar oluşturur. GL_LINES Art arda gelen noktalar arasında çizgiler oluşturur.
Diğer geometrik temel şekiller (2/4) GL_LINE_STRIP Bütün noktalardan geçen bir çizgi oluşturur. GL_LINE_LOOP GL_LINE_STRIP gibi çalışırır fakat ilk ve son noktaları birleştirir. GL_TRIANGLES Üçlü nokta gruplarını bir üçgen gibi ele alır.
Diğer geometrik temel şekiller (3/4) GL_TRIANGLE_STRIP Üçgenlerden oluşan bağlı bir şerit çizer. GL_TRIANGLE_FAN Yine üçgenlerde oluşan fakat fan gibi açılan bir şekil çizer. GL_QUADS Dörtlü nokta gruplarını 4 kenarlı bir çokgen olarak çizer. Noktalar düzlemsel olmalıdır.
Diğer geometrik temel şekiller (4/4) GL_QUAD_STRIP Dörtgenlerden oluşan bağlı bir şerit oluşturur. GL_POLYGON Tüm noktaları kullanarak konveks bir çokgen oluşturur.
Koordinat sistemleri OpenGL de çizim yapılan dikdörtgen şeklindeki pencerenin adı viewport tur. OpenGL de bir pencere oluşturduğunda bu pencere viewport ile doldurulur. Viewport un sol alt köşesi pencere koordinatları ile verilir. Bunun yanında viewport un yüksekliği ve genişliği belirtilir. glviewport(x,y,width,height) Bu sayede aynı pencere içinde birden fazla viewport oluşturabilirsiniz. (3B çizim araçlarındaki gibi). Eğer kameranın aspect (width/height) oranı viewport ile uyumlu değilse, görüntü bozulmuş bir şekilde oluşur. Bu nedenden dolayı, viewport reshape fonksiyonu içinde ayarlanır. Bu daha sonra açıklanacak.
Dünya koordinatları 3B de koordinat sistemleri sağ-el ve sol-el olarak adlandırılır. Çoğu grafik paketi sağ-el koordinat sistemini kullanır. Viewport taki koordinat sistemi (penceredeki pikseller) ile dünya koordinat sisteminin karıştırılmaması gerekir.
Kamerayı ayarlamak OpenGL de kamera konumunu ve yönelimini ayarlamanın en kolay yolu glulookat fonksiyonunu kullanmaktır: glulookat (camx, camy, camz, px, py, pz, upx, upy, upz); Bu çağrı ile kameranın konumu (camx, camy, camz), baktığı yön (px, py, pz) yukarı vektörü (upx, upy, upz) olarak belirlenir. Bu ayarlama yapılmamışsa, default olarak aşağıdaki ayarlar uygulanır: glulookat (0.0, 0.0, 0.0, // kamera konumu 0.0, 0.0, -1.0, // baktığımız yön 0.0 1.0 0.0) // yukarı yönü
Ön tanımlı nesneler (1/2) Örnek 4 Dikdörtgenlerin oldukça yaygın bir şekilde kullanılmasından dolayı bunları çizen hazır fonksiyonlar vardır. void glrectf (GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2) z=0 düzleminde bulunan ve kenarları x ve y eksenlerine paralel olan bir dikdörtgen çizilir. Telkafes (wireframe) veya dolu bir küp çizmek için de: void glutwirecube (GLdouble size) void glutsolidcube (GLdouble size) size boyutunda ve merkezi orjinde olan bir küp çizer.
Ön tanımlı nesneler (2/2) Yine merkezi orjinde olan bir telkafes veya katı bir küre çizmek için: void glutwiresphere (GLdouble radius, GLint slices, GLint stacks) void glutsolidsphere (GLdouble radius, GLint slices, GLint stacks) Koni, torus, tetrahedron (üçgen prizma), oktahedron (sırtsırta iki üçgen prizma) gibi şekiller için de hazır fonksiyonlar GLUT kütüphanesinde vardır. Bilgisayar grafiğinde klasik olarak kullanılan çaydanlık için de hazır fonksiyonlar vardır: void glutwireteapot (GLdouble scale) void glutsolidteapot (GLdouble scale)
Bir nesneye etrafından bakmak Örnek 5 glulookat fonksiyonunu kullanarak bakış noktamızı (viewpoint) bir nesnenin etrafında hareket ettirebiliriz. Bunu yapmak için biraz geometri gerekecek: x = r cosθ z = r sinθ Her frame için Θ değiştikçe, nesneye baktığımız bakış açısı da değişecek. Θ yı sürekli değiştirme işini idle callback i içinde yapıyoruz.
Double-buffering Bir önceki sunuda bahsettiğimiz örnekte double-buffering olarak bilinen bir yöntem kullanılmıştır. Kova örneği. İki buffer kullanılır: Ekranda görünen ve görünmeyen. Çizimler ekranda gösterilmeyen buffer da yapılır ve ekran her yenilendiği zaman, bu bufferdakiler ekranda gösterilen buffer a aktarılır (swapping). Bunu yapmak için display modumuzu bu şekilde çalışması için ayarlıyoruz: glutinitdisplaymode Sonrasında ise glutpostredisplay i çağırarak buffer-swapping işlemini gerçekleştiriyoruz. Neden double-buffering kullanıyoruz? Kullanmazsak güncellemeler düzgün ve yumuşak geçişli olmaz ve ekrandaki modelde flickering oluşur (titreyen bir görüntü).