Game Programming Gems 5 - 1.6에 나온 개선된 절두체 선별에 대한 세미나 자료입니다.

내용은 기존의 절두체를 구현해봤다는 혹 할정도의 계산량 개선을 보여줍니다.

벡터의 내적, 외적과 평면방정식, 삼각함수 정도만 알고 있으면 쉽게 이해할 수 있습니다.

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에 나온 내용이므로 부족한 설명은 책을 참고하시면 됩니다^^
크리에이티브 커먼즈 라이센스
Creative Commons License
2009/09/07 10:24 2009/09/07 10:24



회사 내부 세미나에서 발표한 자료입니다.

발표할 주제를 찾던중 Game Programming Gems 4권에서 좋은 주제를 발견했습니다ㅋ

3차원 모형에 팀색상 입히는 기법에 대한 내용인데요~

실제로 RTS 게임에서 많이 필요로 하는 기술이구요.

또한, 차량이나 피부 등 여러 부분에서 활용할 수 있는 기법입니다.

책에 있는 내용을 토대로 설명한거라 세미나 자료만 봐서는 책의 내용과 크게 다를 점이 없습니다~(실제로 내용도 책에 있는 내용 붙여 넣기~=ㅁ=;;)

하지만 중간에 코드에 제가 분석했던 내용을 달아 놓은게 있으니 도움이 될지도~ㄷㄷ

구현이야 RenderState와 TextStageState를 가지고 장난치는 것이 다기 때문에 어려운 부분은 없을듯 합니다~
크리에이티브 커먼즈 라이센스
Creative Commons License
2009/06/22 14:49 2009/06/22 14:49



회사에서 내부 세미나에서 발표한 자료입니다.

발표한지는 꽤 되었는데요.

정리도 해둘겸 업로드를 하게 됬네요~ㅎ

실제 만든 Export Plugin 코드는 세미나 중간에 보면서 설명해서 자료에는 포함이 안되있네요.

워낙 다들 엔진 사서 개발하시니 Export 자체 개발할 일은 많이 없겠지만 대강의 구조는 알면 좋은듯 합니다.
크리에이티브 커먼즈 라이센스
Creative Commons License
2009/06/22 14:35 2009/06/22 14:35