Sayfalar

8 Aralık 2010 Çarşamba

Arttırılmış Gerçeklik Çalışması 03 - Kod Adı: Beyto

   Sanal Gerçeklik uygulamalarımdan en yeni ve en eğlendiğim çalışmama geldi sıra. Bu çalışmamda ev arkadaşım Beytullah KILIÇ kendi şiirlerinden bir tanesi olan "Zakkum Tadında Teselli"yi okuyarak bana yardım etmiş bulundu :)

   Zamanında dediğim gibi "Birisi çıkıp ders kitabınızdaki konuyu size anlatacak" işte o güne adım adım yaklaşıyorum :)
 
   Şimdi kısaca çalışmamdan bahsedeyim; öncelikle bu bir deneme çalışması olduğu için tam verimli bir sonuç elde edemediğimi söylemem gerekir zira Beytullah'ın çekimini yaptığım webcam'in çözünürlüğü pek iç açıcı değildi. Üstelik ses kaydı da yapmadığı için MP3 player'ımın ses kaydını kullanmak zorunda kaldım. Bunları eş zamanlı hale getirip birleştirdikten sonra arkaplanı temizlemek zorunda kaldım ki en çok sıkıntı yaşadığım kısım burası oldu zira profesyonel stüdyolardaki gibi ekipmana sahip değilim. Ben de isterdim bir adet yeşil ekranımın olmasını ama olsun evimin duvarı da işimi gördü :D

Yine Aynı Markerı Kullandım.
   Diğer bir sıkıntı yaşatan nokta ise Flash'ın bu videodaki sesi kabullenememesiydi ki sanırım bunun nedeni benim videoyu çevirirken "stereo" ses kullanmamdan dolayıydı. zira "mono" yapınca videodaki sesi sorunsuz kabul etti. Hal böyle olunca iş benim için daha kolay tabi. "mono"yu kabul etmeseydi harici ses dosyası yüklemek zorunda kalacaktım ki bu da senkron problemlerini beraberinde getiriyordu ve hiç çekilmiyor.. şansıma bu problemi de mono yardımıyla atlatmış oldum. Belki de daha farklı bir sorun vardı temelinde ama olsun, malum bilgisayar bu hiç belli olmaz bazen sağı solu :)

   Dediğim gibi bu daha ilk aşaması sadece ve deneme amaçlı bir proje. Bir sonraki versiyonunda daha iyi çekilmiş bir video ve daha iyi bir ses kaydı ile gelmeyi planlıyoruz. Ayrıca fondaki telefon sesine aldanmayın bir daha sil baştan kayıt yapmak istemediğimiz için bu şekilde devam ettik :) artık bu küçük detayları da mazur görün lütfen :) Projenin çalışması için yine yandaki marker'ın çıktısını almanız veya da çizimini yapmanız gerekmektedir. Konu ile ilgili önceki yazılarımı okursanız daha detaylı bilgi edinebilirsiniz:

    Arttırılmış Gerçeklik Çalışması 02
    Arttırılmış Gerçeklik Çalışması 01
  
Projeye ulaşmak için tıklayınız. İyi eğlenceler, kolay gelsin :)

3 Aralık 2010 Cuma

AS2 Calışmaları 02 - Kodlarla Çizim

 Ayşen Hoca'nın derste gösterdiği bir örneğin nasıl olabileceğini düşündükten sonra bu örneği geliştirdim. Bir noktası haricinde hepsi kolay ama o noktayı bulmam benim için zahmetli olmuştu. O da çokgen çizim kısmıydı. Bunu teoride yapsam da kodlara dökemiyordum ama sonunda biraz da deneme yanılmayla olayı çözdüm.


this.createEmptyMovieClip("sekil_mc",this.getNextHighestDepth());
sekil_mc.createEmptyMovieClip("ciz_mc",this.getNextHighestDepth());


ilk önce kodlar yardımıyla sekil_mc adlı bir movieClip oluşturdum, daha sonrasında bu yeni oluşturduğum movieClip içerisine de kodlar aracılığıyla ciz_mc adlı bir movieClip oluşturdum. Şimdi neden böyle iki movieClip tercih ettiğimin sorusuna da tercih meselesi desem çok da abes kaçmaz sanırım zira tek bir moveiClip'de de toplanabilirdi olaylar ancak ben ilk movieClip'de temel fonksiyonları yönetirken (position, rotation, alpha, scale gibi) ikinsi yani ciz_mc'de ise çizilecek olan çokgeni yönetmiş oldum. Zaten menüdeki bu kaydırma çubuklarından köşe haricindeki tüm değişkenler sekil_mc'nün o andaki özelliklerini değiştirmeyi amaçlamakta. Köşe değişkeni de ciz_mc'nin köşe sayısını belirlemede işe yaramakta.

