Anasayfa Eğitseller Oyun Yapımı DirectX Eğitselleri Bölüm 7 - 3. Boyuta Giriş - Üçgenler-Transformasyon-Projeksiyon

DirectX Eğitselleri Bölüm 7 - 3. Boyuta Giriş - Üçgenler-Transformasyon-Projeksiyon PDF Yazdır e-Posta
Kullanıcı Değerlendirmesi: / 1
ZayıfEn iyi 
Eğitseller - Oyun Yapımı
Salı, 19 Ağustos 2008 00:09

Bu eğitselimizde 3. boyuta giriş yapacağız. 3B modellerimizin en küçük yapı taşı üçgenlerdir. OpenGL'de ve birçok tasarım programında dörtgenlerde(quad) kullanılmakta olsada DirectX'de bulunmazlar. Örneğin bir kare çizmek için 2 adet üçgene yani 2*3=6 adet vertexe ihtiyacımız var. Tabiki bu söylediğim üçgen-listeleri(triangle-list) için geçerli. Liste yönteminden başka üçgen çizdirmek için 2 yöntem daha var (bkz. triangle strip, bkz. triangle fan) ama onlara değinmeyeceğiz. Şimdi ilk 3B verteximizi inceleyelim.

//3d pozisyon + renk
struct vertex3d
{
float x, y, z;
DWORD color;
};
#define position_fvf D3DFVF_XYZ | D3DFVF_DIFFUSE

Vertex yapısı x,y,z koordinat değerleri ve renk değerinden oluşuyor. Hemen altında FVF'yi tanımladık. Burada 2 adet üçgen çizdireceğiz.Üçgen tanımı şu şekilde:

vertex3d noktalar[] =
{
{-2.0, -2.0, 0.0, D3DCOLOR_XRGB(255,0,0)},
{ 0.0, 2.0, 0.0, D3DCOLOR_XRGB(0,255,0)},
{ 2.0, -2.0, 0.0, D3DCOLOR_XRGB(0,0,255)}
};

Kırmızı, yeşil ve mavi renkte 3 adet vertex ile üçgeni tanımladık. Verilen sırada noktaları kağıt üzerine çizerseniz göreceksiniz ki vertexler saat yönünde verilmiş. Üçgenlerin veriliş yönüne "winding order" denir. 3B ortamlarda yüzeylerin arka yüzlerini göremediğimiz için onları çizdirmek mantıksızdır. Bu sebepten Direct3d'de standard olarak ters-saat(D3DCULL_CCW) yönünde vertexler içeren yüzeyler çizilmez. Buna "backface culling" denir. Bu ayarın nasıl değiştirilebileceğine daha sonra değineceğiz. Şimdi main metoduna bir göz atalım:

int WINAPI WinMain(HINSTANCE hinstance,HINSTANCE prevInstance,PSTR cmdLine,int showCmd)
{
srand(timeGetTime());
    aygit = new Aygit(hinstance,"BosPencere",false,800,600);

ilklemeler();
    aygit->dongu(oyun_dongusu);
    return 0;
}

Aynı şekilde ilklemeleri yapıp oyun döngüsüne giriyoruz. İlklemeleri incelemeden önce transformasyon kavramını açalım. Genel olarak bir koordinat sisteminde yapılan yer değiştirme,rotasyon vb. işlemlere transformasyon diyoruz. Bu işlem sonucunda aslında bir koordinat sisteminden başka bir koordinat sistemine geçmiş oluyoruz. Bunları kullanarak:

1-Bir objenin konumunu başka bir konuma göre ayarlayabiliriz.

2-Objenin rotasyon ve boyutunu ayarlayabiliriz.

3-Objenin görünüş pozisyonunu, yönünü ve perspektifini ayarlayabiliriz.

Burada bahsedeğimiz 4 çeşit transformasyon var.

