DirectX 10 ve Shader Programlama

Transkript

DirectX 10 ve Shader Programlama
KARADENİZ TEKNİK ÜNİVERSİTESİ
Bilgisayar Mühendisliği Bölümü
Bilgisayar Grafikleri Laboratuarı
DIRECTX 10 ve SHADER PROGRAMLAMA
1. Giriş
Bilgisayar donanımının en önemli parçalarından biri olan ekran kartı ile ilgili teknolojik gelişmeler
beraberinde bu donanımı programlayacak yazılımlarda da büyük yenilikler getirmiştir. Bu yazılımlardan biri olan
DirectX, günümüzde ekran kartlarının programlanmasında yaygın olarak kullanılan bir API ’dır.
DirectX 10 'un DirectX 9 'dan en büyük farkı ekran kartını programlamada bütün kontrolün programcıya
devredilmesidir. Bu yüzden en basit bir DirectX 10 uygulaması için bile ekran kartının vertex işlemcisini
programlamak için vertex shader, pixel işlemcisini programlamak için de pixel shader adı verilen programların
yazıldığı HLSL (High Level Shading Language) diline ihtiyaç vardır. Dolayısıyla bu deneyde HLSL vertex/pixel
shader programlarının yüklenip koşulduğu DirectX 10 uygulamaları yapılacaktır.
2. Visual C++ 2008 için DirectX 10 Setlemeleri
Bu bölümde Visual C++ 2008 için gerekli DirectX 10 setlemeleri yapılıp uygulama penceresini mavi
renge boyayacak DirectX 10 programı yazılacaktır.
DirectX uygulamaları geliştirmek için şu an en güncel SDK olan June 2010 DirectX SDK
(http://msdn.microsoft.com/directx) kurulur. “C:\Program Files\Microsoft DirectX SDK (June 2010)” altındaki
include ve lib\x86 klasörlerindeki dosyalar “C:\Program Files\Microsoft Visual Studio 9.0\VC” altındaki include
ve lib klasörlerine kopyalanır. Visual C++ ‘ta Win 32 Application türünden bir Empty Project açılır. Menüden
Project-Properties penceresinde Linker-Input-Additional Dependencies kısmına d3d10.lib ve d3dx10d.lib
yazılır. Projeye eklenen boş “.cpp” uzantılı dosyaya <d3d10.h> , <d3dx10.h> dosyaları include edilir ve ekranda
boş bir pencere oluşturmak için gerekli kodlar yazılır. Bu C++ programına DirectX komutları yazılacağından
deney boyunca “DirectX Programı” olarak bahsedilecektir. Aşağıdaki WinMain(...) fonksiyonundaki
InitWindow(...) çağrısı ile pencere; InitDevice() çağrısı ile de DirectX 10 ile ilgili setlemeler yapılır. Mesaj
döngüsündeki Render() çağrısı ile pencere DirectX komutlarıyla mavi renge boyanır:
int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow )
{
InitWindow( hInstance, nCmdShow );
InitDevice();
MSG msg = {0};
while( WM_QUIT != msg.message )
{
if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
else
Render();
}
return ( int )msg.wParam;
}
Şekil.1: DirectX 10 için lib ve header setlemeleri
DirectX ’te ekranda çizilmek istenen 3D şekil aslında ekran kartının belleğinde tutulur. Bu belleğe Video
RAM (VRAM) denir. VRAM içeriğinin değiştirilmesi ve ekranda görüntülenmesi işlemleri birbirine karışmaması
için double buffering yöntemi kullanılır. Bu yönteme göre front ve back olmak üzere iki adet buffer kullanılır.
Front buffer ekranda o anda görüntülenecek veriyi tutarken back buffer da bir sonraki görüntüye ait veriyi
tutar. Ona sıra geldiğinde back buffer bu sefer front buffer olup onda tutulan veri ekranda görüntülenirken
front buffer da back buffer olarak bir sonra ekranda görüntülenecek veriyi hazırlar. Böylece görüntüler arası
geçişlerde karışıklık (flicker) olmaz. Programda bu bufferlara ait bilgiler InitDevice() fonksiyonundaki
DXGI_SWAP_CHAIN_DESC adlı structure ile setlenir:
DXGI_SWAP_CHAIN_DESC sd;
ZeroMemory( &sd, sizeof( sd ) );
sd.BufferCount = 1;
sd.BufferDesc.Width = width;
sd.BufferDesc.Height = height;
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
sd.BufferDesc.RefreshRate.Numerator = 60;
sd.BufferDesc.RefreshRate.Denominator = 1;
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
sd.OutputWindow = g_hWnd;
sd.SampleDesc.Count = 1;
sd.SampleDesc.Quality = 0;
sd.Windowed = TRUE;
for( UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++ )
{
g_driverType = driverTypes[driverTypeIndex];
D3D10CreateDeviceAndSwapChain( NULL, g_driverType, NULL, createDeviceFlags,
D3D10_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice );
}
Burada sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; ile ekranda görüntülenecek verinin
back buffera yazıldığı söylenir. Son olarak D3D10CreateDeviceAndSwapChain(...) ile Device ve SwapChain
oluşturulur. DirectX komutlarının çağrılmasında Device değişkeni kullanılır. Buradaki Device değişkeninin ismi
g_pd3dDevice ‘dır.
2
Ekranda
görüntülenmek istenen
CreateRenderTargetView oluşturulmalıdır:
veriyi
back
buffera
yazmak
için
aşağıdaki
şekilde
ID3D10Texture2D* pBackBuffer;
g_pSwapChain->GetBuffer( 0, __uuidof( ID3D10Texture2D ),(LPVOID*)&pBackBuffer );
g_pd3dDevice->CreateRenderTargetView( pBackBuffer, NULL, &g_pRenderTargetView );
pBackBuffer->Release();
g_pd3dDevice->OMSetRenderTargets( 1, &g_pRenderTargetView, NULL );
Son olarak çizim yapılacak pencere ile ilgili setlemeler yapılır :
D3D10_VIEWPORT vp;
vp.Width = width;
vp.Height = height;
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
vp.TopLeftX = 0;
vp.TopLeftY = 0;
g_pd3dDevice->RSSetViewports( 1, &vp );
Setlemeler tamamlandığından Render() fonksiyonu ile çizim yapılabilir:
void Render()
{
float ClearColor[4] = { 0.0f, 0.0f, 1.0f, 1.0f };
//red, green, blue, alpha
g_pd3dDevice->ClearRenderTargetView( g_pRenderTargetView, ClearColor );
g_pSwapChain->Present( 0, 0 );
}
Burada ClearColor değişkeni mavi renk için gerekli (R,G,B,A) değerlerini tutar. Ekranın tamamını mavi
renge boyamak için g_pd3dDevice->ClearRenderTargetView(...) komutu kullanılır. Back buffer içeriğini
ekranda görebilmek için de g_pSwapChain->Present(...) komutu gerekir.
Şekil.2: DirectX 10 Mavi Pencere Uygulaması
3
3. DirectX 10 ile Üçgen Çizimi
Bu bölümde ekrana kırmızı renge sahip bir üçgen çizdirilecektir. Çizdirilmek istenen üçgenin köşe
noktalarının (vertex’ler) koordinatları D3DXVECTOR3 türünden tanımlanır. Yalnız çoğu zaman köşe noktaları için
koordinatlardan başka renk, doku koordinatları, normal gibi başka özelliklere ihtiyaç duyulur. Üçgenin köşe
noktalarının bunlardan hangilerini kullandığını belirtmek için aşağıdaki gibi bir structure tanımlaması
yapılmalıdır:
struct SimpleVertex
{
D3DXVECTOR3 Pos;
};
İlerleyen örneklerde SimpleVertex yapısına D3DXVECTOR4 Color, D3DXVECTOR3 Normal ile renk ve
yüzey normali gibi farklı özellikler eklenecektir. Üçgenin köşe noktalarını tutmak üzere vertex buffer
üretilmelidir. Bunun için D3D10_BUFFER_DESC ve D3D10_SUBRESOURCE_DATA setlemelerinin ardıdan
CreateBuffer(...) ile vertex buffer oluşturulur:
SimpleVertex vertices[] =
{
D3DXVECTOR3( 0.0f, 1.0f, 1.0f ),
D3DXVECTOR3( 1.0f, -1.0f, 1.0f ),
D3DXVECTOR3( -1.0f, -1.0f, 1.0f )
};
D3D10_BUFFER_DESC bd;
bd.Usage
= D3D10_USAGE_DEFAULT;
bd.ByteWidth
= sizeof( SimpleVertex ) * 3;
bd.BindFlags
= D3D10_BIND_VERTEX_BUFFER;
bd.CPUAccessFlags
= 0;
bd.MiscFlags
= 0;
D3D10_SUBRESOURCE_DATA InitData;
InitData.pSysMem
= vertices;
g_pd3dDevice->CreateBuffer( &bd, &InitData, &g_pVertexBuffer );
Üçgen çizmede bu noktaya kadar yapılan setlemeler InitDevice() fonksiyonuna yazıldı. Şimdi çizim
aşamasına gelindi. Çizim işlemini yapan Render() fonksiyonunun yeni hali aşağıdaki gibidir:
void Render()
{
float ClearColor[4] = { 0.0f, 0.0f, 1.0f, 1.0f };
// red,green,blue,alpha
g_pd3dDevice->ClearRenderTargetView( g_pRenderTargetView, ClearColor );
D3D10_TECHNIQUE_DESC techDesc;
g_pTechnique->GetDesc( &techDesc );
for( UINT p = 0; p < techDesc.Passes; ++p )
{
g_pTechnique->GetPassByIndex( p )->Apply( 0 );
g_pd3dDevice->Draw( 3, 0 );
}
g_pSwapChain->Present( 0, 0 );
}
Üçgenin 3 köşe noktası g_pd3dDevice->Draw(3,0) komutu ile çizdirilmektedir. Bu komutun dışındaki
satırların anlaşılabilmesi için 1.Giriş bölümünde bahsedildiği gibi ekran kartının Vertex ve Pixel işlemcisini
programlama imkanı sağlayan HLSL dilinden bahsedilmesinde fayda vardır:
4
1. Vertex İşlemci : Bu işlemci adından da anlaşılacağı gibi köşe noktalarını işler. Onların 3D dünya
(world) koordinatlarından 2D ekran koordinatlarına dönüşümü, backface culling (arka yüz kaldırma),
clipping (kırpma), Z-buffering (Z derinlik tamponu ile görünmeyen yüzeyleri kaldırma) ve doku
koordinatı hesabı yapar.
2. Pixel İşlemci : Bu işlemci, vertex shaderdan aldığı ekran koordinatlarındaki 2D poligonların içini
hesaplanan renge boyar.
Bu işlemcileri programlamak için geliştirilmiş dillere Shading Dilleri denir. Bu dillerde vertex işlemciyi
programlamak için yazılan kodlara Vertex Shader; pixel işlemciyi programlamak için yazılan kodlara da Pixel
Shader denir. Vertex shader koordinat; pixel shader renk döndürür.
DirectX 10 ‘un shading dili HLSL (High Level Shading Language) ‘dir ve HLSL programı olmaksızın
DirectX 10 programı yazılamaz. Yukarıdaki g_pd3dDevice->Draw(3,0) komutu koştuğunda gerçekte çizim
işlemini yapan Triangle.fx adlı HLSL programı şöyledir:
matrix World;
matrix View;
matrix Projection;
struct VS_OUTPUT
{
float4 Pos
};
: SV_POSITION;
VS_OUTPUT VS( float4 Pos : POSITION )
{
VS_OUTPUT output = (VS_OUTPUT)0;
output.Pos = mul( Pos, World );
output.Pos = mul( output.Pos, View );
output.Pos = mul( output.Pos, Projection );
return output;
}
float4 PS() : SV_Target
{
return float4(1,0,0,1);
}
// red,green,blue,alpha
technique10 Render
{
pass P0
{
SetVertexShader( CompileShader( vs_4_0, VS() ) );
SetPixelShader( CompileShader( ps_4_0, PS() ) );
}
}
Yukarıdaki HLSL programının anlatımından önce HLSL programlarının DirectX programı içinden
çağrılmasından bahsetmekte fayda vardır:
D3DX10CreateEffectFromFile( "Triangle.fx", NULL, NULL, "fx_4_0", dwShaderFlags, 0,
g_pd3dDevice, NULL, NULL, &g_pEffect, NULL, NULL );
HLSL programları D3DX10CreateEffectFromFile(...) komutu ile çağrılır. Burada Triangle.fx,HLSL
programının ismidir. g_pd3dDevice bilindiği gibi DirectX device değişkenidir. g_pEffect ise HLSL effect
değişkenidir. DirectX programı içinde HLSL programı ile ilgili komutlar g_pEffect değişkeni ile çağrılır. HLSL
dilinde yapılmış programlar "effect" olarak adlandırılır ve ".fx" uzantılı kaydedilirler.
5
HLSL programının shading model 4.0, başka bir değişle DirectX 10 desteği ile derleneceğini
söyler. DirectX 9 shading model 3.0'ı destekler. Örneğin nVidia firmasının ekran kartlarından GeForce 7 serisi
3.0, Geforce 8 ve 9 serisi 4.0’ı destekler. O yüzden DirectX 10 programlarını koşması için ekran kartının en
azından (nVidia için) Geforce 8 veya yukarısı olması gerekir. İşletim sistemi de Vista veya Windows 7 olmalıdır.
DirectX 11 yazılım olarak 1 yılı aşkın bir süredir vardır. Donanım olarak ise nVidia Geforce GTX 400, ATI Radeon
5450 ve yukarısı ekran kartları DirectX 11 ‘i desteklemektedir.
"fx_4_0"
Yukarıdaki programın vertex shaderı VS(...), pixel shaderı PS(), main fonksiyonu da Render() ‘dır.
Bu fonksiyon, InitDevice() içinde g_pTechnique = g_pEffect->GetTechniqueByName("Render") ile
tanıtılmıştır. DirectX programının Render() fonksiyonundaki D3D10_TECHNIQUE_DESC techDesc ve
g_pTechnique->GetDesc(&techDesc) satırları ile HLSL programının Render() fonksiyonu çağrılmış ve bu
fonksiyondaki vertex shader ve pixel shader çağrıları ile çizim işlemi HLSL programına yaptırılmıştır.
Programın başındaki World, View, Projection matrisleri vertex shaderda dünya koordinatlarından
ekran koordinatlarına dönüşümü gerçekleştirmek için kullanılır. World matrisi ile 3D nesneler için ölçekleme
(büyültme, küçültme), dönme (rotasyon) ve öteleme (translation) dönüşümleri yapılır. World matrisi DirectX
programında D3DXMatrixIdentity(&g_World) ile başlangıç değeri olarak birim (identity) matrise setlenmiştir.
View matrisinde bakış noktasının konumu ve bakış doğrultusu ile ilgili bilgiler tutulur:
D3DXVECTOR3 Eye( 0.0f, 3.0f, -8.0f );
// Bakış noktası
D3DXVECTOR3 At ( 0.0f, 0.0f, 1.0f );
// Bakış doğrultusu
D3DXVECTOR3 Up ( 0.0f, 1.0f, 0.0f );
D3DXMatrixLookAtLH( &g_View, &Eye, &At, &Up );
Projection
matrisi perspektif dönüşümü yapmak üzere şu şekilde setlenir:
D3DXMatrixPerspectiveFovLH(&g_Projection, D3DX_PI*0.25f, 1.33f, 0.1f, 100.0f );
Burada D3DX_PI*0.25f, 3D ortamın 45 derecelik bir açı ile gözlemlendiğini, 1.33f pencerenin yatay
düşey oranını (aspect ratio = 800/600), 0.1f ve 100.0f de near ve far planeleri temsil eder. Yani Z derinlik
değeri olarak en yakın Z=0.1f birim ile en uzak Z=100.0f değerine sahip koordinatların arasında kalan görüş
piramidinin (Viewing Frustum) içindeki nesnelerin gözlemlendiğini söyler:
Şekil.3: Görüş Piramidi (Viewing Frustum)
Şekil.4: Sağ, sol el kuralına göre kartezyen koordinatlar
6
ifadesindeki Fov “Field of view”, LH da “Left Handed” demektir.
Sol el kuralına göre 4 parmak +X eksenini gösterirken +Y eksenini gösterecek şekilde döndürüldüğünde baş
parmağın işaret ettiği doğrultu +Z eksenini temsil etmektedir ve bakış noktasından ileriye doğrudur. DirectX sol
el kuralına göre, OpenGL de sağ el kuralına kartezyen koordinatları belirler. Sol el kuralına göre üçgenlerin köşe
noktaları saat yönünde (Clock Wise “CW”) sıralanmalıdır. Bu durumda tam karşımızda Z düzlemine dik duran
duran üçgenin normali bize doğrudur. Yani onu görürüz. Eğer köşe noktaları saat yönünün tersi (Counter Clock
Wise “CCW”) sırada dizilirse bu sefer normal bize bakmaz. Yani back face olur. O yüzden de üçgeni göremeyiz.
“Görünmeyen Yüzeylerin Kaldırılması” deney föyünde back face culling (arka yüz kaldırma) hakkında detaylı
bilgi vardır. Bu örnekte üçgenin bir görünüp bir kaybolması köşe noktalarının dizilişinin dönerken
değişmesinden (CW<-->CCW) kaynaklanmaktadır. D3DXMatrixRotationY(&g_World,t) komutu ile üçgen Y
ekseni etrafında t açısı kadar dönmektedir. Bilindiği gibi nesnelerin konumları ile ilgili ölçekleme, dönme ve
öteleme gibi değişiklikler g_World matrisi ile yapılıyordu.
D3DXMatrixPerspectiveFovLH
Dikkat edilirse HLSL programındaki World, View, Projection matrisleri ile bu matrislere DirectX 10
programında atama yapılırken kullanılan g_World, g_View, g_Projection değişkenleri birbirinden farklıdır.
Bu değişkenlerin değerlerinin HLSL<-->DirectX programları arasında aktarımı ID3D10EffectMatrixVariable*
türünden g_pWorldVariable, g_pViewVariable, g_pProjectionVariable
değişkenleri kullanılarak
aşağıdaki gibi iki aşamada gerçekleştirilir:
1. AŞAMA : InitDevice()
fonksiyonunda:
g_pWorldVariable
g_pViewVariable
g_pProjectionVariable
= g_pEffect->GetVariableByName( "World" )->AsMatrix();
= g_pEffect->GetVariableByName( "View" )->AsMatrix();
= g_pEffect->GetVariableByName( "Projection" )->AsMatrix();
2. AŞAMA : Render()
fonksiyonunda:
g_pWorldVariable->SetMatrix( ( float* )&g_World );
g_pViewVariable->SetMatrix( ( float* )&g_View );
g_pProjectionVariable->SetMatrix( ( float* )&g_Projection );
World, View, Projection matrisleri dünya koordinatlarından ekran koordinatlarına dönüşüm
işlemini gerçekleştirdiğinden HLSL programının VS adlı vertex shaderı tarafından kullanılmışlardır. PS adlı pixel
shader da return float4(1,0,0,1)ile üçgenin içini kırmızıya boyamaktadır.
Şekil.5: DirectX 10 ile Üçgen Çizimi
7
4. DirectX 10 ile Küp Çizimi
Bu uygulamanın üçgen çiziminden en önemli farklı vertex buffera ek olarak index buffer kullanılmasıdır.
Bilindiği gibi vertex buffer köşe noktalarının koordinatlarını tutuyordu. Index buffer bu köşe noktalarını
indisleyerek üçgenleri oluşturur:
DWORD indices[] =
{
3,1,0,
2,1,3,
0,5,4,
1,5,0,
3,4,7,
0,4,3,
1,6,5,
2,6,1,
2,7,6,
3,7,2,
6,4,5,
7,4,6,
};
// 1. ÜÇGEN
// 12. ÜÇGEN
bd.Usage = D3D10_USAGE_DEFAULT;
bd.ByteWidth = sizeof( DWORD ) * 36;
// 36 vertices needed for 12 triangles
bd.BindFlags = D3D10_BIND_INDEX_BUFFER;
bd.CPUAccessFlags = 0;
bd.MiscFlags = 0;
InitData.pSysMem = indices;
g_pd3dDevice->CreateBuffer( &bd, &InitData, &g_pIndexBuffer );
g_pd3dDevice->IASetIndexBuffer( g_pIndexBuffer, DXGI_FORMAT_R32_UINT, 0 );
dizisi ile üretilen index buffer, küpün vertex bufferda tutulan 8 köşe noktasını temsil eden
arası değişen indisleri üçer üçer alarak sol el kuralına uygun olarak saat yönünde üçgenleri oluşturur.
6 yüzeye sahip küpün her bir yüzeyi 2 üçgenden oluştuğundan indices[] dizisinde 6x2=12 üçgeni temsil
etmek üzere toplam 12x3=36 tane indis vardır. Küpün sadece vertex buffer ile de çizilmesi mümkündür. Yalnız
bu durumda 36 tane köşe noktası içeren bir vertex buffer tanımlanmalıdır. Bu ise bellek israfı demektir.
indices[]
[0..7]
Index buffer kullanıldığı için Render() fonksiyonundaki çizim komutu DrawIndexed( 36, 0, 0 )
şeklinde değiştirilmiştir.
Şekil.6: DirectX 10 ile Küp Çizimi
8
Şekil.7: Lambert'in Kosinüs Kanununa göre  diffuse renk katsayısı
5. Aydınlatma (Lighting)
Burada önceki örnekte çizilen küp 2 farklı ışık kaynağı tarafından Lambert'in Kosinüs Kanununa göre
Diffuse renk hesabı yapılarak aydınlatılacaktır. Bu kanuna göre ışık kaynağı tarafından aydınlatılan yüzeyin [0..1]
arası değişen  diffuse katsayısı = dot(L,N) ile hesaplanır. Buradaki dot(L,N) ile L ve N vektörlerinin Skaler
çarpımı yapılmaktadır. Bunlar normalize edilerek birim vektör olarak alındığında skaler çarpım aralarındaki
açının kosinüsünü veririr. O yüzden bu kanuna Kosinüs kanunu denir.
Bilindiği gibi renk hesabı pixel shader fonksiyonunda yapılıyordu. Dolayısıyla pixel shader kodu aşağıdaki
gibi olacaktır:
float4 PS( PS_INPUT input) : SV_Target
{
float4 finalColor
= 0;
float3 toLight
= 0;
float3 Position
= mul( input.Pos, WorldInverseTranspose).xyz;
for(int i=0; i<2; i++)
{
toLight
= normalize( vLightPos[i] - Position );
finalColor
+= saturate( dot( toLight, input.Norm ) * vLightColor[i] );
}
finalColor.a = 1;
return finalColor;
}
döngüsü içinde dot( toLight, input.Norm ) ile ışık kaynağına doğru olan toLight
vektörü ile küpün yüzey normali input.Norm skaler çarpılarak diffuse katsayı hesaplanmakta ve bu değer ışık
kaynağının rengi ile çarpılarak son renk değeri belirlenmektedir. İki tane ışık kaynağı olduğu için döngü iki kere
dönmektedir. İfadedeki saturate(...) fonksiyonu skaler çarpımdan gelebilecek negatif değerleri sıfır yapmak
için kullanılır. Yani negatif değerler için sıfır döndürür.
for(...)
Döngüden önceki satırdaki Position = mul(input.Pos, WorldInverseTranspose).xyz ile vertex
shader tarafından 2D ekran koordinatlarına dönüştürülmüş küpe ait koordinatlar tekrar 3D dünya
koordinatlarına dönüştürülmüştür. Çünkü diffuse katsayı hesaplanırken ışık kaynağına doğru olan toLight
vektörünü hesaplamak için yüzey üzerindeki noktanın 3D dünya koordinatı bilinmelidir.
Yukarıdaki pixel shaderın diffuse renk hesabında kullandığı vLightPos[] ve vLightColor[]
değişkenlerinin değerleri aslında DirectX programından alınmaktadır:
9
D3DXVECTOR4 vLightPos[2] =
{
D3DXVECTOR4( -3.0f, 0.0f,
D3DXVECTOR4( 0.0f, 0.0f,
};
0.0f,
-3.0f,
1.0f ),
1.0f ),
D3DXVECTOR4 vLightColors[2] =
{
D3DXVECTOR4( 1.0f, 0.0f, 0.0f, 1.0f ),
D3DXVECTOR4( 0.0f, 0.0f, 1.0f, 1.0f ),
};
// Kırmızı ışık kaynağı
// Mavi ışık kaynağı
g_pLightPosVariable->SetFloatVectorArray( ( float* )vLightPos, 0, 2 );
g_pLightColorVariable->SetFloatVectorArray( ( float* )vLightColors, 0, 2 );
Kırmızı ışık kaynağı D3DXMatrixRotationZ(...) komutu ile Z ekseni etrafında; mavi ışık kaynağı da
D3DXMatrixRotationY(...)
komutu ile Y ekseni etrafında dönmektedir. Işık kaynakları ayrıca
D3DXMatrixTranslation(...) komutu ile ötelenmekte ve D3DXMatrixScaling(...) komutu ile de
küçültülmektedir. Programın ekran görüntüsü Şekil.8'de verilmiştir:
Şekil.8: Kırmızı ve mavi ışık ile küpün aydınlatılması
Şekil.9: Kırmızı, mavi ve beyaz ışık ile küpün aydınlatılması
6. Deneye Hazırlık

