DirectX 10 Picking Uygulaması

Transkript

DirectX 10 Picking Uygulaması
KARADENİZ TEKNİK ÜNİVERSİTESİ
BİLGİSAYAR MÜHENDİSLİĞİ BÖLÜMÜ
BİLGİSAYAR GRAFİKLERİ LABORATUARI
DirectX 10 Picking Uygulaması
1. Giriş
3D cisimler ile kullanıcının etkileşimine Bilgisayar Grafikleri uygulamalarında sıkça
rastlanmaktadır. Örneğin günümüzdeki FPS (First Person Shooter) tarzı 3D oyunlarda, nişan
alınıp ateş edilen rakip oyuncunun vurulup vurulmadığına karar vermek için ona doğru bir
ışın yollanır ve bu ışın ile rakip oyuncuyu temsil eden modeli oluşturan üçgenler arasında
kesişim testleri yapılır. Bu deneydeki benzeri uygulamada 3D ortamdaki cisimler mouse ile
seçilmeye “picking” çalışılacaktır.
2. 3D Cisme Yollanacak Işının Üretilmesi ve Kesişim Testi
Ekrandaki herhangi bir cismin seçilmesine, tıklanan noktadan 3D cismlere doğru ışın
yollanarak başlanır. Ekranda tıklanan noktaya ait 2D koordinatlardan 3D ortamdaki cisimlerle
kesişim testinde kullanılacak ışının üretilmesi için bir takım transformasyonlar gerekmektedir.
Bilindiği gibi 3D ortamdaki herhangi bir noktanın ekran koordinatlarına dönüşümü
için sırasıyla World, View ve Projection matrisleri ile çarpılır. Dolayısıyla ekranda tıklanan
2D noktadan 3D ışını üretmek için matris çarpımlarının tersi yani ters matrisler ile işlemler
yapmak gerekir.
Çizim yapılacak pencerenin 800x600 çözünürlükte olduğu varsayıldığında bu
pencerenin sol üst köşesinin koordinatları (0,0) sağ alt köşesinin de (799,599) olur. Bu
koordinatlardan pencerenin merkezi (0,0) ‘dan sağa doğru +X, sola doğru –X; yukarı doğru
+Y ve aşağı doğru –Y olacak şekilde normalize edilmiş yani (-1,+1) arası değişen
koordinatlara dönüşüm yapan DirectX 10 kodu aşağıdaki gibidir:
D3DXVECTOR3 v;
v.x = ( ( ( 2.0f * ptCursor.x ) / Width ) - 1 ) / pmatProj->_11;
v.y = -( ( ( 2.0f * ptCursor.y ) / Height ) - 1 ) / pmatProj->_22;
v.z = 1.0f;
Burada ptCursor.x ekranda tıklanan noktanın (0,799) arası değişen x; ptCursor.y de
(0,599) arası değişen y koordinatlarıdır. pmatProj de Projection matrisidir. İşlemleri ters
sırada yaptığımızdan Projection matrisi ile çarpmak yerine ona bölüyoruz.
Yukarıdaki işlemler ışının üretilmesi için yeterli değildir. v vektörü ayrıca World ve
View matrislerinin tersi ile de çarpılmalıdır:
KTÜ Bilgisayar Mühendisliği Bölümü – Bilgisayar Grafikleri Laboratuarı
1
// Get the inverse view matrix
const D3DXMATRIX matView = *g_Camera.GetViewMatrix();
const D3DXMATRIX matWorld = *g_Camera.GetWorldMatrix();
D3DXMATRIX mWorldView = matWorld * matView;
D3DXMATRIX m;
D3DXMatrixInverse( &m, NULL, &mWorldView );
// Transform the screen space
vPickRayDir.x = v.x * m._11 +
vPickRayDir.y = v.x * m._12 +
vPickRayDir.z = v.x * m._13 +
vPickRayOrig.x = m._41;
vPickRayOrig.y = m._42;
vPickRayOrig.z = m._43;
pick ray into
v.y * m._21 +
v.y * m._22 +
v.y * m._23 +
3D space
v.z * m._31;
v.z * m._32;
v.z * m._33;
Bu noktada 2D ekranda tıklanan noktaya 3D uzayda karşılık gelen ışının başlangıç
noktası vPickRayOrig ve doğrultusu vPickRayDir üretilmiştir. Işın İzleme (Ray Tracing)
yapılarak 3D ortamdaki cismin tam olarak hangi üçgenine tıklandığı belirlenmelidir. Bunun
için 2 seçenek söz konusudur : 1. Işın-Üçgen kesişim testi kodu yazmak, 2. DirectX’in
Intersect methodunu kullanmak. Web sayfasındaki kaynak kodda her iki seçenek de vardır.
Intersect methodu kesişim testi sonucu kesişen üçgenlere olan uzaklık, üçgenlerin indisleri,
(u,v) barisentrik koordinatlar gibi bilgiler döndürmektedir. Bu bilgilerden faydalanılarak
hangi üçgene, hatta o üçgen üzerinde hangi koordinatlara tıklandığı hesaplanabilir.
Yukarıdaki kod örnekleri kaynak koddaki Pick() methodundan alınmıştır. Pick()
methodundaki if(GetCapture()) şartı sağlanıyorsa yani mouse ile ekranda bir noktaya
tıklanmış ve GetCapture() methodu ile ekran koordinatları alınmışsa yukarıdaki işlemler ile
ışının başlangıç noktası vPickRayOrig ve doğrultusu vPickRayDir üretilebilir. Sonra
if(g_bUseD3DXIntersect)
şartı
DirectX’in
Intersect
methodunun
kullanılıp
kullanılmayacağına karar vermek içindir. Eğer o kullanılacaksa sonraki if(!g_bAllHits)
şartı ile kesişen bütün üçgenler mi yoksa bunlardan en yakın olanına ait bilgiler mi alınacak
ona karar verilir. if(g_bUseD3DXIntersect) şartı sağlanmıyorsa ışın-üçgen kesişim testi
için gereken işlemler aşağıdaki kod bloğunda verilmiştir:
Burada dwNumFaces = g_Mesh.GetNumIndices(0)/3; ile g_Mesh isimli 3D modelin
indisleri 3’e bölünmüş ve üçgen sayısı olarak dwNumFaces ‘e atanmıştır. fBary1, fBary2
barisentrik koordinatları, fDist de üçgene olan t uzaklığını temsil etmektedir. for(DWORD i
= 0; i < dwNumFaces; i++) ile bütün üçgenler için kesişim testleri yapılmaktadır.
Döngüde öncelikle
D3DXVECTOR3 v0 = pVertices[pIndices[3 * i + 0]].p;
D3DXVECTOR3 v1 = pVertices[pIndices[3 * i + 1]].p;
D3DXVECTOR3 v2 = pVertices[pIndices[3 * i + 2]].p;
i değişkeni ile belirlenen üçgenin köşe noktalarının koordinatları v0, v1 ve v2 ‘ye
kopyalanmıştır. Sonra bizim yazdığımız IntersectTriangle methodu koşularak kesişim
varsa fBary1, fBary2 ve fDist değerleri hesaplanmıştır. Ayrıca g_bAllHits değişkeninin
değerine bağlı olarak ya bütün üçgenler ya da en yakın üçgen için onun indisi ve fBary1,
fBary2, fDist değerleri g_IntersectionArray[] dizisine eklenmiştir:
KTÜ Bilgisayar Mühendisliği Bölümü – Bilgisayar Grafikleri Laboratuarı
2
DWORD dwNumFaces = (DWORD)g_Mesh.GetNumIndices(0)/3;
FLOAT fBary1, fBary2;
FLOAT fDist;
for( DWORD i = 0; i < dwNumFaces; i++ )
{
D3DXVECTOR3 v0 = pVertices[pIndices[3 * i + 0]].p;
D3DXVECTOR3 v1 = pVertices[pIndices[3 * i + 1]].p;
D3DXVECTOR3 v2 = pVertices[pIndices[3 * i + 2]].p;
if( IntersectTriangle( vPickRayOrig, vPickRayDir, v0, v1, v2,
&fDist, &fBary1, &fBary2 ) )
{
if( g_bAllHits || g_nNumIntersections == 0 ||
fDist < g_IntersectionArray[0].fDist )
{
if( !g_bAllHits ) g_nNumIntersections
= 0;
g_IntersectionArray[g_nNumIntersections].dwFace
= i;
g_IntersectionArray[g_nNumIntersections].fBary1
= fBary1;
g_IntersectionArray[g_nNumIntersections].fBary2
= fBary2;
g_IntersectionArray[g_nNumIntersections].fDist
= fDist;
g_nNumIntersections++;
if( g_nNumIntersections == MAX_INTERSECTIONS )
break;
}
}
}
3. Kesişen Üçgenlerin Çizilmesi
Kesişen üçgenlerin çizimi OnFrameRender() methodunda aşağıdaki kod ile yapılır.
Üçgenlerin köşe noktaları g_pVB isimli vertex bufferda tutulmaktadır. Kesişen üçgenlerin
çizimi pd3dDevice->Draw( 3*g_nNumIntersections, 0 ) emri ile gerçekleştirildikten
sonra g_pTechRenderSceneWireframe->GetPassByIndex(0)->Apply(0) ile modele ait
diğer üçgenlerin çizim modu wireframe yapılmıştır. Böylece seçilen üçgen daha belirgin hale
getirilmiştir. Şekil-1’de programdan bir ekran görüntüsü verilmiştir.
if( g_nNumIntersections > 0 )
{
// Draw the picked triangle
UINT Strides[1];
UINT Offsets[1];
Strides[0] = sizeof(D3DVERTEX);
Offsets[0] = 0;
pd3dDevice->IASetVertexBuffers(0, 1, &g_pVB, Strides, Offsets);
pd3dDevice->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
pd3dDevice->Draw( 3*g_nNumIntersections, 0 );
// Set render mode to wireframe
g_pTechRenderSceneWireframe->GetPassByIndex( 0 )->Apply( 0 );
}
KTÜ Bilgisayar Mühendisliği Bölümü – Bilgisayar Grafikleri Laboratuarı
3
Şekil-1: DirectX 10 Picking Uygulaması
4. Deneye Hazırlık
Kesişim testinin döndürdüğü fDist uzaklık değerini kullanarak üçgen üzerindeki
intersectionPoint_t koordinatını hesaplayınız. Ayrıca fBary1, fBary2
barisentrik koordinatları da kullanarak yine üçgen üzerindeki intersectionPoint_uv
koordinatını
hesaplayınız.
Gerek
intersectionPoint_t
gerekse
de
intersectionPoint_uv üçgen üzerindeki koordinatlar olduğundan ikisi de aynı
çıkmalıdır. Programda başlangıç değerleri (0,0,0) olarak setlenmiştir.
5. Deneyin Yapılışı
IntersectTriangle() isimli Işın-Üçgen kesişim testi methodunu “Alan Testi”
yöntemini gerçekleyecek şekilde değiştiriniz.
6. Deney Raporu
Deney Raporu, Rapor.docx adlı şablon belge ile hazırlanacak ve en geç sonraki hafta
deney saatine kadar teslim edilecektir. Rapor, grup olarak hazırlanacaktır. Varsa
Deneye Hazırlık veya Deneyin Yapılışındaki eksikler tamamlanıp rapora eklenecek ve
(USB bellekte getirilen) programlar ile birlikte teslim edilecektir.
KTÜ Bilgisayar Mühendisliği Bölümü – Bilgisayar Grafikleri Laboratuarı
4

Benzer belgeler

dırectx 10 pıckıng uygulaması

dırectx 10 pıckıng uygulaması pd3dDevice->IASetPrimitiveTopology( D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST ); pd3dDevice->Draw( 3*g_nNumIntersections, 0 ); // Set render mode to wireframe g_pTechRenderSceneWireframe->GetPassByInde...

Detaylı

Excel Fonksiyon Tablosunu İndir

Excel Fonksiyon Tablosunu İndir Metin değeriyle belirtilen bir başvuru verir Doğrusal bir eğilimin parametrelerini verir Bir yatırımın dönem sayısını verir Bir veri kümesinin kartil değerini verir Bir dizinin ilk sütununa bakar v...

Detaylı