Local Space Transformation : "Model space" olarakta adlandırılan bu kavram bir modelin üçgenlerini tasarladığımız koordinat sistemidir. Model space kavramı modelleyenin üçgenleri ortamdan bağımsız olarak hazırlamasını sağlamakla beraber, ortamdan bağımsız olduğu için bazı durumlarda farklı efektler oluşturmamızada yarayabilir. Örneğin bir gezegen modeli düşünelim, bu model local olarak 0,0,0 koordinatında olsun. Biz onu kendi Y ekseni etrafında döndürdüğümüz zaman dünyamızın kendi ekseni etrafında dönmesi gibi bir hareket ortaya çıkacaktır. Fakat local pozisyonunu 5,0,0 gibi bir değer yaptığımızda aynı hareket bir yörünge hareketine benzer. (Bkz. Resim1)

Resim 1:

 

Diğerlerini anlatmak için biraz hayal gücü kullanalım. Bir parkta elinizde kameranızla ile çevreyi izliyorsunuz. Çevrede ağaçlar, banklar vb. nesneler var. Bu nesnelerin konum, rotasyon gibi özellikleri "World Transformation". Kameranın özellikleri "View Transfomation". Kamera çektiği görüntüyü lens vb. aygıtlar kullanarak 2B bir resme çevirir. Kameranın lens vb. düzeneğinide "Projection Transformation" ' a benzetebiliriz. Nesneleri world space'de birbirlerine göre belli konumlara yerleştiririz. Rotasyon, boyut gibi özelliklerini ayarlayabiliriz. Bu tip işlemlerin kamera belirsiz bir konumda olduğu zaman hesaplanması zordur. Bu nedenle kamera world space'de 0,0,0 konumundan +z yönüne bakar şekildedir çünkü Direcr3d sol el koordinat sistemini kullanır yani +z ekranın içine doğrudur. Biz kamerayı farklı bir yöne çevirdiğimiz zaman aslında tüm nesneler hareket eder ama kamera aynı konum ve yönde kalır. Bu durumda vertexler "camera space" 'de bulunurlar. Son olarak projection transformasyonu vertexleri kameranın frustum'una yerleştiren karmaşık bir transformasyondur. 3B bir görünüm elde etmek için kullanılan projeksiyona perspektif projeksiyon denir. Direct3d tüm bu transformasyonları matrix'ler aracılığı ile vertexlere uygular ve d3dx bu transformasyonlar için matrix üreten metodlara sahiptir.

void ilklemeler()
{
D3DXMATRIX M;
//view transform
D3DXVECTOR3 position(0,0,-5); //kamera konumu
D3DXVECTOR3 target (0,0,0); //kamera bakış noktası
D3DXVECTOR3 up (0,1,0); //tavan yönü
D3DXMatrixLookAtLH(&M, &position, &target, &up); //view matrixini hesapla
aygit->getDevice()->SetTransform(D3DTS_VIEW, &M); //view matrixini uygula
     //projection transform
D3DXMATRIX P;
D3DXMatrixPerspectiveFovLH(&P, //projeksiyon matrixini hesapla
PI/2.0f, //görüş açısı bkz. FOV
4.0f/3.0f, //ekran oranı örn. 4:3
1, //Bkz. Near Plane
1000); //Bkz. Far Plane

//projeksiyon matrixini uygula
aygit->getDevice()->SetTransform(D3DTS_PROJECTION, &P);
     //ışığı iptal et
aygit->getDevice()->SetRenderState(D3DRS_LIGHTING, FALSE);
}

Bir D3DXMatrix(4*4) yapısı tanımlayarak başladık. View transformation'u yani kamera özelliklerini oluşturan D3DXMatrixLookAtLH yardımcı metoduna pozisyon, bakış yönü ve tavan yönünü veriyoruz. SetTransform metodu istediğimiz transformasyonu uygulamamızı sağlıyor. İlk parametresi transformasyon tipi, ikincisi ise matrix. Oluşan matrixi DTS_VIEW parametresi ile kullanarak view projeksiyonunu ayarlıyoruz. Burada bu işi bir kere yaptık çünkü kamerayı hareket ettirmeyeceğiz. Perspektif projeksiyon matrixi oluşturan D3DXMatrixPerspectiveFovLH metodunun parametreleri sırasıyla: Döndürülecek matrix, görüş açısı (bkz. FOV), ekran oranı(örn. 800/600), frustum'un yakın yüzeyi ve frustum'un uzak yüzeyi(bkz. Frustum). Elde ettiğimiz matirixi D3DTS_PROJECTION sabiti ile kullanarak bu transformasyonuda hallettik. Işığın iptal edilmesi olayına sonra değineceğiz. Şimdi Döngü kodunu inceleyelim:

