karadeniz teknik üniversitesi

advertisement
KARADENİZ TEKNİK ÜNİVERSİTESİ
Bilgisayar Mühendisliği Bölümü
Bilgisayar Grafikleri Laboratuarı
PÜRÜZLÜ YÜZEY ÜRETİMİ
1. Giriş
Cisimlerin yüzey görüntülerindeki parlaklık değişimi iki nedene dayanır. Birincisi yüzey dokusu
(texture), ikincisi ise yüzeydeki pürüzlülüktür. Yüzey pürüzlülüğü, yüzey görüntüsü doku elemanı
kabul edilerek izdüşüm tekniğiyle gerçek anlamda üretilemez. Çünkü doku elemanı olarak
kullanılan resim dosyası sabittir. Yüzeyin pürüzlü görünümü ise o yüzeyi aydınlatan ışık kaynağının
konumuna bağlıdır ve ışık kaynağı konum değiştirdikçe pürüzlü görünüm de değişmektedir. Yani
yüzeyin herhangi bir noktasının çukur/tümsek görünmesi o noktanın ışık kaynağı tarafından
aydınlatılıp/aydınlatılmadığına bağlıdır.
Pürüzlü yüzey üretme yöntemi (“Bump Mapping”) ilk olarak 1978 yılında Jim Blinn tarafından
kullanıldı. Bu yönteme göre klasik doku kaplamada kullanılan resim dosyasındaki renk
değişimlerinden faydalanılarak o resim dosyasının kaplanacağı yüzeyin normali değiştirilir.
Herhangi bir yüzeyin ışık kaynağının konumuna göre rengi belirlenirken normale bağlı hesaplama
yapıldığından kullanılan doku sayesinde değişen normalle birlikte yüzey üzerinde
tümsekler/çukurlar varmış gibi bir görüntü ortaya çıkar. Örneğin taşlardan örülmüş bir duvar dokusu
kullanılsın. Bu doku düzlemsel bir yüzey üzerine bump mapping yöntemine göre kaplandığında
gerçekte yüzey düzlemsel olduğu halde pürüzlü görünecektir.
Bu deneyde bump mapping yöntemine göre pürüzlü yüzeyler üretilecektir. Programlama dili
olarak Visual C++ 2003, grafik programlama API’si olarak da DirectX kullanılacaktır. Visual C++’da
DirectX kodu yazabilmek için Microsoft’un sitesinden DirectX SDK indirilip kurulur.
“C:\Program Files\Microsoft DirectX SDK” altındaki include ve lib klasörleri Visual C++’ın
“C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\PlatformSDK” altındaki include ve lib
klasörlerine kopyalanır.
DirectX tek başına pürüzlü yüzey üretmek için yeterli değildir. Çünkü DirectX’te herhangi bir
poligon boyanırken ışık kaynağına bağlı olarak sadece köşe noktaları (vertex) için renk değeri
hesaplanır. Poligonun içinde kalan noktaların rengi interpolasyonla bulunur. Dolayısıyla DirectX’te
boyama poligon mertebesinde yapılır. Halbuki bump mapping yönteminde doku kaplamada
kullanılacak resim dosyasındaki renk değişimi hesaplanırken piksel mertebesinde çalışılmaktadır.
Ekran kartlarında 2 temel işlemci vardır:
• Vertex İşlemci
• Fragment (Pixel) İşlemci
Vertex işlemci adından da anlaşılacağı üzere vertexler üzerinde, dünya koordinatlarından
ekran koordinatlarına izdüşüm, backface culling, clipping, z-buffering ve doku koordinatı hesabı
yapar. Fragment işlemci de teker teker piksellerin son renk değerini hesaplar. DirectX, OpenGL gibi
API’ler ekran kartlarının sadece vertex işlemcisini programlayabilir. Ekran kartlarının her iki
işlemsini programlayabilmek için geliştirilmiş dillere genel olarak “shading language” denir. Bu
dillerin vertex işlemciyi programlayan kodlarına “vertex shader”; fragment işlmeciyi programlayan
kodlarına da “fragment (pixel) shader” denir. DirectX’in shading dili HLSL (High Level Shading
Language), OpengL’in ise GLSL’dir. HLSL’de yazılan kod D3DXCreateEffectFromFile
komutuyla DirectX ortamında yüklenir ve çalıştırılır (benzeri GLSL ve OpenGL için yapılır).
Dolayısıyla bump mapping için hem DirectX hem de HLSL kodu yazılacaktır. Öncelikle HLSL dili
hakkında genel bilgiler verilecek ardından HLSL’de bump mapping programının nasıl yazılacağı
anlatılacaktır.
2. HLSL Dili Hakkında Genel Bilgiler
HLSL dili syntax yapısı olarak C++ diline oldukça benzemektedir. HLSL dilinde yazılan
kodlara “effect” kodu denir ve “.fx” uzantılı dosyaya kaydedilir.
İlk olarak Şekil-1‘deki gibi küpü mavi renge boyayacak “color.fx” adlı HLSL vertex shader kodu
incelenecektir.
Şekil-1: Küp Örneği
color.fx
uniform extern float4x4 gWVP;
struct OutputVS
{
float4 posH : POSITION0;
float4 color : COLOR0;
};
OutputVS ColorVS(float3 posL : POSITION0, float4 c : COLOR0)
{
OutputVS outVS = (OutputVS)0;
outVS.posH = mul(float4(posL, 1.0f), gWVP);
outVS.color = c;
return outVS;
}
technique ColorTech
{
pass P0
{
vertexShader = compile vs_2_0 ColorVS();
}
}
uniform extern float4x4 gWVP;
Burada uniform biz C++ kodunda değişiklik yapmadıkça değişkenin sabit olduğunu gösterir.
extern ifadesi C++ kodunun bu değişkene dışardan erişebildiğini gösterir. float4x4 ifadesi de
4X4 boyutunda matris olduğunu gösterir. Burada tanımlanan “gWVP” adlı değişken world, view ve
projection matrislerinin bir araya getirilmiş halidir. Yani dünya koordinatlarından ekran
koordinatlarına izdüşüm yapar. Bu matris C++ kodunda hesaplandığından extern olarak
tanımlandı.
2
struct OutputVS
{
float4 posH : POSITION0;
float4 color : COLOR0;
};
Burada tanımlanan structure ColorVS adlı vertex shaderın döndürdüğü değerdir. Structure’ın
2 değişkene sahip olduğu görülür:
float4 posH : POSITION0;
/ / vertex koordinatlarını gösterir.
float4 color : COLOR0;
/ / vertexin rengini gösterir.
Burada :POSITION0 ve :COLOR0 şeklindeki ifadelere “semantic” denir. Dikkat edilirse her iki
değişken de float4 türündendir. Yalnız biri koordinat diğeri ise renk bilgisi tutmaktadır. Ekran
kartında koordinatlar ve renkler farklı registerlarda tutulurlar. Dolayısıyla :POSITION0 ve :COLOR0
semanticleri değişkenin hangi registerda tutulacağını gösterir.
OutputVS ColorVS(float3 posL : POSITION0, float4 c : COLOR0){ . . . }
vertex shaderın ismidir. Dikkat edilirse vertexlerin koordinatlarını ve rengini
parametre olarak almakta ve OutputVS türünden değer döndürmektedir. Bu örnekte ColorVS adlı
vertex shader küpe ait üçgenlerin içini boyayacaktır. Bunun için üçgenlerin koordinatlarına ve
rengine ihtiyaç duymaktadır.
ColorVS
OutputVS outVS = (OutputVS)0;
outVS.posH = mul(float4(posL, 1.0f), gWVP);
outVS.color = c;
return outVS;
Yukarıdaki kodda öncelikle outVS adlı struct değişken OutputVS türünden tanımlanmaktadır.
Daha sonra outVS nin posH ve color değişkenleri setlenmektedir. posH setlenirken posL
değişkeniyle dünya koordinatlarına sahip üçgenler alınıp gWVP matrisiyle çarpılarak ekran
koordinatlarına izdüşüm yapılmaktadır.
technique ColorTech
{
pass P0
{
vertexShader = compile vs_2_0 ColorVS();
}
}
technique ve pass ekran kartının özelliklerine bağlı olarak vertex shaderın türünü
belirlemede kullanılır. Örneğin burada compile vs_2_0 ile ekran kartına vertex shader 2.0 desteği
ile derlenmesi söylenmiştir. Ekran kartını yeteneklerin bağlı olarak 3.0 hatta 4.0 olabilir. Örneğin
GeForce 7 serisi 3.0 ’ı, GeForce 8 serisi 4.0 ’ı desteklemektedir.
Kodda küpün koordinatları ve rengi C++ kodundan alınmaktadır. Dolayısıyla HLSL’de yazılan
vertex shader küpün koordinatları ve renginde bir değişiklik yapmamaktadır. Eğer küpün rengi
vertex shaderda değiştirilmek istenirse örneğin rengi kırmızı olsun denirse kod şu şekilde
değiştirebilir:
OutputVS ColorVS(float3 posL : POSITION0)
{
OutputVS outVS;
outVS.posH = mul(float4(posL, 1.0f), gWVP);
outVS.color = float4(1, 0, 0, 1);
//(R,G,B,A):Reg,Gren,Blue,Alpha
return outVS;
}
3
Programın Visual C++ ortamında yüklenmesi şu şekildedir:
IDirect3DDevice9*
ID3DXEffect*
gd3dDevice;
mFX;
D3DXCreateEffectFromFile(gd3dDevice,"color.fx",0,0,D3DXSHADER_DEBUG,0,&mFX,&errors)
D3DXCreateEffectFromFile komutunda gd3dDevice DirectX device’ını temsil eder.
DirectX’te kod yazmak için öncelikle bir device tanımlamak şarttır. "color.fx" effect kodunu adını
gösterir. mFX de effect’e pointerdır. Nasıl DirectX için device gerekiyorsa HLSL için de mFX
tanımlamak şarttır.
Yüklenen HLSL effectinin koşulması şu şekildedir:
mhTech = mFX->GetTechniqueByName("ColorTech");
mhWVP = mFX->GetParameterByName(0, "gWVP");
gd3dDevice-Clear(0,0,D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,0xffeeeeee,1.0f, 0);
gd3dDevice->BeginScene();
gd3dDevice->SetStreamSource(0, mVB, 0, sizeof(VertexCol));
gd3dDevice->SetIndices(mIB);
gd3dDevice->SetVertexDeclaration(VertexCol::Decl);
mFX->SetTechnique(mhTech);
mFX->SetMatrix(mhWVP, &(mView*mProj));
unsigned int numPasses = 0;
mFX->Begin(&numPasses, 0);
for(unsigned int i = 0; i < numPasses; ++i)
{
mFX->BeginPass(i);
gd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 8, 0, 12);
mFX->EndPass();
}
mFX->End();
gd3dDevice->EndScene();
DirectX’te çizim gd3dDevice->BeginScene() ile gd3dDevice->EndScene() komutları
arasında; HLSL’de ise mFX->Begin() ile mFX->End() komutları arasında olur. for()döngüsü
içinde mFX->BeginPass(i)ile effect dosyasındaki bütün pass lar işlenir. Bizim kodumuzda tek
pass
var. Dolayısıyla for() döngüsü bir kez dönecektir. mFX->BeginPass(i) ile
mFX->EndPass() arasında DrawIndexedPrimitive komutuyla küpe ait üçgenlerin çizimi
yapılmaktadır.
mhTech = GetTechniqueByName("ColorTech") ile effect dosyasından technique
ismi alınır. Daha sonra mFX->SetTechnique(mhTech) ile technique setlenir. Benzeri şekilde
"gWVP" parametresi mhWVP
= mFX->GetParameterByName(0, "gWVP") ile alınır ve mFX>SetMatrix(mhWVP, &(mView*mProj)) ile setlenir.
Kodda geçen aşağıdaki 3 satır küp için gerekli index ve vertex buffer setlemeleri içindir.
gd3dDevice->SetStreamSource(0, mVB, 0, sizeof(VertexCol));
gd3dDevice->SetIndices(mIB);
gd3dDevice->SetVertexDeclaration(VertexCol::Decl);
4
Bu vertex shader örneği adından da anlaşılacağı gibi ekran kartının sadece vertex işlemcisini
programlayan bir örnek oldu. HLSL’nin asıl avantajı pixel işlemciyi de programlayabilmesidir. Bunun
için yazılan koda pixel shader denir. Genelde pixel shader tek başına yazılmaz, vertex shaderla
birlikte yazılır. Vertex shaderın çıktısı olan koordinatlar pixel shadera girdi olur ve pixel shader da
bu koordinatlar için son renk değerini hesaplar. Dolayısıyla pixel shaderın vertex shadera göre
avantajını gösteren en iyi örnek boyama örneğidir. Burada yazılacak olan pixel shaderla bir
çaydanlık (teapot) Phong yöntemine göre boyanacaktır. Yani her bir pixel için Phong’a göre
ambient, diffuse ve specular bileşenler hesaplanacaktır. Pixel shaderın, vertex shadera göre
avantajını göstermek açısından önce tek vertex shader sonra da hem vertex hem de pixel shader
birlikte yazılacak (çünkü pixel shader tek başına yazılmıyordu) ve bu kodların çıktıları
karşılaştırılacaktır. Programı yazmadan önce Phong boyama yönteminden bahsedelim. Phong’a
göre herhangi bir pixelin rengi onun ambient, diffuse ve specular bileşenlerinin toplamıdır. Bu
bileşenler hesaplanırken bakış noktasının, ışık kaynağının konumu ve boyanacak cismin yüzey
normali kullanılır.
Ambient bileşen bütün pixeller için başlangıçta belirlenmiş default bir renktir. Genelde beyazın
tonları seçilir. Işık kaynağı tarafından direkt aydınlatılmayan nesneler siyah görünmezler çünkü
dolaylı olarak yani başka nesnelerden yansıyan ışınlar sayesinde kısmen de olsa aydınlatılırlar. Bu
özelliği boyamada hesaba katmak için ambient bileşen kullanılır.
Diffuse bileşen hesaplanırken ışık kaynağının konumu ve yüzey normali gereklidir. Diffuse
bileşen ışık kaynağına olan vektör ile yüzey normali arasındaki açıdır. Her iki vektör de birim vektör
olduğu durum için açı, bu vektörlerin skaler çarpımıyla bulunur. HLSL’de skaler çarpım
θ=dot(L,N) komutuyla yapılır. Şekil-2’de diffuse bileşen gösterilmiştir:
Şekil-2: Diffuse Bileşen
Specular bileşen hesaplanırken bakış noktasının, ışık kaynağının konumu ve yüzey normali
gereklidir. Specular bileşen ışık kaynağına olan L vektörünün yüzey normali N ’den aynasal
yansıması R vektörü ile bakış noktasına olan C vektörü arasındaki açıdır. Yani β=dot(R,C) ile
hesaplanır. Burada R vektörü R = L - (2L*N)N ile hesaplanır. Specular bileşen Şekil-3’te
gösterilmiştir.
Şekil-3: Specular Bileşen
5
Phong boyama yapan vertex shader aşağıdaki gibidir:
uniform extern float4x4 gWorld;
uniform extern float4x4 gWorldInverseTranspose;
uniform extern float4x4 gWVP;
uniform
uniform
uniform
uniform
uniform
uniform
uniform
uniform
uniform
extern
extern
extern
extern
extern
extern
extern
extern
extern
float4
float4
float4
float4
float4
float4
float
float3
float3
gAmbientMtrl;
gAmbientLight;
gDiffuseMtrl;
gDiffuseLight;
gSpecularMtrl;
gSpecularLight;
gSpecularPower;
gLightVecW;
gEyePosW;
struct OutputVS
{
float4 posH : POSITION0;
float4 color : COLOR0;
};
OutputVS AmbientDiffuseSpecVS(float3 posL : POSITION0, float3 normalL : NORMAL0)
{
OutputVS outVS = (OutputVS)0;
float3 normalW = mul(float4(normalL, 0.0f), gWorldInverseTranspose).xyz;
normalW = normalize(normalW);
float3 posW
= mul(float4(posL, 1.0f), gWorld).xyz;
float3 toEye = normalize(gEyePosW - posW);
float3 r = reflect(-gLightVecW, normalW);
float t
= pow(max(dot(r, toEye), 0.0f), gSpecularPower);
float s = max(dot(gLightVecW, normalW), 0.0f);
float3 spec = t*(gSpecularMtrl*gSpecularLight).rgb;
float3 diffuse = s*(gDiffuseMtrl*gDiffuseLight).rgb;
float3 ambient = gAmbientMtrl*gAmbientLight;
outVS.color.rgb = ambient + diffuse + spec;
outVS.color.a
= gDiffuseMtrl.a;
outVS.posH = mul(float4(posL, 1.0f), gWVP);
return outVS;
}
technique AmbientDiffuseSpecTech
{
pass P0
{
vertexShader = compile vs_2_0 AmbientDiffuseSpecVS();
}
}
6
Programın başında tanımlanan ilk 3 değişken koordinat sistemleri asındaki dönüşüm işlemini
yapmaktadır. Sonra gelen değişkenlerin değerleri şöyledir:
mLightVecW
mDiffuseMtrl
mDiffuseLight
mAmbientMtrl
mAmbientLight
mSpecularMtrl
mSpecularLight
mSpecularPower
=
=
=
=
=
=
=
=
AmbientDiffuseSpecVS
D3DXVECTOR3(0.0, 0.0f, -1.0f);
D3DXCOLOR(0.0f, 0.0f, 1.0f, 1.0f);
D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f);
D3DXCOLOR(0.0f, 0.0f, 1.0f, 1.0f);
D3DXCOLOR(0.4f, 0.4f, 0.4f, 1.0f);
D3DXCOLOR(0.8f, 0.8f, 0.8f, 1.0f);
D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f);
8.0f;
vertex shaderınını başında gerekli koordinat dönüşümleri yapıldıktan
sonra:
float3 toEye = normalize(gEyePosW - posW) ile bakış noktasına olan vektör hesaplanır
float3 r = reflect(-gLightVecW, normalW) ile normalden yansıyan vektör hesaplanır
float t
= pow(max(dot(r, toEye), 0.0f), gSpecularPower) ile specular bileşen
hesaplanır. Burada gSpecularPower specular highlightın yarıçapını belirler. Küçük
gSpecularPower değerleri için yarıçap büyük; büyük gSpecularPower değerleri için de küçüktür.
float s = max(dot(gLightVecW, normalW), 0.0f) ile diffuse bileşen hesaplanır.
float3 spec = t*(gSpecularMtrl*gSpecularLight).rgb;
float3 diffuse = s*(gDiffuseMtrl*gDiffuseLight).rgb;
float3 ambient = gAmbientMtrl*gAmbientLight;
Yukarıdaki 3 satır ile son ambient, diffuse ve specular renk değerleri hesaplanır ve
outVS.color.rgb = ambient + diffuse + spec;
outVS.color.a
= gDiffuseMtrl.a;
ile bu değerler toplanıp, alpha (parlaklık) değeri de eklenerek çaydanlığın son renk bulunur.
Programın ekran görüntüsü aşağıda verilmiştir. Dikkat edilirse henüz hala vertexler üzerinde
işlem yapıldığından görüntüdeki vertexler seçilebilmektedir. Bu programın pixel shader
versiyonununda pixel mertebesinde hesap yapılacağından çok daha yumuşak (smooth) bir görüntü
elde edilecektir. Yani vertexler görünmeyecektir.
7
Bu örenğin pixel shader versiyonunda da benzeri bir kod yazılacaktır. Daha önce de
bahsedildiği gibi pixel shader kodu tek başına yazılmayacak, vertex shaderla birlikte yazılacaktır.
Buna vertex shader kodu koordinatlarla ilgili işlemleri yapacak; pixel shader da renk hesabı
yapacaktır. Dolayısıyla ambient, diffuse ve specular bileşenler pixel shaderda hesaplanıp son renk
değeri bulunacaktır. Pixel shader ve ekran görüntüsü aşağıdaki gibidir.
struct OutputVS
{
float4 posH : POSITION0;
float3 normalW : TEXCOORD0;
float3 posW : TEXCOORD1;
};
OutputVS AmbientDiffuseSpecVS(float3 posL : POSITION0, float3 normalL : NORMAL0)
{
OutputVS outVS = (OutputVS)0;
outVS.normalW = mul(float4(normalL, 0.0f), gWorldInverseTranspose).xyz;
outVS.normalW = normalize(outVS.normalW);
outVS.posW = mul(float4(posL, 1.0f), gWorld).xyz;
outVS.posH = mul(float4(posL, 1.0f), gWVP);
return outVS;
}
float4 AmbientDiffuseSpecPS(float3 posW : TEXCOORD1, float3 normalW : TEXCOORD0) : COLOR
{
BURADA ANBIENT, DIFFUSE, SPECULAR, RENK HESAPLANIR VE COLOR OLARAK DÖNDÜRÜLÜR
}
technique AmbientDiffuseSpecTech
{
pass P0
{
vertexShader = compile vs_2_0 AmbientDiffuseSpecVS();
pixelShader = compile ps_2_0 AmbientDiffuseSpecPS();
}
}
8
3. Bump Mapping
Bump mapping yöntemi daha önce de bahsettiğimiz gibi doku olarak kullanılan resim
dosyasındaki renk değişimlerine bağlı olarak bu dokuyu üzerine kaplayacağımız yüzeyin normalini
pixel pixel değiştirerek tümsekler/çukurlar varmış izlenimi verir. Çünkü yüzey normali değiştiği için
Phong yöntemiyle hesaplanan diffuse ve specular bileşen de değişecektir.
Burada iki türlü doku söz konusudur. Birincisi doku kaplamada kullanılacak resim dosyası;
ikincisi de bu resim dosyasından elde edilecek normal map dosyası. Her iki dosya da resim dosyası
(örneğin .bmp) formatındadır. Yalnız birincisi kaplanacak doku ikincisi ise yüzey normalini
değiştirecek dokudur. Şekil-4’te örnek bir doku ve bu dokudan elde dilmiş normal map dokusu
verilmiştir.
Şekil-4: Solda doku, sağda da bu dokudan elde edilen normal map
Normal map dokusuna dikkat edilirse R,G,B (Red, Gren, Blue) renklerinden oluştuğu görülür.
Yatayda (x-ekseni) değişim varsa Red, düşeyde (y-ekseni) değişim varsa Gren, değişim yoksa da
Blue renge boyanmıştır. Herhangi bir h(xj,yi) pikseli için değişim olup olmadığı aşağıdaki ifadelerle
hesaplanır:
δh h( x j + Δx, y i ) − h( x j − Δx, yi )
=
δx
2Δx
δh h( x j , y i + Δx) − h( x j , y i − Δx)
=
2Δy
δy
9
Bump Mapping pixel shader kodu aşağıda verilmiştir:
float4 NormalMapPS(float3 toEyeT
: TEXCOORD0,
float3 lightDirT : TEXCOORD1,
float2 tex0
: TEXCOORD2) : COLOR
{
toEyeT
= normalize(toEyeT);
lightDirT = normalize(lightDirT);
float3 lightVecT = -lightDirT;
float3 normalT = tex2D(NormalMapS, tex0);
normalT = 2.0f*normalT - 1.0f;
normalT = normalize(normalT);
float3 r = reflect(-lightVecT, normalT);
float t
= pow(max(dot(r, toEyeT), 0.0f), gMtrl.specPower);
float s = max(dot(lightVecT, normalT), 0.0f);
if(s <= 0.0f) t = 0.0f;
float3 spec = t*(gMtrl.spec*gLight.spec).rgb;
float3 diffuse = s*(gMtrl.diffuse*gLight.diffuse).rgb;
float3 ambient = gMtrl.ambient*gLight.ambient;
float4 texColor = tex2D(TexS, tex0);
float3 color = (ambient + diffuse)*texColor.rgb + spec;
return float4(color, gMtrl.diffuse.a*texColor.a);
}
float3 normalT = tex2D(NormalMapS, tex0) ile normal map dokusundan normal
alınmaktadır. Dokudan alınan normal değerleri [0,1] arasına değişmektedir. [-1,1] aralığına
ötelemek için normalT = 2.0f*normalT - 1.0f yapılmıştır. Elde edilen normal değeri ile diffuse
ve specular bileşenler hesaplanmıştır.
Şekil-5’te bump mapping ile üretilmiş bir görüntü verilmiştir:
10
Şekil-5: Bump mapping ile üretilmiş bir görüntü
4. Deneye Hazırlık
•
Örnek programları http://ceng.ktu.edu.tr/~cakir/graflab.html adresinden indirip çalıştırınız.
•
Programlar üzerinde değişiklikler yaparak sonuçlarını gözlemleyiniz. Örneğin specular
bileşen olarak Jim Bliin’in farklı bir yaklaşımı vardır. Burada R yansıma vektörü yerine
H=
•
N +C
half vektörü kullanılır. Vertex/pixel shader kodlarını buna değiştiriniz.
2
Bump Mapping yönteminin Environment bump mapping, Reflection Bump Mapping gibi
türevleri vardır. Bu yöntemler hakkında araştırma yapınız.
11
Download