Ogre Kütüphanesi Bölüm-9 Framelistener ve Tamponlanmamış Girdi-1
Geri Dön

Ogre Kütüphanesi Bölüm-9 Framelistener ve Tamponlanmamış Girdi-1

Anasayfa

A. TEORİK DERS


Bu dersimizde ilk olarak OGRE’nin render döngüsüne değineceğiz. Öncelikle izlediğimiz filmlerin verilerinin depolanma mantığından bahsedelim. Ekranda gördüğümüz koşan bir çocuk, ilerleyen bir otomobil herhangi bir görüntü akışı, ardı ardına geçen resimlerle sağlanır. Kameranın yaptığı işlem ise tam olarak saniyede onlarca kez fotoğraf çekmektir. Kameranın yaptığı bu fotoğraflama işlemi kare/saniye olarak belirtilir. Saniye de 25 kare, 30 kare vb. şeklindedir. Peki, bizim oyun tasarımımızla bunun ne ilgisi var?

DirectX ve OpenGL kütüphaneleri’nin render işlemi de tıpkı video kameralar gibidir. Counter Strike oynamayanımız yoktur. Counter Strike’da ve bazı oyunlarda ekranda yazan FPS değeri bizim ekran kartımızın saniyede aldığı kare sayısıdır. Açılımı: Frame Per Second şeklindedir. Eğer FPS 25’in altına düşerse oyunda kasmalar başlar. İlk çıkan kameralı cep telefonlarında video kaydederken oluşan donmalar da tıpkı bunun gibidir.

Temel mantık hemen hemen şu şekildedir: 3 boyutlu sahnemiz oluşturulur. Kamera nesnemizin ayarlarına göre fotoğrafı çekilir. Monitöre gönderilir. Bu işlem FPS değerimiz 25 ise saniye de 25 kez tekrarlanıyordur. İşlemlerin büyük çoğunluğunu ekran kartımız yaparken işlemcimize de biraz işlem düşer.

http://ustaderslik.com/resim/ders/tfpu0.png

3B oyun programlamayı, diğer programlama alanlarından farklı kılan özelliklerden biri de döngülerin çalışma mantığıdır. Bir for döngüsü ya da while döngüsü oluşturduğumuzda çalışma prensibi işlemcinin zamanlamasına göre gerçekleşir. Oysaki 3B oyun programlamada ana döngümüz ekran kartımızın çektiği her bir fotoğrafa göre, yani her bir kareye göre gerçekleşir. Örneğin, FPS değerimiz 25 ise, bunun anlamı saniyede, ekranda 25 kare görüntüleniyordur. Döngü 25 karenin her biri için tekrar çalıştırılır. Örneğin, ilk karede, terimsel adıyla frame’de, a tamsayısının değeri 0 olsun. Oluşturduğumuz döngüde tam sayısının 1 artırılacağını yazıyoruz. Programı çalıştırdıktan sonra bir saniye geçtiğinde, FPS değeri 25 ise a=25, FPS değeri 30 ise a=30 olacaktır.

Peki, bu döngüleri nasıl kullanacağız? Oyuncumuzu hareket ettirdiğimiz tuşları düşünelim. Genelde W-A-S-D tuşlarıyla hareket ettiriyoruz. Döngüye oyuncu nesnemizin konumunun, W tuşuna basınca Z ekseninde 1 azalacağını söylüyoruz. Oyunu çalıştırdık. W tuşuna basılı tutuyoruz. Oyuncumuz ileri doğru yürüyor. Bu kadar!

Bahsettiğimiz render döngüsü OGRE’de FrameListener sınıfıyla sağlanır. İlk üç derste hazırladığımız Ders1, Ders2, Ders3 sınıflarının hepsi Uygulama Sihirbazı’nın düzenlediği BaseApplication sınıfından türetilmişti. BaseApplication sınıfının tanımına bakarsanız, BaseApplication sınıfının türediği sınıflar arasında FrameListener sınıfı da mevcuttur. Yani şu ana kadar biz hep FrameListener sınıfını kullandık. Kodlamadık çünkü gerekli kodlar BaseApplication sınıfında mevcuttu ve override etmediğimiz için bu kodlar kullanıyordu.

