Ogre Kütüphanesi Bölüm-8 Terrain - Gökyüzü ve Sis
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

profil
OLENVERDGRUP
BEĞEN(1)
BEĞENME(0)
GÖRÜNTÜLENME(1935)
RAPOR ET

A. PROJENİN HAZIRLANMASI



1. Başlarken
Terrain, Türkçe karşılığıyla Arazi, oyunumuzdaki dağları, tepeleri, ovaları barındıran 3d model dosyasıdır. Terrain’i diğer model dosyalarından ayıran özelliği, devasa boyutlarda olmasıdır. Ayrıca, örneğin bir evi izlerken kameranın yönünü çevirdiğimizde, ev model görüş alanımızın dışına çıkacağından görüntülenmeyecektir. Görüntülenmediğinden dolayı ekran kartından, bellekten silinecektir. Ama söz konusu üzerinde durduğumuz Terrain modeli olunca, görüş alanı, belleğe yüklenme ilişkisi bir hayli karmaşıklaşıyor. OGRE, Terrain modelini birçok oyun motoru gibi bir yükselti, heightmap resminden tanımlıyor. Sonra yüzlerce dilime ayırıyor. Ayırdığı dilimlerden kopya çıkarıp, kopya dilimlerin kaplama çözünürlüğü ve model detaylarını düşürerek bellekte daha az yer kaplamasını sağlıyor. Terrain modelinin bize yakın bölümüne orijinal terrain modelini ve kaplamasını kullanıyor. Kameradan uzaklaştıkta, düşük çözünürlükteki kaplamaları ve detaysız Terrain modeli dilimleri yüklüyor. Birçok oyun motorunun farklı tekniklerle yaptığı bu işleme de LOD Renderleme adı veriliyor. Bu sayede bellekten kazanmamız sağlanıyor.

Ayrıca OGRE’de güneş ışığını hesaplanmıyor. Bunun yerine belirlediğimiz ışık kaynağı temel alınarak beyaz ve siyah arasındaki tonlardan oluşan kuş bakışı görünümlü bir resim oluşturuyor. Bu resme ışık haritası anlamında LightMap adı veriliyor. Bu resmi de renderleme işlemi sırasında saydamlaştırıp Terrain modelinin tümünün üzerine koyuyor.

Tüm bu işlemler ve az sonra bahsedeceğimiz işlemler için kullanacağımız yardımcı sınıflara geçelim. Bu yardımcı sınıflardan ilki ve en önemlisi TerrainGroup sınıfıdır. Biz bu sınıftan terrainGrubu nesnesini türettik.

TerrainGroup nesnesi Terrain hazırlarken gerekli olacak hemen hemen her şeyi, daha çok model dosyası, model dosyasının tanımlanacağı terrain resminin ve bunların model oluşturma işlemindeki ayarlarını kapsıyor. Daha çok Terrain model dosyasıyla ilgilendiğini söyleyebiliriz. Mesela, istersek, Terrain modelinin kopyalarını X ve Z eksenlerinde sonsuz kez yan yana döşeyerek, sonsuz bir Terrain’in üzerinde duruyormuşuz havası veriyor.

İkinci yardımcı sınıfımızda TerrainGlobalOptions sınıfıdır. Biz bu sınıftan terrainAyarlari nesnesini türettik. TerrainGlobalOptions sınıfı ise Terrain modelimizin üzerine döşeyeceğimiz kaplamalarımızı belirlememizi, LightMap hazırlanırken kullanılacak ışık kaynağının belirlenmesi vb. işlemleri yapmamızı sağlıyor.

Biz Terrain’i renderlemeden önce, Ogre Terrain Sisteminde gerekli olan nesneleri, parametreleri, döngüleri vb. ayarlamalıyız.

Öncelikle Ders3.h dosyasında hazırladığımız proje şablonuna bir göz atalım. Aşağıdaki resimde mor renkteki terrainEklendi yazısı, terrainEklendi’nin bir değişken olduğunu ifade ediyor. Mavi renkteki yazılar birçok fonksiyon tarafından ortak kullanılan nesneleri, başlığı olan kutucuklarda projemizdeki fonksiyonları temsil ediyor. Şimdi resmimize bakalım.

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

createScene fonksiyonundan başlayarak projemizi hazırlamaya başlayalım.

