반응형

                   ** 화면좌표에서 공간좌표로의 변환 **
                                                    copyrightⓒ Gamza

 

BLACK&WHITE 같은 마우스를 만들려면 마우스의 2D위치를 3D공간좌표로 변환하는것이 필요해집니다. 등장하는 '신의손'이 실제 공간좌표를 갖기때문이죠. 이것은 상당히 효과만점인 반면, 물체를 Pick할줄만 알면 아주 간단하게 끝나는 아주 쉬운 기법입니다.
D3D의 Pick예제를 보면 물체를 picking하는 기법이 깔끔하게 나와있으니 그걸 그대로 사용하도록 하겠습니다.
2D마우스 좌표를 3D좌표로 변환하는 순서는 다음과 같습니다.
(1) 마우스 좌표를 가지고 공간상에 반직선을 만든다. (언프로젝션)
(2) 반직선과 교차하는 폴리곤중 가장 가까운것을 택한다. ( picking )
(3) 직선과 폴리곤의 교점을 구한다.( == 3D마우스 좌표 )

1. 언프로젝션
우선 마우스 좌표에 해당하는 3D점을 하나 구합니다.
( 아래식이 이해가 안되시는 분들은 '언프로젝션 ( Unprojection )' 과 그것에 링크된문서들을 꼭 읽어보세요. 안읽어보셔도 당장 써먹는데야 지장이 없겠지만....배워서 남주는거 아니니깐요.)

 
 m_pd3dDevice->GetViewport(&vp);
 m_pd3dDevice->GetTransform( D3DTS_PROJECTION, &matProj );
 GetCursorPos( &ptCursor );
 ScreenToClient( m_hWnd, &ptCursor );
 v.x = ((  (((ptCursor.x-vp.X)*2.0f/vp.Width ) - 1.0f)) - matProjection._31 ) / matProjection._11;
 v.y = ((- (((ptCursor.y-vp.Y)*2.0f/vp.Height) - 1.0f)) - matProjection._32 ) / matProjection._22;
 v.z =  1.0f;

언프로젝션하는 부분을 주의하세요. D3D예제에 있는대로 하시면 안될경우가 있습니다.
( 투영행렬에 클리핑행렬이 포함된것 같은경우 )
...
이제 카메라 좌표와 구해진 점을 잇는 반직선을 만들면 되죠,

        m_pd3dDevice->GetTransform( D3DTS_VIEW, &matView );
        D3DXMatrixInverse( &m, NULL, &matView );
        vPickRayDir.x  = v.x*m._11 + v.y*m._21 + v.z*m._31;
        vPickRayDir.y  = v.x*m._12 + v.y*m._22 + v.z*m._32;
        vPickRayDir.z  = v.x*m._13 + v.y*m._23 + v.z*m._33;
        vPickRayOrig.x = m._41;
        vPickRayOrig.y = m._42;
        vPickRayOrig.z = m._43;

2. Picking
D3D예제를 보시면 IntersectTriangle 함수를 사용해서 위에서 구한 반직선이 삼각형에 교차하는지를 검사해서 Pick를 수행하게 됩니다.
근디 우리가 해야할건...그중에서 카메라에 젤 가까운넘을 골라내는겁니다.
거럼 ...어떤넘이 카메라에 가장 가까운 넘인가???

BOOL CMyD3DApplication::IntersectTriangle( const D3DXVECTOR3& orig,
                                       const D3DXVECTOR3& dir, D3DXVECTOR3& v0,
                                       D3DXVECTOR3& v1, D3DXVECTOR3& v2,
                                       FLOAT* t, FLOAT* u, FLOAT* v )

IntersectTriangle함수의 6번째 인자(t) 는 출력용 인자입니다. 폴리곤과 반직선의 교점이 카메라에서 얼마나 떨어져 있는지를 알려주죠.
다시말하면....교차가 발견될때마다 출력된 t 값을 조사해서...젤 작은넘을 유지하도록 하면 됩니다.
t가 제일 작은 폴리곤이 실제로 picking된 폴리곤이죠.

3. 3D마우스 좌표계산
최종적인 3D좌표는 반직선과 IntersectTriangle함수의 출력으로 얻어진 t값으로부터 다음과 같이 구해집니다.

3D마우스 좌표 = vPickRayOrig + vPickRayDir * t ;



자...끝났습니다.

참....마우스가 화면상의 어떤것도 선택하고 있지 않을경우를 별도 처리 해야한다는 것을 잊지마세요.
아무것도 선택되지 않았다면 '카메라로부터의 기본거리'를 적용하는 것이 가장 자연스러울듯 합니다.

t = 기본거리 / D3DXVec3Length( vPickRayDir ) ;


이렇게 처리하면 되죠.

이거...응용할데가 많겠죠?
레벨편집기라던가, RPG, 전략시뮬같은데서도 유용하게 쓰일듯...


반응형

+ Recent posts