| OBJ Model Kütüklerini Kullanmak 
 (1058 kelime)
 (426 okuma)
  
 
 
 
 OBJ Model Kütüklerini Kullanmak// Yazdığımız programlarda ve demolarda her zaman
kutular,dikdörtgenler kullanamayız.// Artık ekrana model çıkarma zamanı geldi diyorsanız bu yazı tam sizler için.
 // Bu kodu anladıktan sonra artık diğer model formatlarını kullanmak çok kolay!
 // Bir önceki "C/C++ İle Kütük İşlemlerine Giriş" adlı yazıda metin
dosyalarından bahsetmiştik
 // Şimdi o bilgileri kullanarak bir Obj dosyayı yüklemeyi inceliyeceğiz
 // Basit bir model dosyası (sadece vertex koordinatları ve üçgen(face,triangle)lerin
vertex
 // indeksleri olsun) şu şekilde olabilir:
 
 // Dosyada önce vertexler üç bileşeniyle(x,y,z) verilebilir.Örnek olarak;
 
 // numVertices : 6
 // 1.0 3.0 4.0
 // 2.0 1.0 4.0
 // 5.0 6.0 4.5
 // 0.4 2.0 2.0
 // 3.2 0.4 1.0
 // 3.4 2.5 8.5
 
 // 6 adet vertex'imiz var. Peki ama bunlardan nasıl,hangi üçgenler oluşacak.
 // Bunu çözmek için vertex indeksleri kullanılır.Dosyada indekslerimiz şu şekilde
olsun;
 
 // numFaces 4
 // 0 2 3
 // 4 5 1
 // 5 3 0
 // 1 4 2
 
 // Hepsinden once dosyada kaç vertex,üçgen vs varsa bunlar için önce bellekte dinamik
olarak
 // yer ayırmalıyız.(new,malloc).İsteyenler STL(standart template library) den
<vector> kullanabilir.
 
 // Burada 4 üçgen var. Peki bu rakamlar neyi ifade ediyor.
 // 0 2 3 -> bu rakamlar, 1.üçgenin yukarıda belirttiğimiz vertexlerden 0. 2. ve 3.
vertexi
 // kullanacağını belirtiyor.
 // 2.üçgen 4. 5. ve 1. vertexleri kullanacak vs..
 // Üçgen dizimiz face[üçgensayısı][3] 3 sayısı üçgenin üç köşesi olduğu için
 // vertex dizimiz vert[vertexsayisi] olsun.Birinci(face[0]) üçgeni çizmek için;
 // index1=face[0][0]; index2=face[0][1]; index3=face[0][2];
 // index değişkenleri sırasıyla yukarıda bahsettiğimiz 0 2 3 değerlerini aldı.
 // glVertex3f(vert[index1].x,vert[index1].y,vert[index1].z);
 // glVertex3f(vert[index2].x,vert[index2].y,vert[index2].z);
 // glVertex3f(vert[index3].x,vert[index3].y,vert[index3].z);
 // Tüm model dosyaları bu ve buna benzer yöntemlerle çalışır.
 
 // Obj dosyalarına gelirsek.Obj dosyalari çok basit text dosyalardır.
 // Çoğu model programları obj dosyasını export/import edebilir.Ama çoğu kendine göre
 // dosyaya eklemeler,çıkarmalar yapıyor.Bazısı normal vektörlerini yazar,
 // grup isimlerini ekler,bazısında bu opsiyoneldir vs.İndireceğiniz