2. Kamera Nesnesinin Durumu
İlk olarak kameramızı terrain’imiz için düzenleyeceğiz. Öncelikle kameramızın konumunu, yönünü, yakın kırpma mesafesini ve uzak kırpma mesafesini kuracağız. Sonra bir if kontrolü ekleyeceğiz. if kontrolümüz, kullandığımız RenderSystem kütüphane dosyası (bu OpenGL veya DirectX olabilir) kabul ederse uzak kırpma mesafesini sonsuz olarak ayarlayacak. Terrain modelimiz oldukça büyük olacağından dolayı, uzak kırpma mesafesinin sonsuz ayarlanması mümkün olan en uzak noktayı görmemizi sağlayacak. setFarClipDistance fonksiyonun parametresini 0 olarak ayarlayacağız. Bunun anlamı uzak kırpma mesafesini 0 yapmak değil, aksine sonsuz yapmaktır. Şimdi createScene fonksiyonumuza şu satırları ekleyelim:


// Kameramızın konumunu, bakacağı yönü, yakın ve uzak kırpma mesafelerini ayarlıyoruz:
mCamera->setPosition(Ogre::Vector3(1683, 50, 2116));
mCamera->lookAt(Ogre::Vector3(1963, 50, 1660));
mCamera->setNearClipDistance(0.1);
mCamera->setFarClipDistance(50000);

// Eğer RenderSystem'imiz destekliyorsa uzak kırpma mesafesini sonsuz yapıyoruz:
if (mRoot->getRenderSystem()->getCapabilities()->hasCapability(Ogre::RSC_INFINITE_FAR_PLANE)) {
// 0, sıfır değerini girerek sonsuz olduğunu belirtiyoruz:
mCamera->setFarClipDistance(0); }


3. Kaplama Filtresi Kurma
Kaplama filtreleri, genellikle uzaklığa bağlı olarak renderleme sırasında kaplamaları düzenler. Bir kaplama, kopyalanarak çeşitli boyutlarda küçültülerek kaydedilir. Örneğin orijinal çözünürlüğü 512x512 piksel olan bir kaplama, 256x256, 128x128, 64x64, …, 1x1 çözünürlüklerine küçültülerek kaydedilir. Bu işleme mipmap adı verilir. Kaplama filtreleri de elde edilen mipmap’ları farklı prensiplere göre renderler. Örneğin, kameramıza en yakın alana çözünürlüğü en yüksek olan kaplama yüklenirlerken, bize çok çok uzakta duran, küçük bir nokta halinde gördüğümüz alana en küçük mipmap yüklenir. Bu sayede bellekten tasarruf edilmiş olur.

http://ustaderslik.com/resim/ders/tb5vr.png
Anisotropic Filtresinin Mipmap’ı
Resim: wikipedia.org

http://ustaderslik.com/resim/ders/tb5w1.png
Resmin sol bölümü, Trilinear; sağ bölümü, Anisotropic Filtresi
Resim: wikipedia.org

Bilinear, Trilinear, Anisotropic gibi kaplama filtreleri vardır. Şimdi biz de uygulamamızın kullanacağı kaplama filtresini belirleyeceğiz. Bu işlem MaterialManager sınıfından kontrol edilmekte. getSingleton fonksiyonundan setDefaultTextureFiltering fonksiyonuna ulaşıyoruz ve parametresini TFO_ANISOTROPIC olarak belirliyoruz. setDefaultAnisotropy fonksiyonuyla da yüklenen dokularda kullanılacak varsayılan Anisotropy seviyesini ayarlayacağız. Bu seviye arttıkça filtreleme kalitesi artar, ama aynı zamanda bellek kullanım miktarı da artar. createScene fonksiyonumuza şu satırları ekleyelim:


// Kaplama Filtremizi, Anisotropic Filtresi olarak ve seviyesini de 7 olarak ayarlıyoruz:
Ogre::MaterialManager::getSingleton().setDefaultTextureFiltering(Ogre::TFO_ANISOTROPIC);
Ogre::MaterialManager::getSingleton().setDefaultAnisotropy(7);


4. DirectionalLight ve AmbientLight Kurulumu

Şimdi biz bir DirectionalLight kuracağız. Terrain bileşenimiz bu DirectionalLight’ı güneş olarak kabul edecek. Terrainimizin güneşi görmeyen kısımları gölge, güneşi yani DirectionalLight’ı gören kısımları ise aydınlık olacak. Terrain bileşeni bu işlemi LightMap kullanarak yapacak.

Önceki dersimizde DirectionalLight’ın yönünü setDirection fonksiyonuna vektör değerlerini yazarak tanımlamıştık. Bu dersimizde farklı bir yol izleyeceğiz. gunesYonu isminde bir 3 boyutlu vektör tanımlayacağız. Koordinatlarını girerek istediğimiz bir yöne döndüreceğiz. gunesYonu ismindeki vektör nesnemizi setDirection fonksiyonunu kullanarak DirectionalLight’ımıza gireceğiz. Ama gunesYonu nesnemizi DirectionalLight’a girmeden önceden bir işlem daha yapacağız. Vektörümüzü normalize edeceğiz. Yani birim vektör haline getireceğiz.

