| Bu yazımızda üç 
  boyutlu çizimler üzerinde döndürme, öteleme, yakınlaşma ve uzaklaşma işlemlerinin 
  nasıl yapılacağını ele alacağız. OpenGL ve C başlığı altında yürüttüğümüz yazı 
  dizisinde, bir OpenGL penceresinin nasıl oluşturulduğunu, iki boyutlu ve üç 
  boyutlu çizimlerin nasıl yapıldığını ele almıştık ve OpenGLin bu işlemleri 
  yapan fonksiyonlarını incelemiştik. OpenGL kütüphanesi x, y ve z eksenleri etrafında 
  döndürme, x, y ve z eksenleri boyunca öteleme işlemlerini yapan fonksiyonlar 
  da içermektedir. Daha önce yaptığımız uygulamalarda kısmen kullandığımız bu 
  fonksiyonları bu yazımızda ayrıntılarıyla ele alacağız. 
 
 
  Bu yazımızda, kullanıcının 
  klavyeden gireceği karakterlere göre çizimi belli bir eksen etrafında döndüren, 
  belli eksenler boyunca öteleyen bir uygulama oluşturacağız. Uygulama çalıştırıldığında 
  başlangıçta hiçbir işlem yapılmayacak. Kullanıcı klavyeden belli karakterleri 
  girdiğinde, uygulama girilen bu karakterlere göre işlem yapacaktır. Uygulamanın 
  içeriğini özetleyecek olursak : 
    | void 
        glTranslated(GLdouble x, GLdouble y, GLdouble z); void glTranslatef(GLfloat x, GLfloat y, GLfloat z);
 
 
 | Geçerli 
      görüntü matrisini, parametre olarak verilen öteleme matrisi ile çarparak 
      görüntü matrisini değiştirir. Başka bir deyişle görüntüyü x, y ve z eksenleri 
      boyunca öteler. Fonksiyonların x, y ve z parametreleri öteleme matrisinin 
      değerleridir. glBegin ve glEnd fonksiyonları arasında çağrılırsa GL_INVALID_OPERATION 
      hata kodunu üretir. |   
    | void 
      glRotated(GLdouble angle, GLdouble x, GLdouble y, GLdouble z); void glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z);
 | Geçerli 
      görüntü matrisini, parametre olarak verilen dönüşüm matrisi ile çarparak 
      görüntü matrisini değiştirir. Başka bir deyişle görüntüyü x, y ve z eksenleri 
      etrafında saat yönünde döndürür. Fonksiyonların x, y ve z parametreleri 
      dönüşüm matrisinin değerleridir, angle parametresi ise belirtilen eksen 
      etrafındaki döndürme açısının derece cinsinden değeridir. glBegin ve glEnd 
      fonksiyonları arasında çağrılırsa GL_INVALID_OPERATION hata kodunu üretir. |      - x , y ve z eksenleri boyunca öteleme işlemleri
     - x , y ve z eksenleri etrafında döndürme işlemleri
 
 Daha önce yaptığımız 
  uygulamalarda bir OpenGL çizim penceresi oluşturmuştuk. Bu pencere üzerinde 
  iki ve üç boyutlu çizimler yapmıştık. Bu uygulamamızda yine aynı pencereyi kullanacağız 
  ve üç boyutlu çizim yapacağız. Döndürme ve öteleme işlemlerinde kullanmak üzere 
  global alanda aşağıdaki değişkenleri tanımlayalım :
 
 
 
  Bu değişkenleri 
  ne amaçla kullanacağımıza kısaca değinelim. Uygulamamızda bir küp oluşturacağız. 
  OpenGL kütüphanesi bu kübü, sadece kenar çizgileri ile gösterebilmemize ya da 
  yüzeylerini boyayarak gösterebilmemize izin verir. filled isimli değişkeni de 
  bu durumu belirlemek için kullanacağız. Uygulamanın çalışma zamanında, kullanıcı 
  klavyeden f (fill) tuşuna basarak bu seçeneği değiştirebilecek. Kullanıcı 
  klavyeden t (turn) tuşuna bastığında şekil döndürülecek, tekrar t tuşuna 
  bastığında ise şekil o anki açısıyla sabit biçimde gösterilecek. rotateAngle 
  isimli değişken, şeklin döndürülme açısını belirleyecek. xRotate, yRotate ve 
  zRotate değişkenleri ise şeklin hangi eksenler etrafında döndürüleceğini belirleyecek. 
  Döndürme işlemini başlatmak veya durdurmak için kullanıcı klavyeden t (turn) 
  tuşuna basacak. Döndürme eksenlerini ayarlamak için ise eksen isimlerini ifade 
  eden x, y ve z tuşlarına basacak. xTranslate, yTranslate ve zTranslate 
  değişkenleri, x, y ve z eksenleri boyunca yapılacak öteleme miktarını belirleyecek. 
  Kullanıcı klavyeden l (left), r (right), u (up) ve d (down) tuşlarına 
  bastıkça bu değişkenlerin değerlerini değiştireceğiz. Dolayısıyla öteleme matrisinin 
  değerlerini değiştirmiş olacağız. 
    | BOOL filled 
      = FALSE; BOOL rotate = FALSE;
 GLfloat rotateAngle = 0.0f;
 GLfloat xRotate = 0.0f, yRotate = 0.0f, zRotate = 0.0f;
 GLfloat xTranslate = 0.0f, yTranslate = 0.0f, zTranslate = -7.0f;
 |  
 Uygulamamızda çizim 
  işlemlerini yaptığımız fonksiyon DrawGLScene isimli fonksiyon idi. Uygulamanın 
  çalışma zamanında herhangi bir mesaj alınmadığı sürece bu fonksiyon çağrılır 
  ve ekrana çizim işlemi yapılır. DrawGLScreen fonksiyonunun hemen ardından SwapBuffers 
  isimli fonksiyon çağılır ve görüntü tamponundaki değişiklikler ekrana yansıtılır. 
  Bu uygulamada DrawGLScreen isimli fonksiyonun içeriğini değiştireceğiz. Ekrana 
  önce yapılacak değişikliklerin daha iyi anlaşılması için x, y ve z eksenlerini 
  belirten bir koordinat sistemi çizdireceğiz, ardından bir küp çizdireceğiz. 
  Şimi DrawGLScreen fonksiyonumuzu inceleyelim :
 
 
 
  Fonksiyonda glClear 
  fonksiyonu ile görüntü tamponunu temizledikten sonra, koordinat sistemini çizen 
  DrawCoordiateSystem isimli fonksiyonu çağırıyoruz. Bu fonksiyonun içeriği de 
  şöyledir : 
    | int DrawGLScene(GLvoid) {
     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
     glLoadIdentity();  
           DrawCoordiateSystem();
 
     glLineWidth(1.0f);
     glTranslatef(xTranslate,yTranslate,zTranslate);
     glRotatef(rotateAngle,xRotate,yRotate,zRotate);
 
     if (filled)
        glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
     else
        glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
 
     glBegin(GL_QUADS);
     glColor3f(0.0f,0.5f,0.1f);
     glVertex3f(1.0f,1.0f,-1.0f);
     glVertex3f(-1.0f,1.0f,-1.0f);
     glVertex3f(-1.0f,1.0f,1.0f);
     glVertex3f(1.0f,1.0f,1.0f);
 
     glColor3f(0.0f,0.4f,0.0f);
     glVertex3f(1.0f,-1.0f,1.0f);
     glVertex3f(-1.0f,-1.0f,1.0f);
     glVertex3f(-1.0f,-1.0f,-1.0f);
     glVertex3f(1.0f,-1.0f,-1.0f);
 
     glColor3f(0.0f,0.2f,0.7f);
     glVertex3f(1.0f,1.0f,1.0f);
     glVertex3f(-1.0f,1.0f,1.0f);
     glVertex3f(-1.0f,-1.0f,1.0f);
     glVertex3f(1.0f,-1.0f,1.0f);
 
     glColor3f(0.0f,0.0f,0.5f);
     glVertex3f(1.0f,-1.0f,-1.0f);
     glVertex3f(-1.0f,-1.0f,-1.0f);
     glVertex3f(-1.0f,1.0f,-1.0f);
     glVertex3f(1.0f,1.0f,-1.0f);
 
     glColor3f(0.8f,0.1f,0.2f);
     glVertex3f(-1.0f,1.0f,1.0f);
     glVertex3f(-1.0f,1.0f,-1.0f);
     glVertex3f(-1.0f,-1.0f,-1.0f);
     glVertex3f(-1.0f,-1.0f,1.0f);
 
     glColor3f(0.0f,0.8f,0.0f);
     glVertex3f(1.0f,1.0f,-1.0f);
     glVertex3f(1.0f,1.0f,1.0f);
     glVertex3f(1.0f,-1.0f,1.0f);
     glVertex3f(1.0f,-1.0f,-1.0f);
 
     glEnd();
 
     if (rotate 
        == TRUE)
        rotateAngle += 0.25f;
 
     return TRUE;
 }
 
 
 |  
 
 
  DrawCoordiateSystem 
  fonksiyonundan incelemeye başlayalım. Bu fonksiyonda x, y ve z eksenlerini ifade 
  edecek üç çizgi çizdireceğiz. Eksenlerin diğer çizimlerden ayırd edilebilmesi 
  için öncelikle çizgi kalınlığını değiştiriyoruz. OpenGL kütüphanesinin glLineWidth 
  isimli API fonksiyonu çizgi kalınlığını değiştirir. Bu fonksiyonun prototip 
  bildirimine bakalım : 
    | void DrawCoordiateSystem() {
     glLineWidth(3.0f);
     //x ekseni
     glBegin(GL_LINES);
     glColor3f(1.0f,1.0f,1.0f);
     glVertex3f(-4.0f,-3.0f,-9.0f);
     glVertex3f(1.0f,-3.0f,-9.0f);
     glEnd();  
           //y ekseni
     glBegin(GL_LINES);
     glColor3f(1.0f,1.0f,1.0f);
     glVertex3f(-4.0f,-3.0f,-9.0f);
     glVertex3f(-4.0f,2.0f,-9.0f);
     glEnd();
 
     //z ekseni
     glBegin(GL_LINES);
     glColor3f(1.0f,1.0f,1.0f);
     glVertex3f(-4.0f,-3.0f,-9.0f);
     glVertex3f(-4.0f,-3.0f,-14.0f);
     glEnd();
 }
 
 
 |  
 
 
  glLineWidth API 
  fonksiyonu float türünde bir parametre alır. Bu parametre çizgi kalınlığını 
  belirtir. Varsayılan çizgi kalınlığı 1.0dır. Koordinat sisteminin eksenlerini 
  çizmek için glLineWidth fonksiyonunu 3.0f parametresini geçerek çağırıyoruz 
  ve çizgi kalınlığının 3.0 olmasını sağlıyoruz. Eksen çizgilerini çizmek için, 
  çizimi GL_LINES sembolik sabiti ile başlatıp çizim rengini beyaz yapıyoruz. 
  Ardından eksen çizgilerini glVertex3f fonksiyonunu kullanarak çiziyoruz. 
    | void 
      glLineWidth (     GLfloat width //Çizgi kalınlığı
 );
 |  
 Eksen çizgilerinin 
  çizimini tamamladıktan sonra kübün çizimine geçiyoruz. Çizgi kalınlığını tekrar 
  1.0 yapmak için glLineWidth fonksiyonunu 1.0f parametresini geçerek çağırıyoruz. 
  Şimdi döndürme ve öteleme işlemlerini yapacak olan fonksiyonları çağırabiliriz. 
  Koordinat eksenlerinin bu işlemlerden etkilenmesini önlemek için eksen çizimlerini 
  bu fonksiyonları çağırmadan önce yapıyoruz. Öteleme işlemi için glTranslatef, 
  döndürme işlemi için ise glRotatef fonksiyonunu uygun parametre değişkenlerini 
  geçerek çağırıyoruz. Bu fonksiyonlara geçilen parametre değişkenleri, global 
  alanda tanımlamış olduğumuz değişkenlerdir. Bu değişkenlerin değerlerini uygulamanın 
  çalışma zamanında kullanıcının klavyeden gireceği bilgilere göre güncelleyeceğiz. 
  Böylece her çizim öncesi parametre değişkenlerinin değerleri, dolayısıyla döndürme 
  ve öteleme matrislerinin değerleri değişmiş olacak.
 
 Döndürme ve öteleme 
  işlemlerinin ardından kübün çizimine geçmeden önce çizilecek poligonun çizim 
  modunu belirlemek üzere glPolygonMode OpenGL API fonksiyonunu çağırıyoruz. Bu 
  fonksiyonun prototip bildirimini hatırlayalım :
 
 
 
  glPolygonMode OpenGL 
  API fonksiyonu, çizilecek kapalı alanın pikselleştirilme biçimini ayarlar. Fonksiyonun 
  iki parametre değişkeni bulunmaktadır. İlk parametre değişkeni verilen özellikten 
  etkilenecek olan yüzeyi veya yüzeyleri ifade eder. Bu parametre değişkeni yerine 
  G_FRONT sembolik sabiti geçilirse sadece ön yüzeyler, GL_BACK sembolik sabiti 
  geçilirse sadece arka yüzeyler, GL_FRONT_AND_BACK sembolik sabiti geçilirse 
  hem ön hem de arka yüzeyler atanacak özellikten etkilenecektir. Fonksiyonun 
  ikinci parametre değişkeni atanacak olan özelliği ifade eder. Bu parametre değişkeni 
  yerine GL_POINT sembolik sabiti geçilirse çizilecek olan kapalı alan noktalarla 
  gösterilir, GL_LINE sembolik sabiti geçilirse çizilecek olan kapalı alan alanın 
  kenarlarından geçen çizgilerle gösterilir, GL_FILL sembolik sabiti geçilirse 
  çizilecek olan kapalı alan yüzeyleri boyanarak gösterilir. DrawGLScene fonksiyonunda, 
  eğer filled değişkeninin değeri TRUE ise çizim GL_FILL modunda, filled değişkeninin 
  değeri FALSE ise çizim GL_LINE modunda yapılıyor. Kullanıcının klavyeden gireceği 
  bilgilere göre filled değişkeninin değeri değiştirilerek uygulamanın çalışma 
  zamanında çizim modunu değiştirmek mümkün olmaktadır. 
    | void 
      glPolygonMode (     GLenum face, //İşlemden etkilenecek olan yüzeyler
     GLenum mode //Çizim biçimi
 );
 |  
 Çizim modunu da 
  ayarladıktan sonra küp yüzeylerinin çizimine geçiyoruz. Çizimi GL_QUADS modunda 
  başlatarak küp yüzeylerini dört köşe koordinatlarının değerlerini geçerek çiziyoruz. 
  Her yüzey için glColor3f API fonksiyonu ile başka renk atıyoruz. Bu sayede yaptığımız 
  işlemi uygulamanın çalışma zamanında görebilmemiz kolaylaşacaktır. Küp yüzeylerinin 
  çizimini tamamladıktan sonra eğer çizim döndürülmekte ise, dönme açısının değerini 
  0.25f kadar artırıyoruz. Her çizim sonrası bu değer artırılarak sürekli bir 
  dönme işleminin yapılması sağlanmaktadır.
 
 Çizim fonksiyonumuzdan 
  sonra şimdi pencere fonksiyonumuzu inceleyelim. Pencere fonksiyonunda, gelen 
  mesajları dinleyerek kullanıcının klavyeden gireceği bilgiler doğrultusunda, 
  uygulamada kullandığımız global değişkenlerin değerlerini değiştireceğiz. Önce 
  fonksiyonumuzu inceleyelim :
 
 
 
  Kullanıcının klavyeden 
  girdiği bilgiler, pencere fonksiyonuna WM_CHAR mesajı aracılığı ile iletilirler. 
  Mesaj döngüsünün işlendiği switch-case ifadesinde, WM_CHAR mesajının alınması 
  durumunda önceden belirlediğimiz bazı karakterlerin girildiğinin anlaşılması 
  durumunda belli işlemlerin yapılmasını sağlıyoruz. Klavyeden t tuşuna basıldığında 
  çizimin döndürülme durumunu ayarlıyoruz. Kullanıcı bir kere t tuşuna bastığında 
  rotate isimli değişkenin değeri TRUE olur ve çizim döndürülür. Klavyeden tekrar 
  t tuşuna basıldığında rotate isimli değişkenin değeri FALSE olur ve döndürme 
  işlemi durdurulur. Klavyeden x, y veya z tuşlarına basılması durumunda xRotate 
  , yRotate ve zRotate isimli değişkenlerin değerlerini değiştiriyoruz. Bu tuşlara 
  ilk kez basılması durumunda değişkenlere 1.0 değeri atanır ve değeri 1.0 olan 
  eksenler etrafında döndürme işlemi yapılır. Klavyeden tekrar x, y veya z tuşlarına 
  basılması durumunda bu değişkenlerin değerleri 0.0 olur ve o eksen etrafındaki 
  döndürme işlemi sonlandırılır. 
    | LRESULT CALLBACK 
      WndProc (HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam) {
     static HWND hWndChild;  
           
        switch (uMsg) {
        case WM_CLOSE :
           PostQuitMessage(0);
           return 0;
 
        case WM_SIZE 
        :
           ReSizeGLScene(LOWORD(lParam),HIWORD(lParam));
           return 0;
 
        case WM_COMMAND 
        :
           sbreak;
 
        case WM_CHAR 
        :
 
           if (wParam 
        == t)
              rotate = rotate == TRUE ? FALSE : TRUE;
 
           
        else if (wParam == x)
              xRotate = 
        abs(xRotate - 1.0f);
 
           
        else if (wParam == y)
              yRotate = 
        abs(yRotate - 1.0f);
 
           
        else if (wParam == z)
              zRotate = 
        abs(zRotate - 1.0f);
 
           
        else if (wParam == f)
              filled = 
        filled == TRUE ? FALSE : TRUE;
 
           
        else if (wParam == r)
              xTranslate 
        += 0.25f;
 
           
        else if (wParam == l)
              xTranslate 
        -= 0.25f;
 
           
        else if (wParam == u)
              yTranslate 
        += 0.25f;
 
           
        else if (wParam == d)
              yTranslate 
        -= 0.25f;
 
           
        else if (wParam == i)
              zTranslate 
        += 0.25f;
 
           
        else if (wParam == o)
              zTranslate 
        -= 0.25f;
 
           
        break;
      }
 
      return 
        DefWindowProc(hWnd,uMsg,wParam,lParam);
 }
 
 
 |  
 Klavyeden f tuşuna 
  basılması çizimin biçimini belirlemektedir. f tuşuna ilk kez basılması durumunda 
  filled isimli değişkenin değeri TRUE olur ve çizilen kübün yüzeyleri boyanır. 
  Klavyeden tekrar f tuşuna basıldığında ise filled değişkeninin değeri FALSE 
  olur ve küp sadece kenarlarını sınırlayan çizgilerle gösterilir.
 
 Klavyeden r ve 
  l tuşlarına basılması çizimin x ekseni doğrultusundaki öteleme miktarını değiştirir. 
  Bu tuşlarla çizim sola ya da sağa doğru kaydırılabilir. Klavyeden u veya d 
  tuşlarına basılması çizimin y ekseni doğrultusundaki öteleme miktarını değiştirir. 
  Bu tuşlarla çizim yukarıya veya aşağıya doğru kaydırılabilir. Klavyeden o 
  veya i tuşlarına basılması çizimin z ekseni doğrultusundaki öteleme miktarını 
  değiştirir. Bu tuşlarla çizime yaklaşılması veya çizimden uzaklaşılması sağlanır.
 
 Uygulamanın çalışma 
  zamanındaki görünümü şu şekillerde olacaktır :
 
 
       
 
      
 Bu yazımızda OpenGL 
  ile eksenler boyunca öteleme ve eksenler etrafında döndürme işlemlerinin nasıl 
  yapıldığını ele aldık. Yapmış olduğumuz uygulamayı buradan 
  indirebilirsiniz. Bir sonraki yazımızda görüşmek üzere, mutlu günler dilerim.
 
 
  
  
    * Kaynaklar 
      :    - OpenGL Platform SDK Help Book
 
 
 
                Makale:C ve OpenGL : Döndürme ve Öteleme İşlemleri C ve Sistem Programlama Çiğdem Çavdaroğlu
 |