Game Programming Gems 5 - 1.6에 나온 개선된 절두체 선별에 대한 세미나 자료입니다.
내용은 기존의 절두체를 구현해봤다는 혹 할정도의 계산량 개선을 보여줍니다.
벡터의 내적, 외적과 평면방정식, 삼각함수 정도만 알고 있으면 쉽게 이해할 수 있습니다.
PT만으로는 부족할 듯 해서 구현 코드로 부가 설명을 하였습니다.
내용은 기존의 절두체를 구현해봤다는 혹 할정도의 계산량 개선을 보여줍니다.
벡터의 내적, 외적과 평면방정식, 삼각함수 정도만 알고 있으면 쉽게 이해할 수 있습니다.
PT만으로는 부족할 듯 해서 구현 코드로 부가 설명을 하였습니다.
1. 절두체 생성 과정 비교
- 기존 절두체 생성 코드
bool NMCuller::Make( D3DXMATRIX* pmatViewProj )
{
bool bResult = true;
int i;
D3DXMATRIXA16 matInv;
//! [ dunkhoon : 2009-09-09 ] : 절두체를 구성하는 8개 정점을 투영좌표상의 위치로 설정한다.
m_vFrustum[ 0 ].x = -1.0f; m_vFrustum[ 0 ].y = -1.0f; m_vFrustum[ 0 ].z = 0.0f;
m_vFrustum[ 1 ].x = 1.0f; m_vFrustum[ 1 ].y = -1.0f; m_vFrustum[ 1 ].z = 0.0f;
m_vFrustum[ 2 ].x = 1.0f; m_vFrustum[ 2 ].y = -1.0f; m_vFrustum[ 2 ].z = 1.0f;
m_vFrustum[ 3 ].x = -1.0f; m_vFrustum[ 3 ].y = -1.0f; m_vFrustum[ 3 ].z = 1.0f;
m_vFrustum[ 4 ].x = -1.0f; m_vFrustum[ 4 ].y = 1.0f; m_vFrustum[ 4 ].z = 0.0f;
m_vFrustum[ 5 ].x = 1.0f; m_vFrustum[ 5 ].y = 1.0f; m_vFrustum[ 5 ].z = 0.0f;
m_vFrustum[ 6 ].x = 1.0f; m_vFrustum[ 6 ].y = 1.0f; m_vFrustum[ 6 ].z = 1.0f;
m_vFrustum[ 7 ].x = -1.0f; m_vFrustum[ 7 ].y = 1.0f; m_vFrustum[ 7 ].z = 1.0f;
//! [ dunkhoon : 2009-09-09 ] : 변환에 사용된 뷰행렬과 프로젝션 행렬을 결함 행렬을 역행렬로 구해낸다
D3DXMatrixInverse( &matInv, NULL, pmatViewProj );
//! [ dunkhoon : 2009-09-09 ] : 절두체를 구성하는 정점을 위에서 구한 역행렬로 변환하여 월드 좌표상의 위치로 변환한다
for( i = 0; i < 8; i++ )
D3DXVec3TransformCoord( &m_vFrustum[ i ], &m_vFrustum[ i ], &matInv );
//! [ dunkhoon : 2009-09-09 ] : 가까운 평면의 왼쪽하단 점과 오른쪽 상단점을 더해 반으로 나눠서 카메라의 중점 좌표를 구한다
m_vPos = ( m_vFrustum[ 0 ] + m_vFrustum[ 5 ] ) / 2.0f;
//! [ dunkhoon : 2009-09-09 ] : 위에서 구한 절두체를 구성하는 8개의 정점을 이용해 6개의 평면을 구성한다
D3DXPlaneFromPoints( &m_plPlane[ 0 ], m_vFrustum + 4, m_vFrustum + 7, m_vFrustum + 6 );
D3DXPlaneFromPoints( &m_plPlane[ 1 ], m_vFrustum, m_vFrustum + 1, m_vFrustum + 2 );
D3DXPlaneFromPoints( &m_plPlane[ 2 ], m_vFrustum, m_vFrustum + 4, m_vFrustum + 5 );
D3DXPlaneFromPoints( &m_plPlane[ 3 ], m_vFrustum + 2, m_vFrustum + 6, m_vFrustum + 7 );
D3DXPlaneFromPoints( &m_plPlane[ 4 ], m_vFrustum, m_vFrustum + 3, m_vFrustum + 7 );
D3DXPlaneFromPoints( &m_plPlane[ 5 ], m_vFrustum + 1, m_vFrustum + 5, m_vFrustum + 6 );
return bResult;
}
코드를 보면 기존 절두체의 경우는 매번 역행렬을 구하는 과정, 절두체 8개 점에 역행렬을 곱하는 과정, 절두체를 구성하는 6개의 평면을 구하는 과정이 필요합니다.- 개선된 절두체 생성 코드
void NMFastFrustum::SetPerspective( const float fFOV, const float fViewAspect, const float fNearZ, const float fFarZ )
{
m_fRightFactor = tanf( fFOV );
m_fUpFactor = m_fRightFactor * fViewAspect;
m_fNear = fNearZ;
m_fFar = fFarZ;
}
void NMFastFrustum::Build( const D3DXVECTOR3& vEye, const D3DXVECTOR3& vForward, const D3DXVECTOR3& vRight, const D3DXVECTOR3& vUp )
{
m_vEyePosition = vEye;
m_vForward = vForward;
m_vRight = vRight;
m_vUp = vUp;
}
개선된 절두체의 경우는 코드로 보듯이 초기에 위의 정보만 설정해주면 따로 절두체를 생성하는 과정 자체가 없습니다.- 결론
생성 과정에서만 보아도 개선된 절두체의 경우 계산량이 거의 없다고 볼 수 있으므로 좋다는 것을 알 수 있습니다.
2. 점 포함 판정 비교
- 기존 절두체 포함 판정 코드
bool NMCuller::IsIn( D3DXVECTOR3* pvPos )
{
bool bResult = true;
float fDist;
for( int i = 0; i < 6; i++ )
{
//! [ dunkhoon : 2009-09-09 ] : 평면과 정점을 내적하여.
// 절두체의 검사대상이 되는 평면과 입력된 정점 위치 관계를 파악한다
fDist = D3DXPlaneDotCoord( &m_plPlane[ i ], pvPos );
if( fDist > PLANE_EPSILON )
bResult = false;
}
return bResult;
}
기존 절두체의 경우는 절두체 평면과 검사 대상이 되는 점을 내적하는 과정이 이 6번 반복 되는 것을 알 수 있습니다.- 개선된 절두체 포함 판정 코드
bool NMFastFrustum::IsIn( D3DXVECTOR3* pvPos )
{
D3DXVECTOR3 vOP = *pvPos - m_vEyePosition;
//! [ dunkhoon : 2009-09-09 ] : 앞쪽 벡터와 점을 내적하여 투영된 위치를 구한다.
float f = D3DXVec3Dot( &vOP, &m_vForward );
//! [ dunkhoon : 2009-09-09 ] : 점의 위치가 절두체 범위에 벗어나는지 검사한다.
if( f < m_fNear || m_fFar < f )
return false;
//! [ dunkhoon : 2009-09-09 ] : 오른쪽 벡터와 점을 내적하여 투영된 위치를 구한다.
float r = D3DXVec3Dot( &vOP, &m_vRight );
float rLimit = m_fRightFactor * f;
//! [ dunkhoon : 2009-09-09 ] : 점의 위치가 절두체 범위에 벗어나는지 검사한다.
if( r < -rLimit || rLimit < r )
return false;
//! [ dunkhoon : 2009-09-09 ] : 위쪽 벡터와 점을 내적하여 투영된 위치를 구한다.
float u = D3DXVec3Dot( &vOP, &m_vUp );
float uLimit = m_fUpFactor * f;
//! [ dunkhoon : 2009-09-09 ] : 점의 위치가 절두체 범위에 벗어나는지 검사한다.
if( u < -uLimit || uLimit < u )
return false;
return true;
}
개선된 절두체의 경우는 각 방향 벡터와 검사 대상이 되는 점을 내적하여 해당 방향 벡터에 대한 방향 거리를 재고 제한거리에 점이 들어와 있는지로 판별하고 있습니다.- 결론
점 포함 판정의 경우에서도 개선된 절두체 방식의 계산량이 약 2배 가량 적다고 할 수 있습니다.
3. 비교 결과 화면

실제 계산 속도에서도 2배 가량 빠릅니다.
위 내용은 모두 Game Programming Gems 5 - 1.6에 나온 내용이므로 부족한 설명은 책을 참고하시면 됩니다^^
http://www.monstercode.net/tc/trackback/11
YOUR COMMENT IS THE CRITICAL SUCCESS FACTOR FOR THE QUALITY OF BLOG POST





