OpenGL Eklentilerinin Kullanımı ve Multitexture
(1248 kelime) (897 okuma)
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
|