OpenGL programlamaya giriş

Ubuntu Türkiye Wiki sitesinden
Gezinti kısmına atla Arama kısmına atla

Kurulumu ve derleme

Ubuntu'da OpenGL dosyalarını derlemek için gerekli kütüphanelerden bazıları şunlardır: freeglut3, freeglut3-dev. Şimdilik bize bu kütüphaneler yeterli. İlerledikçe gerekli kütüphaneleri kurabiliriz. Bu kütüphaneleri konsol kullanarak kurmak için:

Görevi: Kurulum
sudo apt-get install freeglut3 freeglut3-dev

komutunu vermek yeterli böylece kütüphaneler kurulacaktır. Diğer bir yöntem de Synaptic Paket Yöneticisi'nden bu kütüphaneleri tek tek kurmaktır. OpenGL'de genelde C/C++ kullanılır. C/C++ kaynak dosyaları da ".cpp" uzantılıdır. Normalde C++ dosyalarını konsol kullanarak derlemek için:

Görevi: Derleme
g++ kaynak.cpp -o program

komutu ile derlenir. Tabii ki bunu derleyebilmek için sisteminizde gcc/g++ derleyicisinin kurulu olması gerekir. Eğer kurulu değilse onu da

Görevi: Kurulum
sudo apt-get install g++

ile kurabilirsiniz. Derlenmiş dosyayı

Görevi: Çalıştırma
./program

şeklinde çalıştırabiliriz. Buraya kadar C++ derleme ile ilgili konulara bir özet geçmiş olduk. Şimdi OpenGL kodlarını derlemek için derleyiciye bazı kütüphanelerin bağlanmasını gerektiğini belirten anahtarlardan bahsedelim. Bu anahtar -l (Küçük L harfi) ardından da bağlanacak dosya gelir. OpenGL dosyalarını derlemek için bize gerekli komut:

Görevi: Derleme
g++ kaynak.cpp -o program -lGL -lGLU -lglut

şeklindedir. Çalıştırmak için de yukarıda söylediğimiz gibi:

Görevi: Çalıştırma
./program

yeterlidir. Eğer bir IDE kullanıyorsanız kütüphanelerin bağlanması için Proje ayarlarına girdikten sonra Linker bölümünden gerekli yerlere gerekli anahtarlarla ayarları yapmanız gerekir. Örneğin NetBeans için soldaki çalıştığımız projeye sağ tık yaptıktan sonra açılan Properties, oradan Linker bölümünde bulunan Command Line altındaki satıra

Görevi: Parametre
-lGL -lGLU -lglut

ekleyerek ayarları yaparız. Bu ayarlar hemen hemen bütün IDE'lerde bu şekildedir. Bu kadar hazırlıktan sonra ilk programımızı yazalım ve derleyelim.

İlk program

#include <GL/glut.h>
void sahne(){
	glClear(GL_COLOR_BUFFER_BIT);	
        glPointSize(5);	
	glBegin(GL_POINTS);	
        glVertex2f(0,0);
	glVertex2f(0.2,0);
	glVertex2f(0.2,0.5);
	glEnd();
	glFlush();
}
int main(int argc, char **argv){
	glutInit(&argc,argv);
        glutCreateWindow("Ilk programimiz");		
	glutDisplayFunc(sahne);						
	glutMainLoop();
	return 0;
}


İlk olarak gluttan bahsedecek olursak GLUT , “OpenGL Utility Toolkit” ‘in kısaltmasıdır.OpenGL uygulamalarının işletim sisteminin pencere sistemlerinden bağımsız olmasını sağlar.Bu apiye ait işlevler glut.... önekini alırlar.Ayrıca bu api sayesinde klavye, mouse hareketlerinide yakalayabilir, oyun moduna geçerek tam ekran uygulamalar, menüler oluşturabiliriz.

Programı satır satır anlatalım.
İlk satırda programa ilgili başlık dosyalarını dahil ettik, zaten C/C++ bilenler buna yabancılık çekmeyeceklerdir. Main fonksiyonundan devam edersek
glutInit(&argc,argv) fonksiyonu bütün OpenGL programlarımızda çağrılması gerekli işlevdir.Bu glutun kullanım için hazırlanması, ilklendirilmesi için gereklidir.Argümanlarını main fonksiyonundan alır.
glutCreateWindow("Ilk programimiz") fonksiyonu ise çizim gerçekleştirebileceğimiz bir pencere oluşturulmasını sağlar, argümanı pencerenin başlığıdır.
glutDisplayFunc(sahne) fonksiyonu ise kendisine parametre olarak geçilen fonksiyonu çağırır ve çizimi yapar.Dikkat ederseniz argümanı bir fonksiyondur.
glutMainLoop() işlevi ise Ana döngü dediğimiz olaya girer.Yani çizim yapıldıktan sonra klavye, mouse hareketlerini bekler.
return 0 programın başarılı bir şekilde sonlandırıldığı bildirir.Bunlar glut apisine ait ayarlardı, hemen hemen bütün programlarımızda bunları ve bir kaç işlev daha ekleyerek kullanacağız.

