Ogre3D + Hydrax Uygulamam:
3DsMax Çalışmalarım:

Üstteki resim Xavyiy'nin hazırladığı Hydrax Demo örneğidir. Onu derlemeyi başardığım için projelerimde bundan sonra Hydrax'da yer alacaktır :)
Projem bu halindeyken ise sadece birkaç nesne eklenmesinden ibaretti ancak karakterin ne dinamik hareketleri mevcuttu ne de deniz veya göl gibisinden bir etkili bir ortam... Sadece kuru bir yüzey ve üzerinde hareket eden sabit bir karakter :)
cout<<"\n\n\n\n buradayim 01 \n\n\n\n";
planeEnt->setMaterialName("Examples/Rockwall-12345");
cout<<"\n\n\n\n buradayim 02 \n\n\n\n";
material Examples/CloudyNoonSkyBox
{technique{pass{lighting offdepth_write offtexture_unit{cubic_texture cloudy_noon.jpg separateUVtex_address_mode clamp}}}
}
ExampleFrameListener(
RenderWindow* win,
Camera* cam,
bool bufferedKeys = false,
bool bufferedMouse = false,
bool bufferedJoy = false
):
Devam edelim; "mDebugOverlay = OverlayManager :: getSingleton() . getByName ("Core/DebugOverlay");" satırı, ekrandaki debug menüsü ile logoyu içerisinde barındıran "Core/DebugOverlay" değerini almıştır ve "showDebugOverlay(true);" fonksiyonuna da parametre olarak true değeri gönderilmiştir. "showDebugOverlay();" fonksiyonu da "mDebugOverlay" değişkenini gösterip kaybedecek şekilde tasarlanmıştır. Bu tasarım şekliyle de kontrol kolaylığı sağlanmıştır. Bu kolaylıktan, klavye tuşlarının ayarlandığı fonksiyona gelince bahsedeceğim.
mKeyboard = static_cast<OIS::Keyboard*>(mInputManager->createInputObject( OIS::OISKeyboard, bufferedKeys ));
mMouse = static_cast<OIS::Mouse*>(mInputManager->createInputObject( OIS::OISMouse, bufferedMouse ));
try
{
mJoy = static_cast<OIS::JoyStick*>(mInputManager->createInputObject( OIS::OISJoyStick, bufferedJoy ));
}
"virtual void updateStats(void)" fonksiyonu her karenin renderleme işlemi bitttikten sonra o karedeki hesaplanan değerlerin ( FPS değerleri ile ekranda o andaki hesaplanan üçgen sayısı gibi ) güncellenmesini sağlamaktadır.// eğer pencere kapanırsa false değer dönder ve fonksiyonu bitir.
if(mWindow->isClosed()) return false;
// klavyeyi ve fareyi sürekli olarak yakala
mKeyboard->capture();
mMouse->capture();
// eğer klavye ve fare kontrolü ExampleFrameListener'a aitse;
if( !mMouse->buffered() || !mKeyboard->buffered() || !buffJ )
{moveCamera();
...
.
}
// eğer klavye kontrolü Listener'da ise ve klavye tuşlarının ayarlandığı
// "processUnbufferedKeyInput" fonksiyonundan false değer dönüyorsa false
// değer dönder ve programı bitir.
if( !mKeyboard->buffered() )
if( processUnbufferedKeyInput(evt) == false )
return false;
// klavyedeki mantık ile aynı şekilde işlemekte.
if( !mMouse->buffered() )
if( processUnbufferedMouseInput(evt) == false )
return false;
Buradaki işlemlerin haricindeki diğer işlemler de hız kontrolü ile alakalıdır. O yüzden pek girmedim. Ne ben tam olarak hatim etmiş değilim ne de fonksiyonun hız mantığını kurmak ile ilgileniyorum bu yazıda. O yüzden devam ediyorum.// Kameranın bağlı olduğu vektörü z konumunda belirlenen mMoveScale değeri kadar hareket ettirir.
if(mKeyboard->isKeyDown(OIS::KC_UP) || mKeyboard->isKeyDown(OIS::KC_W) )
// Aynı şekilde ancak bu sefer x konumunda hareket ettirir, dikkat çevirmez.
if(mKeyboard->isKeyDown(OIS::KC_A))
// Kameranın "mCamera->yaw(-mRotScale);" kod satırı sayesinde sağa dönmesini sağlar
if(mKeyboard->isKeyDown(OIS::KC_RIGHT))
// Çıkışı sağlar
if(mKeyboard->isKeyDown(OIS::KC_ESCAPE) || mKeyboard->isKeyDown(OIS::KC_Q) )
// Debug penceresini gizler veya gösterir
if(mKeyboard->isKeyDown(OIS::KC_F) && mTimeUntilNextToggle <= 0 )
// Filtreler arasında değişim sağlar.
if(mKeyboard->isKeyDown(OIS::KC_T) && mTimeUntilNextToggle <= 0 )
// Ekranın fotoğrafını çeker
if(mKeyboard->isKeyDown(OIS::KC_SYSRQ) && mTimeUntilNextToggle <= 0)
// Ekrandaki nesneleri Solid, Wire ve Point olarak gösterir.
if(mKeyboard->isKeyDown(OIS::KC_R) && mTimeUntilNextToggle <=0)
// Kamera hakkında bazı bilgileri verir.
if(mKeyboard->isKeyDown(OIS::KC_P) && mTimeUntilNextToggle <= 0)
Buna benzer iki tane daha bolca karşılaşacağınız değişken var. Bunlar "timeSinceLastEvent" ile "timeSinceLastFrame"dir. timeSinceLastEvent, değişkeni iki olay arasında geçen süreyi saniye cinsinden ifade etmektedir. timeSinceLastFrame de frameleri ,o anlık ekran görüntüsünü , renderlerkenki geçen süreyi temsil etmekte. Bu süre ne kadar kısa olursa projeniz de o kadar hızlı olmuştur.const OIS::MouseState &ms = mMouse->getMouseState();
if( ms.buttonDown( OIS::MB_Right ) )
"ms" farenin durumunu alıyor ve if şartı ile de bu durum kontrol ediliyor. Eğer ki sağ tuşa ( OIS::MB_Right ) basarsak ( buttonDown ) kameramız farenin konumuna göre yukarı - aşağı veya sağa - sola şeklide hareket edecek, ki bunu sağlayan mTranslateVector.x ile mTranslateVector.y'nin kullanımıdır, basmazsak da kameranın moveCamera() fonksiyonundaki " mCamera-> yaw (mRotX); mCamera-> pitch (mRotY);" satırlarının mRotX ile mRotY parametrelerini değiştirmiş oluruz. Bu şekilde de kameramız bulunduğu konumda farenin yönelimine göre bakış açısını değiştirecektir.Diğer bir önemli dosyamız da “ExampleApplication.h”tır. Bu dosya ile birlikte çalışacak diğer önemli bir dosya da “ExampleFrameListener.h” dosyasıdır. Bu iki dosya daha önceden de bahsettiğim gibi bazı temel değişkenleri içermektedirler. Ancak bu iki dosya arasında temel bir farklılık söz konusudur. Birinci dosyamız yani ExampleApplication dosyamız projemizinde yer almasını istediğimiz temel nesneleri yerleştirdiğimiz kısımken, ExampleFrameListener dosyamız da bu nesnelerin nasıl ve neye göre hareket edeceklerini tanımladığımız kısımdır diyebiliriz. Ancak bu zaruri bir durum değildir. Yani projenizin iki sınıfı da miras alıp birincisinde uygulama diğerinde de hareket olacak şekilde zorlamak zorunda değilsiniz. Yani daha ileri bir seviye Ogre’ci olduğunuzda bunu halledebilecek konuma erişirsiniz ama halihazırda ben de yapamıyorum o yüzden projenizin uygulama kısmını ExampleApplication‘u miras aldırarak, hareket kısmını da ExampleFrameListener‘ı miras aldırarak ilerlemek mantıklı olacaktır.
Şimdi ExampleApplication dosyasının içindeki ExampleApplication sınıfında tanımlanmış bazı değişken ve fonksiyonlara bir göz atalım şimdi. İlk önce “protected” alanda tanımlanmış olan değişkenlere bir göz atalım.
Bunlardan bazılarını bu yazı dizisinin birinci bölümünde görmüştük. Şimdi görmediklerimizle devam edelim.
“ExampleFrameListener* mFrameListener;” ExampleFrameListener yukarıda bahsettiğim gibi hareketlerin olduğu sınıf ve bu kod satırı sayesinde de o sınıftan “mFrameListener” adı altında bir değişken üretmiş olduk.
“Ogre::String mResourcePath;“ satırı da bizim kaynakları nerede tutacağımızı elle yazmamız için string sınıfından üretilmiş bir değişkenden ibarettir ve string ifadeleri tutmaktan öteye pek bir işlevi yoktur. ExampleApplication sınıfının constructor‘unda tanımlı olan mResourcePath‘ın değeri eğer ki uygulamanın çalıştığı platform MAC OS değilse ” ” olacak şekilde ayarlanmış.
Şimdi ExampleApplication’daki değişkenleri bitirdiğimize göre sıra geldi fonksiyonlara.
ExampleApplication sınıfında daha öncedenbahsettiğim go() fonksiyonu tanımlıdır. Bu fonksiyon render işleminin yapılmasını sağlamaktadır. Ancak bu işlem için hem root sınıfından üretilmiş bir değişkene yani mRoot‘a hem de root sınıfının bir fonksiyonu olan startRendering() fonksiyonuna ihtiyaç vardır( Örnek Resim 01 ) . Go() fonksiyonu setup() fonksiyonundan false dönmesi dahilinde bitirlecek şekilde tasarlanmış. Böylece setup() çalışmadan renderleme işlemi de çalışmayacaktır.
Şimdi de setup fonksiyonuna bir göz atalım ( “virtual bool setup(void)” ) Bu fonksiyon ilk önce mRoot değişkenine değer atayarak başlamış. Bu değer atama sırasında pluginlerin tutulduğu “plugin.cfg” dosyası ile birlikte ekran ayarlamalarını yaptığınız diyalog ekranının çıktılarını tutan “ogre.cfg” dosyası ve tüm hareketlerin ( kayıt edilmesi istenilen hareketlerin ) kayıtlarınıtutan “ogre.log” dosyası değişken olarak eklenmiş:
mRoot = OGRE_NEW Root(pluginsPath,
mResourcePath + “ogre.cfg”, mResourcePath + “Ogre.log”);
mRoot değişkeniyle işlemler bittikten sonra setup() fonksiyonunun devamına baktığımızda aşağıda çalıştırdığı bazı fonkisyonları görebilirsiniz.
” chooseSceneManager(); “ fonksiyonu sahne yöneticisinin seçimini yapmak için yapılandırılmış bir fonksiyondur. ” mSceneMgr = mRoot->createSceneManager(ST_GENERIC, “ExampleSMInstance”); ” Satırında da görülebileceği gibi mRoot değişkenine createSceneManager() fonksiyonu sayesinde belirlenen değişkenler çerçevesinde sahne yöneticimizi oluşturmuş bulunmakta. Fonksiyona ilk parametre olarak girilen değişkenler şunlar olabilir:
İkinci parametre olarak bir isim girmenizde fayda var ancak boş bırakırsanız da otomatik bir isimlendirme yapılacaktır fonksiyon tarafından.
“virtual void createCamera(void)” fonksiyonunda mCamera değişkenimiz sahnemize “PlayerCam” adı altında yaratılmıştır. Bu isimlendirme işleminde tek dikkat etmeniz gereken husus başka bir nesnenin adı ile çakışmamasıdır. Kameramızın konumu Z ekseninde 500 br öteye çekilmiştir ve yine Z ekseninde arkaya bakması için -300‘e bakması söylenmiştir.
“virtual void createViewports(void)” fonksiyonu ise kameranın görüş alanını ayarlayan fonksiyondur desem mantıklı olur sanırım, şöyle ki; kameranın görüntüsünün taraf oranı gibi özellikleri ( 4:3, 16:9 gibi ) viewport‘un özellikleridir.
Render sınıfından üretilen mWindow değişkeni, viewport‘tan üretilen vp değişkenine atanmış. ” vp->setBackgroundColour (ColourValue(0,0,0)); “kod satırı ile de evrenimizin arkaplan kaplaması atanmazsa diye arkaplanın rengini siyah yapılmıştır. mCamera-> setAspectRatio( Real( vp->getActualWidth()) / Real( vp->getActualHeight())); kod satırı ekranın yüksekliğini ve genişliğini alıp bunları kameranın taraf oranına eklenmiş oluyor. Yan taraftaki resim için iki farlı taraf oranı değeri girilmiştir ve arkaplan rengi için de turuncu rengi ayarlanmıştır( mCamera->setAspectRatio(16/9) - sol, mCamera->setAspectRatio(2/1) - sağ, ColourValue(1,0.5,0) - Arkaplan Renk Değerleri).
“virtual void createScene(void) = 0;“, işte bu fonksiyona, özellikle de fonksiyonun sıfıra eşitlenmesine dikkat! “createScene” bizim sahnemizi oluşturduğumuz fonksiyondur ancak fonksiyon boş olarak tanımlanmış, içeriğini doldurmak da miras alan sınıfa kalmıştır. Bu benim de yeni öğrendiğim bir konu oldu ama bu tarz fonksiyonların adı “Saf Sanal Fonksiyonlar”dır ve konu hakkında daha detaylı bilgi almak isteyenleri Esat‘ın bloguna yönlendirmemde sakınca yoktur sanırım :) Code::Blocks’da yeni bir proje oluşturduğunuz zaman ExampleApplication sınıfını miras alan sizin yeni projeniz bu fonksiyonu protected alanda içi temel birkaç nesne ile doldurmuş şekilde sunuyor.
“virtual void createFrameListener(void)“ olarak tanımlı foknsiyon da bizim sahnemizde nesnelerin sürekliliğinin sağlandığı sınıfımızdır. Projelerinizde yapı gereği ExampleApplication sınıfını miras alan sizin Application sınıfınız ile ExampleFrameListener‘ı miras alan Listener sınıflarınızın olması mantıklı olacaktır. Şimdi süreklilik ile kastımı ufak bir proje örneğiyle şekillendirmeye çalışayım. Diyelim ki siz Application sınıfınızda içerisinde ana karakteriniz ve onun kullanacağı taşıtı ile birlikte ev, ağaç, çiçek vb nesnleler tanımlayıp sahneye yerleştirdiniz.Ancak bunlardan kimilerinin hareketlenmesine ihtiyacınız var, örneğin taşıt ile karakter gibi hatta çiçeklerin salınım hareketi bile olabilir sanki rüzgar esiyormuş gibi. Bunu ister bu nesneleri global birer değişken olarak tanımlayacak şekilde yapabiliriz, istersek de Application sınıfında tanımlayıp Listener sınıfına çalıştıracağımız fonksiyon aracılığıyla gönderebiliriz. Bu çalışacak olan fonksiyon da createFrameListener fonksiyonudur. Burada “mFrameListener= new ExampleFrameListener( mWindow, mCamera );” kod satırı ile mWindow ile mCamera değişkenleri ExampleFrameListener sınıfına gönderiliyor. Dediğim gibi istersek buraya yeni bir değişken daha ekleriz, bu örneğin karakterimizin sceneNode değişkeni olabilir, ancak buna uygun bir şekilde ExampleApplicationListener sınıfını da düzenlememiz gerekir. Biz bu yüzden bu temel sınıflarda değişiklik yapmadan kendi yarattığımız Application ve Listener sınıflarında bahsettiğim değişiklikleir yapıyoruz. Bu kısımlara ilerleyen yazılarda devam edeceğim. Şimdilik amaç temel mantığı kazandırmak olduğu için teorik olarak devam ediyorum. Bir şekilde Listener sınıfımıza bizim karakterimizin sceneNode‘unu göndermeyi başardık diyelim, şimdi bize bu karakterin hangi durumda nasıl hareket edeceğini anlatmak kalıyor tek yapılması gereken. Örneğin klavyeden “ W “ya basınca ileri hareket etmesi gibi…
ExampleApplication hakkında bu kadar temel bilgi yeterli sanırım. Sıra geldi o zaman ExampleFrameListener‘a… :)
Bize herşeyden önce “Ogre.h” adlı dosyamız lazım. Bu sınıf içerisinde diğer “header” dosyalarını “include” etmektedir. Bu sayede “Ogre.h” dosyamız bizim en temel header dosyamızdır.
“OgreRoot.h” dosyasaında tanımlı olan Root sınıfı bu yapının en temel kök dizinini oluşturur. “Root *mRoot;” kod satırı sayesinde bu sınıfımızdan bir değişken üretmiş olacağız. Bu kök dizini mantığını iyice dallanmış bir ağaç gibi düşünebilirsiniz. Zira mRoot bizim köklerimiz olurken Plugin‘ler ve Config‘ler ile beslenmektedir. Scene Manager‘ımız ise bizim ağacımızın gövdesi olurken dallarımız yerine de Scene Node‘lar gelmektedir. Scene Node‘lar da Entity‘leri tutmaktadırlar.
Şimdi bu yukarıda gördüğünüz sınıflar ile daha fazlasına ve bazı fonksiyonlara sırasıyla el atalım.
İlk önce ağacımızın gövdesi olan sınıf yapısına bakalım, yani Scene Manager‘a. “OgreSceneManager.h” dosyasında bulunan bu sınıf için, sahneye eklenecek olan tüm nesneleri tutan ana yapıdır diyebilirim sanırım. “SceneManager* mSceneMgr;“ kod satırı ile sahnemizin yöneticisi olan sınıfımızdan bir değişken üretmiş oluruz.
“OgreEntity.h” dosyasında bulunan sınıf olan Entity sınıfı bizim mesh ( model ) dosyalarımızı tutacak olan sınıftır. Ancak Entity sadece modeli tutmakla yetinir. Ne onun boyutuna karışır ne konumuna ne de başka özelliklerine. Ancak bazı özellikleri için modelimizin Entity özellikleri bize lazım olacaktır. “Entity *mEntity;” kod satırı ile bu sınıftan bir değişken üretmiş olacağız.
Şimdi modelin bahsettiğim konum ve boyut özelliklerini ayarlayacak olan sınıfımıza geldi sıra. O da “OgreSceneNode.h” dosyasında bulunan “Scene Node” sınıfımız. Bu sınıftan “SceneNode *mSceneNode;“ kod satırı ile üreteceğimiz değişkeni Entity‘den ürettiğimiz değişkene bağla diyerek modelimizi tutan mEntity değişkenini mSceneNode değişkenine bağlamış oluyoruz. Bu bağlama işlemi ise şu şekilde yapılmaktadır: “mSceneNode->attachObject(mEntity); “
Buraya kadar herşey tamamsa şimdi hoş bir özelliği sağlayacak olan sınıfa geldi sıra. Şöyle ki; ekranı isterseniz birden fazla parçaya bölebilir ve bölünen ekranlara da istediğiniz kameranın görüş açısını ekleyebilirsiniz. Ancak bütün bunlar için bize “OgreRenderWindows.h” dosyasında bulunan “RenderWindow” sınıfı lazım. “RenderWindow* mWindow;“ satırı ile ihtiyacımız olan değşkenimizi üretmiş olacağız.
“Camera” sınıfı tahmin edebileceğiniz gibi kameraların sınıfıdır ve bu ” Camera* mCamera; “ kod satırı ile bir adet kamera üretilmiştir. Ama bu kamera henüz bir sahneye veya nesneye bağlanmış konumda değildir. Ancak tamınlanmış standart ayarlar geçerlidir. Örneğin konumu X,Y,Z olarak sıfırdır.
Sahnemizin ışığını oluşturacak olan sınıfımız da tahmin edebileceğiniz gibi “OgreLight.h” dosyasında bulunan “Light” sınıfıdır. “Light *mLight;” şeklinde bir ışık değişken üretilebilir. Bir önceki yazı olan Ogre3D’deki İlk Projemizi Anlamlandırma adlı yazıda ışığın temel fonksiyonlarından setDiffuseColour()” ve “setSpecularColour()” dan bahsetmiştim ancak ışık türünden bahsetmemiştim. Işığımızın üç farklı tipi var. Bunlardan “LT_POINT” değişkeni her tarafa ışık yayabilen bir kaynak niteliği kazandırmaktadır bizin ışık nesnemize. “LT_SPOT” değişkeni ışığımızı bir spot ( koni misali giderek büyüyüen ) ışık haline döndermektedir. “LT_DIRECTIONAL” değişkeni de doğrulusu ve yarıçapı değişmeden ilerleyen bir ışık kaynağına dönüştürür. Son iki tip için de el feneri misali ışık kaynağının baktığı bir yer olması gerekmektedir. Bu da kamera ve ışık için de geçerli bir fonksiyon olan lookAt() fonksiyonu sayesinde olmaktadır. Bu fonksiyonu yazının devamında anlatacağım.
Ogre ekibi Double tipinde “Real” adı altında kendi değişken tipini tanımlamışlar. Sürekli olarak Real tipinde değişkenler üretildiğini görebilirsiniz ki bende alıştım açıkcası bu tipi kullanmaya
“OgreVector3.h” dosyasında bulunan Vector3 sınıfı da oldukça kullanışlı bir sınıftır. Vector3 sınıfından üretilebilecek bir değişkenin X,Y ve Z şeklinde alt parametreleri de bulunur. Örneğin “Vector3 yeniDegisken;“ diye bir değişken ürettiğimizde ” yeniDegisken.x=100; yeniDegisken.z=50; ” demek ile bu vectörün konumunu belirten konuma (” X=100, Y=0, Z=50 “) çekmiş olduk. Ancak Vector3 sınıfından değişken üretmek yerinde yeri geldiğinde ” Vector3(100,0,50) ” şeklinde de kullanmak da tercih edilebilir.
Herşeyden önce dikkat edilmesi gereken bir nokta olarak bahsedyorum, sınıflardan değişken üretmekten ibaret değildir olay. Önemli olan üretilen değişkenlerin ayarlarını yapabilmek ve bu değişkenlere bağlanacak nesneleri ayarlamak ve de onların konumlarını doğru belirleyebilmektir.
Şimdilik bu temel sınıflar iş görür niteliktedir. Sırada bazı temel fonksiyonlarda sıra.
yaw(), pitch() ve roll() fonksiyonları ilk anlatacağım fonksiyon serisi olacaktır. Bu fonksiyonlardan her biri kendine ait olan eksen etrafında nesneleri döndermektedirler.
“ yaw(Degree(90)); “ örnek kodunda da görebileceğiniz gibi Y ekseninde 90 derece döndürmüştür. Degree sınıfı ile Radian sınıfı bu fonksiyonlar için parametrelerinde düzenleme yapmanızla uğraşmamanız için varlar. Bu sınıfları ister değişken üretmek için isterseniz de fonksiyon olarak kullanabilirsiniz. Modeli çevirme işlemi bahsettiğim gibi SceneNode’dan ürettiğimiz değişken üzerinden gerçekleşir. Örneğin şu şekilde; “mSceneNode->yaw(Degree(-270));”
Nesneleri ölçeklendirme işlemi ise yine SceneNode‘a etkiyen scale(X,Y,Z) fonksiyonu ile gerçekleşir. Parametre olarak 1 girildiği zamna ölçeklendirmede herhangi bir değişiklik olmaz çünkü 1 orjinal boyutu temsil eder. sıfır ve üstü değerleri parametre olarak alabilir. Örneğin “mSceneNode->scale(15 , .5 , 2.86f );“ şeklinde parametreler alabilir. Model belirtilen eksende parametre olarak verilen sayı kadar büyür.
Nesnelerin konumunun ayarlanmasını ise iki fonksiyon ile gerçekleştirilebilir. Bunlardan birisi “translate“, diğeri de “setPosition“‘dur. “translate” parametre olarak verilen değer kadar ilerletirken “setPosition” parametre olarak verilen konuma nesnemizi yerleştirir. Örneğin;
Şimdi konum belirledik ölçeklendirme yaptık ancak söz konus nesnemiz bir kamera olursa işler biraz daha farklılaşabiliyor. Zira bir kameranın konumu kadar baktığı yeri de önemlidir.Bu duruma çözüm olacak olan fonksiyon da lookAt(X, Y, Z) fonksiyonudur. Örneğin;
mCamera->setPosition( 300,500,400);
mCamera->lookAt(0,100,0);
Şeklinde bir ayarlama yaptığımızı düşünüysek kamerayı 300(X) – 500 (Y) – 400 (Z) konumuna getirdik ve bu kameranın orjinden uzaklığı bu sayede 500√2 br uzakta oldu. Ancak orjinden 100br yukarı bakacak şekilde ayarlandı.
“mSceneMgr->setAmbientLight(ColourValue(1, 1, 1));“ kod satırı sayesinde ortamın ışığı ayarlanmaktadır. parametre olarak girilen değerler 0-1 arası değişen değerler olmakla birlikte 1 varlığı 0 yokluğu temsil etmektedir. örnekte RGB tonlarının hepsine 1 değeri parametre olarak girilmiş. Bu durumda ortam aydınlık olacaktır ancak 0 olduğu taktirde ortam zifiri karanlık olacaktır.
Evren tipi olarak standart Code::Blocks Ogre3D projesinde setSkyBox() fonksiyonu kullanılmaktadr. Temelde üç farklı seçenek söz konusudur yine daha önce bahsettiğim gibi. Bunlar:
SkyBox evreni, temelinde iç yüzeyi boyalı bir kutudan ibarettir. Ancak biz bu kutunun tam orta noktasında yer almaktayız.
SkyDome yine aynı mantıkla çalışmaktadır ancak bu sefer şekil üst yarım küre şeklindedir.
SkyPlane‘de ise durum biraz daha ilginçleşir. Bu bildiğiniz bir düzlemden ibarettir ve özel durumlar çerçevesinde kullanılmak mantıklıdır. Nedir bu özel durumlar dersek; Örneğin derin bir kuyudan yukarı baktığımız zaman gördüğümüz bulutlar buna örnek olabilir. Çünkü kuyudayken bizim için altımızda ne olduğu önemli değildir veya etrafımızda… Önemli olan üst tarafımızda gördüğümüzdür.
Şimdilik temel sınıflar ve fonksiyonlar için anlatabileceklerim bu kadar. Bu yazı serisinin devamında “ExampleApplication.h” sınıfını ele alacaktır.
//———————————-ORNEK KOD ———————————–
#include
#include
{
public:
SampleApp()
{}
protected:
void createScene(void)
{
mSceneMgr->setSkyBox(true, “Examples/CloudyNoonSkyBox”);
Light* myLight = mSceneMgr->createLight(“Light0″);
myLight->setType(Light::LT_POINT);
myLight->setPosition(0, 40, 0);
myLight->setDiffuseColour(1, 1, 1);
myLight->setSpecularColour(1, 1, 1);
}
};
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#define WIN32_LEAN_AND_MEAN
#include “windows.h”
INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
#else
int main(int argc, char **argv)
#endif
{
SampleApp app;
try
{
app.go();
}
catch( Exception& e )
{
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
MessageBox( NULL, e.getFullDescription().c_str(), “An exception has occured!”, MB_OK | MB_ICONERROR | MB_TASKMODAL);
#else
std::cerr << “An exception has occured: “ << e.getFullDescription();
#endif
}
return 0;
}
//———————————————————————————————
Örnek projemizi oluşturduk ve yukarıdaki kod serisini elde ettik. Şimdi bunları inceleyelim. Bildiğiniz gibi ilk önce main fonksiyonu çalışır ve biz de en alt serideki main() fonksiyonunu bulduk. “SampleApp app;” kodu “SampleApp” sınıfından üretilmiş “app” değişkeni demektir. Try – Catch bloğu arasında “app.go();” tüm işlemi başlatan koddur. Eğer bu süreç başarısızlıkla sonuçlanırsa konsol ekranında hata mesajını verecek olan uyarı kısmı da devamında bulunmaktadır.
Buraya kadar herşey tamamsa, bu “SampleApp” sınıfında ne varmış şimdi ona göz atalım. “class SampleApp : public ExampleApplication” ile Sample sınıfı oluşturulmuş ve Ogre3D ekibinin hazırladığı “ExampleApplication” sınıfı miras alınmıştır. İleriki yazılarda bu sınıf hakkında bilgi vereceğim. O yüzden şimdilik bu sınıfın varlığını ve içinde temel bazı değişkenlerin ( mSceneMgr gibi ) ve fonksiyonların ( go( ) fonksiyonu gibi ) varlığını bilmeniz yeterli olacaktır.
“public” kısmındaki SampleApp() constructor‘unun içinde herhangi bir değişkene atama yapılmamış. Bu biraz keyfi bir durum isterseniz herhangi bir alana, bu public de olabilir private de protected da, bir değişken tanımlayıp, constructor‘una ilk atamayı yapabilir ve fonksiyonlar içerisinde bu değişkenleri kullanabilirsiniz.
“protected” alandaki “void createScene(void)“ fonksiyonu ExapmleApplication fonksiyonundan miras alınma bir fonksiyon olup işlemlerimizi burada yapacağız.
“mSceneMgr->setSkyBox(true, “Examples/CloudyNoonSkyBox”);” satırı bize şu anda gördüğünüz ortamı vermekte. Üç tür ortam tipi var ( skyBox, SkyDome ve SkyPlane şeklinde ) ancak şimdilik bunlara değinmeyeceğim. Bu ortamın kaplama malzemesi ise “Examples/CloudyNoonSkyBox” tır. “mSceneMgr” ise “SceneManager” sınıfından türetilmiş bir değişkendir. Bu değişkende sahnedeki ışıklar, nesneler, cameralar vb tüm varlıklar tutulur. Bu kod serisinde de “mSceneMgr” değişkeni ortamı tutuyor.
“Light* myLight = mSceneMgr->createLight(“Light0″);“ kod satırı ise ışık sınıfından türetilmiş olan “myLight” adlı değişkeni “mSceneMgr” değişkenine “Light0″ adı altında ekliyor.
“myLight->setType(Light::LT_POINT);“ bu ışığın tipini “LT_POINT” olarak belirliyor ( Yine üç tip söz konusu ancak bunlara daha sonra değinmeyi planlıyorum ).
“myLight->setPosition(0, 40, 0);“ kod satırı da ışığımızın konumunu X,Y,Z olarak ayarlamış bulunuyor. Burada şuna değinmek gerekir. Ogre3D’de X-Z ekseni düzlemi temsil ederken Y ekseni de yukarı – aşağı doğrultusunu temsil etmektedir. Yani ışığımızın an itibariyle X ve Z konumunda 0, Y konumunda yerden 40 br yukarıda olacak şekilde ayarlanmıştır.
“myLight->setDiffuseColour(1, 1, 1);” ve “myLight->setSpecularColour(1, 1, 1);” kod satırlarının anlatılması benim için biraz daha zahmetli olacak zira tam emin değilim ben de :) ama anladığım kadarı ile “specular” değeri yumuşak zeminlerden “diffuse” değeri de düzensiz zeminlerden yansıma olayını temsil ediyor. Parametre olarak aldığı değerler de 0-1 arasında değişiyor. Bu durumda vereceğiniz değerler “0.5″ , ” .42″ , ” 0.63f “ veya da ” .9f” şeklinde parametreler alabilir. Bu değişkenlerin ” f “li olabilmelerinin nedenini ben de bilmiyorum :)
İlk örneğimizin tüm olayı bundan ibaret işte :) şimdilik en azından bir fikir sahibi olmuşsunuzdur bu konu hakkında. İlerleyen yazılarda bu değişkenleri değiştirince oluşabilecek farklılıkları gösterip yeni modeller ekleyip durağanlığı biraz daha renklendireceğiz. Hepimize kolay gelsin :)
Öncelikle Ogre3D‘nin sitesine giderek, download kısmına geliyoruz. Buradan önceden derlenmiş olan SDK ( Software Development Kit ) paketlerini indirebileceğiniz gibi ham haldeki derlenmemiş kodları da SVN’den çekebilirsiniz. Ogre3D ekibinin hazırladığı demo örnekleri indirip neler yapılabileceğini de görebilirsiniz. Aynı zamanda Ogre3D’nin diğer programlar ile entegre etmenizi sağlayacak olan gerekli exporter’ları ve plug-in’leri de indirebilirsiniz. Cthugha kod adlı halihazırdaki güncel versiyon olan “1.7.1“ şu anda indirilebilir konumda ancak ben projelerimde “1.6.1 ( OgreSDKSetup1.6.1_CBMingW.exe ) “ sürümünü kullandığım için tavsiyem onu indirmeniz yönünde olacaktır eğer ki projelerimi takip etmek isterseniz :) Dikkat etmeniz gereken bir diğer nokta da indireceğiniz paketin MinGW uyumlu bir SDK paketi olmasıdır. Çünkü uygulamalarımızı yazacağımız ortam Code::Blocks’tur.
1.6.1 SDK paketimizi indirdikten sonra bildiğiniz kurulum ekranı gelecek karşınıza ve sadece ilerle demeniz yeterli olacaktır herhangi bir değişiklik yapmadan.
Kurulacağı dizini belirledikten sonra sıra geldi ilk projenize :) Code::Blocks’umuzu açtık ve yeni bir proje oluştur dedik.
Daha sonra ilk projemizin adına ve hangi dizine yerleşeceğine karar verip devam ettikten sonra önemli bir kısım karşımıza çıktı. Burada bizden iki tane seçenek arasından bir seçim yapmamızı isteyen bir ekran geldi.
Seçeneklerde, Ogre’nin kaynak koduna sahip bir klasör ya da SDK paketinden kurulmuş bir kod olup olmadığını soruyor. Bizde SDK paketinden kurduğumuz için alttaki seçenek ile devam ediyoruz.
Şimdi sıra geldi Ogre3D’nin dizininin belirlenmesine. $(OGRE_HOME) yazılı bir satır göreceksiniz. Bu satır yerinde Ogre’yi kurduğunuz dizinin adresini yazsanız da olur. Burada kurduğunuz paketin yerini belirleyip ilerle derseniz sihirbazın işlemi tamanlanmış olacaktır.
Bu arada bir dip not gireyim, bu değişkenin anlamı zaten o dizin demek ama bu değişkenin nerede tanımlı olduğunu görmek isterseniz eğer
” Bilgisayarım-> Sağ Tık-> Özellikler-> Gelişmiş-> Ortam Değişkenleri “ butonuna tıklayınız. Çıkan diyalog ekranında “Kullanıcı Adı için kullanıcı değişkenleri “ kısmında “Değişken” ve “Değer" başlıklarının arasında OGRE_HOME değişkenini ve sizin kurduğunuz adresi görebilirsiniz. İsterseniz değişkenin ismini veya adresi değiştirebilir ve hatta kendinize özel değişkenler tanımlayabilirsiniz ama çok da karıştırmanızı tavsiye etmem zira sistem için olan değişkenler de alt tarafta listeli konumda :) Bu bilgiyi benimle paylaşan sınıf arkadaşım Selçuk’a da teşekkür etmek isterim :)
Bu dip nottan sonra sihirbazımıza dönelim. İşlemleri tamamladık ve bitir dedikten sonra sihirbaz otomatik olarak en basit örneği oluşturup Code::Blocks’un editör kısmına yerleştirecektir. Şimdi size bu kodu derlemekten başka yapacak birşey kalmıyor. F9 kısa yolu ile kodumuzu derliyoruz ancak o da ne? karşımıza bir ihtimal sizin de karşılaşacağınız bir hata çıktı ( Örnek Resim 05 ) zaten hatasız bir kod olur mu? :)
“d3dx9d_30.dll” bulunamadı… Ne yapıp ne edip bir yerlerden bu DLL dosyasını bulup “C->Windows->System32″ dizininin içine yerleştirmeniz yeterli olacaktır. işte bu ufak hatadan sonra herşey tamamdır. Code::Blocks’a yeniden derle ve çalıştır komutunu verdikten sonra karşımıza “Rendering Subsystem” kısmının içinde yer aldığı Ogre’nin hangi grafik kütüphanesini kullanacağının seçildiği ekran gelecektir. Bu ekranı oyunlara başlamadan önce yapılan ayarlamalar olarak görebilirsiniz. Anti-Aliasing derecesi ve Gama derecesi, Çözünürlük ve Tam Ekran gibi ayarlamaları yapabilmektesiniz grafik kütüphanesinin verdiği destek çerçevesinde. Herhangi birini seçtikten sonra OK diyerek devam ediniz ve aşağıdak ekran çıktısını ( Örnek Resim 06 ) görerek rahat bir nefes alınız. Çünkü artık ilk projenizi üretmiş bulunmaktasınız. Hadi hayırlı olsun :)
Kendinizi hazırlayınız çünkü bu vakitten sonrası hem eğlenceli hem de bi o kadar da zahmetli bir süreç ama emeklerinizin dönüştüğü şeyleri görünce bu işten daha da zevk almaya başladığınızı göreceksiniz :)
NOT:
Code::Blocks’da 1.7.1 sürümünün SDK paketi hakkında dikkat edilmesi gereken önemli bir nokta söz konusu.Kurulum paketini indirdikten sonra bir dizine çıkartınız. Çıkarılan pakette bulunan “include” dizinin içinde var olan “OIS” ve “OGRE” klasörlerinin her birinin içindeki dosyaları kopyalayıp “include” dizininin içine yapıştırınız. Yani bir geri dizine yapıştırmış oldunuz. Aynı zamanda ana dizindeki “boost_1_42″ klasörünün içindeki dizinleri de aynı şekilde “include” dizininin içinde yapıştırınız.
Bu işlemleri yapmamızın nedeni Code::Blocks‘dan kaynaklanıyor. Şöyle ki; yeni bir proje oluşturduğunuz zaman kurulum sihirbazı sizden Ogre dizinini istemekte. Haliyle siz de projenizin dizinini veriyorsunuz sihirbaza, ancak bu noktada sihirbaz bize uyarı veriyor. Verdiğimiz dizinin doğru bir dizin olduğunu ancak Ogre’nin kodlarını barındırmadığını söylüyor. İlginç bir durum ama anladığım kadar ile sihirbazın baktığı “include” dizininin içinde olması gereken belli başlı dosyaları bulamayınca bu problemi size veriyor. Bu Code::Blocks sihirbazının yeni versiyon Ogre sürümü ile uyumsuz olmasıyla alakalı bir durum. Emin değilim ama Ogre AppWizard 1.7.1 kullanmadığınız taktirde direk SDK paketi derlenirken Code::Blocks bu hatayı veriyor.
Bu arada tüm ogre sürümlerini SourceForge’den indirebilir ve gelişimlerini bu adresten (http://sourceforge.net/projects/ogre/files/) takip edebilirsiniz.