void oyun_dongusu()
{
........

//world transform
D3DXMATRIX M;
D3DXMatrixTranslation(&M,-3.0,0.0,0.0);
aygit->getDevice()->SetTransform(D3DTS_WORLD, &M);

//üçgen çiz1
aygit->getDevice()->SetFVF(position_fvf); //vertex tipi
aygit->getDevice()->DrawPrimitiveUP(D3DPT_TRIANGLELIST, //türü
1, //sayisi
noktalar, //vertex bilgisi
sizeof(vertex3d)); //vertex boyutu
     .........

Önce çizilecek nesnenin konumunu ayarladık ve çizdik. Özetle böyle :) D3DXMatrixTranslation metodu x,y,z, değerlerini alarak bir yer değiştirme matrixi oluşturuyor. Böylece nesneyi DTS_WORLD transformasyonu ile çizmeden önce istediğimiz konuma koyabiliriz. 2 üçgen çizeceğimiz için ilkini -3 birim sola yerleştirdik. Çizim işlemi daha öncekilerin aynısı olmakla beraber üçgen çizmek için liste yöntemini kullandık, yani her üçgen için 3 vertex kullandık. Üçgen listelerini index kullanarak daha optimize çizebiliriz. Bu konuya bir sonraki eğitselimizde değineceğiz. Şimdi 2. üçgenin çizimini inceleyeceğiz.

//y-rotasyonunu her seferinde artır
static float rot_y = 0.0f;
rot_y += (float)(aygit->gecenZaman()*0.005);

//matrixleri hazırla
D3DXMATRIX POS;
D3DXMATRIX ROT;
D3DXMatrixTranslation(&POS,3.0,0.0,0.0);
D3DXMatrixRotationY(&ROT, rot_y);
M = ROT*POS;
aygit->getDevice()->SetTransform(D3DTS_WORLD, &M);

//üçgen çiz2
aygit->getDevice()->DrawPrimitiveUP(D3DPT_TRIANGLELIST, //türü
1, //sayisi
noktalar, //vertex bilgisi
sizeof(vertex3d)); //vertex boyutu

İlk önce statik bir rotasyon değeri tanımladık ve bunu her seferinde biraz artırıyoruz. Artırmak için geçen zaman değerini kullandık, böylece dönüş hızı FPS'den bağımsız olacak. 2. üçgeni ekranın biraz sağına(+3) yerleştirip, Y ekseni etrafında döndürücez. Bu iş için 2 tane matrix gerekecek. Yer değiştirme ve rotasyon matrixleri. D3DXMatrixTranslation metodu ile +3 birim sağa kaymak için gerekli matrixi elde ediyoruz. Cismin Y ekseni etrafındaki rotasyonunu belirlemek içinde D3DXMatrixRotationY methodundan dönene matrixi kullanacağız. Oluşan bu iki matrixin çarpımı bize gerekli olan transformasyonu sağlayacak. (3 transformasyon tipinin sıralarının önemli olduğunu belirtmekte fayda var. İstenmeyen sonuçlarla karşılaşmamak için scale (boyut), rotate(döndür), translate(yer değiştir) sırasını unutmayınız.)) Gene setTransform metodu ile trasnformasyonu bitiriyoruz. Son olarak ilk üçgen için yaptığımız çizim çağrısını aynen tekrarlıyoruz. Çalıştırdığınız zaman solda sabit duran , sağda ise Y ekseni etrafında dönen üçgenleri göreceksiniz. Daha önce bahsettiğim üzere üçgenin arka yüzü çizilmeyecek, bunu dönen üçgende çok rahat gözlemleyebilirsiniz.

