• Merhaba Ziyaretçi.
    "Hoşgeldin sonbahar "
    konulu resim yarışması başladı. İlgili konuya BURADAN ulaşabilirsiniz. Sizi de beğendiğiniz 2 resmi oylamanız için bekliyoruz...

C dili ile OpenGL Programlama

Bunun yerine 36 noktayı bi dizide tanımlayıp tek seferde de ekran kartına gönderebilirdim. Böylece ekran kartıyla daha az iletişime geçip tek seferte tüm bilgiyi gönderebilirdim.

Buyrun

PHP:
#include <GL/glut.h>
#include <stdlib.h>

static const GLfloat otuzAltiAdetNokta[] = {
    -1.0f,-1.0f,-1.0f,
    -1.0f,-1.0f, 1.0f,
    -1.0f, 1.0f, 1.0f,
    1.0f, 1.0f,-1.0f,
    -1.0f,-1.0f,-1.0f,
    -1.0f, 1.0f,-1.0f,
    1.0f,-1.0f, 1.0f,
    -1.0f,-1.0f,-1.0f,
    1.0f,-1.0f,-1.0f,
    1.0f, 1.0f,-1.0f,
    1.0f,-1.0f,-1.0f,
    -1.0f,-1.0f,-1.0f,
    -1.0f,-1.0f,-1.0f,
    -1.0f, 1.0f, 1.0f,
    -1.0f, 1.0f,-1.0f,
    1.0f,-1.0f, 1.0f,
    -1.0f,-1.0f, 1.0f,
    -1.0f,-1.0f,-1.0f,
    -1.0f, 1.0f, 1.0f,
    -1.0f,-1.0f, 1.0f,
    1.0f,-1.0f, 1.0f,
    1.0f, 1.0f, 1.0f,
    1.0f,-1.0f,-1.0f,
    1.0f, 1.0f,-1.0f,
    1.0f,-1.0f,-1.0f,
    1.0f, 1.0f, 1.0f,
    1.0f,-1.0f, 1.0f,
    1.0f, 1.0f, 1.0f,
    1.0f, 1.0f,-1.0f,
    -1.0f, 1.0f,-1.0f,
    1.0f, 1.0f, 1.0f,
    -1.0f, 1.0f,-1.0f,
    -1.0f, 1.0f, 1.0f,
    1.0f, 1.0f, 1.0f,
    -1.0f, 1.0f, 1.0f,
    1.0f,-1.0f, 1.0f
};

static const GLfloat renkler[] = {
1,0,0,
1,0,0,
1,0,0,
1,0,1,
1,0,1,
1,0,1,
1,1,0,
1,1,0,
1,1,0,
0,1,0,
0,1,0,
0,1,0,
0,1,1,
0,1,1,
0,1,1,
1,0,0.5,
1,0,0.5,
1,0,0.5,
1,0.5,0,
1,0.5,0,
1,0.5,0,
1,0.5,0.5,
1,0.5,0.5,
1,0.5,0.5,
0.5,0,0,
0.5,0,0,
0.5,0,0,
0.5,0,1,
0.5,0,1,
0.5,0,1,
0.5,1,0,
0.5,1,0,
0.5,1,0,
0.5,0.5,0.5,
0.5,0.5,0.5,
0.5,0.5,0.5

};

static void
resize(int width, int height)
{
    const float ar = (float) width / (float) height;
   
    glViewport(0, 0, width, height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glFrustum(-ar, ar, -1.0, 1.0, 2.0, 100.0);
   
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity() ;
}

static void
display(void)
{
    const double t = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
    const double aci = t*90.0;

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();
     glTranslatef(0,0,-5);
    glRotatef(aci,1,0,1);//x ekseni ve z eksenlerinde döndürüyoruz
    glScalef(0.5,0.5,0.5);

    //36 glVertex3f yerine
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_COLOR_ARRAY);
   
    glVertexPointer(3, GL_FLOAT, 0, otuzAltiAdetNokta);
    glColorPointer(3, GL_FLOAT, 0, renkler);
   
    glDrawArrays(GL_TRIANGLES, 0, 36*3 / 3);
   
    glDisableClientState(GL_COLOR_ARRAY);
    glDisableClientState(GL_VERTEX_ARRAY);

    glutSwapBuffers();
}


static void key(unsigned char key, int x, int y)
{
    switch (key)
    {
        case 27 :
        case 'q':
            exit(0);
            break;
    }

    glutPostRedisplay();
}

static void
idle(void)
{
    glutPostRedisplay();
}


