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