Ogre Kütüphanesi Bölüm-8 Terrain - Gökyüzü ve Sis - 3
UstaDerslik Soru-Cevap Yararlı Araçlar
arama ikon
Diller
Türkçe Türkçe

bilgi UstaDerslik
Bu uyari kutusudur.
Tamam
Anasayfa
İletişim
Üyeler

Ogre Kütüphanesi Bölüm-8 Terrain - Gökyüzü ve Sis - 3

profil
OLENVERDGRUP
BEĞEN(1)
BEĞENME(0)
GÖRÜNTÜLENME(1613)
RAPOR ET
8. terrainTanimlama Fonksiyonu
Bu fonksiyonda terrain dosyamızın oluşturulup oluşturulmadığını soracağız. Eğer oluşturulmamışsa getTerrainImage fonksiyonuna yönlendirme yaparak terrain resmimizi yükleyeceğiz ve sonra terrainimizi belleğe yükleyeceğiz. Eğer önceden terrain dosyamız oluşturulmuşsa, oluşturulmuş olan dosyayı belleğe yükleyeceğiz. Bu işlem için önce uretilenDosyaninIsmi adında bir string oluşturuyoruz. Bu string’e terrainGrubu nesnemiz üzerinden generateFilename fonksiyonunu atıyoruz. Bu fonksiyon önceden createScene fonksiyonunun içinde yazdığımız setFilenameConvention fonksiyonunun ilk parametresini kullanarak bir dosya ismi üretcek. Üretilen bu dosya ismini de uretilenDosyaIsmi string’imize atamış olacağız. Sonra varsayılan kaynak grubunda, yani OGRE’nin dosya yüklemek için tanımladığı dizinlerde, ki bu dizinler C:\OgreSDK dizinin alt klasörleri oluyor, uretilenDosyaIsmi’nin içine yüklediğimiz isimde bir dosyanın olup olmadığını kontrol edeceğiz. Bir if kontrolü oluşturacağız ve bahsettiğimiz işlemi de resourceExists fonksiyonuyla yapacağız.

resourceExists fonksiyonun ilk parametresine dosyanın içinde aranmasını istediğimiz kaynak grubunu, ikinci parametresine dosya ismini barındıran string değerini atayacağız. Atayacağımız kaynak grubu terrainGrubu nesnemizin kullandığı kaynak grubu olacak. Bu kaynak grubunu da terrainGrubu üzerinde getResourceGroup fonksiyonuyla atayacağız. Eğer kaynak grubunda dosya bulunursa resourceExists fonksiyonu bize true değerini döndürecek böylece if fonksiyonunun ilk bölümü aktif olacak. terrainGrubu nesnesi üzerinden çağıracağımız defineTerrain fonksiyonu, kaynak grubundaki bu dosyayı yükleyecek. Ama kaynak grubunda terrain dosyamız bulunamazsa if fonksiyonumuzun ikinci bölümü, yani else bölümü aktif olacak. Image sınıfından resim isimli bir nesne tanımlayacağız. resim isimli nesnemize herhangi bir resim dosyası yüklemeyeceğiz. Bu işlemi getTerrainImage fonksiyonu yapacak. Bunun için oluşturduğumuz resim nesnemizi üçüncü parametresine yazarak, getTerrainImage fonksiyonunu çağıracağız.

getTerrainImage fonksiyonunu çağırırken yazdığımız ilk iki parametrenin anlamını şimdilik düşünmeyin. Terrain oluşturma konusu oldukça kapsamlı olduğundan, bu derste atladığımız bazı noktalara ilerleyen dokümanlarda değineceğiz.

