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ı
pd3dDevice->IASetPrimitiveTopology(
D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST );
pd3dDevice->Draw( 3*g_nNumIntersections, 0 );
// Set render mode to wireframe
g_pTechRenderSceneWireframe->GetPassByInde...
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...