Dersin web sayfasındaki deneyle ilgili kaynak kodları üzerinde değişiklikler yaparak inceleyiniz.

Küpü aydınlatan kırmızı ve mavi ışık kaynaklarına X ekseni etrafında dönen Şekil.9'daki gibi beyaz
renge sahip üçüncü bir ışık kaynağı ekleyiniz. Programınız çalışmasa da deneye getiriniz.
7. Deneyin Yapılışı

Üçgen çizimi örneğindeki kodu değiştirip Şekil.10'daki gibi beyaz renk kare çiziniz.

Çizdiğiniz kare dönerken neden gözden kaybolmaktadır? Açıklayınız.
10
Şekil.10: Beyaz Kare Çizimi
8. Rapor
Rapor, kaynak kodların olduğu klasördeki şablon dosya kullanılarak yazılacaktır. Buradaki:
1. Deneye Hazırlık bölümünde X ekseni etrafında dönen beyaz ışık kaynağının nasıl eklendiği,
2. Deneyin Yapılışı bölümünde de beyaz renk karenin nasıl çizildiği
anlatılacaktır.
11

Benzer belgeler

WebGL Uygulamaları

WebGL Uygulamaları şeklinde düşünebilirsiniz). Bu işlemler rendering sürecinde çalıştırılacak olan main() fonksiyonları içerisinde gerçekleştirilir. Vertex shaderlar, WebGL rendering pipelinenının ilk aşamasını oluşt...

Detaylı