int
main(int argc, char *argv[])
{
    glutInit(&argc, argv);
    glutInitWindowSize(640,480);
    glutInitWindowPosition(10,10);
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);

    glutCreateWindow("3B Kutu");

    glutReshapeFunc(resize);
    glutDisplayFunc(display);
    glutKeyboardFunc(key);
    glutIdleFunc(idle);

    glClearColor(1,1,1,1);
    glEnable(GL_CULL_FACE);
    glCullFace(GL_BACK);

    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);

   

    glutMainLoop();

    return EXIT_SUCCESS;
}


Kod:
glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_COLOR_ARRAY);
    
    glVertexPointer(3, GL_FLOAT, 0, otuzAltiAdetNokta);
    glColorPointer(3, GL_FLOAT, 0, renkler);
    
    glDrawArrays(GL_TRIANGLES, 0, 36*3 / 3);
    
    glDisableClientState(GL_COLOR_ARRAY);
    glDisableClientState(GL_VERTEX_ARRAY);

Bunu sunucu-istemci gibi düşünün. Bir diziyi göndermek için bunun ne dizisi olduğunu söylemeniz lazım. Bu işi glEnableClientState ile yapıyoruz. parametrede ise ne tür veriler göndereceğimizi belirliyoruz. glVertexPointer ile noktalarımızın koordinatlarını gönderiyoruz.1. parametre kaç tane veriden oluştuğu. Biz 3 dedik çünkü x,y,z eğer 2 boyutlu kullansaydık x,y yani 2 kullanacaktık. 2. parametre verinin türü. Float kullandık. 3. parametre dizi nerden başlası. En baştan 0. son parametre dizimiz. glColorPointer, glVertexPointer ile aynı. Sadece renk dizisi için. glDrawArrays ise dizileri nasıl-neye göre basacağını söylememizi sağlar. 1. parametre üç noktadan üçgen yap GL_TRIANGLES. 2. parametre nerden başlayım 0 enbaş. 3. parametre ise kaç nokta var. 36* nokta boyutu/nokta boyutu. yani 36 tane. Eğer biz diziyi dosyadan çekseydik, dizi boyutunu alıp 3 e bölecektik çünkü 3 boyutlu. Böylece 36 adet glVertex3f yazmak yerine 7 adet komut yazmış olduk. Bu performans için oldukça gerekli.

Aslında bu bile hamallık. 36 nokta belirlemek yerine 8 nokta belirlesek sonra bunların indeksini alsak boyutu küçültürüz. Bi sonraki konumuz bu olsun. Görüşürüz. :)
 
Son düzenleme:
glDrawElements

Merhaba.
Bakın burada size hayatınızı düzene sokmayı anlatacam. Tabiiki iyi bir iş, sevgili bir eş, iki tene bebe, ev-arabadan bahsetmiyorum. 8 adet nokta tanımlayıp bunu tekrar tekrar yazmadan belirttiğiniz noktaları nasıl birleştireceğinizden bahsediyorum.

Noktalarımız
Kod:
static const GLfloat sekizAdetNokta[] = {

    -1.0, -1.0,  1.0,
     1.0, -1.0,  1.0,
     1.0,  1.0,  1.0,
    -1.0,  1.0,  1.0,
    -1.0, -1.0, -1.0,
     1.0, -1.0, -1.0,
     1.0,  1.0, -1.0,
    -1.0,  1.0, -1.0
};

İndeksimiz
Kod:
unsigned int kutuIndeksi[] = {
        // on
        0, 1, 2,
        2, 3, 0,
        // alt
        1, 5, 6,
        6, 2, 1,
        // arka
        7, 6, 5,
        5, 4, 7,
        // ust
        4, 0, 3,
        3, 7, 4,
        // sol
        4, 5, 1,
        1, 0, 4,
        // sag
        3, 2, 6,
        6, 7, 3
    };

Burada kutuIndeksi isimli dizide şunu dedik:0. nokta 1. nokta ve 2. noktalar bir üçgen. 2. nokta 3. nokta ve 0. nokta da bir üçgen ...... sekizAdetNokta isimli dizimizin indexleridir bunlar. Tıpkı BMP dosyalarındaki piksellerin renk yerine renk indeksi tutması gibi. JAVA'da bunun sınıfını yapmıştık.
[JAVA] Bit Seviyesinde BMP Dosya Okuma-Yazma-Erişme (Sadece 8 Bit Renk İçin)