FrameListener sınıfı üç fonksiyon barındırır. Bu fonksiyonlar frameStarted, frameRenderingQueued ve frameEnded fonksiyonlarıdır.

http://ustaderslik.com/resim/ders/tfpu7.png

FrameListener, tercüme edersek KareDinleyici, her karede çağrılır. frameStarted fonksiyonu sahnemize tanımladığımız nesneleri, gökyüzünü vb. şeyleri hazırlar, frameRenderingQueued fonksiyonu renderlenen sahne görüntülerini ekranda görüntüler ve yapılacak işlem varsa yapar, frameEnded fonksiyonu da diğer kareye geçilmeden önce yapılacak işlemleri yaparak, daha çok sonraki kareyi etkiler. Bu üç fonksiyon çağrılıp uygulandığı zaman bir sonraki kareye geçilir gerekli kodlar yeniden okunur ve bahsettiğimiz işlemler tekrarlanır. Sonuç olarak FPS değerimiz 25 ise bir saniyede 25 kez bu üç fonksiyon tekrar tekrar çağırılır.

Biz bu derste frameRenderingQueued fonksiyonunu kullanacağız. Az sonra bu fonksiyonu tanımlarken, FrameEvent isimli bir struct ile karşılaşacaksınız. Ne işe yaradığından bahsedelim. Diyelim ki Nvidia veya ATI marka ekran kartı kullanıyorsunuz. OGRE’de boş bir sahneye tek nesne tanımladığınızda FPS değeriniz bir hayli fırlayacaktır. Örneğin FPS değeri 300 olsun. Döngümüzün temel fonksiyonu olan frameRenderingQueued fonksiyonuna tuşa basıldığında nesneyi 15 derece hareket ettirmesini söylüyoruz. FPS değeri 300 olduğu için render döngüsü 1 saniye için nesneyi alacak 4500 derece döndürecek. Her 360 derece tam tur olduğundan nesnemiz 180 derece dönmüş olacak. Bu kesinlikle istemediğimiz bir durum. Yapmak istediğimiz 25 FPS alırken de 300 FPS alırken de nesneyi 15 derece döndürmek. FrameEvent structunun barındırdığı real türündeki ( C++’da Real = float ) timeSinceLastFrame değeri işlemci zamanlamasıyla FPS değeri arasında, son kareden beri geçen zamanı hesaplayarak, bir denklik oluşturacak. Bu sayede tuşa bastığımızda 25 FPS alırken de 300 FPS alırken de nesnemizi 15 derece döndürmüş olacağız.

Dönüşüm boşluklarından bahsedelim. Az sonra oluşturacağımız sahneye bir ninja nesnesi ekleyeceğiz. I-J-K-L tuşlarını tıpkı W-A-S-D tuşları gibi kullanıp ninja nesnemizi hareket ettireceğiz. Shift + J ve Shift + L tuş ikilileriyle ninja nesnemizi kendi etrafında döndüreceğiz. Oluşacak olan sorun şöyledir: Diyelim ki, sahneye bir ninja nesnesi tanımladık. (Resim 1, sahnemizin kuş bakışının temsili resmidir.) Sonra tanımladığımız ninjayı, I-J-K-L tuşlarını kullanarak, hareket ettirdik. (Resim 2) ninjayı kendi etrafında döndürmek için Shift+J tuş ikilisini kullandık. Tam bu sırada bir sorunla karşılaşırız. ninja’mız kendi etrafında dönmek yerine (yani kendi SN’sinin etrafında dönmek yerine) SM nesnesinin, yani mSceneMgr’nin SN’sinin etrafında döner. (mSceneMgr SN’si orijine kurulu olduğu için orijinin etrafında döner.) (Resim 3)

Her SN’nin bağlı olduğu SN’nin etrafında dönmesinin nedeni, bağlı olduğu SN’yi merkez kabul ederek ona göre işlem yapmasıdır. Eğer bir SN, bağlı olduğu SN’nin etrafına dönüyorsa dönüşüm boşluğu, TS_WORLD adlandırılır. Bu varsayılan tanımlamadır. Eğer döndürme işleminden sonra I tuşuna basarak ninjanın ileri gitmesini istersek, tıpkı döndürme işleminde olduğu gibi, kendi önüne doğru ilerlemez, merkez aldığı nokta orijin olduğu için yan yan ilerler.

