OpenGL Eklentilerinin Kullanımı ve Multitexture

OpenGL Eklentilerinin Kullanımı ve Multitexture

Bu yazıda OpenGL eklentilerinin (extension) ne işe yaradıklarını, nasıl kullanıldıklarını anlatmaya çalışacağım. Örnek olarak da multitexture (çokludoku?) kullanımını göstereceğim.

Nedir?

Sürekli gelişen ekran kartı donanımları ile üç boyutlu program geliştirmede kullanılan grafik kütüphaneleri (OpenGL, DirectX, vs) de kendilerini geliştirmek zorundalar. Bir zamanlar yapılması imkansız olan, veya cok zor şekillerde gerçekleştirilebilen işlemler ve yöntemler, artik günümüz donanımı ile mümkün. Donanım üreticileri (nVidia, ATI, vs) hergeçen gün yeni ve daha güçlü bir kart ile karşımıza çıkıyorlar. İlgili API'ler de kendilerini bu değişime uydurmak durumundalar. Önde gelen iki API'yi değerlendirirsek, DirectX yeni teknolojilere desteğini yeni güncellemelerle yapma yolunu seçmiş durumda. Yani, örneğin önümüzdeki yıl çıkacak bir karttaki yepyeni bir özelliği kullanabilmek için DirectX 10 sürümünü beklemeniz gerekli. OpenGL ise, eklenti mekanizması ile bu işi çözmüş durumda. Yeni bir özelliği, donanım üreticisi OpenGL sürücüsüne ekleyip eklenti olarak programcılara hemen sunabilmekte (GL'e bir puan).

Daha basit açıklayabilmek için bir örnek kullanacağım. Multitexture kullanımını ele alalım. Bu özellik donanımlarda belirmeye başlamadan önce, bir 3B nesneyi birden fazla doku (texture) ile kaplamanın yolu, nesneyi birden fazla kez çizmeye dayanıyordu ve dolayısıyla yavaştı. Daha sonra multitexture destekli kartlar ile, nesneyi bir kez çizip, kaplanacağı dokuları karta ardarda göndermek mümkün oldu. Programınızda, multitexture eklentisinin kullanıcının ekran kartı tarafindan desteklenip desteklenmediğini kontrol edip, yükleyip bu özelliği GL ile kullanabiliyorsunuz. Dezavantajı, hiçbir zaman bir eklentinin kullanıcının kartınca desteklendiğinden emin olamazsınız. Bu yüzden, programınız her makinada istediğiniz gibi gözükmeyebilir. (DX bu noktada, eğer kartta desteklenmeyen bir yöntem varsa bunu yazılım ile kötü performanslada olsa emule etmekte, DX'e bir puan). Bunun çözümü olarak ARB (OpenGL Architecture Review Board), kullanılan eklentileri bir standart altına almaya çalışır. Belli başlı, yaygın eklentiler, zamanla ARB standardı altına alınırlar. ARB onaylı eklentileri kullanarak, en azından daha çok üretici tarafindan desteklendiğine emin olursunuz kullandığınız eklentinin. Daha güzeli, OpenGL'in bir sonraki sürümünde ARB eklentileri, dilin içine alınır. Şu anki OpenGL sürümü 1.4'tür ve 2.0 calışmaları da halen sürmekte. Ancak sevgili Microsoft, işletim sistemlerinde sadece OpenGL 1.1'i destekleyen sürücüleri dağıtmaktadır. Yani Windows programcısıysanız, örneğin aslında artik OpenGL API'si içinde yer alan multitexture özelliğini bir eklenti olarak görüp öyle kullanmanız gerekir.

ARB ayrıca varolan tüm GL eklentilerini de kendi bünyesinde tutmaya calışır. [ http://oss.sgi.com/projects/ogl-sample/registry/ ] adresinden bu listeye ve her eklentinin detaylı açıklamasına ulaşabilirsiniz. Aynı adresten, C/C++ programlarınızda bu eklentileri kullanmak icin gerekli olan header (başlık) dosyalarına da erişebilirsiniz. Bugün itibariyle (05. 03. 2003) 27 ARB onaylı, 290'ı henüz ARB tarafindan resmen onaylanmamış eklenti gözükmekte.

Her eklentinin üç bölümden oluşan bir adı vardır. (Örneğin: GL_ARB_multitexture) İlk bölüm, GL, GLX veya WGL öneklerini alabilir. GL OpenGL için, GLX u*ix (unix türevleri..mesela Linux) işletim sistemleri için, WGL ise MS Windows için kullanılan eklentileri belirler. İkinci bölüm eklentinin hangi donanım üreticileri tarafindan desteklendiğini gösterir.

  • ARB – OpenGL Architecture Review Board tarafindan onaylı eklenti

  • EXT – Birden fazla donanım üreticisi tarafindan desteklenen eklenti

  • HP – Hewlett-Packard

  • IBM – International Business Machines (IBM)

  • KTX – Kinetix, 3D Studio Max'i yapanlar

  • INTEL – Intel

  • NV – NVIDIA Corporation

  • MESA – Brian Paul’s freeware portable OpenGL implementation (Linux için OpenGL)

  • SGI – Silicon Graphics

  • SGIX – Silicon Graphics (deneysel)

  • SUN – Sun Microsystems

  • WIN – Microsoft


Son bölüm ise, eklentinin ne işe yaradığını anlatır. Eğer eklentiler ile daha fazla ilgilenmeyi düşünüyorsanız, yukarıdaki adreste bulunan eklentilerin detaylı bilgilerini nasil okuyacağınızı bilmeniz gerekir. [ http://www.opengl.org/developers/code/features/OGLextensions/OGLextensions.html ] adresinden ilgili dökümana ulaşabilirsiniz.

Nasıl?

Gelelim bu eklentileri C/C++ kodunuzun içinde nasıl kullanacağınıza. Başta da belirttiğim gibi, eklentinin sistemde var olup olmadığını kontrol etmeniz gerekir öncelikle. Bu işlemi yapmak için glGetString fonksiyonunu kullanacağız. Her OpenGL sürücüsünden bu fonksiyon ile sürücü (dolayısıyla ekran karti) ile ilgili detaylı bilgiye ulaşabilirsiniz. Biz, eklentilerle ilgili bilgiye ulaşacağız;

const unsigned char* ext = glGetString (GL_EXTENSIONS); // sürücu ile ilgili bilgi edinelim
std::string ext_str = (char*)ext; // temiz kullanım icin STL kullanalım ( #include <string> yapmayı unutmayın...)

Artık ext_str string değişkeninde, desteklenen eklentilerin isimleri (ardarda) bulunmakta.

Örnek olarak multitexture (GL_ARB_multitexture) işleminin nasıl yapılacağını görelim. Elimizdeki listede, GL_ARB_multitexture var mı yok mu diye anlamamız gerekiyor.

bool  m_bMultiTextureSupported = false;
if( std::string::npos != ext_str.find_first_of("GL_ARB_multitexture") )
	m_bMultiTextureSupported = true;

Var ise, runtime (çalışma zamanı) sırasında function pointerlar olarak, OpenGL sürücüsündeki fonksiyona bir pointer almanız gerekir. Nesne çiziminde vertex array yöntemini kullandığımızı düşünerek veriyorum kod örneğini. Bu yüzden, multitexture eklentisi içinden sadece glClientActiveTextureARB ve glActiveTextureARB eklentilerine olan fonksiyon pointer'larını alacağız.

Kısa bir açıklama, her eklenti için birden fazla fonksiyon ve bazu GL değerleri (GLenum) tanımlanmış olabilir. Örneğin multitexture için, sanırım 30 civarı GL fonksiyonu bulunmakta. Ancak bunlar, texture koordinatlarını teker teker yollamak için gerekli fonksiyonlar. Biz vertex array kullanarak, tüm texture koordinatlarını bir kerede yollayacağımızdan, bu fonksiyonlara ihtiyacımız yok.

Fonksiyonlara pointer'ları alma yöntemi her işletim sistemine göre değişmekte. Burada win32 kullanacağım. Bunun için wglGetProcAddress fonksiyonunu kullanacağız.

PFNGLACTIVETEXTUREARBPROC glActiveTextureARB; // fonksiyonlara pointer 1
PFNGLACTIVETEXTUREARBPROC glClientActiveTextureARB; // fonksiyonlara pointer 2

if( m_bMultiTextureSupported )
{
	glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC) wglGetProcAddress("glActiveTextureARB");
	glClientActiveTextureARB = (PFNGLCLIENTACTIVETEXTUREARBPROC) wglGetProcAddress("glClientActiveTextureARB");
}

Kodun başına bir yerlere;

#include <windows.h>
#include <gl\gl.h>
#include <gl\glext.h>          // internetten indirmeniz gerekebilir.. Daha önce verilen linklerde bulabilirsiniz..
#include <string>

eklemeyi unutmayın bu arada.

Hemen hemen sona geldik. Sistemde eklentinin olup olmadığını biliyoruz, ve istediğimiz fonksiyonlara birer pointer'ımız var. Örnekte, indeksli olarak üçgenlerden oluşan bir nesneyi, iki doku kullanarak çiziyoruz. Kodu olabildiğince genel yazmaya çalıştım, umarım hata yoktur (evet test etmedim!). Kullanılan fonksiyonlar ile ilgili bilgi eksiğiniz var ise yardım dosyalarını karıştırmanızı ve ne yapildiğini iyice anlamaya calışmanızı tavsiye ederim.

glEnable(GL_TEXTURE_2D);
if( m_bMultiTextureSupported ) // eklenti var ise
	glActiveTextureARB(GL_TEXTURE0_ARB + 0); // ilk doku seviyesini aktifleştir

glBindTexture(GL_TEXTURE_2D, tex0); // tex0 isimli texture nesnesini GL'e yolla

if( m_bMultiTextureSupported ) // eklenti var ise
{
	glActiveTextureARB(GL_TEXTURE0_ARB + 1); // ikinci doku seviyesini aktifleştir
	glBindTexture(GL_TEXTURE_2D, tex1); // tex1 isimli doku nesnesini GL'e yolla
}

glEnableClientState( GL_VERTEX_ARRAY ); // vertex arrayimizi bu fonksiyon içinde aktif hale getiriyoruz
glEnableClientState( GL_NORMAL_ARRAY ); // normallerimiz bu fonksiyon icinde aktif hale getiriyoruz

if( m_bMultiTextureSupported )	// eklenti var ise
	glClientActiveTextureARB(GL_TEXTURE0_ARB + 0); // Ilk dokuyu aktif hale getir

glEnableClientState( GL_TEXTURE_COORD_ARRAY); // texture array kullanımını aktifleştir

glVertexPointer( 3, GL_FLOAT, 0, ptr_vert); // ptr_vert değişkeninde vertexler duruyor olsun
glNormalPointer( GL_FLOAT, 0, ptr_norm); // ptr_norm değişkeninde normaller duruyor olsun
glTexCoordPointer( 2, GL_FLOAT, 0, ptr_tex0); // ptr_tex0 değişkeninde doku koordinatları duruyor

// sira ikinci dokuda
if( m_bMultiTextureSupported ) // eklenti var ise
{
	glClientActiveTextureARB(GL_TEXTURE0_ARB + 1); // ikinci doku array hazır
	glTexCoordPointer( 2, GL_FLOAT, 0, ptr_tex1); // ptr_tex1 değişkeninde doku koordinatları duruyor
}
	
// nihayet cizim burada tamamlaniyor
glDrawElements( GL_TRIANGLES, index_sayisi, GL_UNSIGNED_SHORT, ptr_indexler );

Çizim işini bitirdikten sonra da, temizlik başlıyor.

if ( m_bMultiTextureSupported )
{
	glClientActiveTextureARB(GL_TEXTURE0_ARB + 1);
	glDisableClientState( GL_TEXTURE_COORD_ARRAY);

	glClientActiveTextureARB(GL_TEXTURE0_ARB + 0);
	glDisableClientState( GL_TEXTURE_COORD_ARRAY);

	glActiveTextureARB(GL_TEXTURE0_ARB); glBindTexture(GL_TEXTURE_2D, 0 );
	glActiveTextureARB(GL_TEXTURE1_ARB); glBindTexture(GL_TEXTURE_2D, 0 );
}
else
	glBindTexture(GL_TEXTURE_2D, 0 );

glDisableClientState( GL_VERTEX_ARRAY );
glDisableClientState( GL_NORMAL_ARRAY );

Sanırım bu kadar.

Bitti

Eklenti kullanımına geri dönersek, özet olarak, eklentinin OpenGL sürücüsünde bulunup bulunmadığını sorguladık, kullanmak istediğimiz fonksiyonlara birer fonksiyon pointer atadık, ardından kod içinde, bu fonksiyonları normal GL fonksiyonları gibi kullandık (her seferinde varlığını da test ederek).

if ( m_bMultiTextureSupported )

satırını durmadan kullanmak uğraştırıci ve çirkin gözükebilir, ama sistemde varolmayan bir eklentiyi kullanırsanız daha çirkin bir mesaj ile programınız çakılacaktır.

Multitexture kullanımı ise aslen gayet basit. Ekran kartına her vertex için bir yerine iki adet texture koordinatı yolluyoruz. Yollamadan önce, sürücüye bunu haber verip, gerekli alanı aktif hale geçiriyoruz.

Bu yazı ile ilgili, hatalar, görüşleriniz, eleştirileriniz için mentat@cfxweb.net adresini kullanabilirsiniz. Ve tabi www.oyunyapimi.org forumlarını. Umarim yazdıklarim işinize yarar.

mentat :: 05.03.2003 :: www.oyunyapimi.org




Bu yazının bulunduğu site: OyunYapimi.org
http://www.oyunyapimi.org

Bu yazı için adres:
http://www.oyunyapimi.org/modules.php?name=Sections&op=viewarticle&artid=27