for (i=0; i<kose+1; i++)
{
        sekil_mc.ciz_mc.lineTo(
               xbas-r*Math.sin((i*derece)*(Math.PI/180)),
               ybas+r*Math.cos((i*derece)*(Math.PI/180))
        );
}

Yukarıdaki kod satırında görüleceği üzere şekil_mc'nin içerisindeki ciz_mc'de  belirlenen köşe sayısı kadar döngü kurulması söyleniyor.xbas pozisyonu ile ybas pozisyonunda bulunan şekilden r yarıçapı kadar uzak mesafedeki konuma geçip çizime başlanıyor. X'in sinüs değeri Y'nin de cosinüs değerini tercih etmişim. Çok da bi fark yok açıkcası başlangıç yönünün değişmesinden başka. Ancak hem X hem de Y için aynı değerler kullanılmamalıdır yani X için sin ve Y için sin veya X için cos ve Y için cos birliktelikleri tercih edilmemelidir zira istenmeyen sonuçlar meydana gelir bu durumda. Dairesel bir hareket için konumlardan birinin zıt trigonometrik özelliklere sahip olması gerekir ( sin-cos veya cos-sin gibi ). Derece değişkeni de 360/kose'nin matematiksel sonucuna eşittir yani o kadarlık bir dereceyle hareket etmesi sağlanmaktadır.

Denemek için tıklayınız.

2 Aralık 2010 Perşembe

AS2 Calışmaları 01 - Paint Örneği

Geçen sene sınav vakitlerinde aklıma gelen bir fikir sonucunda ortaya çıkan paint projesi:

Paint benzeri uygulamamla yaptığım örnek çizimim
 Daha bitirmediğim için şu andaki haliyle tanıtımını yapayım dedim. Yukarıdan aşağıya sırayla;
  • 1. Buton: Kare Fırça
  • 2. Buton: Daire Fırça
  • 3. Buton: Eğik Fırça
  • 4. Buton: Şekil Çizme Aracı
  • 5. Buton ve 6. Buton şimdilik çalışmıyor ama dışarıdan resim çağırma amaçlı hazırlamıştım.
  • Alt menü de çizim araçlarının RGB cinsinden rengini ayarlamakta kullanılıyor. 
  • Fırçanın büyüklüğünü ayarlamak için klavyeden " + " ve " - " tuşlarını kullanınız. Benim klavyem numeric pad sahibi olduğu için hiç laptop aklıma gelmedi. O yüzden biraz daha zahmetli olacak numeric pad sahibi olmayanlar için :(
AS2 kullanarak yapmıştım ve malesef ki pixeller ile çalışmayı bilmediğim için o sıralar olay bir nesneyi duplicate ederek ekrana yapıştırmaktan ibaret. Duplicate etme süresine göre farenin hızına yetişemeyebilir boyama işlemi. Bu yüzdenfareyi çok hızlı kullanmanızı önermem :) Olay kısaca böyle.. İyi denemeler :)
 
Uygulamaya erişmek için tıklayınız.

1 Aralık 2010 Çarşamba

Arttırılmış Gerçeklik Çalışması 02

Dünya - Ay ve Güneş arasındaki ilişkiyi gösterdiğim projemden sonra sıra çok daha öncesinden yaptığım bir projeyi göstermekte... Bu seferkinde ise molekülleri ele eldım ve yapımında papervision3d motorunu kullandım. Bir önceki yazıdaki gerekli olan materyaller bu seferki için de geçerlidir.
Kullanılacak olan marker
  • Kaliteli çözünürlüğe sahip bir webcam
  • Marker çıktısı ( Önceki yazıda kullandığımız markerın aynısı )
  • Flash Player 10 destekli bir tarayıcı
Uygulamanın düzgün çalışabilmesi için öncelikle yukarıda belirtilen gereksinimleri tamamlamış olmanız gerekmektedir. Daha sonrasında ise internet bağlantısının sorunsuz çalışması gerekmektedir. zira modeller dışarıdan çağrılmaktadır ve listede verilen modeller arasında geçiş yapması için ilk önce o modeli yüklemesi gerekmektedir. Bu bir süre alabilir ancak yükleme işlemi sorunsuz tamamlanırsa uygulama da sorunsuz çalışacaktır :) Herkese iyi denemeler :)

