본문 바로가기

Today I Learned

23.06.09 - Picking

Picking은 마우스를 클릭했을 때 클릭한 화면의 좌표를 통해 어떤 삼각형을 선택했는지 확인할 수 있다.

D3DXIntersectTri함수는 정점3개와 Ray의 시작점, 방향벡터를 받아

Ray의 시작점부터 정점 3개가 이루는 평면의 충돌여부와 충돌점까지의 거리를 알 수 있다.

 

우리는 VIBuffer안에서 D3DXIntersectTri함수를 통해 버퍼의 어떤 삼각형과 충돌했는지 알아낼 것이다.

VIBuffer 내부에서 계산해야하므로 마우스를 클릭한 지점으로 쏘는 Ray를 VIBuffer의 로컬 좌표계까지 

변환해야한다. 마우스 클릭은 뷰포트부터 이루어지므로 로컬좌표계까지는 긴 여정이 될 것이다.

 

 

 

뷰포트 -> NDC

 

	vMousePos.x = ptMouse.x / (rcClient.right * 0.5f) - 1.f;
	vMousePos.y = -ptMouse.y / (rcClient.bottom * 0.5f) + 1.f;
	vMousePos.z = 0.f; /* near평면을 클릭하였기 때문에. */

 

 

(0~WinSizeX,0~WinSizeY) 뷰포트 좌표계에서 (-1~1,-1~1)인 NDC좌표계로 변환한다.

 

 

 

NDC-> 뷰 스페이스 

 

	_float4x4		ProjMatrix;
	m_pGraphic_Device->GetTransform(D3DTS_PROJECTION, &ProjMatrix);

	D3DXMatrixInverse(&ProjMatrix, nullptr, &ProjMatrix);	

	/* 뷰스페이스 상의 마우스 위치. */
	D3DXVec3TransformCoord(&vMousePos, &vMousePos, &ProjMatrix);
    
    	m_vMouseRayPos = _float3(0.f, 0.f, 0.f);
	m_vMouseRay = vMousePos - m_vMouseRayPos;

 

그리고 뷰 스페이스로 변환하기 위해 프로젝션 행렬의 역행렬을 MousePos(마우스 좌표)에 곱한다.

TransformCoord로 곱해야 하는 이유가 좌표 변환 관련해서 뭐 있었는데 아직은 정확히 모르겠다 ㅇㅇ..

ray의 시작점 mouseraypos(mouseray시작점)는 카메라이기 때문에 뷰스페이스에서의 카메라의 위치는 원점이다.

ray의 방향벡터는 그래서 vMousePos 자체이다.

 

그 후로 월드 변환, 로컬 변환은 같은 방식으로 뷰 변환 행렬의 역행렬, 월드 변환 행렬의 역행렬을 곱해주면 된다.

mouseraypos는 위치벡터니까 coord로 ray는 방향벡터니까 normal로 곱해주면 된다.

 

 

_bool CPicking::Intersect_Triangle_InLocal(const _float3 * pPointA, const _float3 * pPointB, const _float3 * pPointC, _float3 * pOut)
{
	_float		fU, fV, fDist;

	_bool		isColl = { false };

	isColl = (_bool)D3DXIntersectTri(pPointA, pPointB, pPointC, &m_vMouseRayPos_Local, &m_vMouseRay_Local, &fU, &fV, &fDist);

	if (true == isColl)
	{
		*pOut = m_vMouseRay_Local * fDist + m_vMouseRayPos_Local;
	}

	return isColl;
}

그리고 D3DXIntersectTri함수에서 정점 3개와 mouseraypos,mouseray를 받는데, fU, fV, fDist가 결과로 나온다.

fU와 fV는 0->1번째 정점에서 충돌점의 비율, 0->2번째 정점에서 충돌점의 비율인데 중요하지는 않다.

중요한 건 fDist, mouseraypos에서 충돌점까지의 거리이다. D3DXIntersectTri의 반환 값은 bool로

아예 충돌하지 않는다면 false, 거리가 멀더라도 충돌한다면 true를 반환한다.

충돌점의 좌표는 mouseraypos + mouseray*fDist로 구할 수 있다.