sahne() fonksiyonun içine bakacak olursak ilk satırda çizim için kullanılacak olan tamponları temizliyoruz.Bunu glClear(GL_COLOR_BUFFER_BIT) işlevi ile yapıyoruz.
glBegin(GL_POINTS) işlevinde ise OpenGL ye çizime başlayacağını söylüyoruz.Biz burada çizimimizin noktalardan oluşacağını söyledik, bunun yerine kullanabileceğimiz diğer enumlar ise

                GL_POINTS					Verilen koordinatlara nokta ciz
		GL_LINES					Verilen her iki nokta arasina cizgi ciz
		GL_LINE_STRIP				Verilen noktalari cizgilerle birlestir
		GL_QUADS					Verilen 4 noktaya dortgen ciz
		GL_TRIANGLES				Verilen 3 noktaya ucgen ciz
		GL_TRIANGLES_STRIP			Kenarları cakisik ucgenler ciz, yelpaze seklinde



glPointSize(5) işlevi ise ekrana çizilecek noktanın büyüklüğünü ayarlar.Argüman olarak girilen değer piksel cinsinden noktanın büyüklüğüdür.
glVertex2f(0,0) noktanın koordinatını söylüyoruz.Burayı biraz genişletelim.Buradaki söz diziminden bahsedecek olursak gl... öneki OpenGL nin işlevlerinde bulunan önektir.Vertex koordinatı belirttiğimizi söyleyen bir fonksiyonun ismiymiş gib düşünebiliriz.2 sayısı ise noktamızın 2 boyutlu bir uzayda(yani x-y düzlemi) belirttiğimizi bildirir.f ise argümanların float tipinde olduğunu söyler.Örneğin glVertex3d(0,0,0) gibi bir yazım ise noktamızın 3 boyutlu bir uzayda (x-y-z) argümanları double olan bir noktanın bildirimini yapar.Kartezyen Koordinat sistemini bildiğinizi varsayarak sadece şunları belirtmek istiyorum.Ekranın düşeyi y-eksenidir, yatayı ise x-eksenidir.Ekrandan bize doğru gelen eksen ise z-eksenidir.Bunların üçüde birbirine diktir.Başlnagıç noktası ise ekranın tam ortasıdır.Ekranın en üstü y değerinin 1(bir), en altınında -1 olduğu değerdir.Ekranın sol kenarı x'in -1 sağ kenarın +1 olduğu değerdir.Yani ekran 2 birim uzunluğundadır hem yatay hemde dikey olarak, çizimlerimizi bunlara göre yapmamız lazım.Aksi taktirde çizimimiz ekranda gözükmeyecektir.
glVertex2f(0,0); glVertex2f(0.2,0); glVertex2f(0.2,0.5); ile noktalarımızın koordinatlarını belirtiyoruz.
glEnd() ile nokta çizimimizin bittiğini bildiriyoruz.Çizim bittiğine öre bunları ekrana yansıtmak, ekrana da çizilmesini sağlamak için
glFlush() fonksiyonunu kullanıyoruz.
Kodları ilk.cpp adında bir dosya oluşturarak içine kopyalayınız.Kodları kaydedip konsolda dosyanızın olduğu dizine geçiniz.Derlemek ve çalıştırmak için aşağıdaki komutları sırayla veriniz.

Görevi: Derleme
g++ ilk.cpp -o ilk -lGL -lGLU -lglut
Görevi: Çalıştırma
 ./ilk
OpenGL1.png

Programı derleyip çalıştırırsak ekranda 3 noktanın olduğunu göreceksiniz.Fonksiyonların (glBegin(),glVertex2f()) argümanlarını değiştirerek değişiklikleri gözlemeye çalışınız.İstediğiniz yerlere noktalar koymaya çalışınız ve Vertex mantığını kavrayınız.

Renk

#include <GL/glut.h>

void sahne(){
	glClearColor(1,1,1,0); 			 
	glClear(GL_COLOR_BUFFER_BIT);
	glLineWidth(4);		     
	glBegin(GL_LINES);		  	
	  glColor3f(0,1,0); 	   //Yesil		
	  glVertex2f(-0.9,0.9);
	  glVertex2f(0.9,0.9);
	  glColor3f(1,0,0);        //Kirmizi
	  glVertex2f(-0.9,0.8);
	  glVertex2f(0.9,0.8);
	  glColor3f(0,0,1);		//Mavi
	  glVertex2f(-0.9,0.7);
	  glVertex2f(0.9,0.7);
	  glColor3f(1,1,0);		//Sari
	  glVertex2f(-0.9,0.6);
	  glVertex2f(0.9,0.6);
	glEnd();	
	glBegin(GL_POLYGON);
	  glColor3f(1,0,0);
	  glVertex2f(0,0.5);
	  glColor3f(0,1,0);
	  glVertex2f(-0.5,-0.5);
	  glColor3f(0,0,1);
	  glVertex2f(0.5,-0.5);
	glEnd();
	glFlush();
}
int main(int argc, char **argv){
	glutInit(&argc,argv);	
	glutInitWindowSize(500,500);
	glutInitWindowPosition(20,20);		
	glutCreateWindow("Renkler");		
	glutDisplayFunc(sahne);						
	glutMainLoop();								
	return 0;
}

