ÿþM icrosoft W ord - I a . D 1 _ K apak
Transkript
ÿþM icrosoft W ord - I a . D 1 _ K apak
KARADENİ Z TEKNİ K ÜNİ VERSİ TESİ MÜHENDİ SLİ K FAKÜLTESİ Bİ LGİ SAYAR MÜHENDİ SLİ ĞİBÖLÜMÜ Cg PROGRAMLAMA Dİ Lİ VE Cg İ LE PÜRÜZLÜ YÜZEY DOKUSU ÜRETİ Mİ Bİ Tİ RME TEZİ UMUT DOĞAN Trabzon 2006 KARADENİ Z TEKNİ K ÜNİ VERSİ TESİ MÜHENDİ SLİ K FAKÜLTESİ Bİ LGİ SAYAR MÜHENDİ SLİ ĞİBÖLÜMÜ Cg PROGRAMLAMA Dİ Lİ VE Cg İ LE PÜRÜZLÜ YÜZEY DOKUSU ÜRETİ Mİ UMUT DOĞAN Tezin Bölüme Verildiği Tarih : 02.06.2006 Tezin Savunma Tarihi : 23.06.2006 Tez Danı ş manı : Öğr. Gör. Ömer ÇAKIR Jüri Üyesi : Yrd. Doç. Dr. Murat EKİ NCİ Jüri Üyesi : Yrd. Doç. Dr. Hüseyin PEHLİ VAN Jüri Üyesi : Yrd. Doç. Dr. Tuğrul ÇAVDAR Bölüm Baş kanı : Prof. Dr. Rı fat YAZICI Trabzon, 2006 ÖNSÖZ “Cg Programlama Dili ve Cg ile Pürüzlü Yüzey Dokusu Üretimi” konulu bu çalı ş ma, Karadeniz Teknik Üniversitesi, Mühendislik Fakültesi, Bilgisayar Mühendisliğ i Bölümü’nde “Bitirme Tezi” olarak hazı rlanmı ş tı r. Bitirme tez danı ş manlı ğı nıüstlenerek, gerek konu seçimi, gerekse çalı ş maları n yürütülmesi ve değerlendirilmesi sı rası nda ilgi ve yardı mları nıesirgemeyen saygı değer hocam Öğr. Grv. Ömer ÇAKIR’a ve çalı ş maları m sı rası nda bana yardı mcıolan diğer hocaları m ve arkadaş ları ma teş ekkür ederim. Umut DOĞAN II İ Çİ NDEKİ LER Sayfa No ÖNSÖZ …………………………………………………………………………………… II İ Çİ NDEKİ LER …………………………………………………………………………... III ÖZET …………………………………………………………………………………….. VI ŞEKİ LLER Dİ Zİ Nİ…………………………………………………………………...... VII 1. GENEL Bİ LGİ LER ……………………………………………………………….......... 1 1.1. Cg Nedir ……………………………………………………………………………… 1 1.1.1. Cg: Grafik Donanı mıProgramlama Dili …………………………………………… 2 1.1.2. Cg’nin Veri Akı şModeli …………………………………………………………… 2 1.1.3. Özel AmaçlıGPU – Genel AmaçlıCPU ………………………………………..….. 3 1.1.4. Cg’nin Performans Temeli ….……………………………………………………… 3 1.1.5. Cg’nin Geleneksel Dillerle Birlikte Kullanı mı…………………………………….. 4 1.1.6. Diğer Açı lardan Cg ………………………………………………………………… 6 1.1.7 Cg Programları nı n Sı nı rlıÇalı ş ma Ortamı……………………………………..…… 7 1.2. Vertexler, Fragmentlar ve Grafik Pipeline …………………………………………… 7 1.2.1. Bilgisayar Grafikleri Donanı mı nı n Geliş imi ……………………………………….. 7 1.2.2. Bilgisayar Grafikleri Donanı mı nı n Dört Kuş ağ ı…………………………………… 9 1.2.2.1. GPU Öncesi Dönemde Grafik Hı zlandı rı cı lar …………………………………... 10 1.2.2.2. Birinci Kuş ak GPU’lar ………………………………………………………….. 10 1.2.2.3. İ kinci Kuş ak GPU’lar …………………………………………………………… 10 1.2.2.4. Üçüncü Kuş ak GPU’lar …………………………………………………………. 11 1.2.2.5. Dördüncü Kuş ak GPU’lar ………………………………………………………. 11 1.2.3. Grafik Donanı mıPipeline’ı……………………………………………………….. 12 1.2.3.1. Vertex Dönüş ümü ……………………………………………………………….. 13 1.2.3.2. Primitif Montajıve Pikselleş tirme ……………………………………………… 14 1.2.3.3. İ nterpolasyon, Doku Kaplama, Renklendirme ………………………………….. 15 1.2.3.4. Tarama İ ş lemleri ………………………………………………………………… 15 1.2.3.5. Grafik Pipeline’ıGörselleş tirme ………………………………………………... 15 1.2.4. Programlanabilir Grafik Pipeline’ı………………………………………………... 16 1.2.4.1. Programlanabilir Vertex İ ş lemcisi ………………………………………………. 17 III 1.2.4.2. Programlanabilir Fragment İ ş lemcisi …………………………………………… 19 1.2.5. Cg; Vertex ve Fragment Programlanabilirliği Sağlar ……………………………... 20 1.3. Cg’nin Tarihsel Geliş imi ……………………………………………………………. 21 1.3.1. Cg ve HLSL’yi Geliş tirmek İ çin NVIDIA ve Microsoft İ ş birliği ………………… 22 1.3.2. Etkileş imli Olmayan Shading Dilleri …………………………………………....... 23 1.3.2.1. Shade Ağaçları………………………………………………………………….. 23 1.3.2.2. Renderman Shading Dili ………………………………………………………... 24 1.3.2.3. Donanı ma Uygun Shading Dilleri ………………………………………………. 25 1.3.3. Üç Boyutlu Grafikler İ çin Programlama Arayüzleri ……………………………… 26 1.4. Cg Ortamı…………………………………………………………………………… 26 1.4.1. Standart 3B Programlama Arayüzleri: OpenGL ve Direct3D …………………….. 26 1.4.1.1. OpenGL …………………………………………………………………………. 27 1.4.1.2. Direct3D ………………………………………………………………………… 27 1.4.2. Cg Derleyicisi ve Runtime’ı………………………………………………………. 27 1.4.2.1. Dinamik Derleme Desteğ i ………………………………………………………. 28 1.4.2.2. 3B API’lere Özgü Cg Kütüphaneleri: CgGL, CgD3D ………………………….. 28 1.4.2.3. Cg Runtime Uygulamamı za Nası l Uyum Sağlar ……………………………….. 29 1.4.3. CgFX Araç Takı mıve Dosya Biçimi ……………………………………………... 29 1.4.3.1. CgFX Ne Sağlar ………………………………………………………………… 29 1.4.3.2. Çoklu Shader Örnekleme ……………………………………………………….. 30 1.4.3.3. CgFX ile Sayı sal İ çerik Oluş turma ……………………………………………... 31 1.4.3.4. CgFX Uygulamamı za Nası l Yerleş ir …………………………………………… 31 2. Cg Dİ Lİ Nİ N KURALLARI …………………………………………………………... 33 2.1. Cg Dil Profilleri ……………………………………………………………………... 33 2.2. Cg’de Programları n Tanı mlanması…………………………………………………. 34 2.3. Program Girdi ve Çı ktı ları…………………………………………………………... 34 2.3.1. Vertex Programları ndaki Değiş ken Girdiler ……………………………………… 34 2.3.2. Vertex Programları ndaki Değiş ken Çı ktı lar ………………………………………. 35 2.3.3. Fragment Programları ndaki Değiş ken Çı ktı lar …………………………………… 37 2.4. Veri Tipleri ………………………………………………………………………….. 39 2.4.1. Temel Veri Tipleri ………………………………………………………………… 39 2.4.2. Tip Dönüş ümleri …………………………………………………………………... 40 2.4.3. Yapı lar ve Üye Fonksiyonlar ……………………………………………………... 41 IV 2.4.4. Diziler ……………………………………………………………………………... 42 2.4.4.1. Boyutsuz Diziler ………………………………………………………………… 42 2.4.4.2. Arayüzler ………………………………………………………………………... 42 2.5. İ fadeler ve Operatörler ……………………………………………………………… 43 2.5.1. Kontrol Akı ş ı……………………………………………………………………… 43 2.5.2. Fonksiyon Tanı mlamalarıve Aş ı rıYüklemeler …………………………………... 43 2.5.3. Aritmetik Operatörler ……………………………………………………………... 44 2.5.4. Çarpma Fonksiyonu ………………………………………………………………. 44 2.5.5. Vektör Yapı cı lar ……………………………………..……………………………. 44 2.5.6. Bool ve Karş ı laş tı rma Operatörleri ……………………………………………….. 44 2.5.7. Swizzle Operatörü ………………………………………………………………… 45 2.5.8. Write Mask Operatörü …………………………………………………………….. 45 2.5.9. Koş ullu Operatörler ……………………..………………………………………… 45 2.6. Cg Standart Kütüphane Fonksiyonları……………………………………………… 46 2.6.1. Matematiksel Fonksiyonlar ……………………………………..………………… 46 2.6.2. Geometrik Fonksiyonlar ……………………………………..……………………. 47 2.6.3. Doku Kaplama Fonksiyonları…………………………………………………….. 47 3. Cg VE DIRECT3D İ LE YAZILMIŞKOD ÖRNEKLERİ…………………………… 48 3.1. Cg ile Kod Yazabilmek için Ayarlar ………………………………………………... 48 3.2. Basit Bir Vertex Programı…………………………………………………………... 49 3.3. Dalgalanan Türk BayrağıUygulaması……………………………………………… 57 4. Cg İ LE PÜRÜZLÜ YÜZEY DOKUSU ÜRETİ Mİ…………………………………... 64 4.1. Pürüzlü Yüzey Dokusu Üretimi Programlama Ortamı……………………………... 64 4.2. Pürüzlü Yüzey Dokusu Üretimi Nedir ……………………………………………… 64 4.3. Programda Kullanı lan Algoritmalar ………………………………………………… 65 4.4. Cg ile İ lgili Kı sa Bilgiler ……………………………………………………………. 72 4.5. Cg Runtime ………………………………………………………………………….. 73 4.6. Cg Shader’ları……………………………………………………………………….. 75 4.7. Ana Program ………………………………………………………………………… 78 5. SONUÇLAR ………………………………………………………………………….. 87 6. ÖNERİ LER ……………………………………………….……………………………88 7. KAYNAKLAR ………………………………………………………………………... 89 V ÖZET Bu bitirme tezinde; Cg grafik donanı mı programlama dili, ayrı ntı ları yla anlatı lmı ş tı r. Tez grafik donanı mı nı n geçmiş iyle ilgili bilgiler verdikten sonra GPU’nun çalı ş ma birimlerini açı klamaktadı r. Daha sonra shading dillerinin oluş um süreciyle ilgili ayrı ntı lar anlatı lmı ş tı r. Cg dilinin temel özellikleri, kurallarıtezin önemli bir kı smı nı oluş turmaktadı r. Cg ve Direct3D ile yazı lmı şkod örnekleri açı klanarak ilk kez Cg kodu yazacaklara önemli bilgiler verilmeye çalı ş ı lmı ş tı r. Ana proje olaraksa Cg ve OpenGL kullanarak pürüzlü yüzey üretilmiş tir. Anahtar kelimeler: Cg, C for Graphics, GPU, Direct3D, OpenGL, NVIDIA, Microsoft, Pürüzlü Yüzey Üretimi, Bump mapping, Bilgisayar Grafikleri, Visual C++, Shading, Vertex, Fragment, 3B, CgFX, Cg Runtime VI ŞEKİ LLER Dİ Zİ Nİ Sayfa No Şekil 1.1. Örnek Assembly ve Cg Programları………………………………………. 5 Şekil 1.2. Grafik Donanı mıGeliş imini Sağlayan Etmenler ………………………….. 8 Şekil 1.3. FarklıKuş aklardan NVIDIA GPU’larıiçin Performans Tablosu ……….. 12 Şekil 1.4. Grafik Donanı mıPipeline’ı……………………………………………… 13 Şekil 1.5. Geometrik Primitifler……………………………………………………... 13 Şekil 1.6. Standart OpenGL ve Direct3D Tarama İ ş lemleri ………………………... 16 Şekil 1.7. Grafik Pipeline’ı n Görselleş tirilmesi …………………………………….. 16 Şekil 1.8. Programlanabilir Grafik Pipeline ………………………………………… 17 Şekil 1.9. Programlanabilir Vertex İ ş lemci Akı şDiyagramı……………………….. 18 Şekil 1.10. Programlanabilir Fragment İ ş lemci Akı şDiyagramı……………………. 20 Şekil 1.11. Cg’nin Teknolojisini Miras Aldı ğıKaynaklar …………………………… 21 Şekil 1.12. Cg’nin Geliş tirilme Sürecinde Esinlenilen Kaynaklar …………………... 22 Şekil 1.13. Rob COOK’un Makalesini Temel Alan Bir Shade Ağacı……………….. 24 Şekil 1.14. Standart Bir Cg Uygulaması nda Cg’nin Yeri ……………………………. 29 Şekil 1.15. Cg ve CgFX Kullanan Sayı sal İ çerik Oluş turma Uygulamaları…………. 31 Şekil 1.16. Standart Bir Uygulamada CgFX’in Yeri ………………………………… 32 Şekil 3.1. Basit Bir Vertex Programı……………………………………………….. 56 Şekil 3.2. Dalgalanan Türk Bayrağı………………………………………………… 63 Şekil 4.1. Orijinal 2B Resim ve Pürüzlü Yüzey Uygulanmı şHali …………………. 64 Şekil 4.2. (a) Herhangi bir yüzey Dokusu Şekil 4.3. Normal Map ……………………………………………………………… 66 Şekil 4.4. Yüzeyle İ liş kili Vektörler ………………………………………………... 68 Şekil 4.5. Uzaylar ve Dönüş üm Matrisleri ………………………………………….. 69 Şekil 4.6. Teğet UzayıKoordinatları……………………………………………….. 70 Şekil 4.7. Üçgen ve Vertexleri ……………………………………………………… 73 Şekil 4.8. Cg ile Pürüzlü Yüzey Dokusu Üretimi Ekran Görüntüleri ………………. 86 VII (b) Normal Map …………………... 66 1. GENEL Bİ LGİ LER 1.1. Cg Nedir Cg programlama dili, programlanabilir grafik donanı mıkullanı larak çizilen nesnelerin biçim, görünüm ve hareketlerini kontrol edebilmemizi sağlar. Bu özelliklerin programa dayalıkontrolüyle günümüz grafik iş lemcilerinin inanı lmaz hı z ve kapasitelerini birleş tirir. Bilgisayar grafikleri uygulamacı ları , çizim sanatçı larıve programcı lar Cg dili oluş turulmadan önce ürettikleri gerçek-zamanlıgörüntülerde bu kadar kontrol sahibi olamı yorlardı . Cg, yazı lı m geliş tiricilere kolay kullanı labilir bir programlama platformu sunar ve özel efektlerin hı zlıyaratı lması nı , birçok platformda sinema kalitesinde görüntüler oluş turmayıoldukça basitleş tirir. Yeni bir soyutlama seviyesi sağ layan Cg, geliş tiricilerin grafik donanı mı nı assembly dili kullanarak programlama zorunluluğunu ortadan kaldı rı r. OpenGL, DirectX gibi üç boyutlu (3B) programlama API’leri; Windows, Linux, Macintosh OSX gibi iş letim sistemleri ve Xbox gibi oyun konsolları nda kolayca programlanabilir. Cg; NVIDIA ve Microsoft ş irketlerinin ortak çalı ş malarısonucunda geliş tirilmiş tir. OpenGL API’si ve Microsoft’un DirectX9 için ürettiği High Level Shading Language (HLSL) ile uyumlu çalı ş ı r. oluş turulmuşpopüler, genel amaçlıbir dildir. Popülerliği ve sorunsuz tasarı mınedeniyle C dili kendisinden sonra gelen birçok dil için temel oluş turmuş tur. Örneğ in C++, Java ve C# ‘ı n sözdizimi ve yapı sıbüyük oranda C ‘ye benzer. Cg dili de kendisini C tabanlıbir dil olarak tanı mlar. C veya türevi bir programlama dilini iyi bilen birisi için Cg’yi öğrenmek çok kolay olacaktı r. Öte taraftan; C veya diğer genel amaçlıprogramlama dillerini iyi bilmeyen ancak bilgisayar grafiklerine ilgi duyan ve yeni bir ş eyler öğrenmek isteyen kiş iler için de Cg Umut DOGAN - Bitirme Tezi - Haziran 2006 Cg, ‘C for graphics’ deyiminin kı saltması dı r. C programlama dili 1970’lerde 2 dilini öğrenmek çok zor olmayacaktı r. Çünkü Cg programlarıoldukça kı sa ve anlaş ı labilir yapı dadı r. 1.1.1. Cg: Grafik Donanı mıProgramlama Dili Cg dili; C, C++ ve Java’dan oldukça farklı dı r. Çünkü özel amaçlı dı r. Örneğin, Cg kullanarak bir kelime iş lemci programıyazamayı z. Bunun yerine Cg, grafik donanı mı nı kullanarak nesnelerin biçim, görünüm ve hareketini programsal açı dan kontrol edebilmemizi sağlar. Bilgisayar grafiklerinde bu tarz bir dile shading dili denir. Cg kullanarak ‘shading’ uygulamaları nı n yanı nda fiziksel simülasyonlar da oluş turabiliriz. Genel olarak bir Cg programı , programlanabilir grafik donanı mıkullanı larak bir nesnenin nası l gerçeklenebileceğ ini anlatan detaylıbir reçete olarak düş ünülebilir. Bir yüzeyi engebeli göstermek için veya sanal bir karakteri canlandı rmak için Cg ile programlar yazı labilir. 1.1.2. Cg’nin Veri Akı şModeli Cg ve diğ er shading dilleri, geleneksel programlama dillerinden sadece grafik programlamaya özgü olmaları yla ayrı lmazlar. Bunun dı ş ı nda da önemli farklı lı klara sahiptirler. Çünkü shading dilleri veri akı şhesaplama modeline göre çalı ş ı rlar. Bu modelde hesaplamalar iş lem adı mları ndan akan veriye yanı t olarak oluş ur. Cg programları , bir görüntüyü gerçeklerken iş lenen vertex ve fragmentlardan uğ radı ğıve öbür taraftan dönüş üme uğramı şş ekilde çı ktı ğ ıbir kara kutu gibi düş ünebiliriz. Ancak, buradaki kara kutu tam bir kara kutu özelliği göstermez çünkü Cg programı nıbiz yazdı ğı mı z için kara kutunun içinde neler olup bittiğine biz karar veririz. 3B bir sahne gerçeklenirken her bir vertex iş lendiğinde veya (pikselleş tirici bir fragment ürettiğinde) ilgili vertex (veya fragment) Cg programıçalı ş ı r. Umut DOGAN - Bitirme Tezi - Haziran 2006 oluş ur. Cg programı nıbir tarafı ndan vertex ve fragmentları n girdiği, içerisinde dönüş üme 3 Yeni nesil kiş isel bilgisayarları n ve oyun konsolları nı n tümü 3B modelleri dönüş türme ve pikselleş tirme gibi grafik iş lemlerini yapmakla görevli bir grafik iş leme birimi (GPU, Graphics Processing Unit) içerirler. Cg programıbu GPU içinde çalı ş ı r. 1.1.3. Özel AmaçlıGPU – Genel AmaçlıCPU Bir kiş isel bilgisayar veya oyun konsolu GPU’ya sahip olsa da olmasa da iş letim sistemini veya uygulama programları nıkoş an bir CPU’ya mutlaka sahip olmalı dı r. CPU’lar tasarı msal olarak genel amaçlı dı r ve C++, Java gibi genel amaçlıdillerde yazı lmı ş uygulamalarıçalı ş tı rı rlar. GPU’lar ise, özel amaçlıtasarı mlarınedeniyle 3B sahneleri gerçeklemek gibi grafiksel görevlerde, genel amaçlıbir CPU’dan onlarca kat daha hı zlı dı rlar. Son nesil GPU’lar saniyede on milyonlarca vertex iş leyebilir ve yüz milyonlarca (hatta milyarlarca) fragment pikselleş tirebilirler. Gelecekteki GPU’lar elbette daha da hı zlıolacaklardı r. GPU’nun da genel amaçlı programları CPU’nun çalı ş tı rabileceği kadar hı zlı çalı ş tı ramayacağıunutulmamalı dı r. Cg’nin var oluşnedeni GPU’nun özel amaçlı , yüksek performanslıyapı sı dı r. Genel amaçlıprogramlama dilleri vertex ve fragmentlarıiş lemek gibi özel bir görev için yetersizdirler. Cg diliyse kendini tümüyle bu göreve adamı ş tı r. Cg, GPU’nun çalı ş ma modelini soyutlayan bir yapı ya sahiptir. Etkileş imli görüntü oluş turabilmek için bir 3B uygulama saniyede 15 veya daha fazla görüntüden oluş an canlandı rma oranı na (animation rate) sahip olmalı dı r. Genelde gerçek zamanlıuygulamalarda 60 veya daha fazla çerçeve (frame) kullanı lı r. Bilgisayar ekranlarısürekli tekrar oluş turulmasıgereken bir milyon veya daha fazla piksel içerir. 3B sahneler için GPU, nesnelerin birbirlerini kapatı p kapatmadı ğ ı nıbelirlemek veya piksellerin görünüş ünü geliş tirmek için ekrandaki her pikseli birçok kez iş ler. Yani gerçek zamanlı3B uygulamalar saniyede yüz milyonlarca pikselin güncellenmesini gerektirir. 3B modeller; çokgenleri, çizgileri ve noktalarıoluş turan piksellere dönüş türülmeden önce Umut DOGAN - Bitirme Tezi - Haziran 2006 1.1.4. Cg’nin Performans Temeli 4 uygun bir ş ekilde dönüş türmemiz gereken vertexlerden oluş ur. Bu, saniyede on milyonlarca vertex’in dönüş ümü anlamı na gelir. Ayrı ca, grafik iş leme sürecinde CPU’nun da her bir görüntü için canlandı rmayı güncelleme gibi önemli bir görevi vardı r. Gerçek ş udur ki, hem CPU’ya hem de GPU’nun uzmanlaş mı şgrafik-tabanlıyeteneklerine ihtiyacı mı z vardı r. Hem CPU hem de GPU; sahneleri, 3B uygulama ve oyunları n istediği ş ekilde etkileş im oranları yla kalite standartları nda gerçeklemek için gereklidir. Özetle, yazı lı m geliş tirici, C++ kullanarak 3B bir uygulama veya oyun yazabilir ve daha sonra GPU’nun grafiksel katkı ları ndan yaralanmak için Cg’yi kullanabilir. 1.1.5. Cg’nin Geleneksel Dillerle Birlikte Kullanı mı Cg, hiçbir ş ekilde var olan genel amaçlıbir programlama dilinin yerini almamaktadı r. Cg, GPU’lar için özel olarak tasarlanmı şyardı mcıbir dildir. C ve C++ gibi geleneksel dillerde CPU için yazı lmı şprogramlar, Cg programları nıyüklerken GPU’nun çalı ş tı rmasıiçin Cg runtime’ı nıkullanabilirler. Cg runtime, Cg programları nıGPU’da koş acak ş ekilde yüklemek, derlemek, düzenlemek ve ayarlamak için kullanı lan altyordamlar standardı dı r. Cg, paralel iş lemenin özel bir biçimini sağlar. CPU, geleneksel bir uygulama çalı ş tı rı rken uygulama aynızamanda Cg programları nda yazı lmı şvertex ve fragmentlerin GPU’da paralel iş lenmesini yönetir. icat edilmedi?” sorusu yöneltilebilir. Bu sorunun yanı tıbilgisayar grafikleri donanı mı nı n geliş imiyle ilgilidir. 2001 yı lıöncesinde birçok bilgisayar grafiği donanı mısadece vertex ve fragment iş leme yapabilecek ş ekilde sabit bağlantı lı ydı . Burada “sabit bağlantı lı ” derken algoritmaları n donanı ma bağlıve sabit olduklarıbelirtiliyor. Yani bir programlama dili kullanarak, grafik uygulamaları nıdeğiş tirmek mümkün değildi. Grafik uygulamaları bu algoritmalarda değiş iklikler yapabiliyordu, fakat donanı m tasarlayı cı sı nı n tahmin edemediği bir durum için programcı , donanı mıtekrar programlama yeteneğine sahip Umut DOGAN - Bitirme Tezi - Haziran 2006 Tam bu noktada “Gerçek zamanlıbir shading dili iyi bir fikirse, neden daha önce 5 değildi. Ama bu durum günümüzde değiş ti. Belki de bunun en önemli mimarları ndan birisi Cg dilidir. 2001 sonrası nda grafik donanı m tasarı mıgeliş ti ve yeni GPU’lardaki vertex ve fragment iş leme birimleri gerçekten programlanabilir oldu. Programlanabilir grafik donanı mıüretilmeden önce bunun için bir programlama dili geliş tirmenin bir anlamıyoktu. Günümüzde böyle bir donanı m olduğu için bu donanı mıkolay bir ş ekilde programlamaya gereksinimimiz var. C’nin CPU programlamada getirdiği kolaylı ğı Cg, GPU programlamada sağlamı ş tı r. Cg’den önce GPU’nun programlama özelliklerini kullanabilmek için alçak-seviyeli assembly dili kullanmak gerekiyordu. Karmaş ı k emir sözdizimi ve donanı m kaydedicilerini elle değiş tirme zorunluluğu nedeniyle (DirectX8’deki vertex ve pixel shaderlar ve bazıOpenGL uzantı ları ndaki gibi) GPU programlamak birçok geliş tirici için zor ve zaman alı cıbir iş ti. GPU teknolojisinin geliş mesiyle assembly kodlarıbüyümeye ve karmaş ı klaş maya baş layı nca yüksek seviyeli bir dile gereksinim ortaya çı ktı . Düş ük seviyede programlamayla sağlanan optimum performans yüksek seviyeli GPU programlama dillerinin ortaya çı kması yla optimize derleyiciler tarafı ndan sağlandı . Optimize derleyici, kod çı ktı sı nıoptimize etmekle ve sı kı cıemir tarifeleme iş lemlerini halletmekle görevlidir. Şekil 1.1’de karmaş ı k GPU assembly dili kullanan bir program Şekil 1.1: Örnek Assembly ve Cg Programları Umut DOGAN - Bitirme Tezi - Haziran 2006 parçacı ğıve hemen yanı nda da uygun Cg program parçacı ğ ıverilmiş tir. 6 Görüldüğü gibi donanı m kaydedicilerine yaptı ğıçok özel referanslar nedeniyle assembly kodunu anlamak oldukça güçtür. Tersine, kurallara uygun yazı lmı şbir Cg programıdaha taş ı nabilir, daha okunaklı , hatalardan kolay ayı klanabilir ve kolaylı kla tekrar kullanı labilir bir yapı dadı r. Daha da önemlisi Cg dili, C gibi yüksek seviyeli bir dilde çalı ş manı n avantajları nıve assembly koduyla yazmanı n performansı nısağlar. 1.1.6. Diğer Açı lardan Cg Cg, “küçükte programlama” mantı ğı na uyan bir dildir. Böyle bir dille programlamak, C++ gibi genel amaçlıbir dilde programlamaktan daha çok verimlilik sağ lar. Cg, vertex ve fragment dönüş ümleri üzerinde uzmanlaş tı ğıiçin yazı lı m mühendisliği programları nda kullanı lan birçok karmaş ı k özelliği içermez. C++ ve Java’dan farklıolarak Cg, sı nı f yapı sı nıve nesne tabanlıprogramlamanı n diğer özelliklerini desteklemez. Şu anki Cg sürümlerinde iş aretçiler (pointer) ve bellek tahsisi desteklenmemektedir. Cg’nin dosya girdi/çı ktıiş lemleri için desteği yoktur. Bu kı sı tlamaları n nedeni Cg dili değildir. Günümüz GPU’ları nı n yapı sıbu özelliklerin desteklenmesine izin gerçeklenebilmesine ve vermemektedir. dil yapı sı na Ancak Cg, katı lması na bu özelliklerin ileride olanak sağ layacak ş ekilde yapı landı rı lmı ş tı r. Cg, dizi (array) ve yapı ları(structure) destekler. Modern bir dilin tüm akı ş -kontrol yapı ları na sahiptir: döngüler, koş ullar, fonksiyon çağrı ları . Cg doğal olarak vektör ve matrisleri destekler. Çünkü bu veri tipleri matematik donanı mları na temel oluş tururlar. Cg, Standard Library adıverilen bir fonksiyon kütüphanesine sahiptir. Bu kütüphanede grafiklerle ilgili programlar yazarken gerekli olan birçok fonksiyon bulunmaktadı r. Örneğin Cg Standard Library, yansı tma vektörlerini hesaplamak için reflect adı nda bir fonksiyon içerir. Cg programlarıgöreli yalı tı mla (relative isolation) çalı ş ı r. Yani herhangi bir vertex veya fragment’in iş lenmesinin, aynıanda iş lenmekte olan diğer vertex veya fragment’ler üzerinde bir etkisi yoktur. Cg programı nı n çalı ş masısı rası nda yan etki oluş maz. Vertex ve Umut DOGAN - Bitirme Tezi - Haziran 2006 iş lemleriyle iliş kilidir; grafik programlama ve vektör veri tiplerini destekleyen grafik 7 fragmentler arası nda bağı mlı lı ğı n olmamasıCg programları nı n donanı msal çalı ş ma açı sı ndan yüksek derecede pipeline’lıve paralel olması nısağlar. 1.1.7. Cg Programları nı n Sı nı rlıÇalı ş ma Ortamı CPU için genel amaçlıbir program yazdı ğı mı zda, eğer kurallara uymuş sak sorunsuz bir ş ekilde derlenmesini bekleriz. Çünkü CPU tasarı msal olarak genel amaçlı programlarıçalı ş tı rabilmek için gerekli kaynaklarısağlar. Ancak GPU’da durum farklı dı r. Çünkü GPU özel amaçlı dı r. Bu nedenle bir GPU için yazdı ğ ı mı z programı n baş ka GPU’larda koş up koş amayacağı nıgaranti edemeyiz. Bu nedenle Cg, donanı m profilleri adı nda bir özellik sunar. Her profil belli GPU mimarisi ve grafik API’sinin birleş iminden oluş muş tur. Programı n sadece doğru olmasıyetmez, aynı zamanda uygun profilin de seçilmişolmasıgereklidir. Öneğin bir fragment profili her bir fragment için dörtten fazla doku oluş turulması na izin vermiyor olabilir. Bu durumda uygun profili seçmezsek problemle karş ı laş ı rı z. Profillerle oluş turulan sı nı rlandı rmalar GPU kaynaklı dı r. Sı nı rlandı rmanı n nedeni Cg değildir. NVIDIA firmasıgelecekte daha iyi GPU’lar üretildikçe bu profillerin de güncelleneceği garantisini vermektedir. Cg programları yla ş u anki profillerle yazı lmı ş kodlar gelecekte aynış ekilde çalı ş tı rı labilir olacaklardı r. 1.2. Vertexler, Fragmentlar ve Grafik Pipeline pipeline’ıaçı klanacaktı r. 1.2.1. Bilgisayar Grafikleri Donanı mı nı n Geliş imi Günümüzde bilgisayar grafikleri donanı mıinanı lmaz hı zlarla geliş iyor. Şekil 1.2’de gösterildiği gibi bu hı zlıgeliş meyi sağlayan üç önemli etmen vardı r. Umut DOGAN - Bitirme Tezi - Haziran 2006 Bu bölümde grafik donanı mı nı n tarihsel geliş im süreci ve modern grafik donanı mı 8 Şekil 1.2 : Grafik Donanı mıGeliş imini Sağlayan Etmenler Birinci etmen, Moore yasası dı r. Yarıiletken endüstrisi bir mikroçip üzerinde bulunan transistor sayı sı nıher 18 ayda bir ikiye katlayacağı nıbelirtmiş tir. Moore Yasası olarak bilinen, bilgisayar gücünün bu ş ekilde sabit bir sürede ikiye katlanmasıdaha ucuz ve hı zlıbilgisayar donanı mıanlamı na gelir. İ kinci etmen, görüntü oluş turmanı n paralel yapı sı dı r. Etrafı mı zdaki dünyayısimüle edebilmek için çok sayı da paralel hesaplamalar yapmalı yı z. 3B dünyadaki görüntüleri inanı lmaz hı zda ve gerçeklik oranı nda algı ları z. Bilgisayar grafiklerinde de bu kavrayı ş noktası na gelebilmemiz günümüz teknolojisiyle olanaksı z görünmektedir. Ancak gün geçtikçe görüntü kalitesi çok iyi boyutlara gelmektedir. Şansı mı za, görüntü üretimi paralel bir problemdir. Paralel problemi hı zlıbir ş ekilde çözebilmek için problemi küçük parçalara Üçüncü etmen ise görsel olarak uyarı lmasıve eğlendirilmesi gereken tutkumuzdur. Bu etmen sayesinde donanı m teknolojisinin geliş imini kullanarak görsel güzellikte görüntüler yaratı yoruz. Günümüzde animasyon film endüstrisinin geldiği nokta inanı lmaz boyutlardadı r. Neredeyse her ay sinemalarda bir animasyon film gösterime girmektedir. Bundan 8–10 yı l kadar önce 15–20 dakikalı k bir animasyon film yaratabilmek uzun yı llar, büyük bütçe ve çok sayı da insan gücü gerektiren zor bir iş ti. Bugün ise gerek animasyon filmler gerekse 3B oyunlar kaliteli animasyonlarla oluş turulabilmektedir. Umut DOGAN - Bitirme Tezi - Haziran 2006 bölmek gereklidir. 9 Bilgisayar grafikleri donanı mı , diğer elemanlara nazaran çok daha hı zlıbir ş ekilde ilerlemektedir. Böylece daha kaliteli görüntü üretmek daha da hı zlıbir hale gelmektedir. İ ş te bu nedenler Cg dilinin ortaya çı kı ş ı nıhı zlandı rmı ş tı r. 1.2.2. Bilgisayar Grafikleri Donanı mı nı n Dört Kuş ağı 1990’ları n ortaları nda dünyanı n en hı zlıgrafik donanı mı ; görüntüleri oluş turmak ve ekranda göstermek için birlikte çalı ş an birçok çipin bir araya gelmesinden oluş uyordu. En karmaş ı k bilgisayar grafikleri sistemleri farklıboardlara yayı lmı şdüzinelerce çipten oluş uyordu. Zaman geçtikçe ve yarı iletken teknolojisi geliş tikçe donanı m mühendisleri karmaş ı k çok sayı da çipten oluş an sitemleri tek bir grafik çipinde topladı lar. Bu geliş meler ölçekleme nedeniyle ekonomik yönden avantaj sağ ladı . Günümüzde GPU’lar, bir mikroçipte içerdikleri transistor sayı sıbakı mı ndan CPU’larıgeçmiş lerdir. Transistor sayı sıbir mikroçipe ne kadar bilgisayar donanı mı ayrı ldı ğı yla ilgili kaba bir ölçümdür. Örneğin Intel’in 2.4 GHz’lik Pentium 4’ünde 55 milyon transistor vardı r; öte yandan NVIDIA’nı n GeForce FX GPU’sunda 125 milyondan fazla transistor vardı r. NVIDIA firması , terminolojiye GPU kelimesini “VGA denetleyicisi” terimi PC’deki grafik donanı mı nıtam olarak tanı mlamadı ğı1990’ları n sonunda sokmuş tur. IBM, 1987’de VGA (Video Graphics Array) teknolojisini ilk kez piyasaya sunmuş tu. O zamanlar VGA denetleyicisi, bizim ş u anda akı lsı z çerçeve tamponu (dumb frame buffer) dediğimiz ş eydi. Bu, “CPU tüm pikselleri güncellemekten sorumluydu” anlamı na donanı mıtasarı mcı sıGPU’nun içerisine piksel güncellemelerinden sorumlu akı llıbirimler yerleş tirmiş tir. Endüstri tarihçileri genel olarak dört GPU kuş ağıtanı mlarlar. Her kuş akta GPU performansı ve programlanabilirlik özellikleri geliş miş tir. Ayrı ca her kuş ak 3B programlama arayüzleri olan OpenGL ve DirectX’i etkilemiş tir. OpenGL; Windows, Linux, UNIX ve Macintosh bilgisayarları nda 3B programlama için bir açı k standarttı r. Umut DOGAN - Bitirme Tezi - Haziran 2006 gelmekteydi. Günümüzde CPU, pikselleri nadiren doğrudan iş ler. Bunun yerine grafik 10 DirectX ise Microsoft tarafı ndan geliş tirilmekte olan çoklu ortam programlama arayüzüdür. DirectX, 3B programlama için Direct3D’yi içerir. 1.2.2.1. GPU Öncesi Dönemde Grafik Hı zlandı rı cı lar GPU’lar ortaya çı kmadan önce Silicon Graphics (SGI) ve Evans & Sutherland gibi firmalar özel ve pahalıgrafik donanı mlarıtasarladı lar. Bu firmalar tarafı ndan tasarlanan grafik sistemleri günümüzde de kullanı lan vertex dönüş ümleri, doku kaplama gibi birçok kavramıortaya çı karmı ş tı r. Bu sistemler bilgisayar grafikleri açı sı ndan önemlidir. Ancak çok pahalıolmalarınedeniyle PC’ler ve oyun konsollarıiçin geliş tirilmiştek çipli GPU’ları n baş arı sı na ulaş amamı ş lardı r. Günümüzdeki GPU’lar bu sistemlerden çok daha hı zlıve ucuzdurlar. 1.2.2.2. Birinci Kuş ak GPU’lar GPU’ları n birinci kuş ağı(1998’e kadar) NVIDIA’nı n TNT2’si, ATI’nin Rage’i ve 3dfx’in Voodoo3’ünü içerirler. Bu GPU’ları n önceden dönüş türülmüş üçgenleri pikselleş tirme ve bir veya iki doku uygulama özellikleri vardı . Aynızamanda DirectX6 özellik takı mı nıda gerçekleş tirdiler. Birçok 2B ve 3B uygulamayıçalı ş tı rı rken, CPU’nun her bir pikseli güncelleme özelliğinden yararlandı lar. Ancak bu GPU’ları n iki önemli kı sı tlamasıvardı : Birincisi, 3B nesnelerin vertexlerini dönüş türme yetenekleri yoktu, vertex dönüş ümleri CPU’da yapı lı yordu. İ kincisi, dokularıbirleş tirdikten sonra ilgili pikselin rengini belirlemek için çok az sayı da matematik iş lemi vardı . İ kinci kuş ak GPU’lar (1999 – 2000) NVIDIA’nı n GeForce 256’sıve GeForce 2’si, ATI’nin Radeon 7500’ü ve S3’ün Savage3D’si ş eklinde sı ralanabilir. Bu GPU’lar 3D vertex dönüş ümü ve ı ş ı klandı rması(T&L) yükünü CPU’dan aldı lar. Bu kuş ağa kadar hı zlı vertex dönüş ümü işistasyonlarıile PC’leri ayı ran önemli özelliklerden biriydi. Hem OpenGL hem de DirectX7 donanı msal vertex dönüş ümlerini desteklemektedir. Bu kuş akta bazımatematiksel iş lemler geliş tirilmişolsa da olası lı klar hala sı nı rlı dı r. Öte yandan, bu Umut DOGAN - Bitirme Tezi - Haziran 2006 1.2.2.3. İ kinci Kuş ak GPU’lar 11 kuş ak daha çok ayarlanabilir (configurable) olan, ama hala gerçekten programlanabilir olmayan bir kuş aktı r. 1.2.2.4. Üçüncü Kuş ak GPU’lar Üçüncü kuş ak GPU’lar (2001) NVIDIA’nı n GeForce3’ünü ve GeForce 4 Ti’sini, Microsoft’un Xbox’ı nıve ATI’nin Radeon 8500’ünü içerirler. Bu kuş akta OpenGL ve DirectX7’in belirlediği vertex T&L biçimlerini kullanmak yerine GPU uygulamanı n vertexleri iş lemek için emir ardı ş ı klı ğı nıbelirlemesine izin vermiş tir. Piksel seviyesinde daha fazla ayarlanabilirlik vardı r, ancak bu özellikler hala programlanabilirlik sağ lamamaktadı rlar. Bu GPU’lar vertex programlanabilirliği sağladı ğıama gerçek piksel programlanabilirliği sağlamadı ğıiçin geçişkuş ağı dı r. DirectX8 ve OpenGL uzantı sı ARB_vertex_program uygulamalarda vertex seviyesi programlanabilirlik sağlamı ş tı r. DirectX8 piksel shaderlerıve değiş ik üreticilere özgü OpenGL uzantı ları , fragment seviyesi ayarlanabilirliğ i geniş letmiş tir. 1.2.2.5. Dördüncü Kuş ak GPU’lar Dördüncü ve ş u anki kuş ak olan GPU’lar (2002 ve sonrası ) CineFX mimarisine sahip NVIDIA’nı n GeForce FX ailesini, ATI’nin Radeon 9700’ünü içerirler. Bu GPU’lar hem vertex seviyesi hem de piksel seviyesi programlanabilirlik sağlarlar. Bu kuş akta CPU’nun vertex ve piksel dönüş ümlerindeki yükü büyük oranda GPU’ya kaydı rı lmı ş tı r. DirectX9 ve değ iş ik OpenGL uzantı larıbu GPU’ları n vertex seviyesinde ve piksel seviyesinde programlanabilirliğ ini sağ lamı ş tı r. Şekil 1.3de farklıkuş aklara ait NVIDIA Tabloda kı yaslama yapı lı rken ş u terimler kullanı lmı ş tı r: Süreç – her bir mikroçipi üretmek için kullanı lan yarı iletkenin mikron olarak minimum boyutudur. Transistör – Çiplerin tasarı m ve üretim karmaş ı klı ğı , milyon olarak verilmiş yaklaş ı k değerdir. Antialiasing doldurma oranı– GPU’nun pikselleri doldurma yeteneği, saniyede milyon olarak 32 bit RGBA pikseli ş eklinde verilmiş tir. Umut DOGAN - Bitirme Tezi - Haziran 2006 GPU’larıve özellikleri gösterilmiş tir. 12 Poligon oranı– GPU’nun üçgen çizebilme yeteneği. Saniyede çizilen milyon olarak verilmişüçgen sayı sı dı r. Kuş ak Yı l Ürün Adı Süreç Transistör Antialiasing Poligon Dold. Oranı Oranı Birinci 1998 RIVA TNT 0.25 µ 7M 50 M 6M Birinci 1999 RIVA TNT2 0.22 µ 9M 75 M 9M İ kinci 1999 GeForce 256 0.22 µ 23 M 120 M 15 M İ kinci 2000 GeForce2 0.18 µ 25 M 200 M 25 M Üçüncü 2001 GeForce3 0.15 µ 57 M 800 M 30 M Üçüncü 2002 GeForce4 Ti 0.15 µ 63 M 1200 M 60 M Dördüncü 2003 GeForce FX 0.13 µ 125 M 2000 M 200 M Şekil 1.3: FarklıKuş aklardan NVIDIA GPU'larıİ çin Performans Tablosu Gelecekte GPU’lar ş u anki GPU’ları n programlanabilirlik özelliklerini geliş tireceklerdir. Cg de bu geliş melere sürekli uyumlu olacağı nı n garantisini vermiş tir. 1.2.3 Grafik Donanı mıPipeline’ı Pipeline, sabit sı rayla paralel bir ş ekilde çalı ş an aş amalar (stages) dizisidir. Her aş ama girdisini bir önceki aş amadan alı r ve çı ktı sı nıbir sonraki aş amaya gönderir. Pipeline kavramı ; belli bir anda her otomobilin farklıbir aş amada olduğ u, düzinelerce otomobilin aynıanda üretildiği otomobil üretim tesislerindeki çalı ş ma mantı ğı yla açı klanabilir. Grafik donanı mıpipeline’ıçok sayı da vertex, geometrik primitifler ve fragmentler üzerinde pipeline’lıçalı ş ma biçimiyle çalı ş ı r. gösterilmiş tir. 3B uygulama, geometrik primitifler olarak toplanmı şvertex dizisini GPU’ya gönderir: tipik çokgenler, çizgiler ve noktalar… Şekil 1.5’te görüldüğ ü gibi geometrik primitifleri gösterebilmenin birçok yolu vardı r. Her vertex’in bir durum değeri vardı r. Ayrı ca her vertex renk, ikincil (veya specular) renk, bir veya daha fazla doku koordinatı takı mı , normal vektörü gibi diğer birçok özelliğe de sahiptir. Normal vektörü, yüzeyin vertex ile hangi yönde yüzleş tiğini belirtir ve genelde ı ş ı klandı rma hesaplamaları nda kullanı lı r. Umut DOGAN - Bitirme Tezi - Haziran 2006 Şekil 1.4’te günümüzdeki GPU’lar tarafı ndan kullanı lan grafik donanı mıpipeline’ı 13 Şekil 1.4: Grafik Donanı mıPipeline’ı 1.2.3.1. Vertex Dönüş ümü Grafik donanı m pipeline’ı nda ilk iş lem aş amasıvertex dönüş ümüdür. Vertex dönüş ümü her vertex üzerinde bir dizi matematiksel iş lemler gerçekleş tirir. Bu iş lemlerden bazı larıpikselleş tirici tarafı ndan kullanı labilecek ş ekilde vertex koordinatları nıekran koordinatları na dönüş türmek, doku kaplama için doku koordinatları nıüretmek ve vertex’in Şekil 1.5: Geometrik Primitifler Umut DOGAN - Bitirme Tezi - Haziran 2006 rengini belirlemek için onu ı ş ı klandı rmak ş eklinde sı ralanabilir. 14 1.2.3.2. Primitif Montajıve Pikselleş tirme Dönüş müş vertexlerin sonraki aş amaya doğru akmaları na primitif montajı (primitive assembly) ve pikselleş tirme (rasterization) denir. İ lk önce primitif montajı adı mı nda vertex dizisiyle birlikte gelen geometrik primitifler birleş tirme bilgisine göre vertexlere dönüş türülür. Bu iş lem sonucunda üçgenler, noktalar, çizgiler dizisi oluş ur. Primitifler bakı şpenceresine göre (view frustum, 3B uzayı n görülebilir kı smı ) kı rpı lmayı (clipping) gerektirebilir. Pikselleş tirici, poligonlarıgörünen alanı n içinde veya dı ş ı nda kalması na göre yok sayabilir. Bu iş leme de culling denir. Clipping ve culling aş amaları ndan sonra geri kalan poligonları n pikselleş tirilmesi gereklidir. Pikselleş tirme iş lemi bir geometrik primitif tarafı ndan çevrelenmişpikseller topluluğunu belirleme iş lemidir. Poligonlar, çizgiler ve noktalar her bir primitifin kuralları na göre pikselleş tirilir. Pikselleş tirme sonucunda fragment olarak bilinen piksel gruplarıoluş ur. Bir primitifin vertex sayı sı yla, pikselleş tirildikten sonra üretilen fragmentlerin sayı sıarası nda bir iliş ki yoktur. Örneğin sadece üç tane vertexten oluş an bir üçgen tüm ekranıkaplayı p milyonlarca fragment oluş turabilir. Fragment ve piksel farklıkavramlardı r. Piksel kelimesi, görüntü elemanı(picture element) kelimesinin kı saltı lmı ş ı dı r ve çerçeve tamponunun belli bir noktadaki renk, derinlik ve o yerle ilgili diğer bilgilerini gösterir. Fragment ise belli bir pikseli güncellemek için gerekli durumdur. Fragment terimi kullanı lmaktadı r çünkü pikselleş tirme üçgen gibi her bir geometrik pikselin bulunduğu yer, derinlik değeri ve renk, ikincil renk, bir veya daha fazla doku koordinat kümeleri gibi interpole edilmişbazıparametrelere sahiptir. Bu interpole edilmiş çeş itli parametreler, fragment üretmede kullanı lan belli bir geometrik primitifi oluş turan dönüş türülmüşvertexlerden türetilir. Fragment, “potansiyel piksel” olarak düş ünülebilir. Eğer fragment çeş itli pikselleş tirme testlerini geçerse bu fragment, çerçeve tamponundaki ilgili pikseli günceller. Umut DOGAN - Bitirme Tezi - Haziran 2006 primitifi, primitifin kapladı ğıher pikseli, piksel-boyutlu fragmentlere böler. Bir fragment 15 1.2.3.3. İ nterpolasyon, Doku Kaplama, Renklendirme Bir primitif, sı fı r veya daha fazla fragment’a pikselleş tirilirse interpolasyon, doku kaplama, renklendirme aş amasıfragment değerlerini uygun ş ekilde interpole eder, gerekli doku kaplama ve matematik iş lemleri dizisini gerçekleş tirir ve her fragment’in kesin rengini belirler. Fragment’in kesin rengini belirledikten sonra bu aş ama aynızamanda yeni derinlik belirleyebilir ve hatta fragment’in, çerçeve tamponunun ilgili pikselini güncellemesini engelleyebilir. Bu aş ama bazıfragment’leri yok sayabileceği için aldı ğıher girdi fragment için bir veya sı fı r renkli çı ktıfragmenti verir. 1.2.3.4. Tarama İ ş lemleri Tarama (raster) iş lemleri aş aması , çerçeve tamponu güncellenmeden önce hı zlıbir ş ekilde her fragment için son iş lemler dizisini gerçekleş tirir. Bu iş lemler OpenGL ve DirectX’in standart kı sı mları dı r. Bu adı mda gizli yüzeyler derinlik testi (depth testing) denilen bir yöntemle elemine edilir. Blending, stencil-based shadowing gibi diğer efektler de bu aş amada gerçekleş tirilir. Tarama iş lemleri aş amasıscissor, alpha, stencil ve depth testleri için her fragmenti kontrol eder. Bu testler fragment’in son renk derinliğ ini, piksel konumunu, pikselin derinlik ve stencil değerleri gibi her bir piksel için olan değerleri gerektirir. Eğer herhangi bir test baş arı sı zlı kla sonuçlanı rsa pikselin renk değeri güncellenmez ve fragment atı lı r. Test baş arı yla geçilirse pikselin derinlik değ eri yerine fragment’in derinlik değeri atanı r. Testlerden sonra blending iş lemiyle fragmentin son rengi ilgili pikselin renk değeriyle harmanlaş mı şrenk yazı lı r. Şekil 1.6’da bu iş lemler ardı ş ı klı ğıgörülmektedir. Şekilden görüldüğü gibi tarama iş lemleri aş amasıpipeline aş amalarıserisidir. 1.2.3.5. Grafik Pipeline’ıGörselleş tirme Şekil 1.7’de grafik pipeline betimlenmiş tir. Şekilde iki üçgen pikselleş tirilmiş tir. İ ş lem vertexlerin dönüş türülmesi ve renklendirilmesiyle baş lar. Daha sonra primitif assembly aş aması nda noktalıçizgilerde gösterildiği gibi vertexlerden üçgenler yaratı lı r. Umut DOGAN - Bitirme Tezi - Haziran 2006 birleş tirilir. Son olarak frame buffer’a yazma iş lemiyle pikselin renk değeri olarak 16 Bundan sonra pikselleş tirici (rasterizer), üçgenleri fragmentlerle doldurur. Son olarak vertexlerin register değerleri interpole edilerek doku kaplama ve renklendirme için kullanı lı r. Birkaç tane vertex’ten birçok fragment elde edildiği görülüyor. Şekil 1.6: Standart OpenGL ve Direct3D Tarama İ ş lemleri Şekil 1.7: Grafik Pipeline'ı n Görselleş tirilmesi Günümüzde grafik donanı mı tasarı mı nda yönelim GPU’nun daha fazla programlanabilir olması yönündedir. Şekil 1.8’de programlanabilir bir GPU’nun pipeline’ı nda gerçekleş en vertex ve fragment iş leme aş amalarıgörülüyor. Şekil 1.8, Şekil 1.4’ten daha ayrı ntı lı dı r. Daha da önemlisi vertex ve fragment iş leme adı mları nı programlanabilir birimlere ayrı lmı ş ş ekilde göstermektedir. Umut DOGAN - Bitirme Tezi - Haziran 2006 1.2.4. Programlanabilir Grafik Pipeline’ı 17 Programlanabilir vertex iş lemcisi, Cg vertex programları nı n üzerinde koş tuğu donanı mdı r. Benzer ş ekilde, programlanabilir fragment iş lemcisi ise Cg fragment programları nı n üzerinde koş tuğu donanı mdı r. Şekil 1.8: Programlanabilir Grafik Pipeline Daha önce de belirtildiği gibi GPU tasarı mızaman içerisinde geliş ti ve vertex ve fragment iş lemciler sadece ayarlanabilir olmaktan çı kı p programlanabilir hale dönüş tüler. 1.2.4.1. Programlanabilir Vertex İ ş lemcisi Şekil 1.9 programlanabilir vertex iş lemcisinin akı şdiyagramı nıgöstermektedir. Vertex iş lemenin veri-akı şmodeli her bir vertex’in konum, renk, doku koordinatlarıgibi bütün emirleri alı r ve vertex program sonlanı ncaya kadar çalı ş tı rı r. Emirler konum, normal ve renk gibi vektör değerlerini içeren farklıkaydedici (register) bankları na eriş irler. Vertex öznitelik kaydedicileri (attribute registers) salt okunur özelliktedirler ve vertex için uygulama tarafı ndan belirlenmişdeğerleri içerirler. Geçici kaydediciler (temporary registers) hem okunup hem yazı labilirler ve ara değerleri hesaplamak için kullanı lı rlar. Çı ktısonuç kaydedicileri (output result registers) salt yazı lı rdı rlar. Program sonuçları nıbu kaydedicilere yazmakla sorumludurlar. Vertex programısonlandı ğızaman çı ktısonuç Umut DOGAN - Bitirme Tezi - Haziran 2006 özelliklerinin vertex iş lemciye yüklenmesiyle baş lar. Daha sonra vertex iş lemci, sı rayla 18 kaydedicileri dönüş türülmüşyeni vertex’i içerir. Üçgen kurma ve pikselleş tirmeden sonra, her kaydedicinin interpole edilmişdeğerleri fragment iş lemciye geçirilir. Şekil 1.9: Programlanabilir Vertex İ ş lemci Akı şDiyagramı Vertex iş leme adı mları nı n birçoğu, sı nı rlısayı da iş lem çeş idi kullanı r. İ ki, üç, dört bileş enli kayan noktalıvektörler üzerinde iş lem yapabilen vektör matematik iş lemleri maksimumdur. Vektör olumsuzlama ve component-wise swizzling (vektör bileş enlerinin rasgele yeniden sı ralanması ) için donanı m desteği bu vektör matematik emirlerini olumsuzlama, çı karma ve vektör çarpı mı nıiçerecek ş ekilde geneller. Component-wise write mask tüm emirlerin çı ktı ları nıkontrol etmekle yükümlüdür. Tersi (reciprocal) ve reciprocal karekök iş lemlerini vektör çarpı mıve iç çarpı mlarla birleş tirmek sı rası yla vektör-skaler bölmeyi ve vektör normalizasyonunu etkinleş tirir. Üstel, logaritmik ve trigonometrik yaklaş ı mlar ı ş ı klandı rma, sis ve geometrik hesaplamalarıkolaylaş tı rı r. Özel Umut DOGAN - Bitirme Tezi - Haziran 2006 zorunludur. Bu iş lemler toplama, çarpma, çarpma-toplama, iç çarpı m, minimum ve 19 emirler sayesinde ı ş ı klandı rma ve zayı flatma (attenuation) fonksiyonlarıdaha kolay hesaplanabilir hale gelirler. Bundan baş ka, sabitlerin göreli adreslenmesi, dallanma ve döngüler için akı ş kontrol desteği gibi özellikler son zamanlardaki vertex iş lemcilerde bulunmaktadı r. 1.2.4.2. Programlanabilir Fragment İ ş lemcisi Programlanabilir Fragment iş lemcileri, programlanabilir vertex iş lemcilerle hemen hemen aynımatematik iş lemlerine ihtiyaç duyarlar, ayrı ca doku kaplama iş lemlerini de desteklerler. Doku kaplama iş lemleri iş lemcinin doku görüntüsüne doku koordinatları nı kullanarak eriş mesini sağlar ve daha sonra doku görüntüsünün filtrelenmişbir örneğini döndürür. Yeni GPU’lar kayan-noktalıdeğerler için tam desteğe sahiptir, eski GPU’larda ise sı nı rlıoranda sabit-noktalıveri türleri vardı r. Kayan noktalıiş lemlerin olması na rağmen, düş ük duyarlı klıveri türleri kullanı larak daha etkin bir ş ekilde yapı labilir. Günümüzdeki GPU’lar birçok fragmenti bir kerede iş leyebilecek ş ekilde rasgele dallanmaya sahip değillerdir, ancak donanı mı n geliş mesiyle ilerleyen yı llarda bu özellik eklenebilir. Cg, dallanma (branching) ve yineleme (iterate) yapı ları nısimüle etmek için koş ullu atama ve döngü açma (loop unrolling) iş lemlerini kullanarak fragment programları yazmamı za olanak sağlar. diyagramıverilmiş tir. Programlanabilir vertex iş lemcilerdeki gibi veri akı ş ı , program sonlanı ncaya kadar sı rayla belli emirlerin koş ulması nıgerektirir. Yine aynış ekilde girdi kaydedicileri vardı r. Ancak vertex özelliklerinden farklıolarak fragment iş lemcisinin salt okunur girdi kaydedicileri, fragment’in primitiflerinin her bir vertex için parametrelerinden türetilmiş , interpole edilmişher bir fragment için parametreleri içerirler. Yaz/oku geçici kaydedicileri ara değerleri tutarlar. Salt-yazı lı r çı ktıkaydedicilerine yapı lan yazma iş lemleri fragmentin rengi ve opsiyonel olarak yeni derinliği olurlar. Fragment programı emirleri doku alı mları nı(fetch) içerirler. Umut DOGAN - Bitirme Tezi - Haziran 2006 Şekil 1.10’da günümüzde kullanı lan programlanabilir fragment iş lemcilerin akı ş 20 Şekil 1.10: Programlanabilir Fragment İ ş lemci Akı şDiyagramı 1.2.5. Cg; Vertex ve Fragment Programlanabilirliği Sağlar Uygulama programcı sı ; GPU’daki bu iki programlanabilir iş lemcinin her birine, algoritması nıGPU donanı mı nı n çalı ş tı rabileceği bir dile dönüş türmek için gerekli dili ve derleyiciyi sağlamaktı r. Cg sayesinde programcıŞekil 1.9 ve 1.10’da belirtilen seviyelerde program yazmak yerine C’ye benzeyen yüksek seviyeli bir dille program yazabilir. Umut DOGAN - Bitirme Tezi - Haziran 2006 çalı ş tı rı labilmesi için bir program oluş turmalı dı r. İ ş te Cg’nin buradaki görevi, shading 21 1.3. Cg’nin Tarihsel Geliş imi Cg dili teknolojisini genel olarak, Şekil 1.11’de gösterilen kaynaklardan miras almı ş tı r. Sözdizimi ve anlambilim özellikleri, genel amaçlıC programlama dilinden mirastı r. Ayrı ca, Renderman ve üniversiteler tarafı ndan üretilmişdiğer çevrimdı ş ıshading dillerinden birçok kavram içermektedir. Son olarak, gerçek zamanlıüç boyutluluk sağ layabilmek için gerekli grafiksel fonksiyonelliği OpenGL, Direct3D gibi programlama arayüzlerinden almı ş tı r. Şekil 1.12’de Cg’nin tasarı mısı rası nda ilham alı nan genel amaçlıprogramlama dilleri, 3B API’leri ve shading dilleri gösterilmiş tir. Umut DOGAN - Bitirme Tezi - Haziran 2006 Şekil 1.11: Cg'nin Teknolojisini Miras Aldı ğıKaynaklar 22 Şekil 1.12: Cg'nin Geliş tirilme Sürecinde Esinlenilen Kaynaklar 1.3.1. Cg ve HLSL’yi Geliş tirmek İ çin NVIDIA ve Microsoft İ ş birliği NVIDIA ve Microsoft, Cg dilini geliş tirmek için birlikte çalı ş tı lar. Microsoft benzer özelliklerdeki kendi ürününe High-Level Shading Language (HLSL) ismini vermiş tir. HLSL ve Cg birçok özellikleri ortak olduğundan aynıdil olarak tanı mlanabilirler. HLSL, bileş enidir. Cg ise bütün 3B programlama arayüzlerinden bağı msı zdı r ve hem Direct3D hem OpenGL ile tümüyle bütünleş ik bir ş ekilde çalı ş abilir. Kurallara uygun yazı lmı şbir Cg uygulaması , bir kere yazı lı p hem OpenGL hem de Direct3D ile çalı ş tı rı labilir. NVIDIA’nı n Cg’si tüm 3B programlama arayüzleri ve iş letim sistemiyle uyumlu bir ş ekilde çalı ş maktadı r. Cg; Windows, Linux veya Mac OS X iş letim sistemlerinden herhangi biriyle, Xbox gibi oyun konsolları yla veya gömülmüş(embedded) 3B donanı m platformuyla rahatlı kla çalı ş abilmektedir. Cg programlarıbirçok donanı m üreticisinin Umut DOGAN - Bitirme Tezi - Haziran 2006 Microsoft’un DirectX API’sinin bir parçası dı r. Direct3D, DirectX API’sinin 3B 23 donanı mı yla çalı ş maktadı r çünkü Cg baş arı lıbir ş ekilde Direct3D veya OpenGL üzerinde katman oluş turur. Cg programları3DLabs, ATI, Matrox, NVIDIA gibi birçok büyük grafik donanı mıfirması nı n programlanabilir GPU’sunda sorunsuz bir ş ekilde çalı ş abilmektedir. Cg dilinin çok sayı da donanı m üreticisi tarafı ndan desteklenmesi, çok sayı da API’de kullanı labilmesi, çok sayı da platformda çalı ş masıbu dili programlanabilir GPU’lar için program yazarken kullanı labilecek en iyi dil konumuna sokmaktadı r. 1.3.2. Etkileş imli Olmayan Shading Dilleri RenderMan arayüz standardı , en çok bilinen etkileş imli olmayan shading dili olarak karş ı mı za çı kmaktadı r. Pixar firmasıbu dili, 1980’lerin sonunda filmlerde yüksek kalitede bilgisayar animasyonlarıkullanabilmek için üretti. Pixar, RenderMan’le birlikte PRMan (PhotoRealistic RenderMan) adı nda çevrimdı ş ıbir rendering sistem üretti. Renderman Shading Dili bu sistemin sadece bir bileş eniydi. 1.3.2.1. Shade Ağaçları Render Man Shading Dili, ‘shade ağaçları ’ fikrinden esinlenmiş tir. Rob Cook tarafı ndan 1984’te SIGGRAPH’ta shade ağaçlarıhakkı nda bir makale yayı nlanı yor. Shade ağaçları nı n temel mantı ğı , birçok shading iş lemlerini ağaç yapı sı nda düğümler halinde organize etmektedir. Şekil 1.13’de bakı r renkli bir yüzeyi render etmek için gerekli shade ağacıgösterilmiş tir. Yaprak düğümler, shade ağacı na girdi değerleridir. Yaprak olmayan düğ ümler ise basit shading iş lemlerini temsil etmektedir. Rendering iş lemi sı rası nda Renderer, shade ağacı nıdeğerlendirmek için en üst düğümdeki shading iş lemini uygular. Ancak, verilen bir düğümün değerlendirilebilmesi için önce çocuk düğ ümlerin değerlendirilmesi gerekmektedir. Bu iş lemler rekürsif bir biçimde tüm shade ağacı değerlendirilinceye kadar sürer. Yüzeyde verilen bir noktadaki shade ağacı değerlendirilmesi o noktanı n rengini verir. Shade ağacı , çok hı zlıbir ş ekilde büyüdüğü için ekrandaki tüm nesne ve sahnelerin bir anda render edilmesine olanak sağlamaz. Umut DOGAN - Bitirme Tezi - Haziran 2006 renderer, yüzeyin rengini belirlemek için, verilen yüzeyle shade ağ acı nıdeğerlendirir. 24 Şekil 1.13: Rob COOK'un Makalesini Temel Alan Bir Shade Ağacı Shade ağacıdiyagramlarıshading iş lemlerinin veri-akı ş ı nıgörmek için çok kullanı ş lı dı r. Ancak eğer shade ağaçlarıkarmaş ı ksa diyagramlar anlaş ı lmaz olacaktı r. Pixar’daki araş tı rmacı lar her shade ağacı nı n bir çeş it sı nı rlıprogram olduğunu keş fetmiş ler ve bu keş if yeni bir programlama dili türü olan shading dilinin doğması na neden olmuş tur. 1.3.2.2. Renderman Shading Dili RenderMan Shading Dili, shade ağaçları n büyümesi sonucu oluş muş tur. RenderMan, gerçek zamanlıolmayan shading dilleri arası nda en çok kullanı lan ve en çok bilinenidir. 1990’ları n sonunda yeniden gözden geçirilmişve geliş tirilmiş tir. Umut DOGAN - Bitirme Tezi - Haziran 2006 Renderman Shading dili çevrimdı ş ı(gerçek zamanlıolmayan) bir shading dilidir. 25 1.3.2.3. Donanı ma Uygun Shading Dilleri Bir algoritmanı n donanı msal olarak etkin bir ş ekilde gerçeklenmesi, her aş amanı n sadece bir önceki ve sonraki aş amalarla bağlantı lıolduğ u pipelinelıbir yapı yla oluş turulması na bağ lı dı r. Önceki baş lı klarda açı klanan vertex-tabanlı ve fragment-tabanlı pipelinelar donanı ma uygun yapı lardı r. Ancak PhotoRealistic Renderman’de kullanı lan Reyes algoritmasıetkin donanı m gerçeklemesi için uygun değildir çünkü yüksek oranda geometrik iş lemler yapar. ÇağdaşGPU’ları n tümü vertex ve fragment tabanlıgrafik pipeline içerirler. North Carolina Üniversitesi’ndeki araş tı rmacı lar, 1990’ları n ortası nda PixelFlow adı nda bir programlanabilir grafik donanı mımimarisi geliş tirmeye baş ladı lar. Bu proje bilgisayar grafikleri alanı nda yeni bir konu olan donanı ma uygun shading dilleri geliş tirilmesiyle ilgili projeleri tetikledi. Ancak, PixelFlow çok pahalı ydıve ticari olarak baş arı sı zlı ğa uğ radı . Sonraki yı llarda Silicon Graphics’teki araş tı rmacı lar shaderları OpenGL rendering’in çoklu geçiş lerine (multiple pass) çevirmeye yarayan bir sistem üzerinde çalı ş tı lar. O dönemki OpenGL donanı mıgünümüz GPU’larıgibi programlanabilir olmaması na rağmen OpenGL Shader sistemi shader’dan istenen birçok rendering geçiş lerini yapabilmiş tir. Pat Hanrahan isimli araş tı rmacı lar özel olarak ikinci ve üçüncü kuş ak GPU’lar için bir shading dili geliş tirdiler. Bu dil Stanford Real-Time Shading Language (RTSL) olarak bilinir ve RTSL’de yazı lmı şshaderlarıbir veya daha fazla OpenGL rendering geçiş inde derleyebilmektedir. Stanford’daki bu araş tı rma, NVIDIA firması nıticari özellikli ve donanı ma uygun bir shading dili üretmeye teş vik etti. Bill Mark, bugün Cg dediğimiz shading dilini oluş turmak için 2001 yı lı nda NVIDIA ekibine katı ldıve çalı ş malarıyönetti. Bu süre Umut DOGAN - Bitirme Tezi - Haziran 2006 Stanford Üniversitesi’ndeki Kekoa Proudfoot, Bill Mark, Svetoslav Tzvetkov ve 26 içerisinde NVIDIA, ortak dil sözdizimi ve özellikler konusunda Microsoft ile birlikte çalı ş tı . 1.3.3. Üç Boyutlu Grafikler için Programlama Arayüzleri Cg üzerindeki üçüncü etki 3B programlama arayüzleri DirectX ve OpenGL kaynaklı dı r. Bu programlama arayüzlerinin Cg üzerinde etkisi bir sonraki bölümde anlatı lacaktı r. 1.4. Cg Ortamı Cg, üç boyutlu (3B) karmaş ı k sahneleri programlanabilir GPU’larla gerçek zamanlı bir ş ekilde rendering için gerekli tüm donanı m ve yazı lı m altyapı sı nı n elemanları ndan sadece birisidir. Bu bölümde Cg’nin gerçek 3B uygulamalar ve oyunlarla nası l etkileş tiği açı klanmı ş tı r. 1.4.1. Standart 3B Programlama Arayüzleri: OpenGL ve Direct3D GPU öncesi dönemde PC’deki 3B grafik üretiminde, 3B bir sahneyi üretmek için gerekli tüm vertex dönüş ümlerini ve piksel-itme (pixel-pushing) görevlerini CPU üstleniyordu. Grafik donanı mı nda sadece ekranda gösterilecek piksel tamponları bulunuyordu. Programcı lar kendi 3B grafik rendering algoritmaları nıyazı lı msal olarak oluş turmak zorundaydı lar. Vertex ve fragment iş leme eskiden programlanabilir yapı daydı denilebilir. Ama burada ince bir ayrı ntıvardı : 3B efektler oluş turmak için CPU çok yavaş Günümüzde, 3B uygulamalar, CPU’ya dayalıkendi 3B rendering algoritmaları nı oluş turmak zorunda değiller. Bunun yerine standart 3B programlama arayüzleri olan OpenGL veya Direct3D’yi kullanarak GPU’nun rendering komutları na eriş ebiliyorlar. Umut DOGAN - Bitirme Tezi - Haziran 2006 kalı yordu. 27 1.4.1.1. OpenGL 1990’ları n baş ı nda, Silicon Graphics firması , büyük bilgisayar grafik sistem üreticilerinin oluş turduğu OpenGL Architecture Review Board (ARB) koordinasyonunda OpenGL dilini geliş tirdi. İ lk baş larda OpenGL sadece güçlü UNIX grafik iş istasyonları nda çalı ş ı yordu. Daha sonra ARB’nin kurucu üyelerinden Microsoft, OpenGL’i Windows NT iş letim sisteminde çalı ş abilecek ş ekilde geliş tirdi. Microsoft, bu desteği daha sonra bütün masaüstü iş letim sistemleri için sağ ladı . OpenGL tek bir iş letim sistemine bağlıdeğildir: Unix, Windows ve Mac OSX üzerinde çalı ş abilir. OpenGL geniş leyebilir özelliktedir, yani OpenGL geliş tiricileri OpenGL’e ek özellikler ekleyebilirler. Günümüzde OpenGL uzantı larısayesinde GPU’nun birçok özelliğine eriş ilebilmektedir. 1.4.1.2. Direct3D Microsoft Direct3D ortamı nı , 1995 yı lı nda DirectX’in bir parçası olarak geliş tirmeye baş ladı . Direct3D API, Windows üzerinde çalı ş an bilgisayar oyunlarıiçin en çok kullanı lan grafik API’sidir. DirectX 9 sürümünden itibaren Cg’nin Microsoft sürümü olan HLSL, DirectX API’sinin bir parçasıhaline geldi. 1.4.2. Cg Derleyicisi ve Runtime’ı Hiçbir GPU, Cg programları nıdoğrudan çalı ş tı ramaz. Derleme adıverilen bir Cg programı nıuygulamada kullanı lan 3B programlama arayüzü (OpenGL veya Direct3D) tarafı ndan kabul edilecek biçime dönüş türür. Daha sonra uygulama, dönüş türülmüşhalini tekrar dönüş ümden geçirir. Bu aş amada uygun OpenGL ve Direct3D komutları kullanı larak GPU’nun anlayabileceğ i bir ş ekle dönüş türülür. Son olarak, OpenGL veya Direct3D sürücüsü, programı mı zıGPU’nun gerektirdiği biçime dönüş türür. Bu dönüş ümün detaylarıGPU’nun ve 3B programlama arayüzünün yeteneklerine bağlı dı r. Bazen GPU’lar Cg programları mı zıçalı ş tı rmayabilir, bunun nedeni GPU’nun Cg Umut DOGAN - Bitirme Tezi - Haziran 2006 iş lemle Cg programlarıGPU’nun çalı ş tı rabileceği biçime dönüş türülür. Cg derleyicisi önce 28 programı nı n istediği donanı m desteğini sağlamaması dı r. Örneğin eğer Cg fragment programı mı z derlenmiyorsa bunun nedeni programı mı zda, kullandı ğı mı z GPU’nun desteklediği doku kaplama birimi sayı sı nıaş mı şolmamı z olabilir. 1.4.2.1. Dinamik Derleme Desteği C veya C++ gibi bir dille programı mı zıderlediğimiz zaman derleme iş lemi çevrimdı ş ı(offline) bir süreçtir. Derleyicimiz programı mı zıCPU’nun çalı ş tı rabileceğ i biçime dönüş türür. Programı mı z bir kere derlendiğinde, eğer program kodunu değiş tirmeyeceksek tekrar derlememize gerek yoktur. Bu iş leme statik derleme denir. Cg ise farklıbir biçimde çalı ş ı r, çünkü statik derlemeyi desteklediği gibi dinamik derlemeyi de destekler. Cg derleyicisi ayrı bir program değildir, Cg runtime kütüphanesinin bir parçası dı r. Cg kullanan 3B uygulama ve oyunlar Cg runtime ile linklenmelidir. Daha sonra Cg kullanan uygulamalar Cg programları nıderleyip çalı ş tı rmak için tümü cg öneki ile baş layan Cg runtime yordamları nıçağı rı rlar. Dinamik derleme Cg programları nı n kullanı cı nı n makinesindeki GPU’ya özgü bir ş ekilde optimize edilmesini sağ lar. 1.4.2.2. 3B API’lere Özgü Cg Kütüphaneleri: CgGL, CgD3D Cg çekirdekteki Cg runtime’ı na ek olarak iki yakı n iliş kili kütüphane daha sağlar. Eğer uygulamamı z OpenGL kullanı yorsa, Cg programı mı zıOpenGL sürücülerine dönüş türmek için CgGL kütüphanesini kullanmamı z gereklidir. Benzer ş ekilde eğer CgGL ya da CgD3D kullanı rı z, her ikisini birden kullanamayı z. Çünkü birçok uygulama ya Direct3D ya da OpenGL kullanı r, ikisini birden kullanmaz. CgGL ve CgD3D kütüphaneleri, Cg derleyicisini içeren çekirdek Cg runtime kütüphanesinden oldukça küçüktürler. Görevleri Cg programları nıçalı ş ma zamanıiçin ayarlamada uygun OpenGL ve Direct3D çağrı ları nıyapmaktı r. Bu çağrı lar sayesinde Cg programı mı z GPU’nun anlayabileceğ i bir dile dönüş türülmüşolur. CgGL ve CgD3D Umut DOGAN - Bitirme Tezi - Haziran 2006 Direct3D kullanan bir uygulamamı z varsa CgD3D kullanmamı z gereklidir. Normalde ya 29 kütüphaneleri birçok benzer yordama sahiptir. CgGL kütüphanesindeki yordamlar cgGL ile, CgD3D kütüphanesindeki yordamlarsa cgD3D ile baş lar. 1.4.2.3. Cg Runtime Uygulamamı za Nası l Uyum Sağlar Şekil 1.14’de Cg kütüphaneleri kullanan tipik bir 3B uygulama gösterilmiş tir. Şekil 1.14: Standart Bir Cg Uygulaması nda Cg'nin Yeri 1.4.3. CgFX Araç Takı mıve Dosya Biçimi Cg programları ; 3B modeller, dokular ve diğer veriler üzerinde çalı ş ı r. Herhangi bir veriyle iliş kilendirilmemişbir Cg programıiş e yaramaz. Cg programlarıve verileri uygun 3B programlama arayüzü ayarları nı n yapı lmı şolması nıgerektirir. Genelde 3B model için 1.4.3.1. CgFX Ne Sağlar CgFX tüm efektleri ve görünümü göstermek için standartlaş tı rı lmı ş dosya biçimidir. Microsoft ve NVIDIA, Cg için yaptı klarıortaklı ğıCgFX dosya formatıiçin de gerçekleş tirmiş lerdir. CgFx dosyalarımetin-tabanlı dı r. Cg’nin üst kümesi olan bir sözdizimine sahiptir ve çok sayı da Cg programıiçerebilir. CgFX dosyaları.fx sonekini kullanı rlar. CgFX dosyasıbir efektin tüm render durumları nıtanı mlar. Çoklu geçiş ler, Umut DOGAN - Bitirme Tezi - Haziran 2006 gerekli tüm bilgileri ve iliş kilendirilmişprogramıbir araya getirmek kullanı ş lı dı r. 30 doku durumları , özel vertex veya fragment programlarıtüm bir görünüm ve efekt oluş turmak için kullanı labilir. CgFX dosyaları nıkullanmak ve ayrı ş tı rmak için Cg ile beraber bir araç takı mısunulmuş tur. Cg programlarıvertex ve fragmentlerin tek bir rendering geçiş inde olması nı tanı mlarlar, ancak bazıkarmaş ı k shading algoritmalarıçoklu rendering geçiş leri gerektirir. CgFX karmaş ı k çoklu geçişefektlerini kodlamak için, hangi rendering geçiş inde hangi Cg programı nı n kullanı lacağıdâhil olmak üzere yeterli desteği sunar. CgFX, Cg diline ek olarak üç özellik daha sağlar: 1. CgFX, çoklu rendering geçiş leri ve isteğe bağlıolarak bir efektin çoklu gerçeklenmesini sağlayan mekanizmalara sahiptir. 2. Alpha-test modlarıve doku filtreleme gibi programlanamayan rendering durumları nıde belirtmemize olanak sağlar. Bu rendering durumlarıiçin ayarlar, efekt baş latı ldı ğızaman CPU’da değerlendirilecek basit ifadeler biçiminde olabilir. 3. CgFX, shaderlara ve shader parametrelerine eklenecek ek açı klamalar izin verir. Bu ek açı klamalar, içerik oluş turma uygulamalarıdâhil olmak üzere uygulamalarla ilgili ek bilgiler sağlar. Örneğin bir ek açı klama bir shader parametresi için verilecek değ er aralı ğı nı belirtebilir. 1.4.3.2. Çoklu Shader Örnekleme CgFX dosya formatı , verilen bir shader için Cg programı nı n farklı programıile daha az özellik destekleyen, 2 kuş ak GPU’lar için yazı lmı şbasit bir Cg programı nıaynıanda içerebilir. CgFX dosyası nıyükleyen uygulama ise makinedeki GPU’ya uygun olarak bu programlardan birini seçer. Ayrı ca Direct3D, OpenGL veya OpenGL ext için yazı lmı şCg programlarıCgFX’in çoklu örnekleme özelliğ i sayesinde aynıCgFX dosyası nda bulunabilirler. Umut DOGAN - Bitirme Tezi - Haziran 2006 gerçekleş tirmelerini içerebilir. Örneğin 3. veya 4. kuş ak GPU’lar için yazı lmı şCg shader 31 1.4.3.3. CgFX ile Sayı sal İ çerik Oluş turma CgFX araç takı mı ; tüm CgFX sözdizimini destekleyen CgFX derleyicisi, CgFX dosyaları nıyükleyip değiş tirebilmek için gerekli CgFX runtime API’si ve Maya, 3ds max gibi sayı sal içerik oluş turma (DCC) uygulamalarıiçin eklenti modülleri içerir. Şekil 1.15’te bu uygulamaları n CgFX ile kullanı mıgösterilmiş tir. Şekil 1.15: Cg ve CgFX Kullanan Sayı sal İ çerik Oluş turma Uygulamaları CgFX’ten önce DCC uygulamaları nı n 3B içeriklerini gerçek zamanlıçalı ş ma için gerekli tüm shading özellikleriyle birlikte export edebilecekleri belli bir standart yoktu. oyunlarda gerçek zamanlıolarak kullanma çok basit bir hale gelmiş tir. 1.4.3.4. CgFX, Uygulamamı za Nası l Yerleş ir Şekil 1.16’da 3B API ve Cg runtime bileş enleriyle birleş en CgFX’in uygulamada nası l kullanı ldı ğıgösterilmiş tir. Umut DOGAN - Bitirme Tezi - Haziran 2006 Günümüzde CgFX sayesinde sayı sal içerik oluş turma ve bunları3B uygulamalar ve 32 Umut DOGAN - Bitirme Tezi - Haziran 2006 Şekil 1.16: Standart Bir Uygulamada CgFX'in Yeri 2. Cg Dİ Lİ Nİ N KURALLARI 2.1. Cg Dil Profilleri Tüm CPU’lar hemen hemen aynıyetenekte olduğundan C dili için bütün CPU’larda aynıtemel yetenekler sunulur. Ancak GPU programlama henüz bu seviyede bir genelliğe ulaş amadı . Örneğin günümüzdeki programlanabilir vertex iş lemciler, programlanabilir fragment iş lemcilerden çok daha fazla özellik sunarlar. Cg bu genellik sorununu dil profilleri kavramı nıortaya atarak çözmüş tür. Bir Cg profili belli bir donanı m veya API için desteklenen tüm alt özellikleri tanı mlar. Cg’nin ş u anki sürümünde (Sürüm: 1.4.1, Tarih: Mart 2006) ş u profiller tanı mlı dı r: OpenGL ARB vertex programları OpenGL ARB fragment programları OpenGL NV40 vertex programları OpenGL NV40 fragment programları OpenGL NV30 vertex programları OpenGL NV30 fragment programları OpenGL NV2X vertex programları OpenGL NV2X fragment programları DirectX 9 vertex shaderları DirectX 9 pixel shaderları DirectX 8 vertex shaderları Bu profillerle ilgili ayarlar NVIDIA’nı n sitesinden ücretsiz indirilebilen Cg Toolkit User’s Manual: A Developer’s Guide to Programmable Graphics kitapçı ğı nda bulunabilir. Programı mı zıhangi profile göre yazacaksak bunu koş ma-zamanıprofilini (runtime profile) ve derleyici seçeneğini (compiler option) uygun olana göre ayarlayarak gerçekleş tirebiliriz. Umut DOGAN - Bitirme Tezi - Haziran 2006 DirectX 8 pixel shaderları 34 2.2. Cg’de Programları n Tanı mlanması C’de CPU kodu genellikle main() olarak adlandı rı lan bir programdan ibarettir. Cg programları ysa herhangi bir ismi alabilirler. Program ş u sözdizimine göre tanı mlanı r: <döndürülen değer türü> <program-adı> (<parametreler>) [: <anlamsal-ad>] { /* … */ } 2.3. Program Girdi ve Çı ktı ları GPU’daki programlanabilir iş lemciler veri akı ş ları(data stream) üzerinde çalı ş ı rlar. Vertex iş lemcisi vertexlerin ve fragment iş lemcisi fragmentlerin akı ş larıüzerinde çalı ş ı rlar. Programcı , ana programı n CPU’da tek bir kez koş tuğunu düş ünebilir. Ama GPU’da iş ler böyle değildir. GPU’da akı ş taki her bir eleman için program tekrar tekrar koş ulur. İ ki çeş it program girdisi vardı r: Değiş ken girdiler (varying inputs), girdi verisinin her bir elemanıiçin kullanı lan verilerdir. Fragment programıiçin değ iş ken girdiler interpolantlardı r, örneğin doku koordinatları … Birörnek girdiler (uniform inputs), girdi verisinin ana akı ş ı ndan bağı msı z olarak tanı mlanan değerlerdir ve her akı şelemanı nda değiş mez. Örneğin bir vertex programı birörnek girdi olarak dönüş üm matrisine ihtiyaç duyabilir. Bir vertex programıgenel olarak değiş ik sayı da, farklıgirdileri kabul eder. Örneğin program, her bir vertex için alttaki değiş ken girdileri gerektirebilir: Model uzayıkonumu Model uzayınormal vektörü Doku koordinatları Umut DOGAN - Bitirme Tezi - Haziran 2006 2.3.1. Vertex Programları ndaki Değiş ken Girdiler 35 Örnek olarak alttaki vertex program parçacı ğı nıverebiliriz: struct myinputs { float3 myPosition float3 myNormal float3 myTangent float refractive_index }; : : : : POSITION; NORMAL; TANGENT; TEXCOORD3; outdata foo(myinputs indata) { /* ... */ // Programın içinde, parametreler // “indata.myPosition”, “indata.myNormal” // vb. şekilde referanslanır. /* ... */ } Struct tanı mlaması nda iki nokta üst üsteden sonra gelen ön tanı mlıdeğerlere bağlayı cısemantikler (binding semantics) denir. Altta verilen bağlayı cısemantikler tüm Cg vertex programları nda kullanı labilir: POSITION BLENDWEIGHT BINORMAL BLENDINDICES NORMAL TANGENT PSIZE TEXCOORD0-TEXCOORD7 OpenGL Cg profillerinde değiş ken girdi değ erlerini dolaylıbir ş ekilde özel donanı m kaydedicilere haritalar. Ancak DirectX-tabanlıCg profillerinde böyle bir haritalama söz konusu değildir. 2.3.2. Vertex Programları ndaki Değiş ken Çı ktı lar Vertex programları nı n çı ktı larıpikselleş tiriciden geçer ve fragment programı na çalı ş abilmeleri için üzerlerinde çalı ş acaklarıveriler konusunda iki tarafı n da anlaş mı ş olmasıgereklidir. Uygulama programı yla vertex programıarası nda olduğu gibi vertex programı yla fragment programıarası nda da veri akı ş ıiçin bağlayı cısemantikler kullanı lı r. Umut DOGAN - Bitirme Tezi - Haziran 2006 değiş ken girdiler olarak hazı rlanı r. Vertex ve fragment programları nı n birlikte 36 Alttaki örnekte vertex program çı ktı sıiçin bağ layı cısemantiklerin kullanı mı gösterilmiş tir: // Vertex program struct myvf { float4 pout float4 diffusecolor float4 uv0 float4 uv1 }; myvf foo(/* ... */) { myvf outstuff; /* ... */ return outstuff; } Bu program ise : : : : POSITION; // Pikselleştirme için COLOR0; TEXCOORD0; TEXCOORD1; aynı verinin fragment programda girdi olarak nası l kullanı labileceğini göstermektedir. // Fragment program struct myvf { float4 diffusecolor : COLOR0; float4 uv0 : TEXCOORD0; float4 uv1 : TEXCOORD1; }; fragout bar(myvf indata) { float4 x = indata.uv0; /* ... */ } Alttaki bağlayı cısemantikler tüm Cg vertex profilleri için vertex programları ndan çı ktıolarak kullanı labilirler: PSIZE FOG COLOR0-COLOR1 TEXCOORD0-TEXCOORD7 Tüm vertex programlarıPOSITION bağlayı cısemantiğini kullanan bir vektör çı ktı sıtanı mlamalıve içeriğini ayarlamalı dı r. Bu değer pikselleş tirme için gereklidir. Vertex ve fragment programları n uyumlu çalı ş masıiçin her ikisinin de kendi girdi ve çı ktı larıiçin aynıstruct yapı sı nıkullanmalarıgereklidir. Umut DOGAN - Bitirme Tezi - Haziran 2006 POSITION 37 Bunun için alttaki örnek verilebilir: struct float4 float4 float4 }; myvert2frag { pos uv0 uv1 : POSITION; : TEXCOORD0; : TEXCOORD1; // Vertex program myvert2frag vertmain(...) { myvert2frag outdata; /* ... */ return outdata; } // Fragment program void fragmain(myvert2frag indata ) { float4 tcoord = indata.uv0; /* ... */ } 2.3.3. Fragment Programları ndaki Değiş ken Çı ktı lar Fragment porgram çı ktı ları nda bağlayı cısemantikler her zaman gereklidir. Fragment programları nı n COLOR semantiğini tanı mlamak ve içeriğ ini ayarlamak gibi bir zorunluluklarıvardı r. Bu değer genellikle donanı m tarafı ndan fragmentin son renk değeri olarak kullanı lı r. Bazıfragment profilleri DEPTH vb. çı ktısemantiklerini de desteklerler. Fragment programlar da, vertex programlarda olduğu gibi kendi yapı ları nı n içinde değer döndürebilirler. Ama genellikle çı ktı larıout ş eklinde deklare etmek alı ş kanlı k void main(/* ... */, out float4 color : COLOR, out float depth : DEPTH) { /* ...*/ color = diffuseColor * /* ...*/; depth = /*...*/; } Bir sonraki sayfada verilen örnekte basit bir vertex programıverilmiş tir. Bu program (dağı nı k) diffuse ve aynasal (specular) aydı nlatmayıhesaplamaktadı r. Değiş ken veriler için appin ve vertout adı nda iki struct tanı mlanmı ş tı r. Umut DOGAN - Bitirme Tezi - Haziran 2006 olmuş tur: 38 // Uygulamadan gelen girdileri tanımla. struct appin { float4 Position : POSITION; float4 Normal : NORMAL; }; // Vertex shader çıktılarını tanımla. struct vertout { float4 HPosition : POSITION; float4 Color : COLOR; }; vertout main(appin IN, uniform float4x4 ModelViewProj, uniform float4x4 ModelViewIT, uniform float4 LightVec) { vertout OUT; // Vertex konumunu homojen kırpılmış uzaya dönüştür. OUT.HPosition = mul(ModelViewProj, IN.Position); // Normali, model-uzayından görüntü-uzayına dönüştür. float3 normalVec = normalize(mul(ModelViewIT, IN.Normal).xyz); // Normalize ışık vektörünü tut. float3 lightVec = normalize(LightVec.xyz); // Yarım açı vektörünü hesapla. float3 eyeVec = float3(0.0, 0.0, 1.0); float3 halfVec = normalize(lightVec + eyeVec); // Diffuse bileşeni hesapla. float diffuse = dot(normalVec, lightVec); // Specular bileşeni hesapla. float specular = dot(normalVec, halfVec); // lit fonksiyonunu kullan ve ışıklandırma değerini // diffuse ve specular değerlere göre hesapla. float4 lighting = lit(diffuse, specular, 32); // Beyaz specular materyal float3 specularMaterial = float3(1.0, 1.0, 1.0); // Diffuse ve specular bileşenlerin katkılarını hesapla // ve final vertex rengini çıktı olarak ver. OUT.Color.rgb = lighting.y * diffuseMaterial + lighting.z * specularMaterial; OUT.Color.a = 1.0; return OUT; } Umut DOGAN - Bitirme Tezi - Haziran 2006 // Mavi diffuse materyal float3 diffuseMaterial = float3(0.0, 0.0, 1.0); 39 2.4 Veri Tipleri C gibi, Cg de veri oluş turmak ve iş lemek için gerekli altyapı yısağlar: Temel Veri Tipleri, Yapı lar, Diziler, Tip dönüş ümleri… 2.4.1. Temel Veri Tipleri Cg, 7 temel veri tipini destekler: o float 32 bit IEEE kayan noktalısayı dı r (s23e8). 1 iş aret biti, 23 bit mantis ve 8 bit üsten oluş ur. Bu veri tipi tüm profillerde desteklenir, ancak DirectX 8 pixel profilleri daha düş ük bir duyarlı lı k seviyesi kullanı r ve iş lemlerde bazı kı sı tlamalar yapar. o half 16 bit IEEE-benzeri kayan noktalısayı dı r. o int 32 bit tamsayı dı r. Bazı profillerde kullanı lmaz veya float olarak değerlendirilir. o fixed 12 bit sabit noktalısayı dı r. Tüm fragment profillerinde desteklenir. o bool Kı yaslamalar sonucunda üretilir. if ve koş ullu operatör (?:) yapı ları nda kullanı lı r. Bu veri tip de tüm profillerde desteklenir. Doku nesnesi için gerekli tutaç (handle) altıdeğiş ik biçimde oluş ur: sampler, sampler1D, sampler2D, sampler3D, samplerCUBE ve samplerRECT. Tek bir istisna dı ş ı nda veri tipi tüm pixel, fragment ve NV40 vertex profillerinde desteklenir. Sadece samplerRECT tipi DirectX profillerinde desteklenmez. o string Günümüzdeki profil yapı sı nda Cg program kodları nda string veri tipinin kullanı mı na izin verilmese de Cg runtime API sayesinde kullanı lı p değerleri Umut DOGAN - Bitirme Tezi - Haziran 2006 o sampler* 40 sorgulanabilir. Genelde Cg dosyası nı n içeriğiyle ilgili bilgiler tutmada kullanı ş lı dı r. Cg, aynızamanda temel veri tipleriyle iliş kili yerleş ik vektör veri tiplerine de sahiptir. Bu yerleş ik vektör veri tiplerine örnek olarak ş unlarıverebiliriz: float4 float3 float2 float1 bool4 bool3 bool2 bool1 Ayrı ca 4X4 boyutlu matrislere kadar olan matrislere izin verilir. Bazımatris tanı mlama örnekleri ş öyledir: float1x1 matris1; // Tek elemanlımatris float2x2 matris2; // İ kiye üçlük matris (altıelemanlı ) float4x2 matris3; // Dörde ikilik matris (sekiz elemanlı ) float4x4 matris4; // Dörde dörtlük matris (onaltıelemanlı ) Çok boyutlu float M[4][4] dizisi ile float4X4 M matrisinin tip olarak birbirlerinden farklıoldukları na dikkat edilmelidir. Cg’nin ş u anki sürümünde union ve bit alanlarıyoktur. 2.4.2. Tip Dönüş ümleri operatörüyle olduğ u gibi açı k bir biçimde belirtilebilir. Cg, farklıtiplerin bulunduğu ifadelerde otomatik olarak tip yükseltme yapar. Örneğ in floatvar * halfvar ifadesi floatvar * (float) halfvar ş eklinde derlenecektir. Cg, tek bir istisnai durumda C’den farklıtip-yükseltme kuralları nıuygular: Açı k tip öneki olmayan bir sabit tip yükseltmeye maruz kalmaz. Örneğin halfvar * 2.0 ifadesi halfvar * (half) 2.0 ş eklinde derlenir. Umut DOGAN - Bitirme Tezi - Haziran 2006 Cg’deki tip dönüş ümleri C’de olduğu gibi çalı ş ı r. Tip dönüş ümleri C’deki cast 41 Bu ifade C’de ise ((double) halfvar) * 2.0 ş eklinde derlenir. Cg bu yaklaş ı mı hesaplamaları n daha yavaşyapı ldı ğıyüksek-duyarlıaritmetiği kullanmayıengellemek için uygular. Cg’de sabitler için ş u tip önekleri kullanı labilir: o float için f o half için h o fixed için x 2.4.3. Yapı lar ve Üye Fonksiyonlar Cg’nin yapı lara (struct) yaklaş ı mıC ile aynı dı r. Cg’de C++’daki gibi bir struct tanı mlandı ğı nda kapalıolarak typedef dönüş ümünün yapı lması nısağlar: struct ornekstruct { /* … */ }; ornekstruct s; // Burada s ornekstruct olarak tanımlanıyor. Yapı larda üye değiş kenler gibi üye fonksiyonlar da tanı mlanabilir: struct Foo { float deg; float yardimci(float a) { return deg + a; } }; float4 main(uniform Foo myfoo, uniform float myval) : COLOR { return myfoo.yardimci(myval); } Umut DOGAN - Bitirme Tezi - Haziran 2006 Üye fonksiyonlar alı ş ı lmı ş“.” gösterimi kullanı larak çağrı lı r. 42 2.4.4. Diziler Diziler Cg’de de C’de olduğu gibi tanı mlanı r ve kullanı lı r. Cg iş aretçileri desteklemediğinden diziler her zaman dizi sözdizimi kullanı larak tanı mlanmalı dı r. İ ş aretçi sözdizimi kullanmak doğru değildir. // 5 skinning matrisi kullanan bir dizi kullanan // bir fonksiyon tanımlanması returnType foo(float4x4 matris[5]) {/* ... */}; C’den en önemli fark ş udur: Dizi atamalarıtüm dizinin kopyası nıoluş turur. Parametrelerle geçilen diziler değerle geçilir (passed by value). Yani bir değiş iklik yapı lmadan önce tüm dizinin kopyasıalı nı r. 2.4.4.1. Boyutsuz Diziler Cg, bir veya iki boyutunun uzunluğu belirtilmemişdizileri destekler. Bu sayede alttaki örnekte görüldüğü gibi farklıboyutlardaki diziler üzerinde iş lem yapabilen fonksiyonlar yazmak mümkündür. 2.4.4.2. Arayüzler Java ve C# gibi dillerde bulunan arayüz (interface) dil yapı sıda Cg tarafı ndan desteklenir. Arayüzler soyut olarak özel bir yapı da hangi üye fonksiyonları n nası l deklare edileceğ ini tanı mlar. Üye fonksiyonları n içeriklerinin deklarasyonuyla ilgilenmezler. interface Light { float3 illuminate(float3 P, out float3 L); float3 color(void); }; Umut DOGAN - Bitirme Tezi - Haziran 2006 float myfunc(float vals[]) { ... } float4 main(...) { float vals1[2]; float vals2[76]; ... float myval1 = myfunc(vals1); // eşleşir float myval2 = myfunc(vals2); // eşleşir ... } 43 2.5. İ fadeler ve Operatörler Cg ş u tip ifade ve operatörleri destekler: o Kontrol akı ş ı o Fonksiyon tanı mlamalarıve aş ı rıyüklemeleri (overload) o C’deki aritmetik operatörler o Çarpma fonksiyonu o Vektör yapı cı ları(constructor) o Bool ve karş ı laş tı rma operatörleri o Swizzle operatörleri o Write Mask operatörü o Koş ullu operatörler 2.5.1. Kontrol Akı ş ı Cg ş u C kontrol yapı ları nıkullanı r: o Fonksiyon çağrı larıve return ifadesi o if / else o while o for Bu kontrol yapı ları yla ilgili olarak ayrı ntı lar C ile aynı dı r. Cg’de fonksiyon özyineleme kullanı lmaz. switch, case ve default anahtar kelimeleri ayrı lmı ş(reserved) 2.5.2. Fonksiyon Tanı mlamalarıve Aş ı rıYüklemeleri Örnek fonksiyon tanı mlamalarış uş ekildedir: function function function function fonksiyon1(out float x); // x sadece çıktıdır fonksiyon2(inout float x); // x hem çıktı hem girdidir fonksiyon3(in float x); // x sadece girdidir fonksiyon4(float x); // x sadece girdidir (C’deki kullanım) Fonksiyon aş ı rıyüklemeyeyse ş öyle bir örnek verilebilir: bool ayniFonksiyon(float a, float b) { return (a == b);} bool ayniFonksiyon(bool a, bool b) { return (a == b);} 2.5.3. Aritmetik Operatörler Umut DOGAN - Bitirme Tezi - Haziran 2006 kelimelerdir ama hiçbir profilde ve Cg derleyicisinde desteklenmez. 44 C’deki tüm standart aritmetik operatörleri (+, -, *, /) içerir. Bunlarıhem vektörler hem de skalerler için kullanabilir. Vektör iş lemleri her zaman her bir eleman için uygulanı r. Örneğin float3(a, b, c) * float3(A, B, C) ile float3(a*A, b*B, c*C) aynış eydir. a * float3(A, B, C) ile de float3(a*A, a*B, a*C) aynı dı r. Cg’nin son sürümündeki (Cg 1.4.1) aritmetik operatörler, matris iş lemlerini desteklememektedir. 2.5.4. Çarpma Fonksiyonu Cg’nin mul() fonksiyonu matrislerle matrisleri ve matrislerle vektörleri çarpmak için kullanı lı r. // Matris sütun-vektörü çarpımı matrix-column vector: mul(M, v); // Satır-vektörüyle matris çarpımı row vector-matrix: mul(v, M); // Matrisle matris çarpımı matrix-matrix: mul(M, N); 2.5.5. Vektör Yapı cı lar Cg dört boyutluya kadar olan vektörlerin altta verilen gösterim ş ekliyle oluş turulması na izin verir. 2.5.6. Bool ve Karş ı laş tı rma Operatörleri Cg’de standart C bool operatörlerinin üçü kullanı labilirdir: && lojik AND || lojik OR ! lojik NOT Umut DOGAN - Bitirme Tezi - Haziran 2006 y = x * float4(3.0, 2.0, 1.0, -1.0); 45 Karş ı laş tı rma operatörleri de ş uş ekildedir: < küçük <= küçük veya eşit != eşit değil == eşit >= büyük veya eşit > büyük 2.5.7. Swizzle Operatörü Cg’de swizzle operatörü ( . ) denilen bir operatör vardı r. Kullanı m amacı ; var olan bir vektörün elemanları nı n yeniden düzenlenmesiyle yeni bir vektör elde etmektir. Bazı örnekler ş öyle verilebilir: float3(a, b, c).zyx sonuç olarak float3(c, b, a) verir. float4(a, b, c, d).xxyy float2(a, b).yyxx sonuç olarak float4(a, a, b, b) verir. sonuç olarak float4(b, b, a, a) verir. float4(a, b, c, d).w sonuç olarak d verir. Aynızamanda bir skalerden bir vektör üretmek için de kullanı labilir: a.xxxx sonuç olarak float4(a, a, a, a) verir. 2.5.8. Write Mask Operatörü bileş enlerinden seçileninin üzerine yazmada kullanı lı r. float4 color = float4(1.0, 1.0, 0.0, 0.0); color.a = 1.0; // RGB’yi aynen bırakıp alpha’yı 1.0’a setler 2.5.9. Koş ullu Operatörler Cg, if/else koş ullu ifadesini ve ?: koş ullu operatörünü içerir. Umut DOGAN - Bitirme Tezi - Haziran 2006 Write Mask operatörü ( . ) atama ifadesinin sol kı smı na yerleş tirilir. Bir vektörün 46 float3 clamp(float3 x, float minval, float maxval) { x = (x < minval.xxx) ? minval.xxx : x; x = (x > maxval.xxx) ? maxval.xxx : x; return x; } 2.6. Cg Standart Kütüphane Fonksiyonları Cg, birçok yerleş ik fonksiyon ve bağlama semantikleriyle birlikte önceden tanı mlı yapı yıGPU programcı sı nı n kullanı mı na sunar. Bu fonksiyonları n birçoğu C standart Kütüphane Fonksiyonlarıkadar basit yapı dadı r. Bazı ları ysa karmaş ı k matematiksel iş lemleri çok hı zlıbir ş ekilde yapmamı za olanak sağlar. Cg Standart Kütüphane Fonksiyonlarış u baş lı klar altı nda incelenebilir: o Matematiksel Fonksiyonlar o Geometrik Fonksiyonlar o Doku Kaplama Fonksiyonları o Türev Fonksiyonları o Öntanı mlıYardı mcıstruct Tipleri Cg kullanı cıel kitabı nda, bütün kütüphane fonksiyonları yla ilgili ayrı ntı lı açı klamalar bulunmaktadı r. Tezimde örnek teş kil etmesi açı sı ndan her alt baş lı kta sadece birkaç kütüphane fonksiyonunu açı kladı m. abs(x) : x’in mutlak değeri clamp(x,a,b) : x’i, [a, b] aralı ğı na ş uş ekilde kenetler: - x, a’dan küçükse a değerini döndürür. - x, b’den büyükse b değerini döndürür. - Diğ er durumlarda x değerini döndürür. dot(a,b) : a ve b vektörlerinin iç çarpı mı Umut DOGAN - Bitirme Tezi - Haziran 2006 2.6.1. Matematiksel Fonksiyonlar 47 2.6.2. Geometrik Fonksiyonlar distance(pt1, pt2) : pt1 ve pt2 noktalarıarası ndaki Öklit uzaklı ğ ı normalize(v) : v vektörüyle aynıdoğ rultuda, 1 uzunluklu vektör döndürür. 2.6.3. Doku Kaplama Fonksiyonları tex1D(sampler1D tex, float s) : İ zdüş ümsel olmayan 1B doku kaplama tex3Dproj(sampler3D tex, float4 szq) : İ zdüş ümsel 3B, derinlik kı yaslamalı Ayrı ca türev, hata ayı klama fonksiyonlarıve öntanı mlıfragment program çı ktı yapı larıda bulunmaktadı r. Bu konularla ve üst baş lı klardaki diğer fonksiyonlarla ilgili ayrı ntı lar “Cg User’s Manual”de bulunmaktadı r. Not: Cg Runtime ile ilgili ayrı ntı lar 3B API’ler ve programlama ortamlarıiçin farklı lı klar göstermektedir. Bu yüzden Cg runtime’ı n ayrı ntı ları na “Cg Dilinin Kuralları ” baş lı ğıaltı nda yer vermedim. Direct3D ile yaptı ğı m küçük vertex programları nda Direct3D ile ilgili kurallarıve ana uygulama projem “Cg ile Pürüzlü Yüzey Dokusu Üretimi” baş lı ğı nda da OpenGL ile ilgili olanları nıözet halinde açı klamaya çalı ş tı m. NVIDIA Developer sitesinde bulunan Cg User’s Manual’de bütün Cg Runtime özellikleri Umut DOGAN - Bitirme Tezi - Haziran 2006 ayrı ntı ları yla açı klanmı ş tı r. Gerek duyulmasıhalinde bu kaynağa baş vurulabilirsiniz. 3. Cg VE DIRECT3D İ LE YAZILMIŞKOD ÖRNEKLERİ Bu bölümde sürekli geliş mekte ve yeni özellikler eklenmekte olan Direct3D API’siyle eş güdümlü bir ş ekilde geliş tirilmiş bazıuygulamalar verilmiş tir. Shader programları nı n birçoğunu “Kaynaklar” bölümünde belirtilen kaynaklardan alı p üzerlerinde bazıdeğiş iklikler yaparak buraya ekledim. 3.1. Cg ile Kod Yazabilmek için Ayarlar Bu alt baş lı kta Cg, Direct3D ve Visual C++ ayarlamaları nı n nası l yapı lması gerektiğini anlatacağı m. İ lk kez Cg diliyle programlamaya baş layacak birisi için en ince ayrı ntı sı na kadar her ş eyi açı klamaya çalı ş tı m. Bilgisayarda Visual Studio 2003 kurulu olduğunu varsayı yorum. Eğer kurulu değilse bir ş ekilde Trial veya Express sürümlerinden birisini indirip bilgisayarı nı za kurabilirsiniz. UygulamalarıVisual C++ dili yardı mı yla yazacağı m. Visual C++ dilinde en azı ndan bazıtemelleri bilmek programlarıanlamak açı sı ndan size yardı mcıolacaktı r. 3D API olarak en son DirectX SDK’sı nı(February 2006) Microsoft’un sitesinden indirip bilgisayarı mı za kuruyoruz. Böylece Cg ile ilgili ayarlar hariç tüm önkoş ullarıyerine Cg Toolkit’i de NVidia Developer sitesinden indirip kuruyoruz. Kurulum programı nıindirdiğiniz sayfada “Cg Users Manual”i indirerek bu dilin bütün özelliklerini öğ renmek için bir baş langı ç yapabilirsiniz. Program varsayı lan olarak C:\Program Files\NVIDIA Corporation\Cg\ dizinine kurulacaktı r. Şimdi iş in önemli noktalarıgeliyor. Burada birçok kopyala-yapı ş tı r iş lemi olduğu için eğ er bu iş lemleri adı m adı m yapmazsanı z büyük olası lı kla programı nı z derlenmeyecektir. İ lk önce C:\Program Files\NVIDIA Corporation\Cg dizinindeki include Umut DOGAN - Bitirme Tezi - Haziran 2006 getirmişoluyoruz. 49 ve lib altdizinlerini C:\Program Files\Microsoft Visual Studio .NET 2003\VC7\ dizinine kopyalı yoruz. Kopyalama iş lemi sı rası nda bu dizinlerin üzerine yazmak isteyip istemediğimizi soracaktı r. “Evet” diyoruz. Bu mesajıvermesinin nedeni hedef dizinde de include ve lib dizinlerinin olması dı r. Bizim amacı mı z da bu dizinlerin içeriğini geniş letmektir. Direct3D kodları nı n programı mı zda çalı ş masıiçin C:\Program Files\Microsoft DirectX SDK (February 2006)\Include\ dizininin içeriğini C:\Program Files\Microsoft Visual Studio .NET 2003\VC7\Include\ dizinine kopyalı yoruz. Benzer ş ekilde C:\Program Files\Microsoft DirectX SDK (February 2006)\Lib\x86\ dizininin içeriğ ini de C:\Program Files\Microsoft Visual Studio .NET 2003\VC7\lib\ dizinine kopyalı yoruz. Alternatif olarak program ayarları nda include yoluna DirectX SDK’nı n bulunduğu dizin eklenebilir ama bu yöntem daha garantili bir yöntemdir. Son olarak kullanı ş lıbir özellik olan Visual Studio’da Cg için sözdizimi vurgulama (syntax highlighting) özelliğin etkinleş tirilmesini göstereceğ im. Bunun için ilk adı mda C:\Program Files\NVIDIA Corporation\Cg\msdev_syntax_highlighting dizinine gidip burada bulunan usertype.dat dosyası nıC:\Program Files\Microsoft Visual Studio .NET 2003\Common7\IDE dizinine kopyalı yoruz. Daha sonra aynı dizindeki install_highlighting_vs7.reg dosyası nıçalı ş tı rarak gerekli kayı t girdilerini ayarlı yoruz. Bu sayede kod yazarken anahtar kelimeler vs. sanki herhangi bir .NET diliyle çalı ş ı yormuş uz gibi farklırenklerde olacaktı r. Bu özelliğin kod yazarken epeyce kullanı ş lıolduğunu belirtmeliyim. altyapı yıoluş turmuşolduk. Şimdi program yazmaya baş layabiliriz. 3.2. Basit Bir Vertex Programı Eğer yeni bir proje yaratmak yerine var olan Template’ler üzerinde düzenlemeler yapı lmak isteniyorsa http://www.codesampler.com/index.htm adresindeki Cg shader programlarıiyi bir baş langı ç noktasıolabilir. İ lk olarak Visual Studio 2003 ortamı nıaçı p File -> New -> Project seçiyoruz. Açı lan pencerede Project Types kı smı ndan Other Umut DOGAN - Bitirme Tezi - Haziran 2006 Böylece Cg, Direct3D, Visual C++ üçlüsüyle program yazmak için gerekli bütün 50 Languages’a geçiyor ve Visual C++’ıseçiyoruz. Aynıpencerenin sağı ndaki Templates kı smı ndan proje türünü seçip projemize bir ad veriyoruz. Proje sayfasıaçı ldı ktan sonra Solution Explorer’da Source Files dizinine sağtı klayı p Add -> New Item seçiyoruz. Açı lan pencerede solda Categories altı ndaki Code’u sağdan da C++ File (.cpp) seçiyor ve dosyamı za da bir ad veriyoruz. Tamam’a tı kladı ktan sonra boşbir sayfa açı lı yor. Bu sayfa içerisine Direct3D ve Visual C++ ile ilgili kodlarıyazacağı z. Şimdi Cg Shader’ı nıyazacağı mı z kod dosyası nıhazı rlayalı m. Bu amaçla Solution Explorer’da boşbir yere sağtı klayı p Add -> New Filter seçiyoruz. Ve dizinimize Cg Files ismini veriyoruz. Oluş turduğumuz bu dizine de sağtı klayı p Add -> New Item seçiyoruz. Açı lan pencerede solda Categories altı ndaki Code’u sağdan da C++ File (.cpp) seçiyor ve dosyamı za cg uzantı sı yla biten bir ad (örn. vertex_programi.cg) veriyoruz. Şimdi kod yazmaya baş layabiliriz. Öncelikle ana programı mı zı n içeriğini oluş turuyoruz. Kodlarla ilgili açı klamalar satı r araları nda verilmiş tir. Kodları n büyük kı smı Visual C++ ile ilgili ayarlamalardan oluş tuğ u için bunlarıburada belirtmedim. //----------------------------------------------------------------------// Bu örnekte Direct3D ile basit bir Cg Shader uygulamasının nasıl // yazılacağı anlatılmıştır. //----------------------------------------------------------------------<d3d9.h> <d3dx9.h> <Cg/Cg.h> <Cg/CgD3D9.h> //----------------------------------------------------------------------// Global değişkenler //----------------------------------------------------------------------HWND g_hWnd = NULL; LPDIRECT3D9 g_pD3D = NULL; LPDIRECT3DDEVICE9 g_pd3dDevice = NULL; LPDIRECT3DVERTEXBUFFER9 g_pVertexBuffer = NULL; LPDIRECT3DVERTEXDECLARATION9 g_pVertexDeclaration = NULL; CGcontext CGprogram CGparameter CGparameter g_CGcontext; g_CGprogram; g_CGparam_worldViewProj; g_CGparam_constColor; D3DXMATRIX g_matWorld; D3DXMATRIX g_matView; D3DXMATRIX g_matProj; Umut DOGAN - Bitirme Tezi - Haziran 2006 #include #include #include #include 51 float float g_fSpinX = 0.0f; g_fSpinY = 0.0f; struct Vertex { float x, y, z; DWORD color; }; enum FVF { FVF_Flags = D3DFVF_XYZ | D3DFVF_DIFFUSE }; Vertex g_quadVertices[] { // x y z { -1.0f,-1.0f, 0.0f, { 1.0f,-1.0f, 0.0f, { 1.0f, 1.0f, 0.0f, { -1.0f, 1.0f, 0.0f, }; = renk 0xffffff00, 0xff00ff00, 0xffff0000, 0xff0000ff, }, }, }, } // // // // Sol-alt, Sağ-alt, Sağ-üst, Sol-üst, sarı yeşil kırmızı mavi //----------------------------------------------------------------------// Fonksiyon Prototipleri //----------------------------------------------------------------------void init(void); void render(void); void shutDown(void); void initShader(void); void setShaderConstants(void); //----------------------------------------------------------------------// WindowProc() : Pencerelerle ilgili handler // Pencere handlerları hangi tuşa basıldığında vs. nasıl tepki // verileceği belirleniyor. Örneğin bu programda ekrandaki renkli // dikdörtgen fareyle tutulup çevrildiğinde dönmesi sağlanıyor. // Bu fonksiyonun içeriği de burada gösterilmemiştir. //----------------------------------------------------------------------//----------------------------------------------------------------------// init() : başlatma işlemleri //----------------------------------------------------------------------void init( void ) { g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ); D3DDISPLAYMODE d3ddm; g_pD3D->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &d3ddm ); D3DPRESENT_PARAMETERS d3dpp; Umut DOGAN - Bitirme Tezi - Haziran 2006 //----------------------------------------------------------------------// WinMain() : Uygulamanın giriş noktası // Bu fonksiyonda pencereyle ilgili standart ayarlamalar yapılıyor. // Hemen hemen bütün Visual C++ uygulamaları için standart olduğu ve // farklı uygulamalar için birkaç değişiklik gerektirdiği için burada // ayrıca gösterilmemiştir. //----------------------------------------------------------------------- 52 ZeroMemory( &d3dpp, sizeof(d3dpp) ); d3dpp.Windowed d3dpp.SwapEffect d3dpp.BackBufferFormat d3dpp.EnableAutoDepthStencil d3dpp.AutoDepthStencilFormat d3dpp.PresentationInterval = = = = = = TRUE; D3DSWAPEFFECT_DISCARD; d3ddm.Format; TRUE; D3DFMT_D16; D3DPRESENT_INTERVAL_IMMEDIATE; g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, g_hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &g_pd3dDevice ); g_pd3dDevice->CreateVertexBuffer( 4*sizeof(Vertex), D3DUSAGE_WRITEONLY, Vertex::FVF_Flags, D3DPOOL_DEFAULT, &g_pVertexBuffer, NULL ); void *pVertices = NULL; 0 ); g_pVertexBuffer->Lock( 0, sizeof(g_quadVertices), (void**)&pVertices, memcpy( pVertices, g_quadVertices, sizeof(g_quadVertices) ); g_pVertexBuffer->Unlock(); g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE ); g_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE ); } D3DXMatrixPerspectiveFovLH( &g_matProj, D3DXToRadian( 45.0f ), 640.0f / 480.0f, 0.1f, 100.0f ); g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &g_matProj ); //----------------------------------------------------------------------// initShader(): Vertex shader yükleme ayarları //----------------------------------------------------------------------void initShader( void ) { // Context oluştur... g_CGcontext = cgCreateContext(); cgD3D9SetDevice( g_pd3dDevice ); // Kullanılabilecek en uygun vertex profilini seç... CGprofile vertexProfile = cgD3D9GetLatestVertexProfile(); const char* profileOpts[] = { "-profileopts", "dcls", NULL, }; Umut DOGAN - Bitirme Tezi - Haziran 2006 // // CG'nin gelişmiş arayüzünü kullandığımız için, // Direct3D aygıtını CG2ye geçmeliyiz. // 53 // // Vertex shader'ı oluştur... // g_CGprogram = cgCreateProgramFromFile( g_CGcontext, CG_SOURCE, "dx9_cg_simple.cg", vertexProfile, "main", profileOpts ); // // İkinci parametre TRUE'ya setlendiğinde, gölgelendirme // etkinleştirilir. // Bu sayede g_CGparam_constColor gibi parametrelerimiz bir kere // ayarlanır ve tekrar tekrar ayarlanmasına gerek kalmadan kullanılabilir. // cgD3D9LoadProgram( g_CGprogram, TRUE, 0 ); // // Eğer programınız burada olduğu gibi açık binding semantics // kullanıyorsa, bu semantic'leri kullanarak // vertex deklarasyonu oluşturulabilir. // const D3DVERTEXELEMENT9 declaration[] = { { 0, 0*sizeof(float), D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 }, { 0, 3*sizeof(float), D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0 }, D3DDECL_END() }; // // Sonuç deklarasyonunun shader ile uyumlu olduğundan emin ol... // ); assert( cgD3D9ValidateVertexDeclaration( g_CGprogram, declaration ) // // Bazı parametrelerini isimlerine göre bağla // böylece bunları daha sonra ayarlayabiliriz... // g_CGparam_worldViewProj = cgGetNamedParameter( g_CGprogram, "worldViewProj" ); g_CGparam_constColor = cgGetNamedParameter( g_CGprogram, "constColor" ); Umut DOGAN - Bitirme Tezi - Haziran 2006 g_pd3dDevice->CreateVertexDeclaration( declaration, &g_pVertexDeclaration ); 54 // // Parametrelerimizin beklenen boyutta olup olmadığı kontrol ediliyor... // assert( cgD3D9TypeToSize( cgGetParameterType(g_CGparam_worldViewProj) ) == 16 ); assert( cgD3D9TypeToSize( cgGetParameterType(g_CGparam_constColor) ) == 4 ); // // Program boyunca değişmeyen uniform parametreler ayarlanıyor. // Sadece parametre gölgeleme etkinleştiğinde cgD3D9LoadProgram // çağrısı sırasında tek bir kez ayarlanması yeterlidir. // } D3DXVECTOR4 vConstColor( 0.0f, 0.0f, 1.0f, 0.0f ); cgD3D9SetUniform( g_CGparam_constColor, &vConstColor ); //----------------------------------------------------------------------// shutDown(): Daha önceden başlatılmış tüm nesneleri serbest bırak //----------------------------------------------------------------------void shutDown( void ) { cgD3D9SetDevice(NULL); cgDestroyProgram(g_CGprogram); cgDestroyContext(g_CGcontext); if( g_pVertexBuffer != NULL ) { g_pVertexBuffer->Release(); g_pVertexBuffer = NULL; } if( g_pd3dDevice != NULL ) { g_pd3dDevice->Release(); g_pd3dDevice = NULL; } //----------------------------------------------------------------------// setShaderConstants() : Shader sabitlerini ayarla //----------------------------------------------------------------------void setShaderConstants( void ) { D3DXMATRIX matTrans; D3DXMATRIX matRot; D3DXMatrixTranslation( &matTrans, 0.0f, 0.0f, 4.0f ); D3DXMatrixRotationYawPitchRoll( &matRot, D3DXToRadian(g_fSpinX), D3DXToRadian(g_fSpinY), 0.0f ); Umut DOGAN - Bitirme Tezi - Haziran 2006 } if( g_pD3D != NULL ) { g_pD3D->Release(); g_pD3D = NULL; } 55 g_matWorld = matRot * matTrans; D3DXMatrixIdentity( &g_matView ); D3DXMATRIX worldViewProj = g_matWorld * g_matView * g_matProj; D3DXMatrixTranspose( &worldViewProj, &worldViewProj ); } // world-view-projection matrisi kombinasyonunu yükle cgD3D9SetUniformMatrix( g_CGparam_worldViewProj, &worldViewProj ); //----------------------------------------------------------------------// render() : Sahneyi çizer //----------------------------------------------------------------------void render( void ) { g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_COLORVALUE(0.0f,0.0f,0.0f,1.0f), 1.0f, 0 ); g_pd3dDevice->BeginScene(); g_pd3dDevice->SetVertexDeclaration( g_pVertexDeclaration ); cgD3D9BindProgram( g_CGprogram ); setShaderConstants(); g_pd3dDevice->SetStreamSource( 0, g_pVertexBuffer, 0, sizeof(Vertex) ); g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLEFAN, 0, 2 ); g_pd3dDevice->EndScene(); g_pd3dDevice->Present( NULL, NULL, NULL, NULL ); } Bu uygulamada sadece vertex programıkullandı k. Hangi programıkullanacağı mı z, kaç tane vertex veya fragment shader programıkullanacağı mı z tamamen bize kalmı ş tı r. struct vertex { float4 position : POSITION; float4 color0 : COLOR0; }; struct fragment { float4 position : POSITION; float4 color0 : COLOR0; }; //----------------------------------------------------------------------// IN - her bir vertex için işlenecek gelen veri // worldViewProj - world-view-projection matris kombinasyonu Umut DOGAN - Bitirme Tezi - Haziran 2006 İ lgili vertex programıda ş uş ekildedir. 56 // constColor - sabit renk //----------------------------------------------------------------------fragment main( vertex IN, uniform float4x4 worldViewProj, uniform float4 constColor ) { fragment OUT; // float3'ten float4 oluşturuluyor float4 tempPosition = float4( IN.position.x, IN.position.y, IN.position.z, 1.0f ); OUT.position = mul( worldViewProj, tempPosition ); OUT.color0 = IN.color0; // Belirtilen orijinal rengi kullan return OUT; } Uygulamadan iki ekran görüntüsü Şekil 3.1’de verilmiş tir. Bu program, basit yapı sı sayesinde 32 MB paylaş ı mlıekran kartıkullanan dizüstü bilgisayarı mda rahatlı kla çalı ş tı . Oysa pürüzlü yüzey dokusu üretimi için geliş miş128 MB’lı k bir ekran kartıkullanmak zorunda kaldı m. Buradan Cg’nin esnek profil yapı sı nı n ne kadar yararlıolduğu Şekil 3.1: Basit Bir Vertex Programı Umut DOGAN - Bitirme Tezi - Haziran 2006 görülebiliyor. 57 3.3. Dalgalanan Türk BayrağıUygulaması İ kinci ve son uygulama olarak ekranda dalgalanan Türk bayrağı mı zı n olduğu bir uygulama seçtim. Bu uygulamayıda parçalar halinde inceleyeceğim. Öniş lemci komutları ve global değiş kenlerin birçoğu 3.2. bölümdeki programla aynıolduğ u için bunları belirtmedim. float double double float float g_fElpasedTime; g_dCurTime; g_dLastTime; g_fSpinX = 0.0f; g_fSpinY = 0.0f; float g_fCurrentAngle = 0.0f; float g_fSpeedOfRotation = 10.0f; bool g_bWireFrameMode = false; D3DXMATRIX g_matWorld; D3DXMATRIX g_matView; D3DXMATRIX g_matProj; const int g_nNumVertsX = 16; // x ekseni boyunca bayrak vertexlerinin sayısı const int g_nNumVertsZ = 16; // z ekseni boyunca bayrak vertexlerinin sayısı // Bayrak için gerekli üçgen sayısı const int g_nTriCount = (g_nNumVertsX-1)*(g_nNumVertsZ-1)*2; const int g_nVertCount = g_nTriCount*3; struct Vertex { D3DXVECTOR3 position; D3DXVECTOR3 normal; D3DXVECTOR2 texcoords; enum FVF { FVF_Flags = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1 }; Bayrak dokusunu yüklemek için gerekli fonksiyon alta verilmiş tir. Standart Direct3D komutlarıkullanarak basit bir ş ekilde doku belirlenebiliyor. Arka plandaki iş lemleri Direct3D API’si bizim için hallediyor. void loadTexture( void ) { D3DXCreateTextureFromFile( g_pd3dDevice, "tr_bayrak.bmp", &g_pTexture ); Umut DOGAN - Bitirme Tezi - Haziran 2006 }; 58 g_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); g_pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); } Baş latma iş lemleri init() fonksiyonunda gerçekleş tiriliyor. void init( void ) { g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ); D3DDISPLAYMODE d3ddm; g_pD3D->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &d3ddm ); D3DPRESENT_PARAMETERS d3dpp; ZeroMemory( &d3dpp, sizeof(d3dpp) ); d3dpp.Windowed d3dpp.SwapEffect d3dpp.BackBufferFormat d3dpp.EnableAutoDepthStencil d3dpp.AutoDepthStencilFormat d3dpp.PresentationInterval = = = = = = TRUE; D3DSWAPEFFECT_DISCARD; d3ddm.Format; TRUE; D3DFMT_D16; D3DPRESENT_INTERVAL_IMMEDIATE; g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, g_hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &g_pd3dDevice ); g_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE ); D3DXMatrixPerspectiveFovLH( &g_matProj, D3DXToRadian( 45.0f ), 640.0f / 480.0f, 0.1f, 100.0f ); g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &g_matProj ); loadTexture(); } createMesh(); createMesh() fonksiyonuylaysa bayrak için mesh oluş turuluyor. // kare biçimli bir mesh oluştur. (g_nNumVertsX * g_nNumVertsZ) float dX = (1.0f/(g_nNumVertsX-1)); float dZ = -(1.0f/(g_nNumVertsZ-1)); float dTU = 1.0f/(g_nNumVertsX-1); float dTV = 1.0f/(g_nNumVertsZ-1); int i int x int z float float = 0; = 0; = 0; fSizeFactorX = 8.0f; fSizeFactorZ = 5.0f; Umut DOGAN - Bitirme Tezi - Haziran 2006 void createMesh( void ) { 59 Vertex *v = NULL; g_pd3dDevice->CreateVertexBuffer( g_nTriCount*3*sizeof(Vertex), D3DUSAGE_WRITEONLY, Vertex::FVF_Flags, D3DPOOL_MANAGED, &g_pMeshVertexBuffer, NULL ); g_pMeshVertexBuffer->Lock( 0, 0, (void**)&v, 0 ); // Normal her vertex için aynıdır. for( i = 0; i < g_nVertCount; ++i ) v[i].normal = D3DXVECTOR3(0.0f, 1.0f, 0.0f); for( z = 0, i = 0; z < (g_nNumVertsZ-1); ++z ) { for( x = 0; x < (g_nNumVertsX-1); ++x ) { // İlk üçgen... v[i].position = D3DXVECTOR3(fSizeFactorX*x*dX, 0.0f, fSizeFactorZ*z*dZ ); v[i].texcoords = D3DXVECTOR2(x * dTU, z * dTV); ++i; v[i].position = D3DXVECTOR3(fSizeFactorX*x*dX, 0.0f, fSizeFactorZ*(z+1)*dZ ); v[i].texcoords = D3DXVECTOR2(x * dTU, (z+1.0f) * dTV); ++i; v[i].position = D3DXVECTOR3(fSizeFactorX*(x+1)*dX, 0.0f, fSizeFactorZ*(z+1)*dZ ); v[i].texcoords = D3DXVECTOR2((x+1.0f) * dTU, (z+1.0f) * dTV); ++i; // İkinci Üçgen... v[i].position = D3DXVECTOR3(fSizeFactorX*(x+1)*dX, 0.0f, fSizeFactorZ*(z+1)*dZ ); v[i].texcoords = D3DXVECTOR2((x+1.0f) * dTU, (z+1.0f) * dTV); ++i; v[i].position = D3DXVECTOR3(fSizeFactorX*(x+1)*dX, 0.0f, fSizeFactorZ*z*dZ ); v[i].texcoords = D3DXVECTOR2((x+1.0f) * dTU, z * dTV); ++i; } } } g_pMeshVertexBuffer->Unlock(); Umut DOGAN - Bitirme Tezi - Haziran 2006 v[i].position = D3DXVECTOR3(fSizeFactorX*x*dX, 0.0f, fSizeFactorZ*z*dZ ); v[i].texcoords = D3DXVECTOR2(x * dTU, z * dTU); ++i; 60 Şimdi de initShader() fonksiyonuyla shader bağlantı larıbelirleniyor. void initShader(void) { // Context oluştur... g_CGcontext = cgCreateContext(); // Direct3D aygıtını Cg'ye geç... cgD3D9SetDevice( g_pd3dDevice ); // En uygun profili seç... CGprofile vertexProfile = cgD3D9GetLatestVertexProfile(); const char* vertexOptions[] = { "-profileopts", "dcls", NULL, }; // Vertex shader oluştur... g_CGprogram = cgCreateProgramFromFile( g_CGcontext, CG_SOURCE, "dx9_cg_vertex_turkiye.cg", vertexProfile,"main", vertexOptions ); // Binding Semantics Deklarasyonları const D3DVERTEXELEMENT9 declaration[] = { { 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 }, { 0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0 }, { 0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 }, D3DDECL_END() }; )); assert(cgD3D9ValidateVertexDeclaration( g_CGprogram, declaration g_pd3dDevice->CreateVertexDeclaration( declaration, &g_pVertexDeclaration ); // Bazı parametreleri ada göre bind yap g_CGparam_worldViewProj = cgGetNamedParameter( g_CGprogram, "worldViewProj" ); g_CGparam_currentAngle = cgGetNamedParameter( g_CGprogram, "currentAngle" ); // Prametreler istenen boyutta mı? assert(cgD3D9TypeToSize(cgGetParameterType(g_CGparam_worldViewProj) ) == 16 ); assert(cgD3D9TypeToSize(cgGetParameterType(g_CGparam_currentAngle)) == 4 ); } Umut DOGAN - Bitirme Tezi - Haziran 2006 // Cg programını yükle cgD3D9LoadProgram( g_CGprogram, TRUE, 0 ); 61 Kullandı ğ ı mı z kaynaklarıgeri verirken shutDown() fonksiyonu kullanı lı yor. void shutDown( void ) { cgD3D9SetDevice(NULL); cgDestroyProgram(g_CGprogram); cgDestroyContext(g_CGcontext); if( g_pTexture != NULL ) g_pTexture->Release(); if( g_pMeshVertexBuffer != NULL ) g_pMeshVertexBuffer->Release(); if( g_pd3dDevice != NULL ) g_pd3dDevice->Release(); if( g_pD3D != NULL ) g_pD3D->Release(); } Shader sabitleri setShaderConstants() fonksiyonunda ayarlanı yor. void setShaderConstants( void ) { g_fCurrentAngle -= g_fSpeedOfRotation * g_fElpasedTime; while( g_fCurrentAngle > 360.0f ) g_fCurrentAngle -= 360.0f; while( g_fCurrentAngle < 0.0f ) g_fCurrentAngle += 360.0f; D3DXMATRIX matTrans; D3DXMATRIX matRot; D3DXMatrixTranslation( &matTrans, -4.0f, 2.5f, 10.0f ); D3DXMatrixRotationYawPitchRoll( &matRot, D3DXToRadian(g_fSpinX), D3DXToRadian(g_fSpinY - 90.0f), 0.0f ); g_matWorld = matRot * matTrans; D3DXMatrixIdentity( &g_matView ); D3DXMATRIX worldViewProj = g_matWorld * g_matView * g_matProj; D3DXMatrixTranspose( &worldViewProj, &worldViewProj ); } cgD3D9SetUniformMatrix( g_CGparam_worldViewProj, &worldViewProj ); cgD3D9SetUniform( g_CGparam_currentAngle, &vfCurrentAngle ); Ve sahne oluş turma fonksiyonu da ş uş ekildedir. void render( void ) { g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_COLORVALUE(0.0f,0.0f,0.0f,1.0f), 1.0f, 0 ); Umut DOGAN - Bitirme Tezi - Haziran 2006 D3DXVECTOR3 vfCurrentAngle( g_fCurrentAngle, 0.0f, 0.0f ); 62 g_pd3dDevice->BeginScene(); ); if( g_bWireFrameMode ) g_pd3dDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_WIREFRAME else g_pd3dDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID ); g_pd3dDevice->SetTexture( 0, g_pTexture ); g_pd3dDevice->SetStreamSource(0, g_pMeshVertexBuffer, 0, sizeof( Vertex ) ); setShaderConstants(); g_pd3dDevice->SetVertexDeclaration( g_pVertexDeclaration ); cgD3D9BindProgram( g_CGprogram ); g_pd3dDevice->SetStreamSource( 0, g_pMeshVertexBuffer, 0, sizeof(Vertex) ); g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, g_nTriCount ); g_pd3dDevice->EndScene(); g_pd3dDevice->Present( NULL, NULL, NULL, NULL ); } Ayarlamalarıyukarı daki ş ekilde yaptı ktan sonra Cg programı mı zı n içeriği de ş öyle olmalı dı r. struct vertex { float3 position : POSITION; float3 normal : NORMAL; float2 texcoord0 : TEXCOORD0; }; //----------------------------------------------------------------------// IN - Her bir vertex için işlenecek gelen veri // worldViewProj - model-view-projection matrisi kombibnasyonu // currentAngle - 0 ile 360 arasında tekrar eden bir deger //----------------------------------------------------------------------fragment main( vertex IN, uniform float4x4 worldViewProj, uniform float4 currentAngle ) { fragment OUT; float4 v = float4( IN.position.x, IN.position.y, IN.position.z, 1.0f ); // // // // Öncelikle, vertexlerin Y'lerinin; X'leri ve 0 ile 360 arasında değişen uniform parametre değeriyle toplamı şeklinde yer değiştirmesi için sin() fonksiyonu kullanılıyor. Bu şekilde ekrandaki geometrik şekil sinüs dalgası gibi dalgalanıyor. Umut DOGAN - Bitirme Tezi - Haziran 2006 struct fragment { float4 position : POSITION; float2 texcoord0 : TEXCOORD0; }; 63 // // // // // // // // // // // // // Bayrağımızın tam bir sinüs dalgası gibi dalgalanmasını istemediğimiz için sin()'i tekrar çağırarak bir değişim uyguluyoruz ama bu kez Z değerini kullanıyoruz. Ayrıca bayrak direğine yakın olan vertexlerin çok fazla hareket etmemesini istiyoruz, çünkü fiziksel gerçek böyledir. Bunun için de şöyle yapıyoruz: Bayrak direğine yakın olan değerlerde tekrar X değerlerini kullanarak Y değerlerinin hareketini azaltıyoruz. X değerleri bayrak direğinin yakınlarında 0.0f'den başladığı ve uzaklaştıkça büyüdüğü için bu işlem fazla zorluk çıkarmıyor. Son olarak, görsel güzellik için 0.08f değeri kullanılmıştır. v.y = sin( IN.position.x + currentAngle.x ); v.y += sin( IN.position.z + currentAngle.x ); v.y *= IN.position.x * 0.08f; OUT.position = mul( worldViewProj, v ); OUT.texcoord0 = IN.texcoord0; return OUT; } Uygulamadan iki ekran görüntüsü Şekil 3.2’de görülmektedir. Şekil 3.2: Dalgalanan Türk Bayrağı Böylece Cg ile Direct3D’yi rahatlı kla birlikte kullanabileceğimizi görmüşolduk. Zamanla pratik kazanı larak bunun üstesinden rahatlı kla gelinebilinir. Ayrı ca bu uygulamalar için Visual C++, Direct3D, Cg’nin üçün de bilmek zorunda olmak bir dezavantaj gibi görülebilir. Ama Cg birçok dil ve 3D API kullanarak kod yazmamı za olanak sağladı ğıiçin C#, VB.NET veya baş ka bir dille yazmanı n da pek bir zorluğu bulunmamaktadı r. Dördüncü bölümde Cg dili kullanı larak pürüzlü yüzey dokusu üretilmeye çalı ş ı lacaktı r. Umut DOGAN - Bitirme Tezi - Haziran 2006 Burada en kafa karı ş tı rı cınokta ne zaman ve nası l shader bağlantı ları nı n kurulacağı dı r. 4. Cg İ LE PÜRÜZLÜ YÜZEY DOKUSU ÜRETİ Mİ 4.1. Pürüzlü Yüzey Dokusu Üretimi Programlama Ortamı Pürüzlü yüzey dokusuyla ilgili kodu OpenGL ve Cg kullanarak yazdı m. Kodları n yazı mısı rası nda Visual Studio 2003 ortamı nıkullandı m. Dil olarak da Visual C++ tercihimdi. 4.2. Pürüzlü Yüzey Dokusu Üretimi Nedir Pürüzlü yüzey dokusu üretimi basitçe Şekil 4.1’de görüldüğü gibi iki boyutlu dokuları n üç boyutlu gibi görünmesini sağlamak olarak açı klanabilir. Şekil 4.1: Orijinal 2B Resim ve Pürüzlü Yüzey Uygulanmı şHali (bump mapping) hemen hemen aynıiş lemi ifade ederler. Çünkü pürüzlü yüzey dokusu oluş tururken yaptı ğı mı z işdoku üzerinde verilen piksel için o anki ı ş ı k yoğunluğunu değerlendirmektir. Pürüzlü yüzey dokusu üretimi (bump mapping) ilk olarak, 1978 yı lı nda Blinn tarafı ndan yazı lan bir makalede ortaya atı lmı ş tı r. Geçen yı llar süresince ana algoritma üzerinde bir çok optimizasyon iş lemi gerçekleş tirilmeye çalı ş ı lmı şve farklıpürüzlü yüzey Umut DOGAN - Bitirme Tezi - Haziran 2006 Piksel baş ı na ı ş ı klandı rma (per pixel lighting) ve pürüzlü yüzey dokusu üretimi 65 dokusu üretimi teknikleri üretilmiş tir. Bu konulardaki tartı ş malarıkonunun özünden sapmamak amacı yla buraya almı yorum. Ancak “Kaynaklar” kı smı nda verdiğim kaynaklar farklıpürüzlü yüzey dokusu üretimi teknikleriyle, GPU üzerinde gerçeklenmesiyle ilgili gerekli alt yapı yısağlamaktadı r. Tezimdeki amacı m da GPU üzerinde pürüzlü yüzey dokusu üretimini gerçekleş tirmek olduğ undan bu tip kaynaklardan sı k sı k yararlandı m. Özellikle aydı nlatma modelleriyle ilgili kaynaklar önemli bilgiler içermektedir. Tezimde 1978 yı lı nda Blinn tarafı ndan önerilen teorik algoritmaya yakı n bir algoritma kullandı m. Algoritmanı n ayrı ntı larıbir sonraki baş lı kta açı klanmı ş tı r. 4.3.Programda Kullanı lan Algoritmalar Sı radan iki boyutlu bir doku ele alalı m. Bu dokunun yüzeyi düzdür ve doku yüzeyinin normalleri Şekil 4.2a’da görüldüğü gibi direkt yukarı ya doğru olacaktı r. İ ş te bu yüzden eskiden üç boyutlu oyunlarıoynarken küp ş eklindeki bir kutuya yaklaş tı ğı mı zda kutunun derinliği yokmuşgibi görünürdü. Bu yüzden de iki boyutlu dokular kullanı lan oyunlardan çok çabuk bir ş ekilde sı kı lı rdı k. Bu problemin çözümü, sahneyi gerçekledikçe doku üzerinde ı ş ı k yoğunlukları nı sürekli değiş tirmektir. Örneğin Şekil 4.1’de sağ daki resimde ı ş ı ğı n sol üst köş eden geldiğ ini düş ünelim. Bu durumda taş ı nı ş ı ğa doğru bakan uçlarıı ş ı ğa bakmayan uçları ndan daha parlak görünecektir. İ ş te bizim istediğimiz görüntü de böyle bir görüntüdür. Yaptı ğı mı z ise her piksel için renk yoğ unluğunu hesaplamak ve böylece dokuya sahte bir derinlik kazandı rmaktı r. Böylece oyuncu gerçekten üç boyutlu bir dünyada oynadı ğı nı Verilen doku öğesine (texel, texture element) ait ı ş ı k yoğunluğunu hesaplayabilmek için her bir doku öğesine ait yüzey normallerini bilmeliyiz. İ ş te bu noktada normal map devreye giriyor. Normal map, her bir doku öğesi için yüzey normallerinin yön bilgisini tutar. (Şekil 4.2b). Şekil 4.2b’de altta çizilmişkavisli yüzey normallerin benzetmeye çalı ş tı ğıgerçek yüzeydir. Umut DOGAN - Bitirme Tezi - Haziran 2006 düş ünecek ve oyundan daha büyük keyif alacaktı r. 66 Şekil 4.2: (a) Herhangi bir yüzey dokusu (b) normal map Gerçek bir normal map ise Şekil 4.3’te gösterilmiş tir. Bu ş ekil ilk bakı ş ta biraz garip gelebilir ama ş ekille ilgili açı klamalardan sonra neden böyle olduğ u daha iyi anlaş ı lacaktı r. Dokunun sol alt köş esinde belirtilen üç eksenden x ekseni sağa, y ekseni yukarıve z ekseni de ekrandan dı ş a doğ rudur. Şimdi kı rmı zı yla x, yeş ille y ve maviyle de z eksenini gösterelim. Şekle yakı ndan bakı lı rsa +x eksenine doğru bakan kenarları n kı rmı zı , +y eksenine doğru bakanları n yeş il ve yüzeyden dı ş a doğru çı kan kı sı mları nda mavi renkte olduklarıgörülür. Dokumuzun yapı sıitibariyle birçok kı sı m ekrandan dı ş a doğru olduğu Şekil 4.3: Normal Map Bu projede gerçekleş tirdiğim önemli noktalardan birisi, verilen doku öğesi için seçilmişrengi o konumdaki normalin yönü olarak belirlemektir. Normalin yönü üç koordinatla gösterilmektedir. Bu koordinatlar [x, y, z] ‘dir ve her biri [-1,1] aralı ğı nda değerler almaktadı r. Ama dokumuzdaki renkler RGB (red, green, blue) ş eklinde temsil edilmekte ve [0,1] aralı ğı nda değerler alabilmektedir. Kı rmı zıdeğerleri x, yeş il değerleri y Umut DOGAN - Bitirme Tezi - Haziran 2006 için normal map’in büyük kı smımavi renktedir. 67 ve mavi değerleri z olarak yorumlamak istiyorum. Bu yüzden [-1,1] aralı ğı ndaki değerleri [0,1] aralı ğı na dönüş türmem gerekli. Bu iş leme renk değerlerini açma (decompressing) deniyor. Renk değerlerini gerçek koordinat değerlerine açmak için ş u eş itlik kullanı lı yor: x = 2.0 * (renkDegeri - 0.5) 0 değerini renkDegeri – 1 olarak belirlemeliyiz. Bu noktada her bir doku öğesi için normallerin yönünü normal map’ten okuyup yorumlayabilecek hale gelmişolduk. Aydı nlatma eş itliği dinamik aydı nlatmayla uğraş ı rken önemlidir. Alttaki ş ekilde formüle edilebilir: I = A + att*(D + S) Burada; I son renk yoğunluğudur. A çevre aydı nlı ğı dı r (ambient light). Çevre aydı nlı ğı nıeklememizin nedeni gerçek dünyayıtaklit edebilecek ş ekilde tümüyle karanlı k alanları n oluş ması nıengellemektir. Bu yüzden tüm piksellere uygulanacak bir varsayı lan ı ş ı k tanı mladı k. att ise ı ş ı ğı n zayı flama miktarı nı(attenuation) temsil etmektedir. Tüm ı ş ı k kaynakları nda ı ş ı ğı n eriş ebileceği bir maksimum uzaklı k vardı r. Bu mesafe, üzerinde çalı ş ı lan piksel için renk solgunluğunun ne kadar olacağı n belli eder. D, yayı nı k (diffuse) renktir. Yayı nı k renk, ı ş ı k bir nesneye çarptı ğı nda gördüğümüz renktir. Formülde I = D değiş ikliği yaparak aydı nlatma eş itliğini biraz daha basitleş tirdim. Yani programda tek ilgileneceğimiz bileş en yayı nı k bileş en olacaktı r. Buna göre formül; I = Dl * Dm * clamp(L•N, 0, 1) ş eklini alacaktı r. Burada; Dl: ı ş ı ğı n yayı nı k rengidir. Dm: nesne üzerindeki materyalin yayı nı k rengidir. L: Yüzey üzerindeki bir noktadan ı ş ı k kaynağı na doğru olan vektördür. Umut DOGAN - Bitirme Tezi - Haziran 2006 S, aynasal (specular) renktir. Nesnenin yansı ttı ğıı ş ı ktı r. 68 N: Üzerinde çalı ş tı ğ ı mı z piksel için yüzeyin normalidir. L•N ise L ve M’nin iç çarpı mı dı r. Basitleş tirilmişaydı nlatma eş itliğimize göre verilen herhangi bir piksel için baş arı lı bir ş ekilde ı ş ı k yoğunluğunu hesaplayabilmek için üç parametreye ihtiyacı mı z vardı r. L ile N arası ndaki iç çarpı mla baş layalı m. Burada L basit bir ş ekilde o anki vertexin konumunu ı ş ı k pozisyonundan çı karı larak bulunabilir. N de daha önce açı kladı ğı m normal map’ten kolay bir ş ekilde okunabilir. Dm, yani üzerinde çalı ş ı lan doku öğesi için materyalin rengi orijinal dokudaki rengi kullanacağ ı z. Şekil 4.1’de verdiğimiz örnekte Dm renginin gri taşrenginde olduğu görülüyor. Dl ise ı ş ı ğ ı n rengidir ve genellikle beyazdı r. Şekil 4.4: Yüzeyle İ liş kili Vektörler Bu kı sma kadar pürüzlü yüzey dokusu üretimiyle ilgili teoriyi büyük oranda bitirmişolduk. 3B API’lerde modelview ve projeksiyon matrisleri önemli kavramlardı r. Pürüzlü yüzey dokusu üretimi projemde de bu kavramlarıkullandı ğı m için açı klama gereği duydum. Modelview ve projeksiyon matrisleri bir vertexi nesne uzayı ndan (object space), Umut DOGAN - Bitirme Tezi - Haziran 2006 Şekil 4.4’te yüzeyle iliş kili vektörleri görsel olarak açı klamaya çalı ş tı m. 69 ekran uzayı na (clip space) taş ı mak için kullanı lı r. Nesne uzayıkod yazarken kullandı ğı mı z koordinat sistemidir. Örneğin OpenGL’de glTranslatef(10.0f, 0.0f, -20.0f) komtunu kullanı p bir nesneyi x,y,z koordinatları nda ötelememiz gibi. Tüm nesne uzayı vertexlerini monitörümüzde düzgün bir ş ekilde görüntülenebilmesi için ekran uzayı na dönüş türmeliyiz. Bu iş lem birbirine bağlımodelview ve projeksiyon matrisleriyle nesne uzayı ndaki bir vertexin çarpı lması yla olur.(Eğer shader kullanmı yor olsaydı k bu iş lem OpenGL tarafı ndan otomatik olarak yapı lı yor olacaktı .) Farklıuzaylar arası ndaki iliş kiler ve bu uzayları n birbirlerine nası l dönüş türüleceğ i Şekil 4.5: Uzaylar ve Dönüş üm Matrisleri Bu noktada biraz da teğet uzayıüzerinde duralı m. Teğet (veya doku) uzayıŞekil 4.6’da görüldüğü gibi yüzeyle ilgili bir uzaydı r. Umut DOGAN - Bitirme Tezi - Haziran 2006 Şekil 4.5’te gösterilmiş tir. 70 Şekil 4.6: Teğet UzayıKoordinatları S teğetini x ekseni, T teğetini y ekseni ve normali de z ekseni olarak düş ünebiliriz. Şekilden de görüldüğ ü gibi yüzey üzerindeki her bir vertexin kendi teğet uzayıvardı r. (Her bir köş ede bir tane olmak üzere toplamda dört vertex). Üç eksen belli bir vertex için temel oluş turur ve teğ et uzayı(tanjant veya doku uzayıda denir) adıverilen bir koordinat uzayı oluş tururlar. Eğer eksenleri bir matrisle temsil edecek olursak TBN matrisini (Tangent, Binormal, Normal) elde etmişoluruz. Burada T ile S teğeti, binormal ile de T teğeti ifade edilmektedir. (Tx, Bx, Nx) (Ty, By, Ny) Teğet uzayı ndaki herhangi bir noktayıbu matrisle çarparsak noktayınesne uzayı na çevirmişoluruz. Verilen bir vertex için teğet temelini hesaplamak için alttaki eş itliği kullanacağı z. Bu eş itliğin nası l elde edildiğiyle ilgili ayrı ntı lar için Kaynaklar kı smı na bakabilirsiniz. Umut DOGAN - Bitirme Tezi - Haziran 2006 (Tz, Bz, Nz) 71 Buradan T ve B matrislerini; ş eklinde elde ederiz. Burada; Δv2v1 vertex1’ den vertex2’ ye olan vektördür. (V2-V1) Δv3v1 vertex1’den vertex3’ye olan vektördür. (V3-V1) Δc2c1T v2.dokuKoord.x – v1.dokuKoord.x Δc2c1B v2.dokuKoord.y – v1.dokuKoord.y Δc3c1T v2.dokuKoord.x – v1.dokuKoord.x Δc3c1B v2.dokuKoord.y – v1.dokuKoord.y ve ş eklindedir. Normal map ve aydı nlatma eş itliğ i anlatı lı rken yüzeydeki herhangi bir vektör ve ı ş ı k vektörünün iç çarpı mı nıyapmak istediğimizi belirtmiş tik. Yüzey normali teğet uzayı nda bulunmaktadı r ve ı ş ı k vektörü de nesne uzayı nda bulunmaktadı r. İ ş te bu noktada, iç çarpı mı n bir anlam ifade edebilmesi için bu iki vektörün aynıuzayda olması nıistiyoruz. Bu nedenle önümüzde ş u iki seçenek var: 1) Iş ı k vektörünü teğet uzayı na dönüş türmek Birinci seçeneğin daha mantı klıolduğu görülmektedir. Eğer ikinci seçeneği seçmiş olsaydı k normal map’teki tüm normalleri nesne uzayı na dönüş türmemiz gerekecekti. Bu da önemli miktarda performans düş üş ü demektir. TBN matrisi teğet uzayı ndan nesne uzayı na dönüş türdüğ ü için biz bunun tam tersi yönde iş lem yapmalı yı z. Yani altta görüldüğü gibi TBN matrisinin tersini almalı yı z. Umut DOGAN - Bitirme Tezi - Haziran 2006 2) Normal map’teki tüm yüzey normallerini nesne uzayı na dönüş türmek 72 Bir de optimizasyon gerçekleş tirdik. Sadece üçgenlerle uğraş tı ğı mı z için her bir üçgene ait tek bir ters TBN matrisi hesaplamamı z yeterlidir. Yani her bir vertex için hesaplama yapma zorunluluğumuz ortadan kalkmı ş tı r. Ama burada önemli olan nokta üçgen her döndürüldüğünde ter TBN matrisi tekrar hesaplanmalı dı r. Üçgenin ötelenmesi için yeniden hesaplama gerektirmez. Yani tek yapmamı z gereken ters TBN matrisini ı ş ı k vektörüyle çarpmaktı r. Böylece ı ş ı k vektörünü teğet uzayı na taş ı mı şve iç çarpı m hesaplamasıiçin hazı r hale getirmiş olduk. Pürüzlü yüzey dokusu üretirken yaptı ğı mı z iş lemleri ş öyle bir özetleyelim: 1) Tüm üçgenler için ters TBN matrisi hesapla. (Sadece baş langı çta ve dönme olduğunda yapı lmasıgerekiyor.) 2) Iş ı k vektörünü hesapla bu vektörü nesne uzayı ndan teğet uzayı na taş ı . 3) Normal vektörünü normal haritası ndan oku ve aralı ğı[-1,1]’den [0,1] aralı ğı na aç. 4) Iş ı k vektörüyle normalin iç çarpı mı nıyap. Daha sonra bu çarpı mla ı ş ı ğ ı n rengini ve yüzey materyalinin rengi çarparak sonuç yayı nı k rengini bul. 5) Bütün bu iş lemleri verilen yüzeydeki her piksel için tekrarla. Önceki baş lı klarda Cg’nin NVIDIA firmasıtarafı ndan geliş tirilmişbir shader dili olduğunu belirtmiş ; tarihçesi ve sözdizimiyle ilgili ayrı ntı larıvermiş tim. Shader, grafik kartı mı zı n GPU’suna indirdiğimiz küçük bir programdı r. Shader, doğrudan grafik kartı nı n üzerinde koş tuğundan çok güçlüdür ve doku ve matris gibi ş eylere doğ rudan eriş ebilir. Umut DOGAN - Bitirme Tezi - Haziran 2006 4.4.Cg ile İ lgili Kı sa Bilgiler 73 4.5. Cg Runtime İ ki tür shader vardı r: Birincisi vertex shader ve ikincisi de fragment (pixel) shader. Vertex shader glVertex3f() gibi komutlarla ekrana çizdiğ imiz her vertex için çağrı lı r. Şekil 4.7’deki gibi üç tane glVertex3f() çağrı sıalan bir üçgen çizdiğimizi düş ünelim. Bu, aktif olan vertex shader’ı n üç kez çağrı lması nıgerektirecektir. Daha sonra üç vertex arası ndaki maddeyi (burada maviyle doldurulmuşkı sı m) tümüyle çizilinceye kadar üçgen boyunca interpole ediyoruz. Üçgen üzerinde interpole ettiğimiz her piksel için fragment shader çağrı lı yor. Şekil 4.7: Üçgen ve Vertexleri Temelde vertex shader, vertexlerin istediğimiz uzaya dönüş türülmesiyle uğraş ı r. Örneğ in vertex shader, ı ş ı k vektörünün nesne uzayı ndan teğ et uzayı na dönüş türülmesi için mükemmel bir yerdir. Öte yandan fragment shader iş in sihirli kı smı nı n olduğu yerdir. Fragment shader Cg’yi uygulamamı zda düzgün bir ş ekilde kullanmak için bazıayarlamalar yapmamı z gerekiyor. Öncelikle Cg context oluş turmalı yı z. Cg context çok sayı da Cg programıiçin bir konteynerdir. Cg programıvertex veya shader programıolabilir. Ben de uygulamamda öncelikle Cg context yarattı m. Daha sonra bir vertex ve bir fragment programıyaratı p bu programlarıCg context’e bağladı m. Bütün Cg programlarıCg context’e sahip olmalı dı r. Umut DOGAN - Bitirme Tezi - Haziran 2006 her piksel için çağrı ldı ğı ndan pürüzlü yüzey hesaplamaları mı zda kullanabiliriz. 74 Ayrı ca önemli noktalardan biri de Cg profile’dir. Farklıgrafik kartlarıolduğu ve birçoğu Cg’nin tüm shader özelliklerini desteklemediği için Cg profile tanı mlamaları sayesinde belli bir donanı m platformu için Cg özellik kümesi tanı mlanmı şolur. Vertex shaderları n fragment shaderlardan farklıözellikleri olduğu için her biri için ayrıbir profile’a ihtiyacı mı z vardı r. Daha sonra Cg context oluş tururken, her bir Cg programıiçin programı mı zı n çalı ş tı ğıbilgisayarı n özelliklerine göre en uygun profili döndüren Cg profil fonksiyonunu çağı rı yoruz. Daha sonra bu profilleri vertex ve fragment programları na iliş tiriyoruz. Burada en önemli avantaj kodlamamı zıstatik olarak belli bir profil için yapı yor olmamamı zdı r. Bunun yerine uygun profil koş ma zamanı nda (runtime) Cg profil fonksiyonu tarafı ndan belirleniyor. Böylece uygulamamı zı n çalı ş tı ğ ımakineye en uygun profili seçmişoluyoruz. Cg’deki önemli özelliklerden birisi de CG shaderlarla uğraş ı rken OpenGL’de veya Direct3D’de dokularıyapabildiğimiz gibi burada da istediğimiz an shaderlarıetkinleş tirip pasifleş tirebiliyoruz. Bu ş ekilde uygulamamı zda istediğimiz kadar shader program kullanabiliyor ve uygulamamı zı n ihtiyaçları na göre bunlar arası nda geçiş ler yapabiliyoruz. Ama aynıanda sadece bir vertex ve bir fragment programıetkin olabiliyor. Eğ er bütün rendering olayları nıshader programlarıyerine 3B API’mizin halletmesini istiyorsak tek yapmamı z gereken bütün etkin shaderlarıpasifleş tirip gerekli ayarlamalarıyapmaktan ibarettir. Cg’nin bir baş ka özelliğiyse shaderlarıkoş ma zamanı nda veya koş ma zamanı ndan Cg derleyicisinin güncellenmişbir sürümünün özelliklerini de kullanma ş ansı mı z olur. Böylece ana program derlendikten yı llar sonra bile shader çok daha verimli bir ş ekilde koş abilir. Umut DOGAN - Bitirme Tezi - Haziran 2006 önce derleyebiliyor olmamı zdı r. Eğer koş ma zamanıderlemesinden yararlanacak olursak 75 4.6. Cg Shaderları Öncelikle Cg shader programları nıaçı klamakla baş lı yorum. İ lk programı mı z vertex shader programı . Vertex programı nı n görevi ı ş ı k vektörünü nesne uzayı ndan teğet uzayı na dönüş türmektir. Ayrı ca kullandı ğı mı z shader OpenGL’in vertex handling mekanizması nı n yerini aldı ğıiçin her bir vertex konumunu nesne uzayı ndan ekran uzayı na manuel olarak dönüş türmemiz gerekmektedir. Önceki sayfalardaki teorik kı sı mda belirttiğim gibi bunu yapabilmek için birleş tirilmişmodelview ve projeksiyon matrisleriyle vertex konumu çarpı lmalı dı r. İ ş te bütün bu iş lemleri yapan vertex shader program kodu açı klamaları yla birlikte altta verilmiş tir. Görüldüğü gibi program çok kı sa ve anlaş ı labilir bir biçimdedir. void main( in float4 position : POSITION, // Üzerinde çalışılan vertexin konumu, // vertex shader için bu parametre zorunludur. in float2 texCoords : TEXCOORD0, // Veriyi shader'a göndermek için, // glMultiTexCoord2fARB(GL_TEXTURE0_ARB, ...) kullanıyoruz. in float3 vTangent : TEXCOORD1, // Veriyi shader'a göndermek için, // glMultiTexCoord3fARB(GL_TEXTURE1_ARB, ...) kullanıyoruz. in float3 vBinormal : TEXCOORD2, // Veriyi shader'a göndermek için, // glMultiTexCoord3fARB(GL_TEXTURE2_ARB, ...) kullanıyoruz. in float3 vNormal : TEXCOORD3, // Veriyi shader'a göndermek için, // glMultiTexCoord3fARB(GL_TEXTURE3_ARB, ...) kullanıyoruz. out float4 positionOUT : POSITION, // Dönüştürülmüş vertex konumunu fragment shadera gönder out float2 normalCoordsOUT : TEXCOORD1, // Normal map'in doku koordinatlarını fragment shadera gönder out float3 vLightVector : TEXCOORD2, // Dönüştürülmüş ışık vektörünü fragment shadera gönder const uniform float4x4 modelViewProjMatrix, // Birbirine bitiştirilmiş modelview ve projeksiyon matrisleri const uniform float3 vLightPosition) // Işık küresinin nesne uzayındaki konumu { Umut DOGAN - Bitirme Tezi - Haziran 2006 out float2 texCoordsOUT : TEXCOORD0 // Doku map'in doku koordinatlarını fragment shadera gönder 76 // Işık vektörünü hesapla vLightVector = vLightPosition - position.xyz; // Işık vektörünü nesne uzayından teğet uzayına dönüştür float3x3 TBNMatrix = float3x3(vTangent, vBinormal, vNormal); vLightVector.xyz = mul(TBNMatrix, vLightVector); // Üzerinde çalışılan vertexi nesne uzayından ekran uzayına dönüştür positionOUT = mul(modelViewProjMatrix, position); // Doku map ve normal map'in koordinatlarını fragment shadera gönder texCoordsOUT = texCoords; normalCoordsOUT = texCoords; } Bazıparametrelerden sonra kullandı ğı mı z iki nokta üst üste (:) karakteri Cg’ye bu parametreyi belli bir OpenGL çağrı sı na bağlamak istediğimizi belirtmektedir. Benzer ş ekilde eğ er Direct3D API’si kullanmı şolsaydı m bu sefer de çağrıDirect3D ile ilgili olacaktı . Örneğin “: POSITION” “baseCoords : TEXCOORD0” ile glVertex3f() çağrı sı nı n değerini alı r ve ile de glMultiTexCoord2fARB(GL_TEXTURE0_ARB, ...) komutuyla ayarladı ğı mı z değ erler kümesini alı r. “: POSITION” değerine bağlama semantiği (binding semantic) denir. Burada dikkat edilirse her ikisi de aynıdeğerleri içermesine rağmen doku ve normal map koordinatları nıfragment shader’a ayrıayrı gönderiyoruz. Bunun nedeni eski grafik kartları yla uyumluluğu sağlayabilmektir. Tekörnek (uniform) parametreler program boyunca çok fazla değ iş meyen parametrelerdir. Örneğ in ne ı ş ı k konumu ne de birleş tirilmişmodelview ve projeksiyon matrisleri, dörtgenimizi oluş turan dört vertexi oluş tururken hiç değiş ikliğe uğramazlar. Böylece ekrana bir ş ey çizmeye baş lamadan önce tek biçim değ erlerini main.cpp dosyamı zda ş u ş ekilde // Vertex shaderdaki "modelViewProjMatrix" parametresini üzerinde çalışılan modelview ve projeksiyon matrislerine ayarla cgGLSetStateMatrixParameter(g_modelViewMatrix, CG_GL_MODELVIEW_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY); // Vertex shaderdaki ışık konumu parametresini ayarla cgGLSetParameter3f(g_lightPosition, g_vLightPos.x, g_vLightPos.y, g_vLightPos.z); Ayrı ca shader’da out parametrelerini de bağlama sözdizimlerine nası l bağladı ğ ı mı z önemlidir. Bu sayede bunlarıfragment shader’dan doğrudan okuyabiliriz. Birazdan Umut DOGAN - Bitirme Tezi - Haziran 2006 ayarlı yoruz: 77 açı klayacağı m gibi örneğin vLightVector değeri TEXCOORD2’ye bağ lanmı ş tı r ve fragment shader’da da TEXCOORD2 semantiğine bağlıolarak okunur. Yukarı da açı klamasıverilen vertex shader kodu, olayı n teorik boyutu anlaş ı ldı ğı nda çok kolay bir ş ekilde yazı labilir. Fragment shader ise ş öyledir: void main( in float4 colorIN : COLOR0, in float2 texCoords : TEXCOORD0, // Doku map'in doku koordinatları in float2 normalCoords : TEXCOORD1, // Normal map'in doku koordinatları in float3 vLightVector : TEXCOORD2, // Dönüştürülmüş ışık vektörü (tanjant uzayında) out float4 colorOUT // O anki pikselin son rengi : COLOR0, uniform sampler2D baseTexture : TEXUNIT0, // Duvar dokusu uniform sampler2D normalTexture : TEXUNIT1, // Duvar dokusunun normal mapi uniform float3 fLightDiffuseColor) // Işık kaynağının yayınık rengi { // Işık vektörünü normalize etmeliyiz çünkü yüzey üzerinde doğrusal olarak interpole ediliyor, // yani biz interpole ettikçe vektörün boyutları değişiyor. vLightVector = normalize(vLightVector); // Normal map'teki normaller (renkler) [0, 1] aralığında olduğundan bunları // gerçek normal (vektör) doğrultularına açmalıyız. // ([0, 1] -> [-1, 1]) float3 vNormal = 2.0f * (tex2D(normalTexture, normalCoords).rgb 0.5f); // Yayınık bileşeni hesapla ve sonuç rengi olarak 'colorOUT' içine // Yayınık bileşen şu şekilde tanımlanmıştı: I = Dl * Dm * clamp(L•N, 0, 1) // saturate() aynen clamp() gibi çalışır ama [0;1] arasında kenetlenmeyi gerektirir. colorOUT.rgb = fLightDiffuseColor * tex2D(baseTexture, texCoords).rgb * saturate(dot(vLightVector, vNormal)); } Burada da dikkat edilirse her ş ey çok sade bir ş ekilde teorik temeller üzerine kurulmuş tur. Gereksiz hiçbirş ey yoktur sadece ilgili bağlamalar yapı lmı şve fragment shader’da yapı lmasıgereken hesaplamalar belirtilmiş tir. Umut DOGAN - Bitirme Tezi - Haziran 2006 yaz. 78 Buraya kadar olan kı sı m shader’larla ilgiliydi. Aslı nda genelde yararlandı ğı m bütün kaynaklarda shader oluş turulması yla ilgili bütün ayrı ntı lar açı klanmı şancak bu shader’ları OpenGL veya Direct3D’ye nası l bağlayacağı m açı klanmamı ş tı . Tezimde uygulama programı yla ilgili açı klamalarıyaptı ğı m bu kı sı mda OpenGL’e nası l bağlandı ğı nı anlatmaya çalı ş tı m. Direct3D’ye bağlanması nıise küçük örneklerin bulunduğu bir baş ka baş lı kta elimden geldiğ ince açı klamaya çalı ş tı m. 4.7. Ana Program İ lk olarak Cg programları yazabilmek için gerekli include dosyaları nı n programı mı za eklenmesiyle baş lı yoruz. Derleyicimizin yani Visual Studio 2003’ün include ve lib dizinlerine (C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7), Cg programları yazabilmemiz için gerekli kütüphaneleri (C:\Program Files\NVIDIA Corporation\Cg) kopyaladı ğı mı zıvarsayı yorum. Bu ayarlamalarla ilgili kı sı mlar tezin diğer bölümlerinde ayrı ca belirtilmiş tir. Ayrı ca bir OpenGL extension olan OglExt kütüphanesinin include ve lib dizinleri de aynıyere kopyalanmalı dı r. //CG'nin ihtiyaç duyduğu headerlar #include <CG/cg.h> #include <CG/cgGL.h> // CG'nin ihtiyaç duyduğu library dosyaları #pragma comment (lib, "cg.lib") #pragma comment (lib, "cgGL.lib") // OglExt.lib OpenGL Extensions library dosyası #pragma comment (lib, "OglExt.lib") Daha sonra InitCG() fonksiyonunda Cg ayarlamalarıyapı lı yor ve Cg shader BOOL InitCG() { // Sorun oluşursa Cg tarafından çağrılacak fonksiyonu ayarla // tanımlaması biraz altta cgSetErrorCallback(CGErrorCallback); // shader programlarımızı tutacak Cg context oluştur g_context = cgCreateContext(); Umut DOGAN - Bitirme Tezi - Haziran 2006 programlarıoluş turuluyor. 79 // Fragment shader için çalışılan makinadaki ekran kartına göre // en uygun profili seç g_fragmentProfile = cgGLGetLatestProfile(CG_GL_FRAGMENT); cgGLSetOptimalOptions(g_fragmentProfile); if (g_fragmentProfile == CG_PROFILE_UNKNOWN) { g_pLog.PrintLn("Desteklenmeyen Ekran Kartı! Uygun Fragment Shader Profili Bulunamıyor!"); return FALSE; } // Vertex shader için çalışılan makinadaki ekran kartına göre // en uygun profili seç g_vertexProfile = cgGLGetLatestProfile(CG_GL_VERTEX); cgGLSetOptimalOptions(g_vertexProfile); if (g_vertexProfile == CG_PROFILE_UNKNOWN) { g_pLog.PrintLn("Desteklenmeyen Ekran Kartı! Uygun Vertex Shader Profili Bulunamıyor!"); return FALSE; } // Fragment program oluştur. // cgCreateProgramFromFile() şu parametreleri alıyor: // Bir CG context, CG dosyasının türü (GL_SOURCE henüz derlenmemiş bir shader okuduğumuzu belirtiyor), // Cg shader dosya adı, az önce oluşturduğumuz Cg profili, shaderdaki başlangıç fonksiyonunun adı. g_fragmentProgram = cgCreateProgramFromFile(g_context, CG_SOURCE, "FragmentShader.cg", g_fragmentProfile, "main", 0); if (!g_fragmentProgram) return FALSE; // Fragment programı yükle cgGLLoadProgram(g_fragmentProgram); // Vertex programı oluştur g_vertexProgram = cgCreateProgramFromFile(g_context, CG_SOURCE, "VertexShader.cg", g_vertexProfile, "main", 0); if (!g_vertexProgram) return FALSE; // Sahnedeki iki üçgen için de TBN matrisini hesapla CalculateTBNMatrix(g_vQuad[0], g_vTexCoords[0], g_TBNMatrix[0]); CalculateTBNMatrix(g_vQuad[1], g_vTexCoords[1], g_TBNMatrix[1]); // Vertex ve fragment shaderlara geçeceğimiz parametreleri al. // Bunu “main(int gecPar)” gibi düşünebiliriz. // Altta yaptığımız işlem parametreler için bir referans almak (gecPar gibi) // değerlerini Cg programının dışında ayarlayabiliriz. Bağlantıları alt satırlarda.. g_modelViewMatrix = cgGetNamedParameter(g_vertexProgram, "modelViewProjMatrix"); g_lightPosition = cgGetNamedParameter(g_vertexProgram, "vLightPosition"); Umut DOGAN - Bitirme Tezi - Haziran 2006 // Vertex programı yükle cgGLLoadProgram(g_vertexProgram); 80 g_lightDiffuseColor = cgGetNamedParameter(g_fragmentProgram, "fLightDiffuseColor"); // Işık küresini oluştur. g_lightSphere = gluNewQuadric(); return TRUE; } Alttaki kod parçacı ğıise iş in mantı ğı yla ilgili önemli bir bölümdür. Dörtgenimizi iki üçgenden ve verilen doku koordinatları ndan oluş acak ş ekilde ayarladı k. Burada dikkat edilmesi gereken bir nokta da iki tane TBN matrisi kullandı ğı mı zdı r. Daha önce belirttiğim gibi bu programda üçgenlerle ilgileniyoruz ve her bir üçgen için bir tane TBN matrisi kullanmamı z yeterlidir. // Dörtgenimizin koordinatları (herbiri 3 vertexten oluşan 2 üçgen) CVector g_vQuad[2][3] = { { CVector(-10.0f, -10.0f, -40.0f), CVector(10.0f, -10.0f, -40.0f), CVector(10.0f, 10.0f, -40.0f) }, { CVector(-10.0f, 10.0f, 40.0f), CVector(-10.0f, -10.0f, -40.0f), CVector(10.0f, -10.0f, 40.0f) } }; // 2 üçgen için doku koordinatları CVector2 g_vTexCoords[2][3] = { { CVector2(0.0f, 0.0f), CVector2(1.0f, 0.0f), CVector2(1.0f, 1.0f) }, { CVector2(0.0f, 1.0f), CVector2(0.0f, 0.0f), CVector2(1.0f, 0.0f) } }; // 2 tane TBN matrisi (her bir üçgen için bir tane).Her matris 3 vektörden oluşuyor. CVector g_TBNMatrix[2][3]; Altta verdiğim fonksiyon ise hata geri çağı rma fonksiyonudur. Cg shader’larla ilgili bir problem oluş tuğunda oluş an hatalarla ilgilenmektedir. Programda verilen hata mesajları nı n büyük çoğunluğu İ ngilizce olacaktı r. Bunun nedeni dil tanı mlanı rken böyle void CGErrorCallback() { // Hata mesajını log dosyasına yaz: // cgGetErrorString() ortaya çıkan hatayı döndürür. // cgGetLastListing() hatanın daha açıklayıcı bir çıktısını verir. g_pLog.PrintLn("%s - %s", cgGetErrorString(cgGetError()), cgGetLastListing(g_context)); } Program sonlandı rı ldı ğı nda gerekli temizlik iş lemleriniyse DestroyCG() fonksiyonu yapmaktadı r. Umut DOGAN - Bitirme Tezi - Haziran 2006 tanı mlanmaları dı r. 81 void DestroyCG() { // Işık küresini yok et ve serbest bırak if (g_lightSphere) gluDeleteQuadric(g_lightSphere); // Cg contex yok edilince bağlı tüm programlar da yok edilir cgDestroyContext(g_context); } Ekranda herhangi bir ş eyi gerçekleyebilmek için ilk önce her bir üçgen için TBN matrisini hesaplamamı z gerekmektedir. CalculateTBNMatrix() fonksiyonu bu amaçla oluş turulmuş tur. Girdi olarak üç parametre almaktadı r: - TBN matrisini hesaplamak istediğimiz üçgen - Verilen üçgenin doku koordinatları - Hesaplanmı ş veriyle dolduracağı mı z ve çağı ran fonksiyona döndüreceğimiz TBN matrisi Bu bilgiler ı ş ı ğı nda ShaderUtils.cpp dosyası nda bulunan CalculateTBNMatrix() fonksiyonunun içeriği ş öyledir: void CalculateTBNMatrix(const CVector *pvTriangle, const CVector2 *pvTexCoords, CVector *pvTBNMatrix) { // Üçgenin her bir vertexi için teğet tabanını hesapla // // TBN matrisini hesaplamak için üçgenin sadece ilk vertexini kullandık, eğer istersek // diğer ikisinden birini de kullanabilirdik. Sonuç değişmezdi. int i = 0; // Üzerinde çalışılan vertexten üçgenin diğer iki vertexine olan vektörleri hesapla CVector v2v1 = pvTriangle[nNextIndex] - pvTriangle[i]; CVector v3v1 = pvTriangle[nPrevIndex] - pvTriangle[i]; // // // // // Bitirme Raporunda belirtilen eşitlikler: c2c1_T = V2.texcoord.x – V1.texcoord.x c2c1_B = V2.texcoord.y – V1.texcoord.y c3c1_T = V3.texcoord.x – V1.texcoord.x c3c1_B = V3.texcoord.y – V1.texcoord.y // c2c1_T ve c2c1_B'i hesapla float c2c1_T = pvTexCoords[nNextIndex].x - pvTexCoords[i].x; float c2c1_B = pvTexCoords[nNextIndex].y - pvTexCoords[i].y; Umut DOGAN - Bitirme Tezi - Haziran 2006 // Sağdaki indexi ve o anki indexin solunu hesapla int nNextIndex = (i + 1) % 3; int nPrevIndex = (i + 2) % 3; 82 // c3c1_T ve c3c1_B'i hesapla float c3c1_T = pvTexCoords[nPrevIndex].x - pvTexCoords[i].x; float c3c1_B = pvTexCoords[nPrevIndex].y - pvTexCoords[i].y; float fDenominator = c2c1_T * c3c1_B - c3c1_T * c2c1_B; if (ROUNDOFF(fDenominator) == 0.0f) { // Sıfıra bölme hatası riskiyle karşılaşmamak için // teğet matrisini birim matrise setliyoruz pvTBNMatrix[0] = CVector(1.0f, 0.0f, 0.0f); pvTBNMatrix[1] = CVector(0.0f, 1.0f, 0.0f); pvTBNMatrix[2] = CVector(0.0f, 0.0f, 1.0f); } else { // tersi değerini bir kere hesapla ve tümü için kullan (performans artışı sağlar) float fScale1 = 1.0f / fDenominator; // T ve B hesaplanıyor CVector T, B, N; T = CVector((c3c1_B * v2v1.x - c2c1_B * v3v1.x) * fScale1, (c3c1_B * v2v1.y - c2c1_B * v3v1.y) * fScale1, (c3c1_B * v2v1.z - c2c1_B * v3v1.z) * fScale1); B = CVector((-c3c1_T * v2v1.x + c2c1_T * v3v1.x) * fScale1, (-c3c1_T * v2v1.y + c2c1_T * v3v1.y) * fScale1, (-c3c1_T * v2v1.z + c2c1_T * v3v1.z) * fScale1); // N normali, T ve B arasında vektör çarpımı yapılarak hesaplanıyor N = T.CrossProduct(B); // tersi değerini bir kere hesapla ve tümü için kullan // (performans artışı sağlar) float fScale2 = 1.0f / ((T.x * B.y * N.z - T.z * B.y * N.x) + (B.x * N.y * T.z - B.z * N.y * T.x) + (N.x * T.y * B.z - N.z * T.y * B.x)); pvTBNMatrix[1].x = -B.CrossProduct(N).y * fScale2; pvTBNMatrix[1].y = N.CrossProduct(T).y * fScale2; pvTBNMatrix[1].z = -T.CrossProduct(B).y * fScale2; pvTBNMatrix[1].Normalize(); } } pvTBNMatrix[2].x = B.CrossProduct(N).z * fScale2; pvTBNMatrix[2].y = -N.CrossProduct(T).z * fScale2; pvTBNMatrix[2].z = T.CrossProduct(B).z * fScale2; pvTBNMatrix[2].Normalize(); Umut DOGAN - Bitirme Tezi - Haziran 2006 // Ters TBN matrisinin hesaplanması // Temel vektörleri pvTBNMatrix içinde tutuyoruz. pvTBNMatrix[0].x = B.CrossProduct(N).x * fScale2; pvTBNMatrix[0].y = -N.CrossProduct(T).x * fScale2; pvTBNMatrix[0].z = T.CrossProduct(B).x * fScale2; pvTBNMatrix[0].Normalize(); 83 Şimdi de ası l sihrin gerçekleş tiği ve her ş eyin ekrana bası ldı ğıRender() fonksiyonuna geldik. Burada ı ş ı klar gerçekleniyor çoklu doku kaplama ayarlanı yor, vertex ve fragment shaderlar etkinleş tiriliyor ve ekranı mı zı n ortası nda dörtgen oluş turan RenderQuad fonksiyonu çağrı lı yor. void Render() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); glPushAttrib(GL_CURRENT_BIT); // Beyaz ışık kaynağı glColor3f(1.0f, 1.0f, 1.0f); glPushMatrix(); // Işık kaynağının dairesel bir yörüngede dönmesini istiyoruz. Burada biraz trigonometri uyguluyoruz. // Bu hesaplamada zaman çarpanını kullanmıyoruz (bunun nedeni // bazı bilgisayarlarda bilgisayar hızına göre hızlı veya yavaş olmabilme olasılığıdır.) g_fRotAngle += (float)PI * 0.02f * g_fLightSpeed; g_vLightPos.x = cosf(g_fRotAngle) * 10.0f; g_vLightPos.y = sinf(g_fRotAngle) * 10.0f; // Işık küresini konumlandırıp gerçekliyoruz glTranslatef(g_vLightPos.x, g_vLightPos.y, g_vLightPos.z); gluSphere(g_lightSphere, 1.0f, 20, 20); glPopMatrix(); glPopAttrib(); // Vertex ve fragment profillerini etkinleştir ve vertex ve fragment programlarına bağla cgGLEnableProfile(g_vertexProfile); cgGLEnableProfile(g_fragmentProfile); // Vertex shaderdaki "modelViewProjMatrix" parametresini üzerinde çalışılan // modelview ve projeksiyon matrislerine ayarla cgGLSetStateMatrixParameter(g_modelViewMatrix, CG_GL_MODELVIEW_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY); // Vertex shaderdaki ışık konumu parametresini ayarla cgGLSetParameter3f(g_lightPosition, g_vLightPos.x, g_vLightPos.y, g_vLightPos.z); // Fragment shaderdaki yayınık ışığı ayarla cgGLSetParameter3f(g_lightDiffuseColor, 1.0f, 1.0f, 1.0f); // Duvar dokusunu etkinleştir ve bağla glActiveTextureARB(GL_TEXTURE0_ARB); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, g_uiRockTexture); Umut DOGAN - Bitirme Tezi - Haziran 2006 cgGLBindProgram(g_vertexProgram); cgGLBindProgram(g_fragmentProgram); 84 // Normal mapi etkinleştir ve bağla glActiveTextureARB(GL_TEXTURE1_ARB); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, g_uiNormalTexture); RenderQuad(); // Vertex ve fragment profillerini tekrar devre dışı bırak cgGLDisableProfile(g_vertexProfile); cgGLDisableProfile(g_fragmentProfile); // Dokuları devre dışı bırak glActiveTextureARB(GL_TEXTURE0_ARB); glDisable(GL_TEXTURE_2D); glActiveTextureARB(GL_TEXTURE1_ARB); glDisable(GL_TEXTURE_2D); } RenderQuad() fonksiyonu da altta gösterilmiş tir. Burada üçgen oluş tururken GL_TRIANGLE yerine GL_TRIANGLE_FAN kullanmamı n nedeni 6 vertex yerine 4 vertex kullanarak optimizasyon sağlamı şolmamdı r. Ayrı ca ters TBN matrislerini glMultiTexCoord3fARB() çağrı ları yla belirttiğimize dikkat ediniz. void RenderQuad() { glBegin(GL_TRIANGLE_FAN); // Duvar dokusu ve normal map için doku koordinatlarını ayarla glMultiTexCoord2fARB(GL_TEXTURE0_ARB, g_vTexCoords[0][0].x, g_vTexCoords[0][0].y); bir bir belirle ve g_TBNMatrix[0][0].x, g_TBNMatrix[0][1].x, g_TBNMatrix[0][2].x, // Sol alt vertexi çizdir glVertex3f(g_vQuad[0][0].x, g_vQuad[0][0].y, g_vQuad[0][0].z); // ------------------------------------------------------------ // // Duvar dokusu ve normal map için doku koordinatlarını ayarla glMultiTexCoord2fARB(GL_TEXTURE0_ARB, g_vTexCoords[0][1].x, g_vTexCoords[0][1].y); // Sağ alt vertexi çizdir glVertex3f(g_vQuad[0][1].x, g_vQuad[0][1].y, g_vQuad[0][1].z); Umut DOGAN - Bitirme Tezi - Haziran 2006 // teğet matris vektörlerini ilk üçgen için bunları vertex shader'a gönder glMultiTexCoord3fARB(GL_TEXTURE1_ARB, g_TBNMatrix[0][0].y, g_TBNMatrix[0][0].z); glMultiTexCoord3fARB(GL_TEXTURE2_ARB, g_TBNMatrix[0][1].y, g_TBNMatrix[0][1].z); glMultiTexCoord3fARB(GL_TEXTURE3_ARB, g_TBNMatrix[0][2].y, g_TBNMatrix[0][2].z); 85 // ------------------------------------------------------------ // // Duvar dokusu ve normal map için doku koordinatlarını ayarla glMultiTexCoord2fARB(GL_TEXTURE0_ARB, g_vTexCoords[0][2].x, g_vTexCoords[0][2].y); // Sağ üst vertexi çizdir glVertex3f(g_vQuad[0][2].x, g_vQuad[0][2].y, g_vQuad[0][2].z); // ------------------------------------------------------------ // // Duvar dokusu ve normal map için doku koordinatlarını ayarla glMultiTexCoord2fARB(GL_TEXTURE0_ARB, g_vTexCoords[1][0].x, g_vTexCoords[1][0].y); // teğet matris vektörlerini ikinci üçgen için bir bir belirle ve bunları vertex shader'a gönder glMultiTexCoord3fARB(GL_TEXTURE1_ARB, g_TBNMatrix[1][0].x, g_TBNMatrix[1][0].y, g_TBNMatrix[1][0].z); glMultiTexCoord3fARB(GL_TEXTURE2_ARB, g_TBNMatrix[1][1].x, g_TBNMatrix[1][1].y, g_TBNMatrix[1][1].z); glMultiTexCoord3fARB(GL_TEXTURE3_ARB, g_TBNMatrix[1][2].x, g_TBNMatrix[1][2].y, g_TBNMatrix[1][2].z); // Sol üst vertexi çizdir glVertex3f(g_vQuad[1][0].x, g_vQuad[1][0].y, g_vQuad[1][0].z); glEnd(); } Böylece Cg shader dili kullanarak pürüzlü yüzey dokusu üretmişoldum. Bu bölümün son sayfası nda programdan bazıekran görüntüleri verdim. Programda ı ş ı k küresi Page Up / Page Down tuş larıkullanı larak ekrandan içeri / dı ş arıdoğru gönderilebiliyor. Ayrı ca sol / sağ/ yukarı/ aş ağıtuş larıile ı ş ı k kaynağı nı n konumu değiş tirilebiliyor. - / + tuş ları ysa ı ş ı k küresinin dönme hı zı nıyavaş latı p hı zlandı rmaya yarı yor. Ayrı ca Esc tuş una bası ldı ğı nda uygulama penceresi kapatı lı yor. Bütün bu ayarlamalar ve fazlasıVisual C++ Umut DOGAN - Bitirme Tezi - Haziran 2006 kodları yla gerçekleş tirilmişbir ş ekilde Init.cpp dosyası nda bulunmaktadı r. (a) (b) (c) (d) (e) Şekil 4.8: Cg ile Pürüzlü Yüzey Dokusu Üretimi Uygulaması ndan Ekran Görüntüleri (a) Iş ı k küresi sağdayken (b) Iş ı k küresi soldayken (c) Iş ı k küresi tepedeyken (d) Iş ı k küresi duvarı n arkası ndayken (e) Iş ı k kaynağıekrana yakı nlaş tı rı lmı ş ken Umut DOGAN - Bitirme Tezi - Haziran 2006 86 5. SONUÇLAR Bitirme projesi olarak “Cg Programlama Dili ve Cg ile Pürüzlü Yüzey Dokusu Üretimi” konusunu seçerken bu konunun yararlı olup olamayacağ ı konusunda çekincelerim vardı . Fakat Cg dilini araş tı rmaya baş ladı ktan sonraki süreçte grafik programlamanı n ne kadar genişve keyifli bir alan olduğ unu fark ettim. CPU için yazı lan programlar bütün dünyada standartlaş maya baş ladı . Yani bir veritabanıuygulamasıyazabilmek için çok fazla yetenek ve bilgiye gereksinim kalmamı ş durumda. Oysa Bilgisayar Grafikleri alanı nda gerçek dünyanı n simülasyonundan, animasyonlara kadar onlarca farklıçalı ş ma alanı nda ürünler verebilmek olasıdurumda. Bilgisayar Grafikleri, bilgisayar bilimleri disiplinlerinin bütün önemli dalları ndan parçalar içeriyor. Bu nedenle çok önemli bir alandı r. Ayrı ca günümüzde geliş miş bilgisayar oyunları na ve animasyon filmlere olan talep de üst seviyelere çı kmı ş tı r. Cg programlama dili sayesinde CPU’nun üzerindeki ağı r yükü hafifletip bu yükü GPU’nun üzerine paylaş tı rı yoruz. Hem de bunu karmaş ı k assembly kodları yla değil yüksek seviyeli bir dilin özelliklerini kullanarak yapabiliyoruz. Cg, henüz 5 yaş ı nda genç bir dil. Standartlar konusunda bazısorunlar devam ediyor ancak grafik donanı mıhı zlı geliş imini sürdürdükçe Cg’nin de standart ve kolay kullanı mlıbir noktaya eriş eceğini düş ünüyorum. karş ı mı za çı kı yor. Ayrı ca pürüzlü yüzey dokusu üretimi de 3B bilgisayar oyunları nda daha gerçekçi sahneler yaratabilmek için önemli bir önkoş ul konumundadı r. Cg ve pürüzlü yüzey dokusu bir araya gelince ise Blinn’in 1978’de önerdiğ i ve 30 yı la yakı n bir süredir üzerinde çalı ş malar yapı lan pürüzlü yüzey dokusu üretiminde epeyce yol kat edilmiş oluyor. Umut DOGAN - Bitirme Tezi - Haziran 2006 Sonuç olarak Cg, üzerinde çalı ş ı lmaya değecek kalitede ve esneklikte bir dil olarak 6. ÖNERİ LER Bitirme tezimin; GPU programlamaya geçmekte, karmaş ı klı ğıve zorluğu nedeniyle çekinmekte olanlar için temel bir Türkçe kaynak olması nıdiliyorum. Özellikle Cg dili üzerine yazı lmı şilk Türkçe kaynaklardan birisi olduğu için yararlıolacağ ı nıumuyorum. Bilgisayar grafikleri ve GPU programlama alanı nda araş tı rma yapmak ve çalı ş mak isteyenlere özellikle matematik ve fizik bilgilerini güçlendirmelerini öneriyorum. Projeyi hazı rlarken bu alanlarda önceki bilgilerimin ne kadar yetersiz olduğunu fark ettim ve bu bilgileri elimden geldiğince geliş tirmeye çalı ş tı m. Bir diğer önemli nokta da bilgisayar bilimlerinin bütün alanları nda olduğu gibi bilgisayar grafikleri alanı nda da yeterli Türkçe kaynak olmaması dı r. “Bilgi paylaş ı ldı kça çoğalı r” ilkesinin bizim insanları mı z tarafı ndan da anlaş ı lmasıve uygulanmasıen büyük dileklerimden birisidir. Paylaş ı lacak bilginin olmamasınedeniyle Türkçe kaynak sı kı ntı sı çekilmesiyse daha vahim bir durumdur. Bu eksiklikleri elimizden geldiğince kapatmaya çalı ş malı yı z. Elbette Türkiye’nin bir biliş im ülkesi olabilmesi, iyi planlanmı şdevlet politikaları ve eğitime verdiğ i katkı lar sayesinde olabilir. Dilerim önümüzdeki on yı llarda teknolojiyi Umut DOGAN - Bitirme Tezi - Haziran 2006 sadece tüketen değil aynızamanda üreten bir ülke olabilmenin gururunu yaş arı z.