Anasayfa Eğitseller Oyun Yapımı 3B Obje Uzayında Direct3D Sprite

3B Obje Uzayında Direct3D Sprite PDF Yazdır e-Posta
Kullanıcı Değerlendirmesi: / 16
ZayıfEn iyi 
Eğitseller - Oyun Yapımı
Cuma, 06 Temmuz 2007 11:41
3B Obje Uzayında Direct3D Sprite

             ( Güvenç Şahin: Bu e-Posta adresi istek dışı postalardan korunmaktadır, görüntülüyebilmek için JavaScript etkinleştirilmelidir )



Bu ders DirectX de 2 boyutlu spriteları 3 boyutlu obje uzayında renderlamayı anlatmaktadır. Örneklerde verilecek kodlar C++ da yazılmıştır. Hepinizin bildiği gibi teknoloji ile ilgili bir çok konuda olduğu gibi malesef oyun yapımı konusunda da bir çok terim ve terminolojinin Türkçe karşılığı yok. Bazı terimlerin ise Türkçe karşılıkları olmasına rağmen çok fazla Türkçe kaynak bulamayacağınız için ileride karşılaşacağınız bu terimleri İngilizce olarak kullanıyorum ancak mümkün olduğunca karşılığı olan terimleri belirteceğim.

             Temel olarak sprite 2 boyutlu bir texture'dır(kaplama). Genellikle spritelar UI(User Interface-Kullanıcı Arabirimi), HUD(Heads Up Display), yazı ve bazı özel efektleri yapmak için kullanılmaktadırlar. Tüm UI, HUD ve yazı için kullanılan spritelar Ortho Mode'da çalışmaktadırlar. Bunun anlamı spriteın 2 boyutlu ekran uzayında kullanılmasıdır. Bu tür spriteların posizyon vektörleri 2 boyutludur(x,y), x ekran genişliğini y ise ekran yüksekliğini temsil eder. Bu spritelar sadece ekran uzayına bağlıdırlar ve kamera matriximizden bağımsızdırlar işte bu yüzden kullanımları obje uzayında kullanmakdan daha basittir. Ancak malesef 3 boyutlu bir oyun yaparken spriteları 2 boyut üzerinde kullanmak efekt yapmak için çok da elverişli değildir. Bu yüzden etkileyici efektler elde etmek için aslında 2 boyutlu olan spriteları 3 boyutlu obje uzayımızda sanki 3 boyuta sahiplermiş gibi kullanmak zorundayız.

        “Nasıl” kısmına gelmeden önce spriteları ne tür durumlarda kullandığımızı ve ileride kullanacağımız birkaç terimi öğrenmemiz gerekli.              

Spriteları Neden Kullanıyoruz ?

                 Spritelar oyunlarda ateş, duman, patlama, bulutlar gibi birçok efekti yapmakda kullanılır. Tüm bu efektlerin dinamik olduğunu farkettiniz mi? Bu bize spritelar ile efekt yaparken animasyon yada bağımsız hareket içeren bazı uygulamalar kullanmamız gerektiğini göstermektedir. Daha önce de söylediğim gibi “Nasıl” kısımına birazdan geleceğiz bu yüzden şimdilik sprite ile efektler yapmak için animasyon kullanacağımızı bilmeniz yeterlidir.

                Efektler için 3 boyutlu modelleri değilde  2 boyutlu sprite kullanmamız hem çok daha kolay hemde çok daha verimli bir yol olacaktır. Örneğin bir bulut elde etmek için 3 boyutlu bir model kullandığınızı hayal edin. Bu en basit anlamda modelin yuzlerce yüzeye sahip olacağını gösterir. Oysa ki sprite için sadece bir adet yüzey bizim için yeterli olacaktır.



Terimler

Bilboarding:  Billboarding aslında 2 boyuta sahip bir texture'ı 3 boyutlu obje uzayında kameramıza her pozisyonda en iyi açı ile sanki 3 boytluymuş gibi göstermek için kullanılan bir teknikdir. Genellikle kameranın görüş açısı(Camera Frustum) her zaman sprite ile dik açı yapmaz. Bu da aslında 2 boyuta sahip bir texture'ı, 3 boyutlu olarak göstermeye çalışırken sorunlara neden olur. Bunu grafik üzerinde açıklayalım.
 
 
                             Figür 1                                                            Figür 2                                                             Figür 3
 