Main fonksiyonumuza yeni eklediğimiz glut işlevlerini anlatarak başlayalım.Bunlardan ilki glutInitWindowSize(500,500); Çizim için oluşturulacak olan pencerenin boyutunu ayarlamamızı sağlar.Argümanlarından ilk değer pencerenin yataydaki genişliği, ikinci değer ise pencerenin yüksekliğidir.
Bir diğer yeni glut işlevimiz ise glutInitWindowPosition(20,20); buda yeni oluşturulacak olan pencerenin ekranın neresinde açılacağını, oluşturulacağını ayarlamamızı sağlar.Argüman olarak geçilen ilk değer sol kenardan olan uzaklık, ikinici değer ise üstten olan uzaklıktır.Başka bir değişle ekranın sol üst köşesini (0,0) koordinat sisteminin başlangıç noktası seçilirse sağa doğru x-ekseni artışı, aşağı doğruda y-ekseni artışı kabul edilir.Bu işlevin varsayılan değeri (-1,-1)dir.Buda pencerenin yerini pencere yöneticisi belirler.
Sahne fonksiyonumuzun içine geçersek ilk işlev glClearColor(1,1,1,0); temizleme rengini ayarlar.Bir nevi arkaplan gibi düşünebiliriz.Ekranı temizle komutu verdiğimiz zaman ekran bu renge boyanır.Bu fonksiyon 4 argüman alır.İlk üçü renklerle alakalı, dördüncü argüman ise alpha dediğimiz saydamlık ölçüsüdür.Bu işlevin varsayılan değeri glClearColor(0,0,0,0) dır.Siyah ve mat arkaplan.


Biraz renkler hakkında bilgi verelim.3 ana rengimiz var bunlar Kırmızı,Yeşil,Mavi dir.(Kısaca ve ingilizce kısaltmalarla akılda kalması kolay olur.RGB)Diğer renkler bu renklerin farklı tonlarda karışımıyla elde edilir.Mesela beyaz bu üç rengin tamamının karışımıyla elde edilir.Buda arkaplan ayarlarken kullandığımız gibi ClearColor(1,1,1,0) ile olur.Tahmin edeceğiniz gibi 1 bu renkten maksimum miktarda kat demektir, 0 ise hiç katma demektir.0-1 arasında istediğiniz değeri verebilirsiniz.


Ekranı temizlettikten sonra kullandığımız yeni fonksiyon glLineWidth(4); çizgi kalınlığını ayarlar.Bundan sonra çizeceğimiz çizgiler 4 piksel genişliğinde olacaktır.
glBegin(GL_LINES) ile çizime başladığımızda verilen noktalar arası çizgiler çizilir.Şöyleki 1. ve 2. nokta arası, 3. ve 4. nokta arası, 5. ve 6. nokta arası..... Eğerki 1.noktadan 2.ye, 2. noktadan 3.ye, 3.noktadan 4.ye... çizilmek istenirse GL_LINE_STRIP enumu kullanılmalıdır.
Kodlarda gördüğünüz gibi önce rengimizi yeşil olarak ayarlıyoruz.İki nokta arasına 4 piksel genişliğinde bir çizgi çiziyoruz.Şimdi birazda OpenGL kurallarından bahsedelim.Bir renk seçtikten sonra rengi değiştirene kadar yapılan bütün işlemlerde seçili renk kullanılır.Aynı kural çzgi kalınlığı, nokta büyüklüğü gibi ayarlarda da geçerlidir.Kural bu basit, elinize kalem almak gibi düşünün elinize kırmızı kalemi aldıktan sonra değiştirmeden çizdiğiniz bütün şekiller kırmızı olacaktır.
Programda sırayla Yeşil, Kırmızı, Mavi, Sarı çizgiler çiziliyor.
glBegin(GL_POLYGON) ile polygon çizimine başlanılır.Bu nasıl bir şeydir diye soracak olursanız. Verilen noktalar sırayla çizgilerle birleştirilir ve daha sonra içide boyanır.Programda 3 noktalı bir polygon çiziliyor, ama her nokta verilirken çizim rengi değiştirildiği için renklerin farklı tonlarda karışmasından dolayı renkli bir şekil oluşuyor.

