본문 바로가기

예전/3D

피킹참조자료 주움

출처 - 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