Figür 1 de kameranın görüş açısı sprite ile dik açı yapmıştır. Bu oyuncunun sprite'ı tam karşıdan gördüğü anlamında gelmektedir. Bu durumda herhangi bir sorun yoktur. Ancak eğer kamera Figür 2 deki gibi sprite etrafında 90 derece dönerse spriteın sadece 2 boyutu olduğundan dolayı oyuncu hiçbirşey göremez. Bu durumda sprite'ımızı Figür 3 deki gibi kendi etrafında(y ekseninde) kameranın pozisyonu ve bakış açısına göre dödürmemiz gerekir. Bu herzaman oyuncunun spriteı tam karşıdan görmesini sağlar ve aslında 2 boyutlu olan spriteın 3 boyutlu bir görünüm kazanmasına olanak verir. Biz bu tekniğe billboarding diyoruz.

Animated Sprite: Daha öncede söylediğim gibi efekt yapmak için kullanacağımız spritelar için bir animasyon kullanmamız gerekir. Örneğimizde kullanacağımız çörek texture'ı aşağıdaki gibidir.
 
 
Görmüş olduğunuz gibi resimde çöreğin  30(5*6)  farklı açıdan görünüşü bulunmaktadır. Bunlar fakrlı resimler değil sadece 3 boyutlu bir çöreğin farklı açılardan görünüşleridir. Bu texture'ı sahnemizde renderlarken her karede sadece texture'da bulunan karelerden birini renderlayacağız. Örneğimiz için bu kareler 64 * 64 pixelden oluşmaktadır. Gerçekçi bir görüntü elde etmek için sadece siyah olmayan kısımları renderlayacağız. Bunun için “alpha blending” yöntemini kullanacağız.

 

Alpha Blending: Alpha Blending transparan texturelar elde etmek için kullanılır. Bunu yapmak için dosya formatları alpha kanal bilgilerini tutarlar ve biz resmi hazırlarken saydam olmasını istediğimiz bölgeleri yada ne kadar saydam olmasını istediğimizi belirtiriz. Ancak tüm resim formatları alpha kanallrını desteklemez. PNG, DDS, TGA ve benzeri dosya formatları alpha kanalı bilgilerini tutarlar ancak örneğimizde kullandığımız BMP alpha kanal bilgilerini tutmaz. İşte bu yüzden alpha için başka bir yol kullanacağız. Sadece siyah olan kısımların saydam olmasını istiyoruz.

 

“Nasıl” Kısmı:

          Bundan sonraki kısımları kod üzerinde açıklayacağım. Standart olarak Direct X sdk larında karşılaşacağınız tiplerde değişken ve obje isimleri seçmeye çalıştım ve genellikle sdk larda kullanılan sıra ile kodladım. Bu kodları okumanızda yardımcı olacaktır.

Code Kısmı:
 

// Öncelikle global objelerimizi yaratıyoruz.

// Sprite Texture'ımız

LPDIRECT3DTEXTURE9      g_SpriteTexture = NULL;

// Sprite Objemiz

LPD3DXSPRITE            g_Sprite  = NULL;

 

 

 

 

 

// Resim dosyasını okuyarak bu resmi texture olarak kullanmamız gerekli.

// Örneğimizdeki donut resmini texture olarak kullanacağız.

IDirect3DDevice9* pd3dDevice;

 

// D3DXCreateTextureFromFileExA fonksiyonu hakkında daha fazla bilgi için lütfen

// buraya basınız.

D3DXCreateTextureFromFileEx( pd3dDevice,"donut.bmp",

320, // Resmin genişliğini elle giriyoruz.

384, // Resmin yüksekliğini elle giriyoruz.

1,  

                            D3DPOOL_DEFAULT,

                            D3DFMT_UNKNOWN,

                            D3DPOOL_DEFAULT,

                           D3DX_DEFAULT,

                            D3DX_DEFAULT,

                            D3DCOLOR_COLORVALUE(0.0f,0.0f,0.0f,1.0f),

                            NULL,

                            NULL,

                            &g_SpriteTexture );

 

pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);

pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);

 

 

 

D3DXCreateSprite( pd3dDevice, &g_Sprite );

 

 

 

// Bu aşamada donut.bmp isimli resim dosyamızı okuduk ve g_SpriteTexture objemize yükledik.

// Daha sonra g_Sprite objemizi yarattık.

 

 

 

 

// Render

void  RenderFunction( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime )

{

 

// Render Sprite

 

// Sahneyi renderlamaya başlıyoruz

pd3dDevice->BeginScene();

 

// Oyuncumuzun(FPS) Camera World ve View matrix(D3DXMATRIX)                                                                                                                                                                                                                                            // m_CameraWorldMatrix m_CameraViewMatrix                                                                                                                          // Oyuncumuzun kamera pozisyonu ve bakış yönü(D3DXVECTOR3)                                                                                                        // EyePoint                                                                                                                                                       // LookAtPoint

// Spriteımızı 3 boyutlu obje uzayında kullanabilmek için oluşturduğumuz gerekli matrixler

D3DXMATRIXA16    m_SpriteWorldViewMatrix;

D3DXMATRIXA16    m_PositionMatrix;

D3DXMATRIXA16    m_ScalingMatrix;

D3DXMATRIXA16    m_RotationMatrix;

 

 

// Spriteın pozisyon ve merkez koordinatları

D3DXVECTOR3 vPosition( 60.0f, 80.0f, 200.0f );

D3DXVECTOR3 vCenter( 0.0f, 0.0f, 0.0f );

 

// Sprite da animasyon kullanabilmemiz için gerekli olan kare sayısını tutmakda kullanacağımız // static int değişkenimiz. Başlangıçta ilk kareyi renderlamak için // başlangıç değerimiz 0.

static int nFrame = 0;

 

 

// Animasyonda kullanmak için bir dörtgen oluşturuyoruz. Animasyonun her karesinde textureın

// 64 * 64 pixellik bir karesini kullanacağız.

RECT srcRect;

srcRect.top    = (( nFrame / 5 ) * 64);

srcRect.left   = (( nFrame % 5 ) * 64);

srcRect.bottom = srcRect.top  + 64;

srcRect.right  = srcRect.left + 64;

 

// Billboarding

// Billboarding yapmanın birden fazla yolu vardır. Spriteınızı doğrudan kamera poziyonuna göre döndürebilirsiniz. Ancak burada hem daha kolay olduğu hemde daha   // rahat kavrandığı için basit bir hesaplama ile spriteın ne yönde ne kadar döneceğini bulup bunu uygulayacağız.  Ancak şunu söylemekde yarar var ki               // kullanacağımız trigonometrik hesaplamalar biraz fazla  işlem anlamına gelmektedir ve çok sayıda sprite kullanılırken işlem yükü bakımından çok uygun bir yöntem // olmamaktadır. Bakış yönümüzden pozisyonumuzu çıkartarak dir vektörünü buluruz.

D3DXVECTOR3 vDir = LookAtPoint – EyePoint;

 

// Eğer ki vDir vektörünün x değeri 0 dan büyükse spriteımızı y ekseni etrafında kod da görüldüğü gibi çeviririz.

if( vDir.x > 0.0f )

D3DXMatrixRotationY( &m_RotationMatrix, -atanf(vDir.z/vDir.x)+D3DX_PI/2 );

// Eğerki değer 0 dan küçük ise bu sefer sprite ters yönde döner.

else

D3DXMatrixRotationY( &m_RotationMatrix, -atanf(vDir.z/vDir.x)-D3DX_PI/2 );

 

 

// Sprite Matriximizi kuruyoruz  

// Spriteın 3 boyutlu pozisyon koordinatı (vektörel)

D3DXMatrixTranslation( &mPositionMatrix, vPosition.x, vPosition.y, vPosition.z );

// Spriteın ScalingMatrixi. Bu spriteın boyutunu belirler. Spriteımızı WorldMatrix e göre scale etmeliyiz. Aksi takdirde sprite çok büyük yada çok küçük olur.

D3DXMatrixScaling( &m_ScalingMatrix, 0.04f, 0.04f, 0.04f );

 

D3DXMatrixMultiply( &m_PositionMatrix, &m_PositionMatrix, &m_ScalingMatrix );

D3DXMatrixMultiply( &m_PositionMatrix, &m_RotationMatrix, &m_PositionMatrix );

 

 

// Kameramızın World ve View matrixleri ile spriteımızın m_PositionMatrixini kullanarak      // spriteımızın m_SpriteWorldViewMatrixini oluşturuyoruz.

m_SpriteWorldViewMatrix = m_PositionMatrix * m_CameraWorldMatrix * m_CameraViewMatrix;

 

 

// D3DXSPRITE_OBJECTSPACE flagini kullanıyoruz. Bu spriteımızın 2 boyutlu değil 3 boyutlu obje // uzayında olacağı anlamına gelir. D3DXSPRITE_ALPHABLEND flag     // spriteın alphası olduğu anlamına gelir. Textureın siyah kısımları saydam olacak.

g_Sprite ->Begin(  D3DXSPRITE_OBJECTSPACE | D3DXSPRITE_ALPHABLEND | D3DXSPRITE_SORT_DEPTH_BACKTOFRONT );

 

g_Sprite ->SetTransform(&m_SpriteWorldViewMatrix);

g_Sprite ->Draw( g_SpriteTexture, &srcRect, &vCenter, &vPosition, D3DCOLOR_COLORVALUE(1.0f,1.0f,1.0f,1.0f) );

g_Sprite ->End();

 

 

// Sahneyi renderlamayı bitiriyoruz

pd3dDevice->EndScene();

 

 

// Renderlamayı bitirdikden sonra animasyon için kullandığımız zamanı yenilemeliyiz.

 

// fElapsedTime double değişken. Geçen zamanı bildirir.

static float fAnimTimer = 0.0f;

fAnimTimer += fElapsedTime;

 

 

// Eğer AnimTimer 0.01 den büyük ise spriteın renderlanan karesini bir sonrakine geçiririz.

// Bunu yapmak için nFrame e bir ekleriz. Animasyon hızı spriteın kare sayısına göre değişiklik gösterir. Bunun anlamı daha büyük yada daha küçük kare sayısına sahip bir animasyonu olan sprite kullanacaksanız 0.01  // değerini yeni spriteınkine göre değiştirmelisiniz.

if( fAnimTimer > 0.01f )

{

    ++nFrame;

 

// Eğer nFrame animasyonumuzun kare sayısından (5*6) büyük nframe = 0 ilk kareye geri döner.

    if( nFrame > 29 )

    nFrame = 0;

 

    fAnimTimer = 0.0f;

}

 

 

 

}

 

 

 

 

 

// Çıkmadan önce yarattığımız objeleri serbest bırakmalıyız.

// Bu işlem render sonunda değil program çalışmayı bitirmeden önce yapılmalıdır.

SAFE_RELEASE( g_Sprite );

SAFE_RELEASE( g_SpriteTexture );

 
 
Sonuç:

Aşağıda benim motorumdan alınmış ve derste kullanılan donut sprite'ı ile elde edilmiş birkaç ekran görüntüsü var.
 
 
Kodda görmüş olduğunuz gibi her karede sprite'ın sadece bir karesini alpha ile renderlıyoruz ve kamera açısına göre spriteı döndürerek 3 boyutlu bir görünüm elde ediyoruz.

Umarım bu ders sizler için yararlı olmuştur. Bana Bu e-Posta adresi istek dışı postalardan korunmaktadır, görüntülüyebilmek için JavaScript etkinleştirilmelidir adresine mail atarak ulaşabilirsiniz.
Son Güncelleme ( Cuma, 06 Temmuz 2007 11:46 )
  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.