OpenGL Renkler.png

Bu konuda da anlatılacaklar sanırım bu kadar yeterli...

Klavye hareketleri ve dönüşümler

//Klavye hareketleri ve donusumler
//Tasima, dondurme ve olcekleme

#include <GL/glut.h>
#include <iostream>
using namespace std;

void sahne();
void klavye(unsigned char,int,int);

int main(int argc, char **argv){
	cout<<"w - yukari, s - asagi, a - sola, d - saga dogru tasir"<<endl;
	cout<<"j - x ekseni etrafinda, k - y ekseni etrafinda, l - z ekseni etrafinda 10 derece dondurur."<<endl;
	cout<<"q - büyüt, e kücült"<<endl;
	glutInit(&argc,argv);
	glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB);	//Cift tamponlu bir pencere olusturmak icin
	glutInitWindowSize(500,500);		
	glutInitWindowPosition(20,20);			
	glutCreateWindow("Klavye ve Donusumler");		
	glutDisplayFunc(sahne);		
	glutKeyboardFunc(klavye);		//Klavyeden herhangi bir tusa basildigi zaman calistirilir
	glutMainLoop();								
	return 0;
}
void sahne(){
	glClear(GL_COLOR_BUFFER_BIT);	
	glBegin(GL_QUADS);
	 glVertex2f(-0.2,0.2);
	 glVertex2f(0.2,0.2);
	 glVertex2f(0.2,-0.2);
	 glVertex2f(-0.2,-0.2);
	glEnd();
	glutSwapBuffers();		//Cift tamponda glFlush() yerine kullanılır.On tamponla arka tampon yer degistirir
}
void klavye(unsigned char tus,int x,int y){
	if(tus=='w'){
		glTranslatef(0,0.1,0);
	}
	if(tus=='s'){
		glTranslatef(0,-0.1,0);
	}
	if(tus=='d'){
		glTranslatef(0.1,0,0);
	}
	if(tus=='a'){
		glTranslatef(-0.1,0,0);
	}
	if(tus=='j'){
		glRotatef(10,1,0,0);
	}
	if(tus=='k'){
		glRotatef(10,0,1,0);
	}
	if(tus=='l'){
		glRotatef(10,0,0,1);
	}
	if(tus=='q'){
		glScalef(1.5,1.5,1.5);
	}
	if(tus=='e'){
		glScalef(0.5,0.5,0.5);
	}
	sahne();
}

Main fonksiyonune eklediğimiz yeni işlevlerden ilki glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB); Görüntü modunun çift tamponlu olacağını bildirir, diğer parametre ise renk sisteminin RGB olacağını söyler.Çift tampon bize animasyon gibi çizimlerde daha net bir görüntü sağlar.Görüntü ilk önce arka tamponda çizilir daha sonra glutSwapBuffers() komutu ile ön tamponla yer değiştirir.glutSwapBuffers() burada daha önce kullanığımız glFlush() yerine kullanıyoruz.Çift tamponda glutSwapBuffers() kullanılır.
Main içerisine eklediğimiz bir diğer yeni işlev ise glutKeyboardFunc(klavye); program ana döngü içerisnde iken (MainLoop()) klavye hareketlerini inceler.Klavyeden herhangi bir tusa basıldığında argüman olarak bildirilen fonksiyonu gerekli parametreleri bildirerek çağırır, bizim örneğimizde bu klavye fonksiyonu bu fonksiyonda 3 parametreden olusur.Birincisi char tipinde klavyeden basılan tusu bildiren değişkendir.Diğer ikisi int tipinde farenin o anki konumunu tutan değişkenlerdir.klavye() fonksiyonu içerisinde ise OpenGL nin dönüşüm işlevlerini kullandık.Bunlar Taşıma, Döndürme ve Ölçeklendirmedir.Bunlar sırasıyla glTranslatef(), glRotatef(),glScalef();
glTranslatef(float,float,float); glTranslatef olduğu için 3 tane float tipinde değişken alır.Koordinat sisteminin başlangıç noktasını bu 3 argüman ile bildirilen noktaya taşır.
glRotatef(float,float,float,float) ilk parametrede bildirilen derece cinsinden döndürme miktarıdır.Diğer 3 parametre ise döndürme noktasının koordinatıdır.Yani belirtilen nokta etrafında belirtilen açı kadar döndürür.
glScalef(float,float,float); Üç parametre alır. Her biri sırasıyla koordinat sistminin varsayılan ölçekleriyle çarpılır.Kısaca sayılar 0 dan küçükse ufaltılır, 1 den büyükse büyütülür.

OpenGL Klavye.png

Basit klavye hareketleri bu şekildedir ama dikkat ederseniz tuşa basıldıktan sonra bir miktar tepki gecikmektedir.