Bitirmeden önce daha önce bahsi geçen setRenderState, wireframe ve ışık iptali konularından bahsedelim. RenderState'ler(Bkz. 3DRENDERSTATETYPE) vertex ve pixel işlemlerinin birçok ayarını belirlerler. Burada wireframe(tel) görüntü elde etmek için D3DRS_FILLMODE isimli state'i değiştirdik. Sonucunu ENTER'a basarak gözlemleyebilrsiniz. Transform edilen vertexler ışıklandırma işlemine tabi tutulurlar. Biz sahneye ışık eklemediğimiz için ışıklandırmayı iptal etmez isek hiç birşey göremeyiz. Daha önce kullandığımız 2B vertexler(untransformed) ise otomatik olarak ışıklandırılırlar. ::SetRenderState(D3DRS_LIGHTING, FALSE) şekilnde ışıklandırmayı kapattık. Son olarak "backface culling" 'in nasıl ayarlandığından bahsedelim. ::SetRenderState(D3DRS_CULLMODE, X) şeklinde aşağıdaki değerleri kullanarak saat-yönünde, saatin aksi yönünde çizilen üçgenleri "cull" edebiliriz. Tümünü çizdirmek için ise "D3DCULL_NONE" değerini vermek yeterli.

D3DCULL_NONE //tümü çizilir
D3DCULL_CW //saat yönünde olanlar çizilmez
D3DCULL_CCW
//saatin aksi yönünde olanlar çizilmez

Kaynak Kodu İndir



-------- EKSTRALAR --------

Ekran Kartı Bilgisi Kodu:

http://directx.oyungelistirici.net/dx/onbilgi.rar

Kavramlar:
 
http://www.oyungelistirici.net/index.php/egitseller/14-oyunyapimi/233-kavramlar

DirectX Kaynakları:

http://www.chadvernon.com/blog/tutorials/
http://www.directxtutorial.com/
http://www.zanir.szm.sk/index.html
http://www.pieterg.com/
http://www.32bits.co.uk/
http://triplebuffer.devmaster.net/tutorials/archive/
http://www.two-kings.de/
http://www.mvps.org/directx/indexes/index.htm
http://www.drunkenhyena.com/cgi-bin/directx.pl

DirectX Kitapları:

http://www.amazon.com/ adresinde DirectX'i aratmanız yeterli.

-------- ÖNEMLİ --------

-Bu sitedeki dökümanlar Türkçe kaynak eksikliği yüzünden hazırlanmış ve ihtiyaç duyanların serbest kullanımına sunulmuştur.

-Sunulan kodlar ve bilgilerin doğruluk ve etkinlikleri konusunda bir garanti verilmemekle beraber her türlü talep ve düzeltmelerinizi mail yada ilgili forum başlığı yoluyla iletebilirsiniz

-Dökümanlarda daha çok genel kavramlara değinilmiş olup detaylı bilgi edinmek için directx dökümanını ve çeşitli kaynakları (özellikle kitap) okumanız tavsiye edilir. Farklı kaynakların bağlantılarını bu dökümanın sonunda bulabilirsiniz.

-Bu eğitsellerden verim alabilmek için orta düzeyde c++ bilgisi yeterlidir. Onun dışında winAPI hakkında bilgi sahibi olmak directx'i kavramakta size yardımcı olacaktır. Ayrıca eğitseller ardışık bağlantılı olduğu için bu işte yeni iseniz sırayla gitmeniz tavsiye edilir.

-Örnek kodlar Virusl Studio 2003 projeleridir, vs2005 ile de kullanılabilir.

-Kavramları Türkçeleştirmek için çok çaba sarfedilmemiştir, çoğu yerde İngilizce isimler kullanılmıştır. Merak ettikleriniz için kavram sözlüğüne bakabilirsiniz.

-İndireceğiniz yazılımlardan dolayı PC'nizin ya da bünyenizin zarar görmesi durumunda sorumluluk kabul etmeyiz, geçmiş olsuna gelebiliriz :)

-Yazılanların hakkı saklı değildir, sağda solda ben yaptım diye dağıtabilirsiniz :)
 
Yunus KARA
Son Güncelleme ( Salı, 19 Ağustos 2008 01:23 )
  Yorum yok.
Yorum ekle. (0 yorum)

 

OyunGelistirici.net - Türk Oyun Yapımcılarının Buluşma Noktası

Bu sitede yazılan tüm yazıların hakları yazarlarına aittir. İzin alınmadan yayınlanamaz.

Bu sitede Firefox kullanmanız önerilir. En az 1024 x 768 masaüstü çözünürlüğü tavsiye edilir.