본문 바로가기

프로그래밍/공부관련

지형픽킹


게임 프로젝트실습이라는 네이버카페에서 우연히 얻은자료
카페주인장 빈잉님에게 감사할따름이다.

*Picking 설명

: 마우스 클릭에 의한 화면 좌표를 3D 지형과의 충돌체크를 통하여 3D공간상의 좌표를 얻어냄

 

1.마우스 클릭을 통한 스크린 좌표 얻기

FAR PASCAL XApp::MsgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)

{

         static int iXPos,iYPos;

         switch(uMsg)

        {

          case WM_KEYDOWN:

             if(wParam == VK_ESCAPE)

            ::DestroyWindow(hWnd);

            break;

           case WM_LBUTTONDOWN:

             iXPos = LOWORD(lParam);

             iYPos = HIWORD(lParam);

          

             Pick_Test(hWnd);

             ====생략======

         }

 

           2. 클릭한 지점에 대하여 pick클래스 초기화

          

           void XApp::Pick_Test(HWND hWnd)

            {

                     D3DXVECTOR3 vxCursor,vxCameraPos;

                     POINT ptCursor;

                     GetCursorPos(&ptCursor);

                     ScreenToClient(hWnd, &ptCursor);   //마우스 위치얻기

             

                     //---------------picking ray 생성---------------

                     m_pPick->PickTestInit(ptCursor.x, ptCursor.y);

 

                     //----------------- 지형 Picktest----------------

                     m_pTerrain->m_isPick = FALSE;    //지형 picktest설정 OFF

                      m_pTerrain->InitPickTest();          

                      m_pTerrain->m)isPick = TRUE;       //지형 pickTest설정 ON

 

                3.Picking 클래스 구성

                 class XPick

                  {

                          //picking광선 설정

                          D3DXVECTOR3 m_cPickRayOrig          // start

                          D3DXVECTOR3 m_cPickRayDir            // dir

                          D3DXVECTOR3 m_cPickRayEnd          // end

 

                          void PickTestInit( int mouseX, int mouseY);          // picking광선 셋팅

                          bool IntersectTriangle(D3DXVECTOR3 &, D3DXVECTOR3 &, D3DXVECTOR3

                                                              &, float &);      // 충돌여부 판정

 

                           //---------------------------------------------------------

                       picking 광선 설정 ( 총돌 체크할 대상과 picking광선을 같은 좌표계로 만들어준다)

 

                        void XPick::PickTestInit(int mouseX, int mouseY);

                        {

                                D3DXMATRIX matProj, matView, matWorld;

                                D3DVIEWPORT9 vp;

                                D3DXVECTOR3  v;

                    

                                //view,proj 행렬을 얻는다.

                                Device->GetViewPort(&vp);

                                Device->GetTransform(D3DTS_PROJECTION, &matProj);

 

                                 //스크린좌표에서 투영창으로의 변환 공식

                            v.x = (((((mouseX - vp.X) * 2.0f / (float),_rt.right) - 1.0f )) -matProj._31) /

                                          matProj._11;

                            v.y = ((-(((mouseY - vp.Y) * 2.0f / (float),_rt.bottom) - 1.0f )) -matProj._32)/

                                           matProj._22;

                            v.z = 1.0f;

 

                             //카메라의 역행렬을 구한다.

                             Device->GetTransform(D3DTS_VIEW, &matView);

                             D3DXMatrixInverse( &matView, NULL, &matView);    //역행렬

 

                  //picking광선 구하기(월드상의 좌표 = view의 역행렬 x 투영창 좌표)

                 m_vPickRayDir.x = v.x * matView._11 + v.y * matview._21 + v.z * matView._31;

                 m_vPickRayDir.y = v.x * matView._12 + v.y * matview._22 + v.z * matView._32;    

                 m_vPickRayDir.z = v.x * matView._13 + v.y * matview._23 + v.z * matView._33;          

                  

                  //카메라 위치

                  m_vPickRayOrig.x = matView._41;     

                  m_vPickRayOrig.y = matView._42;

                  m_vPickRayOrig.z = matView._43;

 

                  //월드의 역행렬을 구한다.

                  Device->GetTransform(D3DTS_WORLD, &matWorld);

                  D3DXMatrixInverse(&matWorld, NULL, &matWorld );      //역행렬

 

                  //광선을 지역좌표로 변환시킨다 ( 로컬좌표 = 월드의 역행렬 x월드좌표)

                D3DXVec3TransformCoord(&m_vPickRayDir, &m_vPickRayDir, &matWorld);                

                D3DXVec3TransformCoord(&m_vPickRayOrig, &m_vPickRayDir, &matWorld);

                }

 

                4.지형에서의 pick test

 

                :현재화면의 로컬좌표로 변환한 picking광선을 구하였으므로 이와의 충돌 여부만 판

                정하면 됨

                 //지형 picking여부 결정

 

                 void Terrain::InitPickTest()

                  {

                          m_IsPickFace = FASLE;      //선택된면이 없음

                           m_mindist = 10000.0f           //픽킹 광선의 길이 설정(일반적으로 길게 잡아줌)

                   }        

 

                    //실제적 picktest( 삼각형을 이루는 정점 3개를 가져와 picking광선과 충돌여부를

                     판정)

 

                      for(int i = 0; i < m_nTriangles; i++)

                      {

                         //--------------------------인덱스값 얻어오기

                            index = (LPWORD) pI + baseindex;

                            index2 = (LPWORD) pI + baseindex+1;

                            index3 = (LPWORD) pI + baseindex+2;

                            

                           //정점의 로컬좌표값

                          vec[0] = D3DXVECTOR3(m_pvHeightMap[*index].p.x, m_pvHeightMap

                                          [*index].p.y, m_pvHeightMap[*index].p.z);

                          vec[1] = D3DXVECTOR3(m_pvHeightMap[*index2].p.x, m_pvHeightMap

                                          [*index2].p.y, m_pvHeightMap[*index2].p.z);

                           vec[2] = D3DXVECTOR3(m_pvHeightMap[*index3].p.x, m_pvHeightMap

                                          [*index3].p.y, m_pvHeightMap[*index3].p.z); 

 

                          //-------------삼각형 교차 체크----------------------

                         //교차하는 점들 중에서 가장 가까운점을 선택하면 그것이 가장 정확한 충돌 삼각

                         // 형이다.

 

                         if( m_pPick->IntersectTriangle(vec[0], vec[2], dist))  //교차한 경우 교차한

                          //점과의 거리를 반환한다.

                         {

                                 if( m_mindist > dist)

                                  {

                                          if(dist > 0.0f)

                                          {

                                                 m_IsPickFace = TRUE;

                                                 m_mindist = dist;            //가장가까운 거리를 선택한다(point)

                                           }

                                   }

                          }

                           baseindex += 3;

                       

                       }

                      

                          5.교차한 교점을 구하기

                           :picking 광선에 구해준 가장 가까운 거리를 곱하면 그것이 방향 벡터가 충돌한

                           지점이 된다.

                          

                           if( m_IsPickFace)              //unit가 선택이 않될때

                           {

                                 m_vPositionOfMouse = m_pPick->m_vPickRayOrig + m_pPick->

                                                                   m_vPickRayDir * m_mindist;

                            }

 

                            =================================================================

                          충돌체크함수

                          => IntersectTriangle( vec[0], vec[1], vec[2], dist)의 분석 (추후)

                           :: 세개의 정점을 가지고 picking광선과 교차판정을 수행하는 함수이다.

 

                           boo;::XPick::IntersectTriangle(D3DXVECTOR3 &v0, D3DXVECTOR3 &v1,

                                                                       D3DXVECTOR3 &v2, float &dist )

                           {

                                    float det,u,v;

                                    D3DXVECTOR3 pvec,tvec,qvec;

                                     D3DXVECTOR3 edge1 = v1 - v0;

                                      D3DXVECTOR3 edge2 = v2 - v0;

 

                                     D3DXVec3Cross(&pvec, &m_vPickRayDir, &edge2);

 

                                     det = D3DXVec3Dot(&edge1, &pvec);

         

                                    if( det < 0.0001f)

                                           return false;

                                    tvec = m_vPickRayOrig - v0;

                                    u = D3DXVec3Dot(&tvec, &pvec);

         

                                    if(u < 0.0f || u > det)

                                             return false;

       

                                     D3DXVec3Cross( &qvec, &tvec , &edge1);

                                     v = D3DXVec3Dot(&m_vPickRayDir, &qvec);

     

                                     dist = D3DXVec3Dot(&edge2, &qvec);

                                     dist += (1.0f / det);

  

                                     return true;

                            }

[출처] 지형 픽킹 |작성자 anthony119

'프로그래밍 > 공부관련' 카테고리의 다른 글

CString -> char *  (0) 2010.03.21
[mfc] 휠........  (0) 2010.03.13
D3D reSet 과 lostDevice을 고려하고 시작을 했어야 했는데........  (0) 2010.03.01
d3d 라이트  (0) 2010.02.21
Directx9.0c 버퍼관련..  (0) 2010.02.08