Şimdi gelelim bu indeksve diziyi belirtmeye:
Kod:
glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_COLOR_ARRAY);
   
    glVertexPointer(3, GL_FLOAT, 0, sekizAdetNokta);
    glColorPointer(3, GL_FLOAT, 0, renkler);
   
    //glDrawArrays(GL_TRIANGLES, 0, 36*3 / 3);
    glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, &kutuIndeksi);
   
    glDisableClientState(GL_COLOR_ARRAY);
    glDisableClientState(GL_VERTEX_ARRAY);

glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, &kutuIndeksi);
1. parametre 3 noktadan üçgen yap, 2. parametre indeks uzunluğu (36 adet indeks olduğundan 36 verdik), 3. parametre indeks dizisinin tutulduğu tür, 4. parametre indeksin adresi.

PHP:
#include <GL/glut.h>
#include <stdlib.h>

static const GLfloat sekizAdetNokta[] = {

    -1.0, -1.0,  1.0,
     1.0, -1.0,  1.0,
     1.0,  1.0,  1.0,
    -1.0,  1.0,  1.0,
    -1.0, -1.0, -1.0,
     1.0, -1.0, -1.0,
     1.0,  1.0, -1.0,
    -1.0,  1.0, -1.0
};

static const GLfloat renkler[] = {
1,0,0,
1,0,1,
1,1,0,
0,1,0,
0,1,1,
1,0,0.5,
1,0.5,0,
1,0.5,0.5

};

unsigned int kutuIndeksi[] = {
        // on
        0, 1, 2,
        2, 3, 0,
        // alt
        1, 5, 6,
        6, 2, 1,
        // arka
        7, 6, 5,
        5, 4, 7,
        // ust
        4, 0, 3,
        3, 7, 4,
        // sol
        4, 5, 1,
        1, 0, 4,
        // sag
        3, 2, 6,
        6, 7, 3
    };

static void
resize(int width, int height)
{
    const float ar = (float) width / (float) height;
    
    glViewport(0, 0, width, height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glFrustum(-ar, ar, -1.0, 1.0, 2.0, 100.0);
    
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity() ;
}

static void
display(void)
{
    const double t = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
    const double aci = t*90.0;

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();
     glTranslatef(0,0,-5);
    glRotatef(aci,1,0,1);//x ekseni ve z eksenlerinde döndürüyoruz
    glScalef(0.5,0.5,0.5);

    
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_COLOR_ARRAY);
    
    glVertexPointer(3, GL_FLOAT, 0, sekizAdetNokta);
    glColorPointer(3, GL_FLOAT, 0, renkler);
    
    //glDrawArrays(GL_TRIANGLES, 0, 36*3 / 3);
    glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, &kutuIndeksi);
    
    glDisableClientState(GL_COLOR_ARRAY);
    glDisableClientState(GL_VERTEX_ARRAY);

    glutSwapBuffers();
}


static void key(unsigned char key, int x, int y)
{
    switch (key)
    {
        case 27 :
        case 'q':
            exit(0);
            break;
    }

    glutPostRedisplay();
}

static void
idle(void)
{
    glutPostRedisplay();
}


int
main(int argc, char *argv[])
{
    glutInit(&argc, argv);
    glutInitWindowSize(640,480);
    glutInitWindowPosition(10,10);
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);

    glutCreateWindow("3B Kutu");

    glutReshapeFunc(resize);
    glutDisplayFunc(display);
    glutKeyboardFunc(key);
    glutIdleFunc(idle);

    glClearColor(1,1,1,1);
    glEnable(GL_CULL_FACE);
    glCullFace(GL_BACK);

    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);

    

    glutMainLoop();

    return EXIT_SUCCESS;
}

Burada hala performans kaybı olacak. Her döngüde hep aynı şeyleri ekran kartına gönderip duruyoruz. 1 kez gönderelim ve sonra her seferinde çağıralım. Böylelikle her döngüde ekran kartıyla daha az iletişim kuracaz ve performans uçacak. Bi sonraki konumuz bu olsun.;) OpenGL'de buna DisplayList deniyo. Avantajları ve dezavantajlarına bakalım. Sonra görüşürüz ;)
 
OpenGL Display List Nedir, Avantajları ve Dezavantajları

Merhaba;
Geldik bi sonraki yazımıza. :)