getTerrainImage fonksiyonunu çağırdıktan sonra alt satırda, üçüncü parametresine resim nesnemizi atayarak defineTerrain fonksiyonunu çağıracağız. Yani yüklenen resmi kullanarak terrain dosyamızı oluşturtmuş ve belleğe yükletmiş olacağız. else bölümünde son olarak da terrainEklendi değerimizi true olarak ayarlayacağız. Bahsettiğimiz işlemler terrainTanimlama fonksiyonumuza eklenince aşağıdaki şekilde görünüyor. Siz de kopyalayarak kendi uygulama dosyanızdaki terrainTanimlama fonksiyonuna ekleyin:


void Ders3::terrainTanimlama(long x, long y) {
// createScene fonksiyonunda terrainGrubu üzerinden çağırdığımız setFilenameConvention fonksiyonunun
// ilk parametresini kullanarak bir isim üretir ve bu ismi uretilenDosyaninIsmi string'ine atar:
Ogre::String uretilenDosyaninIsmi = terrainGrubu->generateFilename(x, y);
// uretilenDosyaninIsmi string'ine atanan isimde bir dosyanın olup olmadığını arar.
// Bulursa bu dosyayı yükler. Bulamazsa getTerrainImage fonksiyonunu kullanarak terraini tanımlama resmimizi yükler:
if (Ogre::ResourceGroupManager::getSingleton().resourceExists(terrainGrubu->getResourceGroup(), uretilenDosyaninIsmi)) {
terrainGrubu->defineTerrain(x, y); } else {
Ogre::Image resim; getTerrainImage(x % 2 != 0, y % 2 != 0, resim);
terrainGrubu->defineTerrain(x, y, &resim);
// Son üç satırda terrainimizin tanımlama resmini yüklemiş olduğumuzdan terrainEklendi değişkenini true yapıyoruz:
terrainEklendi = true; } }


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

9. getTerrainImage Fonksiyonu

getTerrainImage fonksiyonunu terrainTanimlama fonksiyonunda çağırırken resim isminde bir nesne atadık. Fonksiyonumuzun tanımlama satırındaki atananResim nesnesinin yerine resim nesnesi geçecek. getTerrainImage fonksiyonumuzun içinde atananResim nesnesi üzerinden load fonksiyonunu çağıracağız. Bu fonksiyonun ilk parametresinde yüklenecek olan resim dosyasını, ikinci parametresinde yüklenecek resim dosyasının bulunduğu kaynak grubu belirtilir. getTerrainImage fonksiyonundaki iki if kontrolü ise farklı bir amaçla yazılır. Bilinmesi şimdilik çok gerekli olmadığından dolayı genişletilmiş bölümde açıklamalarına yer verdik. getTerrainImage fonksiyonuna bahsettiğimiz işlemleri yaptığımızda fonksiyonumuz şu şekilde görünüyor:


