이글은 D3D의 Pick예제에 나와있는 IntersectTriangle에 관한 설명입니다. 이 함수가 하는일이나 사용법에 대해선 예제에 잘 나와있기때문에 이런것을 설명하지는 않습니다. 이글의 목적은 함수 자체가 어떤 원리로 동작을 하는지를 이해하는것이죠.
if( *u < 0.0f || *u > det ) return FALSE; if( *v < 0.0f || *u + *v > det ) return FALSE;Picking일 경우 IntersectTriangle이 출력하는 u,v를 사용하면 마우스의 3차원 위치와 카메라와의 거리를 쉽게 구할수 있습니다.
D3DXVec3Cross( &pvec, &dir, &edge2 ); FLOAT det = D3DXVec3Dot( &edge1, &pvec ); *u = D3DXVec3Dot( &tvec, &pvec ); FLOAT fInvDet = 1.0f / det; *u *= fInvDet;사실 여기까지가 설명의 끝입니다.
D3DXVec3Cross( &qvec, &tvec, &edge1 ); *v = D3DXVec3Dot( &dir, &qvec ); *v *= fInvDet;IntersectTriangle은 연산을 수행하는 도중 판정결과를 알 수 있다면 바로 리턴하는 방식으로, 필요없는 연산이 일어나지 않도록 구성되어있습니다.
if( det < 0.0001f ) return FALSE;이 비교문은 코딩 차원에서 본다면 0으로 나누는 에러방지와 det값과 u,v값의 비교를 쉽게해주는 역할을 합니다만, 수학적으로 보면 이코드의 또다른면을 볼 수 있게됩니다.
여기서 잠깐! D3D8.1 버젼부터는 det에 절대값을 취함으로써 뒤집어진 면도 교차라고 판정하도록 되어있습니다. 사실 이전 버젼의 예제들은 det값을 그대로 사용해서, IntersectTriangle함수가 반직선과 삼각형의 교차판정뿐 아니라 뒤집어진 삼각형이 아닌지까지 검사하도록 만들어져 있었던겁니다. 이것을 함수의 목적에 맞도록 수정했다고나 할까요? 하지만 det에 절대값을 취하는 부분만 없애면 '별도의 연산없이' 뒤집어진 삼각형을 검사해낼 수 있다는것을 꼭 알아두시길... |
*t = D3DXVec3Dot( &edge2, &qvec ); *t *= fInvDet;우선 설명을 하기전에 t와 det를 적당히 변형하도록 하겠습니다.
//-----------------------------------------------------------------------------
// Name: IntersectTriangle()
// Desc: Given a ray origin (orig) and direction (dir), and three vertices of
// of a triangle, this function returns TRUE and the interpolated texture
// coordinates if the ray intersects the triangle
//-----------------------------------------------------------------------------
BOOL CMyD3DApplication::IntersectTriangle( const D3DXVECTOR3& orig,
const D3DXVECTOR3& dir, D3DXVECTOR3& v0,
D3DXVECTOR3& v1, D3DXVECTOR3& v2,
FLOAT* t, FLOAT* u, FLOAT* v )
{
// Find vectors for two edges sharing vert0
D3DXVECTOR3 edge1 = v1 - v0;
D3DXVECTOR3 edge2 = v2 - v0;
// Begin calculating determinant - also used to calculate U parameter
D3DXVECTOR3 pvec;
D3DXVec3Cross( &pvec, &dir, &edge2 );
// If determinant is near zero, ray lies in plane of triangle
FLOAT det = D3DXVec3Dot( &edge1, &pvec );
D3DXVECTOR3 tvec;
if( det > 0 )
{
tvec = orig - v0;
}
else
{
tvec = v0 - orig;
det = -det;
}
if( det < 0.0001f )
return FALSE;
// Calculate U parameter and test bounds
*u = D3DXVec3Dot( &tvec, &pvec );
if( *u < 0.0f || *u > det )
return FALSE;
// Prepare to test V parameter
D3DXVECTOR3 qvec;
D3DXVec3Cross( &qvec, &tvec, &edge1 );
// Calculate V parameter and test bounds
*v = D3DXVec3Dot( &dir, &qvec );
if( *v < 0.0f || *u + *v > det )
return FALSE;
// Calculate t, scale parameters, ray intersects triangle
*t = D3DXVec3Dot( &edge2, &qvec );
FLOAT fInvDet = 1.0f / det;
*t *= fInvDet;
*u *= fInvDet;
*v *= fInvDet;
return TRUE;
}