Bi önceki yazıda performans demiştik. Performans Türkçe karşılığı "başarım" imiş. Neyse buna takılmayalım.
Bu zamana kadar display fonksiyonumuzda nesneleri sürekli çizdik. Her döngüde çizdik. Bunu şöyle düşünün bir kurye ile evrak göndereceksiniz. Kuryeye diyorsunuz ki falanfilan mh. falan sk. 20/10 semt/il. Hep aynı adrese gönderiyorsunuz adamı ve her seferinde bu adresi bi kağıda yazıp veriyorsunuz. Bunun yerine bu adresi bi kere verip, "Performans Bilgisayar" isimli bi iş yeri olduğunu belirtin. Sonraki gönderilerinizde "Performans Bilgisayar" şeklinde adres verirseniz, her seferinde adres yazmanıza gerek kalmaz. Biz OpenGL'ye basacağımız objeleri isimlendirip tanımlıyoruz. Sonra tanımladığımız listeden ne istiyosak onu çağırıyoruz. Her seferinde objeleri çizmemiz gerekmiyo.
Bi göz atalım:
Kod:
GLuint index = glGenLists(1);
//obje oluşturuyoruz, üçgen olsun
glNewList(index, GL_COMPILE);
    glBegin(GL_TRIANGLES);
    glVertex3f.....
    glVertex3f.....
    glVertex3f.....
    glEnd();
glEndList();
_________

// Ekrana bu şekilde basarız
glCallList(index);
__________

//listemizi siliyoruz
glDeleteLists(index, 1);

Yapacağımız şey şu: Önce glGenLists fonksiyonu ile taban indexi oluşturuyoruz. Bunu bi adres gibi düşünün.Zaten bi adres :) (taban indeksinin ne olduğunu birazdan açıklayacam). Bu adresi bi integer tam sayı değişkeninde tutuyoruz. (Bu arada pointer mantığında oluşturulan her pointer hafızada integer kadar yer tutar. İstersen char * tanımla, değişmez. Bu bir adrestir. Yani int yeterli olacaktır). Daha sonra glNewList ve glEndList çağrıları arasında objemizi çiziyoruz.Bu arada bu işleri bir kez yapmak için "init" gibi bir kereye mahsus çağrılacak bi fonksiyon yapın. glCallList ile de index işaretçisinin gösterdiği objeyi "display" da çiziyoruz. glDeleteLists ise listeyi silmemizi sağlar.

Önemli: Eğer glVertexPointer,glColorPointer ....,glDrawArrays ,glDrawElements gibi fonksiyonlarla obje basıyorsanız, glNewList ve glEndList çağrılarını glEnableClientState ve glDisableClientState fonksiyonlarının arasında yapmalısınız. Zira glNewList ve glEndList istemci tarafında çalışır. Ayrıca geri dönüş değeri alamazsınız. Çünkü geri dönüş sunucuda olur. Bu bi dezavantajdır. Bir dezavantaj ve sizi hayal kırıklığına uğratacak şudur ki glNewList ve glEndList arasında glRotate, glScale, glTranslate gibi fonksiyonlara değişken giremezsiniz. Yani float xdeharketet=15.0f; xdeharketet+=3.0f; glTranslate(xdeharketet,0,0); gibi bi tanımlamada o an xdeharketet değeri kadar listeye yazılır. Bi değişkene bağlanamaz. Çünkü önceden tanımlama bunu gerektirir. Yani bi animasyonda kullanamazsınız. Statik bi obje olmalı. Örneğin büyük haritalar için çok idealdir. Dinamik objelerde Vertex Array veya Vertex Buffer Object kullanmanızı öneririm.

Gelelim avantajlarına: Her seferinde obje yeniden çizilmediği için performans uçacaktır. Sanki hiç çizim yapmıyormuşsunuz gibi işlemci yorulmaz. Çizilen objeler bilgisayar ram'inde değil ekran kartı ram'inde tutulur. Hani deriz ya "senin ekran kartın kaç cigabayt, benimki 2lik" falan diye. İşte o ram bu ram (rem diye okuyunuz. yoksa manidar oluyo:D). Başka aklıma gelen ..... kullanımı kolay, gözleri güzel :D:D yerine göre kullanışlı diyelim ve devam edelim.

GLuint index = glGenLists(1); hakkında söylemek istediğim diğer olay şu. Parametresini verdiğiniz sayı kadar liste uzunluğu oluşur. Eğer glGenLists(5); deseydim işaretçi için 5 listelik alan ayıracaktı ve şöyle cağıracaktim index+0,index+1,index+2,index+3,index+4. Bu bir taban adresi için liste uzunluğu denebilir.

Güzel örnek:
Kod:
GLuint index = glGenLists(10);  // taban adresi için 10 liste kadar alan ayır
GLubyte lists[10];              // en fazla 10 list

glNewList(index, GL_COMPILE);   // ilk index+0
...
glEndList();