TS_WORLD kodunun açılımı: TransformSpace_World şeklindedir. Bunu Dünya’nın dönüşüm boşluğu olarak çevirebiliriz. Eğer bir SN’nin dönüşüm boşluğunu TS_LOCAL olarak belirlersek, SN’ye yapılan tüm işlemler onun merkezine göre düzenlenir. Bir bakıma kendisini orijin olarak kabul eder. TS_LOCAL kodunu da bölgesel dönüşüm boşluğu olarak çevirebiliriz. Biz ninja nesnemizde TS_LOCAL dönüşüm boşluğunu kullanırsak, döndürme işlemi ninja nesnemizin kendisine göre yapılacak, olaşan sorunlar ortadan kalkacaktır. (Resim 4)

http://ustaderslik.com/resim/ders/tfpuj.png Resim-1
http://ustaderslik.com/resim/ders/tfpul.png Resim-2
http://ustaderslik.com/resim/ders/tfpup.png Resim-3
http://ustaderslik.com/resim/ders/tfpur.png Resim-4

Son olarak UnBufferred Input, Türkçe anlamıyla Tamponlanmamış Girdi konusuna değinelim. Burada Input(Girdi) olarak isimlendirilen işlem, klavyede veya farede bir tuşa basıldığında ya da fare hareket ettirildiğinde bize gelen mesajdır. Yani klavyeden bir tuşa basıldığında bilgisayarımız bir bilgi almış olur. Örneğin “A tuşuna basıldı!” şeklinde olsun. Bu mesaja girdi adı verilir. Aynı şekilde bilgisayara bağladığımız joystick’lerden, gamepad’lerden de girdi alınır.

OGRE, girdi işlemlerini OIS(Object-Oriented Input System) kütüphanesiyle gerçekleştirir. OIS, Türkçe anlamıyla Nesne-Yönelimli Girdi Sistemi’dir. Eğer isterseniz farklı bir kütüphane de kullanabilirsiniz.

Az sonra hazırlayacağımız sahneye bir ışık kaynağı ekleyeceğiz. Farenin sol tuşuna tıkladığımızda ışık kapalıysa açılacak, açıksa kapanacak. Yani ışığı aç/kapat işlemi yapacağız. Ama bu işlemi yaparken bir sorun oluşacak. FPS değerimiz eğer 30 ise farenin tuşuna saniyenin otuzda biri sürede basıp çekmemiz lazım! “Nasıl yani?” diyeceksiniz. Bilgisayarımız işlemleri çok çok kısa sürede gerçekleştirdiği için bizim farenin tuşuna parmağımızı bir kez basıp çekmemiz, söz gelimi 15 kare boyunca sürüyor. İstediğiniz kadar hızlı basıp çekmeyi deneyin. Kesinlikle parmağınız, renderlenen bir 1 kare’nin ekranda kaldığı süreden, daha uzun süre, fareye basılı kalacak. Bu durumda yaptığımız işlem şu şekilde olacak: “1.Kare: Aç/Kapat, 2.Kare: Aç/Kapat, 3.Kare: Aç/Kapat, 4.Kare: Aç/Kapat, 5.Kare: Aç/Kapat, 6.Kare: Aç/Kapat, 7.Kare: Aç/Kapat, 8.Kare: Aç/Kapat, ...”. Sonuç olarak ışığı açtınız mı kapattınız mı belli olmayacak.

Bahsettiğimiz ardı ardına girdi alma sorununu çözmek için bir önceki karede kullandığımız tuşa basılıp basılmadığını, her karede, sorgulayacağız. Tamponlanmamış Girdinin tam olarak ne olduğunu bir sonraki ders olan Tamponlanmış Girdi dersini inceleyince çok kolay anlayacaksınız. Bu yüzden bu derste Tamponlanmamış Girdi’nin teknik olarak ne olduğuna değinmiyoruz. Ama küçük bir bilgi verelim; her karede ayarlanan tuşun basılıp-basılmadığını kontrol ettiğimiz için yaptığımız girdi işlemleri, tamponlanmamış girdi adını alıyor.



Anasayfa

Tüm Hakları Saklıdır. ©Arleone 2013-UstaDerslik