void getTerrainImage(bool flipX, bool flipY, Ogre::Image& atananResim) {
// Terrain'imizi tanımlamak için kullanacağımız resmi belirliyoruz:
atananResim.load("terrain.png", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
if (flipX)
atananResim.flipAroundY();
if (flipY)
atananResim.flipAroundX(); }


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

10. initBlendMaps Fonksiyonu
initBlendMaps fonksiyonu, terrainYapilandirma fonksiyonunda tanımladığımız kaplamların yükseklik etkenine göre düzenlenmesini sağlar. Örneğin terrain’in en alçak noktasından 40 birim yüksekliğe kadar toprak kaplaması, 40 birim yükseklikten 70 birim yüksekliğe kadar taşlık, kayalık kaplaması yerleştirilmesini belirler. Belirlediğimiz yükseklikler arasında kaplama atarken keskin geçişler yapmaz. Bir kaplama dosyasının bitip diğerinin başlayacağı noktayı merkez alarak iki kaplama dosyasını birbirine karıştırır. initBlendMaps fonksiyonunun içeriğini direk yazıp geçeceğiz. İlerleyen dokümanlarda detaylarına değineceğiz. Gerekli tüm fonksiyonlar yazıldıktan sonra initBlendMaps fonksiyonu şu şekilde görünecektir:


void Ders3::initBlendMaps(Ogre::Terrain* terrain) {
Ogre::TerrainLayerBlendMap* blendMap0 = terrain->getLayerBlendMap(1);
Ogre::TerrainLayerBlendMap* blendMap1 = terrain->getLayerBlendMap(2);
Ogre::Real minHeight0 = 70;
Ogre::Real fadeDist0 = 40;
Ogre::Real minHeight1 = 70;
Ogre::Real fadeDist1 = 15;
float* pBlend0 = blendMap0->getBlendPointer();
float* pBlend1 = blendMap1->getBlendPointer();
for (Ogre::uint16 y = 0; y < terrain->getLayerBlendMapSize(); ++y) {
for (Ogre::uint16 x = 0; x < terrain->getLayerBlendMapSize(); ++x) {
Ogre::Real tx, ty;
blendMap0->convertImageToTerrainSpace(x, y, &tx, &ty);
Ogre::Real height = terrain->getHeightAtTerrainPosition(tx, ty);
Ogre::Real val = (height - minHeight0) / fadeDist0;
val = Ogre::Math::Clamp(val, (Ogre::Real)0, (Ogre::Real)1);
*pBlend0++ = val;
val = (height - minHeight1) / fadeDist1;
val = Ogre::Math::Clamp(val, (Ogre::Real)0, (Ogre::Real)1);
*pBlend1++ = val; } }
blendMap0->dirty();
blendMap1->dirty();
blendMap0->update();
blendMap1->update(); }


11. frameRenderingQueued Fonksiyonu
Terrain üretme işlemini göstermek için ve bu işlem tamamlandığında kaydetmek için bu fonksiyonu kullanacağız. Tanımlayacağımız boolean değerini ve return komutunu atlıyoruz. Bir sonraki derste uzun uzadıya bu fonksiyonu anlatacağız. Asıl işlemlere geçmeden önce boolean değerini ve return komutunu frameRenderingQueued fonksiyonuna ekleyelim:


bool ret = BaseApplication::frameRenderingQueued(evt);
return ret;


Boolean değeri ve return komutunun arasına yazacağımız birinci if kontrolünden bahsedelim. Birinci if kontrolümüzün parametresinde, terrainGrubu nesnemiz üzerinden isDerivedDataUpdateInProgress fonksiyonunu çağıracağız. Eğer terrainGrubu o an terrain dosyasını üretiyorsa bu fonksiyona bize true değerini döndürecek. Ve birinci if kontrolü aktif olacak. Birinci if kontrolümüzü de frameRenderingQueued fonksiyonuna ekleyelim:

bool ret = BaseApplication::frameRenderingQueued(evt); 
// Birinci if kontrolümüz terrainGrubu'nun, terrain dosyamızı üretip üretmediğini kontrol edecek:
if (terrainGrubu->isDerivedDataUpdateInProgress())
{ } else { }
return ret;


Birinci if kontrolümüzün için dolduralım. Ders3.h dosyasında tanımladığımız bilgiEtiketi nesnesiyle ilgileneceğiz. Label sınıfı render penceresinde göreceğiniz yazı alanlarından biridir. isDerivedDataUpdateInProgress fonksiyonu eğer true değerini döndürüyorsa, bunun anlamı terrainGrubu nesnemiz terrain dosyasını üretmektedir, bu şart sağlanıyorsa Label sınıfından türettiğimiz bilgiEtiketi nesnesini kullanarak ekrana yazı yazdıracağız.

bilgiEtiketi nesnemizin aktif olması için SdkTrayManager sınıfından BaseApplication’da türetilen mTrayMgr nesnesine konumlandırmamız gerekiyor. SdkTrayManager sınıfının detaylarına bu derste inmeyeceğiz. Yalnız şunu belirtelim ki moveWidgetToTray fonksiyonunu kullanarak bilgiEtiketi nesnemizi mTrayMgr nesnemize konumlandıracağız.

Sonraki işlemimiz ise bilgiEtiketi nesnemizin görünür yapmak için show fonksiyonunu çağırmak olacak. Birinci if kontrolümüzün else bölümünde bahsettiklerimizin tam zıddını yapacağız. isDerivedDataUpdateInProgress fonksiyonu false döndürürse, bu bölüm çalışacak. Şu ana kadar anlattığımız işlemleri frameRenderingQueued fonksiyonuna ekleyelim:

bool ret = BaseApplication::frameRenderingQueued(evt);
// Birinci if kontrolümüz terrainGrubu'nun, terrain dosyamızı üretip üretmediğini kontrol edecek:
if (terrainGrubu->isDerivedDataUpdateInProgress()) {
// bilgiEtiketi nesnemizi kullanabilmek için mTrayMgr nesnemize kaydediyoruz:
mTrayMgr->moveWidgetToTray(bilgiEtiketi, OgreBites::TL_TOP, 0);
// bilgiEtiketi nesnemizi ekranda görünür yapıyoruz:
bilgiEtiketi->show();
} else {
// Eğer terrainGrubu, terrain dosyamızı üretmiyorsa bilgiEtiketi nesnemizi mTrayMgr nesnemizden siliyoruz:
mTrayMgr->removeWidgetFromTray(bilgiEtiketi);
// bilgiEtiketi nesnemizi ekrandan siliyoruz:
bilgiEtiketi->hide(); }
return ret;


Aklınıza şöyle bir soru gerebilir: program açıldığında ilk seferde true dönerse bilgiEtiketi’ni mTrayMgr’ye bağlayıp ekranda göstereceğiz. Ama ya false dönerse ne olacak? mTrayMgr’ye bağlamadığımız bir nesneyi ondan nasıl kaldıracağız veya görünür olup olmadığını bilmediğimiz bir nesneyi nasıl görünmez yapacağız?

Belirtmemiz gereken iki nokta var. Birincisi, frameRenderingQueued fonksiyonu sonraki derste uzun uzadıya bahsedeceğimiz çok özel bir fonksiyondur. Program açık kaldığı sürece, bu fonksiyonun içindeki işlemler tekrar tekrar yapılacak. İkinci nokta, programımız ilk kez çalıştırıldığında terrainGrubu nesnemiz, az sonra ekleyeceğimiz saveAllTerrains fonksiyonuyla ürettiği dosyayı, createScene fonksiyonunda tanımladığımız setFilenameConvention fonksiyonunun parametrelerini de kullanarak hard diskimize kaydedecek. bilgiEtiketi sadece programı ilk çalıştırdığımızda karşımıza çıkacak. Çünkü terrain dosyası ilk çalıştırmamızdan sonra her seferde hard diske kaydettiğimiz dosyadan yüklenecek. isDerivedDataUpdateInProgress fonksiyonu sadece terrain, hard diskteki bir dosyadan yüklenmediği zaman, ilk kez üretilirken true değerini döndürür.

Sıradaki işlemimiz ikinci bir if kontrolü oluşturmaktır. İkinci if kontrolümüzü, birinci if kontrolümüzün ilk bölümünün içine oluşturacağız. Küçük bir hatırlatma yapalım: terrainTanimlama fonksiyonu tüm işlemleri bittikten sonra terrainEklendi değişkenini true olarak ayarlıyordu. İkinci if kontrolümüz de terrainEklendi değişkeninin durumuna göre işlem yapacak. isDerivedDataUpdateInProgress fonksiyonu true döndürüyorsa ve terrainEklendi değişkeni de true ise programımız terraini defineTerrain fonksiyonuyla tanımlamıştır ama hâlâ terrain ile ilgili diğer işlemlerle meşguldür. Bu durumda bilgiEtiketi nesnemiz üzerinden setCaption fonksiyonuyla “Terrain olusturuluyor, Lutfen bekleyiniz…” yazdıracağız.

Eğer isDerivedDataUpdateInProgress fonksiyonu true döndürüyorsa ama terrainEklendi değişkeni false ise programımız terrainTanimlama fonksiyonunun herhangi bir satırında ya da getTerrainImage fonksiyonuna yönlendirilmiş olabilir. Resmî eğitim dosyasında kaplama dosyalarını güncelleştirmekle meşgul olacağını söylüyor. Bu yüzden bu sefer bilgiEtiketi nesnemize “Kaplamalar guncellestiriliyor, Lutfen bekleyiniz…” yazdıracağız.

Birinci if kontrolümüze dönelim. terrainGrubu’nun terrain’inimizi üretip üretmediğini sorguluyorduk. isDerivedDataUpdateInProgress fonksiyonu, üretiliyor anlamında true döndürüyordu. Terrain üretme işlemi bittiğinde isDerivedDataUpdateInProgress fonksiyonu false döndürecek ve else bölümü işlemleri çalışacak. Else bölümüne üretilen terrainimizi hard diskimize kaydetmesi için saveAllTerrains fonksiyonu, parametresine true girerek atayacağız. Sonrada terrainEklendi değişkenini false olarak ayarlayacağız. Ama bu iki işlemi terrainEklendi değişkeninin durumunu kontrol eden üçüncü bir if kontrolünün içinde yapacağız.

Peki, neden üçüncü bir if kontrolüne ihtiyaç duyuyoruz, doğrudan else bölümüne yazsak olmaz mı? En başa dönelim. isDerivedDataUpdateInProgress fonksiyonunun true döndürmesinin şartı neydi? Terrain bilgilerini dosyadan yüklemek yerine üretme işlemi yapmasıydı. Programı ikinci kez çalıştırdığımızda terrainTanimlama fonksiyonu içindeki resourceExists fonksiyonu, kaydedilen terrain dosyasını bulacak ve bu dosyadan terraini yükleyecek. Terrain üretilmediği, yani dosyadan yüklendiği için isDerivedDataUpdateInProgress fonksiyonu false döndürecek. Ayrıca, terrainTanimlama fonksiyonu kaydedilen terrain dosyasını bulduğu için terrainTanimlama fonksiyonundaki if kontrolü else bölümüne atlamayacak. Else bölümüne atlamadığı için de terrainEklendi değişkeni false olarak kalacak. frameRenderingQueued fonksiyonumuzdaki birinci if kontrolüne dönelim. Eğer saveAllTerrains fonksiyonunu else bölümüne doğrudan yazarsak, program ilk kez çalıştırıp-sonlandırıldıktan sonra her çalıştırıldığında terrain bilgileri tekrar tekrar bir dosya olarak hard diskimize kaydedilecek. Ama terrainEklendi değişkenin durumunu kontrol eden bir üçüncü if kontrolü içine saveAllTerrains fonksiyonunu yazarsak, ilk seferden sonra diğer seferlerde program çalıştığında terrainEklendi değişkeni, terrainTanimlama fonksiyonu true olarak ayarlamadığı için, false olarak dönecek. Böylelikle terrain bilgilerimizi bir kez kaydettikten sonra tekrar tekrar kaydetmeyeceğiz. Ayrıca, saveAllTerrains fonksiyonunun altına terrainEklendi değişkeni false olarak tanımlıyoruz. Çünkü frameRenderingQueued fonksiyonunun diğer her şeyden bağımsız olarak, program çalıştığı süre boyunca tekrar tekrar çalıştırıldığını söylemiştik. Sürekli çalıştırıldığından dolayı terrain bilgilerimizi yüzlerce kez kaydetmesini önlemek istiyoruz.

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



Kod
Kalın
Vurgu
Resim
Video
Url
CEVAPLA
Tüm Hakları Saklıdır. ©Arleone 2013-2014 UstaDerslik






Giriş
Şifremi Unuttum...
Şifre Talep
  Kuralları Kabul Ediyorum.
Kaydol