Vektörü normalize etme işlemini bir tür sadeleştirme olarak düşünebilirsiniz. Örneğin, kesirli sayılarda, 2/4 denktir 1/2 değerine. Yaptığımız bu tip bir şey. Vektörümüzün konumunu değil, yönünü kullanacağız. Bu sebeple koordinat değerlerini mümkün olan en düşük değerle bilgisayar hafızamızda saklamamız yeterli. Normalize işlemi, 3 koordinatın her birinin, vektörün uzunluğuna bölünmesiyle elde ediliyor. Yeni koordinatlar -1 ila 1 arasında oluyor. Vektör normalize yapıldıktan sonra elde edilen vektöre birim vektör deniyor. Sonuç olarak, koordinatlarınızda 100, 200 vb. yüksek değerler varsa ve sizin için vektörünüzün işaret ettiği konum değil vektörün yönü önemliyse normalize yaparak, bilgisayar hafızasından kazanıyorsunuz.gunesYonu isminde bir 3 boyutlu vektör tanımlıyoruz. Vektörümüzü normalize ediyoruz. gunes isminde bir ışık nesnesi oluşturuyoruz. Türünü setType fonksiyonuyla DirectionalLight olarak belirliyoruz. gunes nesnemize setDirection fonksiyonuyla gunesYonu vektörümüzü yön olarak atıyoruz. gunes nesnemizin Diffuse rengini setDiffuseColour fonksiyonuyla beyaz renkte kuruyoruz. Bu işlem için parametreyi White olarak ayarlamamız yeterli. Specular rengini setSpecularColour fonksiyonuyla açık gri bir renk olarak belirliyoruz. AmbientLight’ımızı ise normal siyah renkten ayırt edilmeyecek durumda olan çok çok hafif, açık tonda, bir siyah renk olarak kuruyoruz. createScene fonksiyonumuza şu satırları ekleyelim:


// DirectionalLight'ımızın yönünü belirlemek için kullanacağımız vektörümüzü ayarlayıp, normalize ediyoruz:
Ogre::Vector3 gunesYonu(0.55, -0.3, 0.75);
gunesYonu.normalise();

// gunes isimli ışık nesnemizi DirectionalLight olarak belirliyoruz ve yönünü, Diffuse ve Specular renklerini kuruyoruz:
Ogre::Light* gunes = mSceneMgr->createLight("gunesIsigi"); gunes->setType(Ogre::Light::LT_DIRECTIONAL);
gunes->setDirection(gunesYonu);
gunes->setDiffuseColour(Ogre::ColourValue::White);
gunes->setSpecularColour(Ogre::ColourValue(0.4, 0.4, 0.4));

// Sahnemizin AmbientLight'ını kuruyoruz:
mSceneMgr->setAmbientLight(Ogre::ColourValue(0.2, 0.2, 0.2));


5. Arazi Yapılandırma

TerrainGlobalOptions sınıfından, terrainAyarlari isimli bir nesne oluşturacağız. terrainAyarlari nesnemiz Terrain’imizin temel ayarlarını barındıracak. Ayrıca bu nesneyi tanımlarken farklı bir tanımlama yapacağız. C++ dilindeki new anahtarı yerine OGRE_NEW anahtarını kullanarak tanımlama yapacağız. terrainAyarlari nesnemiz, Ders3.h dosyasında zaten tanımlanmış durumda. OGRE_NEW anahtarını kullanarak onu dinamik olarak tanımlanan bir nesne yapacağız.

Peki, dinamik tanımlama nedir? Normal şartlarda programımızın exe dosyası çift tıklandığında açılmadan önce kullanacağı alanı bellekten ayırır ve kapanana kadar ayırdığı alanı korur. Eğer dinamik olarak bir değer, nesne vb. bir şey tanımlarsak, programız çalışmadan önce bellekten yer ayırmak yerine, çalıştıktan sonra bellekten yer ayırır. Program çalışırken gerekli işlemleri yaptıktan sonra ayırdığı alana ihtiyacı kalmazsa, ayırdığı alanı bırakır, yani siler. Bu şekilde bellekten tasarruf etmiş oluruz. Dinamik bellek yönetimi OGRE ile ilgili değildir. Bir programlama tekniğidir.

Şimdi biz de TerrainGlobalOptions sınıfından tanımlanmış, terrainAyarlari isimli nesnemizin dinamik olduğunu belirteceğiz. Bu işlemin formatı şöyledir: “nesne = OGRE_NEW sınıf”. createScene fonksiyonumuza şu satırları ekleyelim:


// terrainAyarlari nesnemizi, dinamik bir nesne olarak belirliyoruz:
terrainAyarlari = OGRE_NEW Ogre::TerrainGlobalOptions();


Şimdi ise TerrainGroup sınıfından oluşturulan, terrainGrubu nesnesinin dinamik olacağını belirteceğiz. Genelde tanımlama işlemi yaparken parametreler nesneden sonra, nesneye tanımlanırdı. Fakat dinamik tanımlamada parametre atarken de format biraz değişiyor. Nesnenin türediği sınıfın yanına parametreler tanımlanıyor. Format şu şeklide: “nesne = OGRE_NEW sınıf(parametreler)”.

Tanımlamada kullanacağımız terrainGrubu nesnesinin parametreleri ise şöyle: ilk parametre, bağlanılacak olan SM nesnesi; ikinci parametre, terrain’in hizalanacağı tabanının oturacağı eksenler; üçüncü parametre,tanımlamada kullanılan kare resmin bir kenarının uzunluğu; dördüncü parametre, terrain tanımlama resminin bir kenarının uzunluğunun, OGRE ortamında hangi değere karşılık geleceğidir. Daha anlaşılır olması için örneklendirelim: örneğin ikinci parametreyi X-Y olarak ayarlarsak sahneyi açtığımızda terrain dik duracaktır, bir bakıma dünya 90 derece dönmüş gibi düşünebilirsiniz. Bu yüzden X-Z olarak ayarlıyoruz.

Üçüncü parametrede ise örneğin terraini oluşturan resim 513x513 piksel boyutundaysa, bu parametre 513 oluyor.

Dördüncü parametresi örneğin terrainimiz sahnede 12.000x12.000 birim boyutlarında bir yer kaplayacaksa, 12000 olarak ayarlanıyor. Bu durumda 513 denktir 12000 gibi bir eşitlik ortaya çıkıyor. Yani sahnede 12000x12000 birimlik bir kare oluşturulacak ve resim dosyası büyütülüp küçültülerek bu karenin içine oturtulacak.

Ayrıca terrainimiz oluşturulduktan sonra onu bir dosya olarak kaydedeceğiz. Bu dosyanın ismini ve uzantısını belirleyen fonksiyon ise setFilenameConvention fonksiyonudur. İlk parametresine oluşturulacak olan dosyanın ismini, ikinci parametresine ise uzantısı belirliyoruz.

setOrigin fonksiyonu ile de terrainimizin orijinini kuruyoruz. Buradaki orijin sahnenin kullandığı orijin noktası değildir. Buradaki orijin terrain modelimizin, onu konumlandırırken kullandığımız merkez noktasıdır. Vektör sınıfından çağırdığımız ZERO vektörü, (0, 0, 0) vektörüdür. Şimdi tüm bu anlattıklarımızı uygulayalım. createScene fonksiyonumuza şu satırları ekleyelim:


// terrainGubu nesnemizi, dinamik bir nesne olarak; kaydedilirken aldığı dosya adını ve uzantısını;
// terrainimizin orjinini (burada terrain modelinin merkez noktası kastediliyor) belirliyoruz.
terrainGrubu = OGRE_NEW Ogre::TerrainGroup(mSceneMgr, Ogre::Terrain::ALIGN_X_Z, 513, 12000.0f);
terrainGrubu->setFilenameConvention(Ogre::String("Ders3Terrain"), Ogre::String("dat"));
terrainGrubu->setOrigin(Ogre::Vector3::ZERO);


İlerleyen satırlarda terrainAyarlari ve terrainGrubu nesnelerimizi kullanarak terrainimiz için gerekli işlemleri yapacağız. Bu işlemleri terrainYapilandirma fonksiyonunda yapacağız. Bu işlemler arasında terrainimizin LightMap’ını oluşturma işlemi de var. LightMap işlemleri için LightMap’ın temel aldığı ana ışık kaynağını belirtmek zorundayız. Ana ışık kaynağı DirectionalLight olmak zorundadır. Bu nedenle terrainYapilandirma fonksiyonumuzun parametresi bir ışık nesnesi alıyor. Bizim sahnemizin ana ışığı, gunes nesnesi. LightMap için terrainYapilandirma fonksiyonunu, parametresini gunes olarak belirleyip çağırıyoruz. terrainYapilandirma fonksiyonunun içeriğini az sonra yazacağız. Şimdi, createScene fonksiyonumuza şu satırları ekleyelim:


// terrainYapilandirma fonksiyonunu, parametresini gunes olarak belirleyip çağırıyoruz.
terrainYapilandirma(gunes);



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