glNewList(index+9, GL_COMPILE); // bu da 10. list index+9
...
glEndList();
...

// 1. 3. 5. 7. 9. listler
lists[0]=0; lists[1]=2; lists[2]=4; lists[3]=6; lists[4]=8;

glListBase(index);              // glCallLists için taban adresi
glCallLists(5, GL_UNSIGNED_BYTE, lists);

Kodu incelediğinizde açıklamanın gerekmediğini göreceksiniz. Liste tanımlarken her seferinde index'i artırıyoruz tabiiki tanımladığımız alan kadar en fazla. Sonra glListBase ile basılacak listlerin taban adresini ayarlıyoruz. Sonra bi glCallLists için indis oluşturuyoruz. Ve glCallList den farklı olarak glCallLists ile hepsini birden çağırıyoruz. glCallLists 1. parametre liste uzunluğu,2. parametre listenin türü, 3. parametre liste.

Sizin için hazırladığım örnek:
PHP:
#include <GL/glut.h>
#include <stdlib.h>
#include "iostream"

GLuint index;
static const GLfloat sekizAdetNokta[] = {

    -1.0, -1.0,  1.0,
     1.0, -1.0,  1.0,
     1.0,  1.0,  1.0,
    -1.0,  1.0,  1.0,
    -1.0, -1.0, -1.0,
     1.0, -1.0, -1.0,
     1.0,  1.0, -1.0,
    -1.0,  1.0, -1.0
};

static const GLfloat renkler[] = {
1,0,0,
1,0,1,
1,1,0,
0,1,0,
0,1,1,
1,0,0.5,
1,0.5,0,
1,0.5,0.5

};

unsigned int kutuIndeksi[] = {
        // on
        0, 1, 2,
        2, 3, 0,
        // alt
        1, 5, 6,
        6, 2, 1,
        // arka
        7, 6, 5,
        5, 4, 7,
        // ust
        4, 0, 3,
        3, 7, 4,
        // sol
        4, 5, 1,
        1, 0, 4,
        // sag
        3, 2, 6,
        6, 7, 3
    };

static void
resize(int width, int height)
{
    const float ar = (float) width / (float) height;
   
    glViewport(0, 0, width, height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glFrustum(-ar, ar, -1.0, 1.0, 2.0, 100.0);
   
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity() ;
}

static void
display(void)
{
    const double t = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
    const double aci = t*90.0;

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();
     glTranslatef(0,0,-5);
    glRotatef(aci,1,0,1);//x ekseni ve z eksenlerinde döndürüyoruz
    glScalef(0.5,0.5,0.5);

    glCallList(index);
   

    glutSwapBuffers();
}


static void key(unsigned char key, int x, int y)
{
    switch (key)
    {
        case 27 :
        case 'q':
            exit(0);
            break;
    }

    glutPostRedisplay();
}

static void
idle(void)
{
    glutPostRedisplay();
}

void hazirlik(void){
    index = glGenLists(1);
   
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_COLOR_ARRAY);
   
    glNewList(index, GL_COMPILE);
       
    glVertexPointer(3, GL_FLOAT, 0, sekizAdetNokta);
    glColorPointer(3, GL_FLOAT, 0, renkler);
   
    //glDrawArrays(GL_TRIANGLES, 0, 36*3 / 3);
    glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, &kutuIndeksi);
   
    glEndList();
   
    glDisableClientState(GL_COLOR_ARRAY);
    glDisableClientState(GL_VERTEX_ARRAY);
    }


int
main(int argc, char *argv[])
{
       
         if(AllocConsole())
    {
        SetConsoleTitleA("Ayiklama Ekrani");
        freopen("CONOUT$", "wb", stdout);
        freopen("CONOUT$", "wb", stderr);
    }
   
   
    glutInit(&argc, argv);
    glutInitWindowSize(640,480);
    glutInitWindowPosition(10,10);
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
   
    glutCreateWindow("3B Kutu");

    glutReshapeFunc(resize);
    glutDisplayFunc(display);
    glutKeyboardFunc(key);
    glutIdleFunc(idle);

    glClearColor(1,1,1,1);
    glEnable(GL_CULL_FACE);
    glCullFace(GL_BACK);

    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);

    hazirlik();

    glutMainLoop();

    return EXIT_SUCCESS;
}

Bi sonraki yazımız ne hakkında olur bilmiyorum. Kaplamalara bakalım yada ışıklandırmaya. Bakalım hayırlısı :)
 
Son düzenleme:
Geri
Top