*.obj(MilkShape3D'de
 // kaydedilmişdir www.milkshape3d.com) dosyasını açıp incelerseniz
 // v,vt,vn,f ile başlayan satırlar göreceksiniz.
 // Diğer satırları gözardı edebiliriz.
 // Dosyada:
 // 'v' ile başlayan satırlar vertexi belirtir ve sonraki 3 sayi vertexin x,y,z bileşenleridir
 // 'vt' doku kordinatlarını(Texture Coordinates) sonraki 2 sayi u,v bileşenleridir.
 // 'vn' vertex normallerini belirtir.3 sayi x,y,z bileşenleridir.
 // 'f' ise yukarıda anlattığım üçgenlerin vertex,normal,doku kordinatları
indeksleri içindir.
 // Dikkat ettiyseniz 9 değer var
 // f v1/vt1/vn1 v2/vt2/vn2 v3/vt3/vn3
 // v1/vt1/vn1 üçgenin 1. köşesinin vertex,normal,doku kordinati indeksi diğerleri
2.3.köşeler
 // Bu üçgenin sadece hangi vertexlerden oluştuğu değil buna ek olarak hangi doku
 // koordinatları(vt),ve hangi normalleri(vn) kullandığını da anlatıyor bu satır.
 // Kullanacağımız tipler ve basit obj sınıfı şu şekilde
 // Doku kordinatlarını saklamak için kullanacağız
 struct Vektor2{
 float u;
 float v;
 };
 
 // Vertex ve normal değerlerini saklamak için
 struct Vektor3{
 float x;
 float y;
 float z;
 };
 
 // Dikkat ettiyseniz üçgenden bahsederken hep hangi vertex,hangi normal vs diyorum
 // Çünkü bu yapıda vertexlerin,normallerin,doku kordinatlarının kendileri değil
indeksleri
 // saklanıyor.
 
 // Bir üçgenin hangi vertex,normal,doku koordinatlarını kullandığını saklamak için.
 // Bu bilgi ile o üçgenin vertexini,normalini bulup çizeceğiz.
 struct OBJ_Face
 {
 int vertexIndex[3]; // Bu üçgenin hangi vertexlerden oluştuğunu
belirten indeks
 int textureIndex[3];// Hangi doku kordinatlarını kullandığını gösteren
indeks
 int normalIndex[3]; // Hangi normali kullandığını gösteren indeks
 };
 
 class CObj
 {
 
 public:
 
 //Yapıcı ve yıkıcı metodlar
 CObj();
 
 ~CObj();
 
 // LoadObj üye fonksiyonu parametrede
belirten dosyadan verileri okuyup
 // üye değişkenlerimize atıyacak.
 void LoadObj(const char *dosya);
 
 // Modelimizi çizmek için
 void Render();
 
 // Ayrılan belleğin program sonunda geri iadesi için
 void Destroy();
 
 private:
 
 // Bu metod sayesinde modelimizin kaç
adet vertex,normal,doku koordinati ve üçgene
 // sahip olduğunu öğrenip aşağıda m_num ile başlayan değişkenlere
atıyoruz.
 void GetNums(FILE *fp);
 
 int m_numVerts; // Vertex sayısı
 int m_numNormals; // Normal sayısı
 int m_numTexCoords; // Doku koordinatları sayısı
 int m_numFaces;    // Üçgen sayısı
 
 // Bu işaretçilere, yukardaki sayılar kadar yer ayrılacak.
 Vektor3
        *m_pVerts; //
vertex dizisi
 Vektor3
        *m_pNormals; //
normal dizisi
 Vektor2
        *m_pTexCoords;//
doku koordinatlari dizisi
 OBJ_Face    *m_pFaces;    // üçgen indeksleri dizisi
 
 };
 
 // Metodlarımızıda inceleyelim.
 void CObj::LoadObj(const char *dosya)
 {
 FILE *fp;
 
 // Dosyadan okunacak her satır bu değişkende
 char satir[255];
 
 fp = fopen(dosya,"rt");
 
 // Dosya açılamadıysa ekrana uyarı
mesajı çıkarıp programdan çıkalım.
 if(fp==NULL){
 printf("\n%s acilamadi!\n",dosya);
 exit(0);
 }
 
 // vertex,normal vs.. sayısını öğrenip
bellekte yer ayırıyoruz GetNums() ile.
 GetNums(fp);
 // getStr() fonksiyonu 3.parametresinde verilen karakterle başlıyan satırı okumak için
 // Bunun amacı:örneğin v satırları arasında boşluk, yorum satırı
veya ilgilenmediğimiz bir
 // satır varsa onu atlamak.
 // v 1.0 2.0 2.0
 // # exported by...
 // v 3.0 2.0 4.0
 // gibi..burada # ile başlıyan satırla ilgilenmiyoruz.
 // Dosyanın başından itibaren sayısı kadar vertexleri okuyoruz
 for(int i=0;i<m_numVerts;i++)
 {
 getStr(fp,satir,'v');
 sscanf(satir,"v %f %f
%f",&m_pVerts[i].x,&m_pVerts[i].y,&m_pVerts[i].z);
 }
 // Doku koordinatları
 for(i=0;i<m_numTexCoords;i++)
 {
 getStr(fp,satir,'v');
 sscanf(satir,"vt %f
%f",&m_pTexCoords[i].u,&m_pTexCoords[i].v);
 }
 // Normaller
 for(i=0;i<m_numNormals;i++)
 {
 getStr(fp,satir,'v');
 sscanf(satir,"vn %f %f
%f",&m_pNormals[i].x,&m_pNormals[i].y,&m_pNormals[i].z);
 }
 
 // Kodu kısaltmak için geçici fc değişkenini
tanımladık ve sıfırladık
 OBJ_Face fc={0};
 
 // üçgen bilgisi okunuyor.
 for(i=0;i<m_numFaces;i++)
 {
 
 getStr(fp,satir,'f');
 sscanf(satir,"f %d/%d/%d %d/%d/%d
%d/%d/%d",&fc.vertexIndex[0],&fc.textureIndex[0],&fc.normalIndex[0],
 &fc.vertexIndex[1],&fc.textureIndex[1],&fc.normalIndex[1],
 &fc.vertexIndex[2],&fc.textureIndex[2],&fc.normalIndex[2]
 );
 m_pFaces[i]=fc;
 }
 
 // Dokumuzu yüklüyoruz.
 LoadTexture(texture,"claymore.bmp");
 // Dosyayı da kapattık.
 fclose(fp);
 
 }
 void CObj::Render()
 {
 // modelimizi çizmek için yapmamız
gereken artık çok basit.2 döngü işimizi görüyor.
 // 1.si 0 dan m_numFaces'e kadar bir döngü yani tüm üçgenleri çağıracagiz
 // 2.si ise her üçgende 3 tane v,vt,vn olacagından 0 dan 2 ye kadar
bir döngü
 
 // en içteki for da o anki üçgenin v,vn,vt indeksleri için bu değişkenler
 // Yine kodu kısaltmak için tanımlıyoruz.
 int i_v,i_vn,i_vt;
 
 // indeksimizi aldıktan sonra vertex,normal,vs.. dizimizden ilgili
vertex,normal,doku kor
 // dinatinin baslangic adresini bu işaretçilerde saklıyoruz
ki.Bunları glVertex,glNormal
 // glTexCoord'a parametre olarak geçirelim.
 
 Vektor3 *vV,*vN;
 Vektor2 *vT;
 
 // Dokumuzu seçiyoruz.
 glBindTexture(GL_TEXTURE_2D, texture);
 
 glBegin(GL_TRIANGLES);
 
 for(int i=0;i <m_numFaces;i++)
 {
 for(int j=0;j<3;j++)
 {
 //
Şu anki üçgenin ilgili köşesinin ilgili bileşeninin indeksini alıyoruz.
 i_v
        = m_pFaces[i].vertexIndex[j];
 i_vn
    = m_pFaces[i].normalIndex[j];
 i_vt
    = m_pFaces[i].textureIndex[j];
 
 //
bu indeksler vasıtasıyla ilgili vertexi,normali.vs buluyoruz.
 //
Burada indekslerden 1 çıkarmamızın nedeni Obj dosyasında
 //
örneğin f 1/1/2 2/3/1 3/1/2 // Hiç sıfır yok
 //
burada üçgenin ilk köşesinin vertex indeksi 1 ama biz biliyoruz ki
 //
kastetdiği vertex m_pVerts[1] değil m_pVerts[0]
 //
Dolayısıyla 1 eksiltiyoruz.
 
 vV
= &m_pVerts[i_v-1];
 vN
= &m_pNormals[i_vn-1];
 vT
= &m_pTexCoords[i_vt-1];
 
 //
Son olarak da bunları opengl'ye gonderiyoruz.
 glNormal3f(vN->x,vN->y,vN->z);
 glTexCoord2f(vT->u,vT->v);
 glVertex3f(vV->x,vV->y,vV->z);
 }
 
 }
 
 glEnd();
 
 }
 
 // Obj dosyaları pek kullanışlı değil. Ama bu işi öğrenmek için çok iyi bir başlangıç.
 // Bu dosyayı Milkshape'de kaydettim. Aslında dosyanın kullandığı dokuların dosya
isimleri ayrı
 // bir (*.mtl) dosyada saklanıyor. Ama tek dokumuz olduğu için onu ihmal ettim. Eger
modelde
 // birden fazla grup(modellerle uğraşanlar bilirler) varsa bunlar için ayrı doku falan
 // varsa bu kodlarda biraz oynama yapmak gerekecekti.Zaten bu obj dosyasını fazla
kullanmayacağımız
 // için fazla da karıştırmak istemedim kodu.
 
 // Geriye kalan açıklamaları indireceğiniz dosyalarda bulabilirsiniz.Bu döküman ile
ilgili görüşlerinizi belirtmek yada
 // aklınıza takılan konularda sorular sorabilmek için www.oyunyapimi.org sitesinin
forumlarını kullanabilirsiniz. İyi çalışmalar.
 UzMaN :: 2003 :: www.oyunyapimi.org |