출처 - http://blog.naver.com/clous02?Redirect=Log&logNo=110023792724
픽킹
★광선과 물체
-광선의 표현
-시작점과 끝점
-시작점과 방향(픽킹할때 사용)
★물체의 형태
-구
-박스
-지형
★픽킹의 전체 순서
-스크린 포인트로 부터 광선의 도출
-광선을 픽킹 대상 모델의 월드공간으로 변환
(삼각형일경우 지역좌표계로 들어가서 해야할 경우도 있음)
-픽킹 광선과 교차하는 물체 확인
★고정 파이프 라인의 역추적
-고정파이프 라인의 이해
-월드변환-> 뷰변환 -> 프로젝션뷰변환 -> 뷰포트 변환후 출력
-실제 물체는 월드좌표계에 존재
-뷰포트 역변환 -> 프로젝션변환 -> 뷰변환후 충돌체크
-스크린 포인트 s를 통해 투영창에 대응되는 p를 얻는다. (뷰포트 변환)
-원점에서 출발하여 p를 통과하여 발생되는 픽킹 광선을 계산
★픽킹의 순서
1)현재 마우스 포인트 좌표 획득
1.MouseEvent
2.GetCurrentPos screentoclient 로 클라이언트 좌표계로 변환(GetCurrentPos로 읽을 때만 사용)
2)획득한 좌표로 부터 프로젝션 변환 이전으로 변환
뷰포트 역변환 -> 프로젝션 전단계로
프로젝션 역변환 -> 화면 비율 전단계인 동차 좌표계로
3)광선의 원점과 방향 결정
원점 : 카메라의 원점
방향 : 현재 화면이 Z = 1인 동차 좌표의 확대임
D3DXVec3Normalisze
4)뷰변환을 한다 (Camera의 View 의 역행렬로 변환)
D3DXVec3TransformCoord
D3DXVec3TransformNormal
★뷰포트 관련 함수
-D3DVIEWPORT9 vp;
-m_device->SetViewport( &vp )
-m_device->GetViewport()
★뷰포트 변환 행렬
Width/2 0 0 0
0 -Width/2 0 0
0 0 MaxZ-MinZ 0
X+Width/2 Y+Height/2 MinZ 1
(2차원에서는 Y는 역으로 커짐)
스크린포인트 S = (Sx, Sy)는 투영창의 포인트 p = (Px, Py, Pz)를 뷰포트 변환한 결과
역으로 2 * 2의 사이즈가 800*600이 되었기 떄문에 뷰포트에서 확대 된만큼 다시 나누어 동차좌표계로 들어 오게 한다.
★뷰포트에서 광선 처리 함수
Ray CalcPickingRay(int x, int y)//마우스의 위치 좌표를 받는다.
{
float px = 0.0f;
float py = 0.0f;
D3DVIEWPORT9 vp;
Device->GetViewport(&vp); //800* 600모드 등 현재의 화면 모드를 알기위함
D3DXMATRIX proj; //프로젝션은 화면의 비율과 근거리 원거리를 확인하기 때문에 이를 시정하기 위하여
Device->GetTransfor( D3DTS_PROJECTION &proj);
px = ((( 2.0f * x) / vp.Width) -1.0f) / proj(0,0); //프로젝션 행렬 스케일 배열값 _11
py = ((( -2.0f * y) / vp.Height) + 1.0f) / proj(1, 1); //프로젝션 행렬 스케일 배열값 _22
Ray ray; //구조체로 지정되어 있다.
ray._origin = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
ray._direction = D3DXVECTOR3(px, py, 1.0f); //한점의 위치를 기준으로 방향이 결정된다.
return ray;
}
★D3DXVec3TransformCoord
지정된 행렬에 의해 3D 벡터를 변환 해, 그 결과를 w = 1 에 투영 한다.
D3DXVECTOR3 *WINAPI D3DXVec3TransformCoord( D3DXVECTOR3 *pOut,
CONST D3DXVECTOR3 *pV,
CONST D3DXMATRIX *pM
);
★D3DXVec3TransformNormal
지정된 행렬에 의해 3D 벡터 법선을 변환 한다.
D3DXVECTOR3 *WINAPI D3DXVec3TransformNormal( D3DXVECTOR3 *pOut,
CONST D3DXVECTOR3 *pV,
CONST D3DXMATRIX *pM
);
★삼각형 픽킹 방법
-D3DXIntersect ( 메쉬와 충돌체크 )
-D3DXIntersectTri ( 삼각형과 충돌체크 ) 지역좌표까지 따라들어가야 한다.
-D3DXIntersectSubset ( 메쉬의 일부 서브셋과 충돌 체크 )
-계산에 의한 방법
★충돌에 관한 정보를 갖는
typedef struct D3DXINTERSECTINFO{
DWORD FaceIndex; //면의 인덱스
FLOAT U, V;
FLOAT Dist; //거리값
}D3DXINTERSECTINFO, *LPD3DXINTERSECTINFO;
★D3DXIntersect
-월드 변환하기 전의 좌표를 가지고 광선과 메쉬의 충돌체크를 한다
-광선이 그 물체의 지역좌표계로 들어가야 한다.
-충돌 점계산은 V1 + U(V2 - V1) V(V3 - V1)
레이가 메쉬에 해당될지 어떨지를 판정한다.
HRESULT D3DXIntersect(
LPD3DXBASEMESH pMesh,
CONST D3DXVECTOR3 *pRayPos,
CONST D3DXVECTOR3 *pRayDir,
BOOL *pHit,
DWORD *pFaceIndex, //광선과 가장 가까운 면의 인덱스 번호를 리턴
FLOAT *pU, //U
FLOAT *pV, //V
FLOAT *pDist,
LPD3DXBUFFER *ppAllHits,
DWORD *pCountOfHits
);
★D3DXIntersectTri
-버텍스의 좌표가 월드 좌표계 내무에 있는 좌표를 대상으로 한다(실제 버텍스 좌표를 대상으로 한다)
지정된 레이가 지정된 삼각형에 교차시킨다. D3DXIntersect 에 유사한 기능을 제공한다.
BOOL D3DXIntersectTri(
const D3DXVECTOR3 *p0,
const D3DXVECTOR3 *p1,
const D3DXVECTOR3 *p2,
const D3DXVECTOR3 *pRayPos,
const D3DXVECTOR3 *pRayDir,
FLOAT *pU,
FLOAT *pV,
FLOAT *pDist
);
-함수의 리턴값으로 충돌 여부를 확인
★D3DXIntersectSubset
-전체 메쉬가 아니라 그 일부인 서브셋을 가지고 충돌체크를 한다.
지정된 레이가 지정된 메쉬 서브 세트에 교차시킨다. D3DXIntersect 에 유사한 기능을 제공한다.
HRESULT D3DXIntersectSubset(
LPD3DXBASEMESH pMesh,
DWORD AttribId,
const D3DXVECTOR3 *pRayPos,
const D3DXVECTOR3 *pRayDir,
BOOL *pHit,
DWORD *pFaceIndex,
FLOAT *pU,
FLOAT *pV,
FLOAT *pDist,
LPD3DXBUFFER *ppAllHits,
DWORD *pCountOfHits
);
'예전 > 3D' 카테고리의 다른 글
[3D] GetTransform과 GetViewport (0) | 2012.09.27 |
---|---|
2D 좌표를 3D좌표로 바꾸는 함수 (0) | 2012.09.27 |
[UI엔진] 처음 내 프로젝트를 만들고서 (0) | 2012.09.27 |
[3D] 김벌락 (Gimbal Lock) (0) | 2012.09.06 |
[3D] Direct3D 초기화 (0) | 2012.09.06 |