Denemek için tıklayınız.

    30 Kasım 2010 Salı

    Arttırılmış Gerçeklik Çalışması 01

    "Yeni Gözde: Arttırılmış Gerçeklik" adlı yazımda tanıtımını yaptığım uygulamayı denemek için tıklayınız.

    Bu uygulamanın çalışması için;
    Uygulamada Gerekli Olan Marker.
    •  bir adet iyi bir çözünürlüğe sahip webcam,
    • "Marker" adı verilen özel tanıtılmış bir şekil, (Bu markerı indirmek için tıklayınız. İster çiziniz, ister çıktısını alınız, hiç farketmez. Tek dikkat etmeniz gereken husus, marker'ın şeklinde bir değişiklik yapmamanızdır.)
    • Son olarak da Flash Player 10'un tarayıcınızda kurulu olması gerekmektedir.

    Yukarıdaki gereksinimleri sağlıyorsanız eğer şimdi uygulamayı deneyebilirsiniz. Şimdi yapmanız gereken tek şey kamerayı marker'ı görecek şekilde tutmanızdır. 30 - 40cm'den ortalama işlemesi lazım ama bu tabi ki de sizin kameranızın kalitesiyle de doğru orantılıdır. Bir yerden sonra da olayın performansı biraz da bilgisayar ile alakalıdır. Yapımında Away3D kütüphanesi kullansam da kaliteden taviz vermek zorunda kaldım ortalama her bilgisayarda çalışabilsin diye. Umarım herhangi bir sıkıntı yaşatmaz size :)

    Kısaca şöyle çalışmaktadır; kameradan alınan görüntüye threshold filtresi uygulanarak elde edilen ortamda marker'daki gibi bir şekle sahip bir konum aramaktan ibaret tüm olay. Tabi genel yapı bu kadar ama olayın alt yapısı hiç de küçümsenemeyecek kadar derin ve güzel. Emeği geçen herkesi tebrik etmek lazım.

    Uygulamayı denemek için tıklayınız. İyi eğlenceler..

    3 Kasım 2010 Çarşamba

    Yeni Gözde: Arttırılmış Gerçeklik

    Sanalın ve gerçeğin iç içe geçmeye başladığı bir döneme girdik çoktan. 3D filmler çıktı, hemen ardından 3D film çekmenize imkan verecek kameralar, hatta fotoğraf makineleri çıktı, daha doğrusu uygun fiyata indirgendi. 3D için daha gelişmiş ekranlar ürelitdi falan filan. Bu böyle sürüp giderken biraz arkada kalmış sesini pek duyuramamış ama önemi yeni yeni keşfedilen bir konuya değinmek istiyorum, Arttırılmış Gerçekliğe ( Augmented Reality ).

    Arttırılmış gerçeklik uygulamarı yeni yeni Türkiye standartlarında piyasaya reklam amaçlı kullanılmaya başlandı. Danone'de Haber Türk'te bunlara dair örnekler bulmanız mümkün artık. Ancak bu uygulamayı ilk önce "Abbas Güçlü ile Bizim Mucitler" adlı Kanal D'de düzenlenen bir yarışmada görmüştüm. Birisi bilgisayar mühendisliğinden diğeri de edebiyat bölümünden olan iki arkadaşın geliştirdiği bir sistemdi bu.Sistem marker adı verilen özel tanıtılmış şekilleri yorumlayacak şekilde yapılandırılmıştı.Bu markerlar ise kendi hazırladıkları bir kitapın içerisine yerleştirilmişti. Sistemin bu kitapdaki markerları tanıması içinse webcam aracılık ediyordu. Ne zaman kitaptaki bir marker sistem tarafından yakalansa o markerın üzerine sistem tarafından tanımlanmış olan 3D model çıkıyordu ve başlıyordu o sayfadaki konuları anlatmaya...

    O sıralar da pek yaygınlaşamadı bu sistem ancak ben ise bu uygulamaları geçen sene bulabildim ve geliştirmeye başladım. Şimdilerde benim kullandığım sistem action script 3'ü temele almış, ancak As3 olması biraz da hantallığı beraberinde getiriyor. C++ için yazılış olan sistemler mevcut ama haliyle AS3 için yazılana oranla kullanım açısından daha karmaşık ve zor ancak performans açısından kesinlikle daha iyi. AS3'ün geliştirilip bu hantallığından kurtulması dileğiyle. Hazırlamış olduğum bu kısa videoda yaptığım temel örnekleri tanıtmak istedim, Buyrunuz:

    4 Eylül 2010 Cumartesi

    sonunda :)

    Uzun çabaların sonunda nasıl olduğundan da emin olmadığım bir şekilde ;) Hydrax'ı derlemeyi başardım. Bu benim için CEGUI'yi çözdükten sonraki en büyük mutluluğumdur. Artık projelerim Hydrax ile daha görsel bir hal alacaktır inşallah :) Teşekkürler Xavyiy bu harika çalışman için :)

     İşte bahsettiğim çalışmamın kısa videosu:

    En sonki çalışmalarımdan en baştaki çalışmalarıma doğru birkaç resim:



    Ü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 :)

    Bu projemde Hydrax olmadan deniz denemem mevcuttu ancak karadan denize geçişteki süreç keskin hatlarla belliydi. O yüzden görsel açıdan çok da etkili bir proje değildi.


    Bu resimde ise sahne ışığını CEGUI ile yönetip kısmıştım ama Sinbad karakterinin üzerindeki particle efekt devam edecek şekilde ayarlı olduğu için hoş bir etki yarattı :) CubeMap ise sahne ışığına bağlı olmadığı için sanırım ışığı kısmamdan etkili olmadı.

    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 :)

    3 Eylül 2010 Cuma

    ve sıkıntılı anlar başlar :)

    Olası Problemler:
    Programcılık yaparken sıkıntı yaşayacağınız iki durum mevcuttur. Bunlardan birincisi derleme sırasında meydana gelen hatalardır ancak kod sistemini biliyorsanız çözümünüz kolaydır. İkinci probleminiz ise sıkıntı yaratacak bir durumdur ki o da derleme sonrası porgramın çökmesidir. Eğer ki bir de nerede çöktüğünden emin değilseniz o zaman işkence başlar. Bu duruma çözüm olarak şunu önerebilirim : "cout<< "\n\n\n BURADAYIM \n\n\n";" :) evet cout inanılmaz yardımcı bir fonksiyondur. Şöyle ki; Çöktüğünü düşündüğünüz yere yakın bir kod satırına cout ile bir uyarı metni yazın. Zira programınız derlemede sıkıntı yaratmayacağı için ilerleyecektir ancak program kaçarı yoktur yine çökecektir. Mühim olan bu metinden önce veya sonra çökmesi. Önce çökerse de sonra çökerse de birkaç kod satırı öncesine veya sonrasına bir cout daha ekleyerek hangi kos satırını uygulamakta sıkıntı yaşadığını görebilirsiniz. Örneğin;
    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";

    İlk cout çıktısı karşınıza çıkıyor ama ikincisi karşınıza çıkmıyorsa bunun nedeni aradaki satırda çökmesidir. Şimdi planeEnt, Entitiy sınıfından türetilmiş bir nesnedir. Bu Entity sınıfının içerisine bakarsanız "void setMaterialName(const String& name);" adlı fonksiyonu görebilrisiniz. Zaten kod yazmada hata olsaydı derleyici hatanın kaynağını gösterirdi. Bu fonksiyonun parametresi ile alakalı bir durumdur ki nedeni de "Examples/Rockwall-12345" isimli dosyanın kaplama matertalleri arasında mevcut olmamasından kaynaklıdır. Temelinde de bu dosya dışarıdan, derleme sonrasında çağrıldığı için bu problem gerçekleşmektedir. Eğer ki projeye include edilebilen bir dosya olsaydı zaten hatanın kaynağı ortaya çıkardı.

    Diğer olası problemlere de "cfg" dosyalarına yanlış dosya ve dizinler verilmesinden kaynaklanabilir. Bunun çözümü için de log dosyasını takip etmeniz gerekmektedir. Çökmeden önceki kod satırında ne yazdığı önemlidir ve oradan tahmin etmeniz gerekir.

    Başka olası bir neden de terrain.cfg ( nasıl kullanıldığına ve yapıldığına sonra değineceğim ) dosyasında gerçekleşmektedir. Ancak buradaki problem biraz daha farklılaşabilir. İsimlendirmeler olması gerektiği gibidir ancak program yine çökmektedir. Nedeni ise terrain.cfg dosyasının dışarıdan siyah-gri-beyaz tonlamasına sahip ( gri renk ölçeğine sahip ) png dosyası çağırmasından dolayıdır. Eğer ki bu PNG dosyası olması gerektiği pikselde veya gri renk ölçeğinde değilse bile çökmelere neden olabilir.

    Çağrılan modellerin özelliklerinde bozukluk varsa çökmelere neden olabilir.

    Nesnelerin isimlendirmesinde aynı isim kullanırlırsa çökmelere neden olabilir.

    Dışarıdan çağrılan bir dosyanın ismi ile projenin içersinde bulunan bir dosyanın isminin aynı olması çökmeye neden olabilir.

    Yani görebileceğiniz gibi çökmelerin asıl nedeni dışarıdan çağrılan dosyaların içerisiyle uyumsuzluğundan kaynaklanmaktadır. Gözden kaçabilecek ufak bir hata günlerinizi yemenize neden olur aman dikkat ne diyeyim :)

    2 Eylül 2010 Perşembe

    ogre3D ve temel sınıflar ve dosyalar – bölüm 4

    Şimdiye kadar temel birkaç sınıftan bahsettik, üstüne Ogre3D ekibinin hazırlamış olduğu ExampleApplication ile ExampleFrameListener adlı iki sınıfı inceledik. Hayli kullanışlı sınıflar olduğunu gördükten sonra sıra geldi biraz daha derine inmeye :) Bu seferki yazımda ise kod sisteminde bulunan kaplamaların nereden ve nasıl atandığından, nasıl yeni materyaller tasarlayabileceğimizden bahsedeceğim. Ayrıca bazı önemli dizinlerden bunları bizim de etkin kullanabileceğimizden bahsedeceğim.

    Öncelikle OgreSDK klasörümüzü açalım, karşımıza ilk önce " bin " klasörümüz çıkacaktır. Bu klasör bizim projemizin " Debug " ve " Release " çıktılarını barındıran klasörümüzdür. Ekranın fotoğrafını çekerseniz ( ExampleFrameListener sınıfını kullanıyorsanız geçerlidir. Eğer ki kulllanmıyorsanız da harici olarak siz bu fonksiyonelliği kazandırabilirsiniz elbette ) bu resim otomatik olarak Debug dizininin içine kaydedilir. Ayrıca debug ve release dizinlerinin içerisinde bazı cfg, *_d.dll (debug dizini için ), *.dll ( release dizini için ) ve log dosyaları mevcuttur ki bunlar gerekli harici çıktı veya girdi dosyalarıdır. Örneğin " *.log " dosyaları yaptığımız eylemlerin kaytılarını tutarlar içerlerinde. " *.cfg " dosyaları da önemli olan girdi bilgilerini barındırır. Örneğin " resources.cfg " dosyası en önemli cfg dosyasıdır. Zira bu dosya " FileSystem " adı altında klasör sistemini ve " Zip " adı altında bazı önemli zip dosyalarının adreslerini içerisinde barındırır. Bu adreslemenin yanlış veya eksik yapılması derleme hatalarından ziyade programın çökmesine neden olabilecek hataları beraberinde getirir. Aynı şekilde " plugin.cfg " dosyasının içerisine, o dizinde bulunmayan pluginlerin ( ki bunlar aynı dizinde bulunan dll dosyalarımızdır. ) kayıtları girildiğinde de çökmeye neden olur.

    "Bin" dizinini hallettikten sonra sıra geldi "docs" klasörüne ki o da Ogre'nin yardım sayfasını içermektedir. Bu dizinin üstünde durmuyorum ve devam ediyorum.

    "include" dizini tahmin edebileceğiniz gibi önemli bir dizindir zira kodlarımızı içerisinde barındırır. Eğer ki harici bir kütüphaneyi projenize dahil etmek istiyorsanız bu dizine atmanızda fayda vardır zira toplu düzenli görünür en azından :)

    "samples" dizinimiz ise içerisinde Ogre3D ekibinin önceden hazırladığı örnek projeleri içermektedir. Kullanışlı bir dizindir, sık sık bu dizindeki projelere göz atmak durumunda kalacaksınız ister istemez :) en azından bende bolca böyle oldu :)

    "media" klasörünün içeriği ise bizi en çok ilgilendirecek olan kısımdır. İçerisinde bulunan "gui" klasörü, CEGUI ile yapılmış olan menüleri tutan dosyaları barındırır. CEGUI ile menü yapımına gireceğim zaman bu dosyaları nasıl kullanacağımızdan bahsedeceğim. "models" klasörümüz adından da anlaşılabileceği gibi mesh uzantılı modellerimizi barındırmaktadır içerisinde. "packs" klasörü ise Ogre'nin temel evren resimlerini barındırmakta içerisinde. Bununla birlikte resources.cfg dosyasında mevcut olan zip dosyaları da burada bulunmaktadır. Bazı dosyaları zip halinde paketleyip kullanmak tercih edilebilir. Ayrıca nasıl 3dsMax'de nasıl evren yapabileceğimize de değineceğim. "particle" klasörümüzde ise bizim efektlerimiz mevcuttur, örneğin havai fişek efekti burada barınmakta. "PCZAppMedia" klasöründe ise terrain ( belli bir gri renk ölçeğine sahip bir resimde beyazların yükseltiyi, siyahların da alçaltıyı temsil ettiği bir yüzey yapım metodu. İleride bu tekniğe detaylı değinmeyi düşünüyorum. ) nesnesinde yükseltiyi yapacak olan resimler burada tutulmaktadır. "material" klasörüen girecek olursak karşımıza "program", "script" ve "texture" adlı üç klasör daha gelecektir. "programs" kısmı benim direkt olarak kullandığım bir klasör olmadı ama yapacağınız çalışmalar dolaylı da olsa buraya erişmiştir. Zira burada çeşitli compositor efektleri için gerekli olan temel dosyalar mevcut anladığım kadarı ile. Bu kısım ile ilgili pek bir bilgim yok o yüzden yanlış bir bilgi vermeden devam ediyorum sıradaki klasöre. "scripts" klasöründe ise karşımıza bir dizi "*.material" dosyası çıkıyor beraberinde birkaç farklı dosya tipi ile birlikte. Ancak burada en çok yardımımıza koşan dosyalar yine "Example" ile başlayan dosyalarımız olacaktır. Example.material, Example.compositor, Example-Water.material gibi dosyaların içinde yine yığın halinde örnekler mevcut. Özellikle şu sıralar yapacağımız seviyedeki örnekler için bize Example.material dosyamız lazım. Gelelim "textures" klasörüne. Burada bulunan resim dosyaları da "models" klasörümüzün içerisindeki mesh uzantılı modellerimizin kaplama malzemeleri ile example.material dosyamızın içerisindeki kaplama malzemelerini barındırmaktadır. Aynı şekilde terrain nesnemizin de yüzey kaplaması buradadır.

    Şimdi sırayla bu Example dosyalarına göz atalım. Önce Example.material dosyamızın içine gireceğiz. İçerisinde "material Examples/... " şeklinde bir dizi seri vardır. Örneğin "material Examples/CloudyNoonSkyBox" bizim standart projemizdeki evren kaplamasıdır. "mSceneMgr ->setSkyBox (true, "Examples/ CloudyNoonSkyBox");" kod satırındaki "Examples/CloudyNoonSkyBox" adlı bu kaplama malzemesi Example.material dosyasının içerisinde yer almaktadır:

    material Examples/CloudyNoonSkyBox
    {
    technique
    {
    pass
    {
    lighting off
    depth_write off

    texture_unit
    {
    cubic_texture cloudy_noon.jpg separateUV
    tex_address_mode clamp
    }
    }
    }
    }

    setSkyBox () fonksiyonundan bir ortam yarattığımız için tahmin edebileceğiniz gibi evrenimiz, tam merkezinde bulunduğumuz bir küpten ibaret. Küp olduğu için de cubic_texture kısmında cloudy_noon.jpg resmi tanımlanmış. "Debug" dizininde bulunan "media.cfg" dosyasında
    "CubeMap=cloudy_noon.jpg" satırıyla bunun bir CubeMap olduğu söylenmiş. "media\packs\" dizinindeki "cubemapsJS.zip" dosyasında ise
    • cloudy_noon_BK.jpg,
    • cloudy_noon_DN.jpg,
    • cloudy_noon_FR.jpg,
    • cloudy_noon_LF.jpg,
    • cloudy_noon_RT.jpg,
    • cloudy_noon_UP.jpg.
    adlı altı tane resim bulunmaktadır. Bu altı resim asıl küp evrenimizi temsil etmektedir. material dosyasında kaplama malzemesi olarak cloudy_noon.jpg kullanılması demek aslında bu altı resimin kullanılması demek anlamına gelmektedir. Zaten eğer ki "cloudy_noon" diye OgreSDK dizininde aratırsanız bulabileceğiniz sonuçlar bu altı resimden ibaret olacaktır.

    ogre3D ve temel sınıflar ve dosyalar – bölüm 3

    Temel sınıflar yazı dizimde sıra geldi üçüncü bölüme. Bir önceki yazımda ExampleApplication sınıfından bahsetmiştim, bu seferki yazımda da ExampleFrameListener sınıfından bahsetmek istiyorum.
    Şimdi öncelikle sınıfımızın içindeki değişkenlere bir göz atalım. İçlerinde en dikkat çekici nitelikte olanlar aşağıdakiler gibidir. Diğerleri de önceden bahsettiğim değişkenlerdendir. O yüzden şimdi bize yeni ve önemli olanlarla devam edelim.
    • std::string mDebugText;
    • TextureFilterOptions mFiltering;
    • Overlay* mDebugOverlay;
    • OIS::InputManager* mInputManager;
    • OIS::Mouse* mMouse;
    • OIS::Keyboard* mKeyboard;
    • OIS::JoyStick* mJoy;
    "mDebugText" değişkeni strig sınıfından bir değişkendir ve tahmin edebileceğiniz gibi string ifadeler içindir.
    "mFiltering" değişkeni "TextureFilterOptions" kümesinin elemanlarıdır. Bu elemanlardan "TFO_BILINEAR" constructor'da aktifleşmiş durumda. Yani projeniz "TFO_BILINEAR" filtresi aktif olacak şekilde size sunuluyor. Klavyeden " T " tuşuna bastığınız zaman küme elemanları arasında değişiklik yapıyor. Bunun ayarlamalarını da yine ExampleFrameListener'ın bir fonksiyonu halletmektedir. Ancak buna yine sonra değineceğim. Şimdi bu kümenin elemanlarıyla devam edelim. "TFO_NONE, TFO_BILINEAR, TFO_TRILINEAR, TFO_ANISOTROPIC" değerleri bizim kullanabileceğimiz değişkenlerdir. Ancak bu değişkenler arasında ne gibi farklılıklar var tam ben de emin değilim. Size aşağıdaki örnekte bu değişkenler arasındaki farkı göstermek istedim. Buradan da anlaşılabileceği gibi en düzgün görüntü veren filtre tipi TFO_ANISOTROPIC filtredir. Ancak iyi olan performansı da en çok zorlayandır mantığıyla sisteminiz iyise ve iyi optimize edilmiş kodlarınız varsa kullanmanızı tavsiye edebilirim :)




    "mDebugOverlay" değişkeni de projemizi derledikten sonra karşımızla çıkan sağ alt taraftaki ogre logosu ile birlikte sol alt taraftaki debug menüsünü tutan değişkenidir.

    OIS ( Object-Oriented Input System ) sınıfından üretilen değişkenler de bizim klavye fare joystick gibi birimlerin sınıfıdır dersek yanlış olmaz sanırım. "mInputManager" değişkeni de mMouse, mKeyboard ve mJoy değişkenlerinin yöneticisidir.
    Değişkenler ile işlerimizi hallettikten sonra şimdi de önemli olan bazı fonksiyonlara bakalım.

    "Constructor"tan başlayalım. ExampleApplication sınıfı ExampleFrameListener'dan bir nesne ürettiği zaman parametre olarak mWindow ve mCamera değişkenlerini göndermiştir. Burada da görebileceğiniz gibi constructor diğer paremetrelerini false olarak atamış bulunmakta. Peki bu false değerlerini true yaparsak ne olur? O zaman kontroller miras alınan bu sınıftan alınıp sizin üreteceğiniz kodlara kalır. Yani siz herhangi bir tanımlama yazpmazsanız ne klavyenizden gelen komutlar alınır ne de farenizden. O yüzden buraya dikkat :)
    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.
    Yine "constructor"a ait olan aşağıdaki kod satırlarında her nesne kendi sınıfının varlığı olarak yaratmış ve bunları mInputManager değişkeninin kontrolüne bağlamış. Ancak bende "try" bloğu arasında mJoy değişkeninde bir problem kendini göstermeye başladı. Sebebinden emin değilim zira önceden bu problem ortaya çıkmazdı. Şöyle kısaca problemden bahsedeyim. Kod sorunsuz derlenmekte ancak konsol ekranında bu satıra gelince program kendini kapatmataydı. Bu kod satırını iptal etmek zorunda kaldım. joystik kullanma gibi bir durumum söz konusu olmadığı için de herhangi bir probleme neden olmamakta artık.
    
    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.
    "bool frameRenderingQueued(const FrameEvent& evt)" fonksiyonu da içerisinde bulunan değerleri o karenin renderleme işlemi bitene yani frameEnded olana kadar yapmayı sürdürmekle yükümlüdür. Tahmin edebileceğiniz gibi bir de frameStarted kısmı mevcuttur ancak frameListener'ın içinde tanımlı olan bu fonksiyonları ExampleFrameListener miras alırken frameStarted alınmamıştır. Şimdi bu fonksiyonun içeriğine bakalım.
    // 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.

    "bool frameEnded(const FrameEvent& evt)" fonksiyonu da karenin renderleme işlemi bitince o kareye ait hesaplama bilgilerini updateStats() fonksiyonu aracılığıyla debug penceresine göndermekle yükümlü bir fonksiyondur.

    "virtual void moveCamera()" fonksiyonunda ise kameranın konumlarını o anda hesaplanan değerler çerçevesinde ayarlayan bir fonksiyondur. "mCamera->yaw(mRotX); mCamera->pitch(mRotY);" satırları kamerayı çevirirken "mCamera-> moveRelative (mTranslateVector);" kod satırı kamerayı hareket ettirmektedir aynı move() fonksiyonunun yaptığı gibi ama biraz farklı bir şekilde. Şöyle ki; X eksenine bakan bir kameranız orjinde yer almakta diyelim. Bu kamerayı hangi eksende hareket ettirirsek ettirelim hem move() hem de moveRelative() ile baktığı konumu değişmeyecektir. Ancak kamerayı bir eksende 90 derece çevirirsek işler değişmekte. Bu sefer move() fonksiyonu yine kamerayı döndermeden önceki gibi davranırken moveRelative() fonksiyonu kameranın dönmüş konumunda ilerlemesini sağlamakta. Böylece göreceli bir çevirme söz konusu olmakta...
    "virtual bool processUnbufferedKeyInput(const FrameEvent& evt)" fonksiyonu da klavyeden bir tuşa basılırsa ve o basılan tuş tanımlıysa yapılacak eylemleri kontrol eder. Önemli birkaç tuş kontrolüne bir göz atalım şimdi:
    // 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)   
    
    Yukarıdaki kod satırlarından da anlaşılabileceği gibi belirlenen tuşa basılırsa demekten ibaret tüm olay. Eğer klavyeden " R " tuşuna basılırsa oluşacak olan değişimi yukarıdaki resimde görebilirsiniz. Soldan sağa doğru sırayla "Point" , "Wireframe" ve "Solid" teknikleridir.

    mTimeUntilNextToggle
    değişkeni de tuşa basılma arasındaki süreyi ifade ediyor dersem yanlış olmaz diye düşünüyorum. 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.


    "virtual bool processUnbufferedMouseInput(const FrameEvent& evt)" fonksiyonu da eğer farenin sağ tuşuna basıldıysa şeklinde ayarlanmıştır.
    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.

    İşte olay bundan ibaret :) bu iki sınıfı da hallettik diyelim artık sıra geldi Ogre3D dizininin içindeki bazı önemli dosya ve klasörlere. O da artık bir sonraki yazıda.

    1 Eylül 2010 Çarşamba

    ogre3D ve temel sınıflar ve dosyalar – bölüm 2

    Temel sınıfları anlattığım Ogre3D ve temel sınıflar ve dosyalar – bölüm 1 başlıklı yazıdan sonra sıra “exampleApplication.h” ile “exampleApplicationListener.h” dosyalarını incelemekte…

    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.

    • Root *mRoot;
    • Camera* mCamera;
    • SceneManager* mSceneMgr;
    • ExampleFrameListener* mFrameListener;
    • RenderWindow* mWindow;
    • Ogre::String mResourcePath;

    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();
    • createCamera();
    • createViewports();
    • createScene();
    • createFrameListener();

    ” 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:

    • ST_GENERIC : En küçük sahne yöneticisi yapısıdır. Herhangi bir sahne içeriği veya yapısı için optimize edilmemiştir. Temel düzeydeki sahneler için idealdir.
    • ST_INTERIOR : Bu seçenekte sahne yöneticisi yapısı iç mekanları renderlemek için optimize edilmiştir.
    • ST_EXTERIOR_CLOSE : Sahne yöneticisi yapısı orta seviyede görünürlüğe sahip dış mekanları renderlermek için optimize edilmiştir.
    • ST_EXTERIOR_FAR : Artık pek tercih edilmeyen bir seçenekmiş kendsisi hatta yerine ST_EXTERIOR_CLOSE veya ST_EXTERIOR_REAL_FAR kullanılması tercih edilirmiş.
    • ST_EXTERIOR_REAL_FAR : Sahne yöneticisi yapısı en geniş evrenleri haritaları yüzeyleri de desteklemeye uygundur.

    İ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… :)

    ogre3D ve temel sınıflar ve dosyalar – bölüm 1

    Daha önceki “Ogre3D’deki İlk Projemizi Anlamlandirma” başlıklı yazımda da anlattığım gibi Code::Blocks’da yeni bir Ogre projesi oluşturduk ancak bu projemizde herhangi bir değişiklik yapmamıştık.Çünkü daha temel sınıfların ve dosyaların ne işe yaradığından bahsetmedik. Şimdiki yazımda da bu konuya değinmek istiyorum.

    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;

    • mSceneNode ->translate(Vector3( 350, 15, 550 ));
    • mSceneNode->setPosition( yeniDegisken.x, 20, yeniDegisken.z );

    Ş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:

    • mSceneMgr->setSkyDome(true, “Examples/CloudySky”);
    • mSceneMgr->setSkyBox(true, “Examples/CloudySky”);
    • mSceneMgr->setSkyPlane(true, “Examples/CloudySky”);

    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.

    ogre3d'deki ilk projemizi anlamlandırma

    //———————————-ORNEK KOD ———————————–

    #include
    #include
    class SampleApp : public ExampleApplication
    {
    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 :)