|
Işık kullanarak ortamdaki nesneleri aydınlatabilir ve daha gerçekçi görünmelerini sağlayabiliriz. Daha önceleri vertex renklerini kendimiz tanımlamıştık yada dokudan almıştık. Direct3d'nin ışıklandırma sisteminde vertex'in rengi aşağıdakiler kombinasyonu ile hesaplanır: -Nesnenin materyali ve dokusu -Eğer varsa vertex renk değerleri(diffuse+specular) -Sahnenin ambians(ambient) değeri ve ortamdaki ışıkların aydınlatması Direct3d'nin ışıklandırma sistemini kullandığınızda aydınlatma hesaplarını direct3d'ye bırakırsınız. Bunun dışında gelişmiş ışıklandırma teknikleri yapmak için yöntemlerde vardır. Bkz. shader. Gerçek hayatta ışık gözümüze gelmeden önce yüzlerce yüzey tarafından emilir ve yansılıtır. Bunu gerçek zamanlı olarak simule etmek oldukça masraflı bir iştir, bu yüzden direct3d'nin ışık hesaplama yöntemi nispeten daha sadedir. Genel olarak ışık hesaplamasını şöyle yazabiliriz: Global Aydınlanma = Ambient ışık + Diffuse ışık + Specular ışık + Emissive ışık Ambient Işık : Bu ışık tipi tüm sahneye etkiyen sabit bir ışık olarak görülür.Her yönde eşittir ve bir nesnenin tüm vertexlerini aynı miktarda aydınlatır. Bir mekanda direkt olarak ışık almayan yerler genede yansıyan ışıklardan dolayı bir miktar aydınlanırlar. Bu tip bir aydınlatmayı simule etmek için ambians ışık kullanmak çok ucuz ve tatmin edici bir yöntemdir. Diffuse Işık : Bu tip ışık bir yöne sahip olup çarptığı yüzeyden her yöne yansır. Yansıma miktarı çarptığı yüzeyin normali ve materyaline göre şekillenir. Bu ışık vertex'leri farklı miktarlarda aydınlatır ve 3B hissi verir. Yansıma her yöne olduğu için eşit dağılımlı görünür. Specular Işık : Daha karmaşık bir hesaplama isteyen specular ışık, diffuse ışık gibi her yönde değil belirli açılar dahilinde parlama benzeri bir görüntü oluşturur. Diffuse ışıkta izleyicinin yeri önemli değil iken burada bakış açısıda önemlidir. Emissive Işık : Bu ışık tipindede direkt olarak nesnenin ışık değeri atanmış gibi olur. Ortamda ışık olmasa bile emissive değeri verdiğinizde nesne sabit bir şekilde aydınlanacaktır. Bir cismin ne kadar ışık yansıtacağı ışık kadar kendi maddesel özelliklerinede bağlıdır. Bunu simule etmek içinde nesnelere materyal denen değerler atarız. Bir ortamda kırmızı ışık varsa ve nesnenin materyali sadece mavi ışığı yansıtıyorsa bu nesne siyah görünecektir. Materyalde ışık gibi ambient,diffuse,specular ve emissive değerleri içerir. Bunlara ek olarak birde güç(power) değeri vardır ki oda specular ışık yansımalarının sertliğini belirler. Vertex'lerin ışık hesaplamalarına girmeleri için normal değerlerini içermeleri gerekir. Normal vertexin bakış yönünü belirten bir birim vektördür. Direct3d'de ışık hesaplanırken yüzey normali kullanılır. Yüzey normali ile vertex normalleri çoğu zaman aynı değildir bu yüzden bir yüzeyi oluşturan vertexlerin normallerinin ortalaması alınarak yüzey normali hesaplanır. //3d pozisyon + normal + uv struct vertex3d { vertex3d(){} //yapıcı metod vertex3d(float _x, float _y, float _z, float _nx, float _ny, float _nz,float _u, float _v) { x = _x; y = _y; z = _z; nx = _nx; ny = _ny; nz = _nz; u = _u; v = _v; } float x, y, z; float nx, ny, nz; float u, v; }; #define light_fvf D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1
Gördüğünüz gibi vertex tanımına normal değerlerini ekledik ve FVF tanımınada D3DFVF_NORMAL sabitini dahil ettik. //vertex buffer'ı doldur - 24 vertex vertex3d* vertices; vbuffer->Lock(0, 0, (void**)&vertices, 0); //ön yüz vertices[0] = vertex3d(-1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f); vertices[1] = vertex3d(-1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f); vertices[2] = vertex3d( 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f); vertices[3] = vertex3d( 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f); //arka yüz vertices[4] = vertex3d(-1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f); vertices[5] = vertex3d( 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f); vertices[6] = vertex3d( 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f); vertices[7] = vertex3d(-1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f); //tavan yüzü vertices[8] = vertex3d( -1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f); vertices[9] = vertex3d( -1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f); vertices[10] = vertex3d( 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f); vertices[11] = vertex3d( 1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f); //taban yüzü vertices[12] = vertex3d(-1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f); vertices[13] = vertex3d( 1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f); vertices[14] = vertex3d( 1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f); vertices[15] = vertex3d(-1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f); //sol yüz vertices[16] = vertex3d(-1.0f, -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f); vertices[17] = vertex3d(-1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f); vertices[18] = vertex3d(-1.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f); vertices[19] = vertex3d(-1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f); //sağ yüz vertices[20] = vertex3d( 1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f); vertices[21] = vertex3d( 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f); vertices[22] = vertex3d( 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f); vertices[23] = vertex3d( 1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f); vbuffer->Unlock(); Kullandığımız şekil küp olduğu için vertex normalleri basit değerler(vertexin baktığı yön değerlerini verdik). Daha komplike nesneler için vertex normallerinin hesaplanması daha zordur. Örnek olarak p1,p2,p3 vertexlerinin oluşturduğu bir üçgende , oluşan yüzeyin normalini bularak vertex normali olarak atayabiliriz ama bu pek sağlıklı sonuçlar doğurmaz. Onun yerine v vertexini paylaşan tüm yüzeylerin normallerinin ortalamasını almak(normal averaging) daha uygundur. Daha sonra göreceğimiz mesh yapılarının normallerini hesaplamak içinse d3dx bize yardımcı olacak. //ışığı ayarları aygit->getDevice()->SetRenderState(D3DRS_LIGHTING, true); aygit->getDevice()->SetRenderState(D3DRS_NORMALIZENORMALS, true); aygit->getDevice()->SetRenderState(D3DRS_SPECULARENABLE, true);
Bir ışık nesnesi tanımlamadan önce aygıtı ışık kullanımına hazırlayalım. İlk olarak ışık hesaplamasını aktif hale getiriyoruz. Hesapladığımız normallerin transformasyonlar sırasında değişebileceğini göz önünde bulundurarak bunların her seferinde normalize edilmeleri güvenli olacaktır. Son olarak specular ışık hesaplaması varsayılan durumda kapalı olduğu için onu da açıyoruz. Sahneye ışık eklerken bunun bir sınırı olduğunu unutmayınız, şuan ki tüm donanımlar(en azından benim bildiğim) aynı anda en fazla 8 ışık kullanımı destekliyorlar. Tabiki kendi ışık sisteminizi yazarak bu sınırları aşabilirsiniz. //ışık ekle D3DLIGHT9 isik; isik.Type = D3DLIGHT_DIRECTIONAL; isik.Ambient = D3DXCOLOR(0.25,0.25,0.25,1.0); isik.Diffuse = D3DXCOLOR(1.0,1.0,1.0,1.0); isik.Specular = D3DXCOLOR(0.75,0.75,0.75,1.0); isik.Direction = D3DXVECTOR3(1.0,-1.0,1.0);
Direct3d'de bir ışık kaynağı D3DLIGHT9 yapısıyla tanımlanır. Direct3d'de 3 çeşit ışık türü vardır, bunlar: D3DLIGHT_POINT (nokta ışık) D3DLIGHT_SPOT (spot ışık) D3DLIGHT_DIRECTIONAL (yönlü ışık) Neye benzediklerini kavramak için Bkz Resim1. Tip parametresi dışında ışık yapısında şu parametreler bulunur: Diffuse : Diffuse ışık rengi. Specular : Specular ışık rengi. Ambient : Ambient ışık rengi. Position : Işığın konumu, directional(yönlü) ışık için kullanılmaz. Direction : Işığın yönü, point(nokta) ışık için kullanılmaz. Range : Işığın menzili, karekök(max_float) 'dan büyük olamaz, directional ışık için kullanılmaz. Falloff : Spotlight için kullanılır, iç ve dış halkalar arası geçişte ışığın zayıflama miktarını belirtir. Attenuation0-1-2 : Işığın uzaklıkla zayıflama miktarının hesaplanmasında kullanılırlar, directional ışık için kullanılmaz. Theta : Spotlight için iç halkanın açısını belirtir(Radyan). Phi : Spotlight için dış halkanın açısını belirtir(Radyan). Resim 1:
//ışığı aç aygit->getDevice()->SetLight(0, &isik); aygit->getDevice()->LightEnable(0, true);
Işığı tanımladıktan sonra onu SetLight metodu ile atamalı ve LightEnable metodu ile aktive etmeliyiz. İlk parametre 0-7 arası bir değer olup kaçıncı ışık olduğunu belirtir. //material ayarla D3DMATERIAL9 mat; mat.Ambient = D3DXCOLOR(1.0,1.0,1.0,1.0); mat.Diffuse = D3DXCOLOR(1.0,1.0,1.0,1.0); mat.Specular = D3DXCOLOR(0.5,0.5,0.5,1.0); mat.Emissive = D3DXCOLOR(0.0,0.0,0.0,0.0); mat.Power = 10; aygit->getDevice()->SetMaterial(&mat); Son olarak D3DMATERIAL yapısı ile bir materyal tanımlıyoruz. Alt alanlarından daha önce bahsetmiştik. Burada beyaz renkli bir materyal tanımladık. SetMaterial metodu ile mevcut materyalide atamış olduk. Buradan sonra daha önce yaptığımız gibi bir döngüde çizim işlemleri yapılıyor. -Diğer ışık tipleri ve kullanımlarıyla ilgili çalışma yapmanız önerilir. Kaynak Kodu İndir -------- EKSTRALAR -------- Ekran Kartı Bilgisi Kodu: http://directx.oyungelistirici.net/dx/onbilgi.rar Kavramlar: http://www.oyungelistirici.net/index.php/egitseller/14-oyunyapimi/233-kavramlar DirectX Kaynakları: http://www.chadvernon.com/blog/tutorials/ http://www.directxtutorial.com/ http://www.zanir.szm.sk/index.html http://www.pieterg.com/ http://www.32bits.co.uk/ http://triplebuffer.devmaster.net/tutorials/archive/ http://www.two-kings.de/ http://www.mvps.org/directx/indexes/index.htm http://www.drunkenhyena.com/cgi-bin/directx.pl DirectX Kitapları: http://www.amazon.com/ adresinde DirectX'i aratmanız yeterli. -------- ÖNEMLİ -------- -Bu sitedeki dökümanlar Türkçe kaynak eksikliği yüzünden hazırlanmış ve ihtiyaç duyanların serbest kullanımına sunulmuştur. -Sunulan kodlar ve bilgilerin doğruluk ve etkinlikleri konusunda bir garanti verilmemekle beraber her türlü talep ve düzeltmelerinizi mail yada ilgili forum başlığı yoluyla iletebilirsiniz -Dökümanlarda daha çok genel kavramlara değinilmiş olup detaylı bilgi edinmek için directx dökümanını ve çeşitli kaynakları (özellikle kitap) okumanız tavsiye edilir. Farklı kaynakların bağlantılarını bu dökümanın sonunda bulabilirsiniz. -Bu eğitsellerden verim alabilmek için orta düzeyde c++ bilgisi yeterlidir. Onun dışında winAPI hakkında bilgi sahibi olmak directx'i kavramakta size yardımcı olacaktır. Ayrıca eğitseller ardışık bağlantılı olduğu için bu işte yeni iseniz sırayla gitmeniz tavsiye edilir. -Örnek kodlar Virusl Studio 2003 projeleridir, vs2005 ile de kullanılabilir. -Kavramları Türkçeleştirmek için çok çaba sarfedilmemiştir, çoğu yerde İngilizce isimler kullanılmıştır. Merak ettikleriniz için kavram sözlüğüne bakabilirsiniz. -İndireceğiniz yazılımlardan dolayı PC'nizin ya da bünyenizin zarar görmesi durumunda sorumluluk kabul etmeyiz, geçmiş olsuna gelebiliriz :) -Yazılanların hakkı saklı değildir, sağda solda ben yaptım diye dağıtabilirsiniz :)
Yunus KARA
|