LOD
쿼드트리를 사용한 LOD의 구현은 놀랍게도 ZQuadTree.h에 두개의 함수를 추가하는것으로 해결된다.
그것도 다섯줄정도밖에 안된다
- DX 라이브러리가 지원을 잘 해줘서 그런거지 구현이 결코 간단하지만은 않다
ZQuadTree.h 수정
float _GetDistance(D3DXVECTOR3* pv1, D3DXVECTOR3* pv2)
{
return D3DXVec3Length(&(*pv2 - *pv1));
}
// 카메라와 현재 노드와의 거리값을 기준으로 LOD값을 구한다
int _GetLODLevel(TERRAINVERTEX* pHeightMap, D3DXVECTOR3* pCamera, float fLODRatio)
{
float d = _GetDistance((D3DXVECTOR3*)(pHeightMap+m_nCenter), pCamera);
return max((int)(d*fLODRatio), 1);
}
// 현재 노드가 LOD등급으로 볼 때 출력이 가능한 노드인가?
BOOL _IsVisible(TERRAINVERTEX* pHeightMap, D3DXVECTOR3* pCamera, float fLODRatio)
{
return ((m_nCorner[CORNER_TR] - m_nCorner[CORNER_TL]) <= _GetLODLevel(pHeightMap, pCamera, fLODRatio));
}
_IsVisible()함수는 카메라와 현재 노드와의 거리에 따른 LOD 등급을 구해서 쿼드트리의 출력 여부를 결정한다. 이때, LOD 등급을 구해주는 함수는 _GetLODLevel()이고, 카메라와 노드 중앙 정점과의 거리를 구해주는 함수는 _GetDistance()다. 이것을 추가하는 것만으로도 우리는 훌륭한 LOD지형을 구현할 수 있다.
문제는 LOD등급이 서로 다른 메시들끼리 공존하기 때문에 LOD등급이 다른 경계부분에서 균열이 발생하는 것을 막지 못하고 있다는 것이야.. 이 처리는 다음에~
메인도 수정해야겠죠?
인자가 수정되는 곳은 연쇄적으로 다 수정해줘야한다
ZTerrain.h 수정
HRESULT Create( LPDIRECT3DDEVICE9 pDev, D3DXVECTOR3* pvfScale, float fLODRatio, LPSTR lpBMPFilename, LPSTR lpTexFilename[MAX_TERRAIN_TEX] );
fLODRatio 인자가 생겨났다.
ZTerrain.cpp 수정
HRESULT ZTerrain::Create( LPDIRECT3DDEVICE9 pDev, D3DXVECTOR3* pvfScale, float fLODRatio, LPSTR lpBMPFilename, LPSTR lpTEXFilename[4] )
{
m_pd3dDevice = pDev;
m_vfScale = *pvfScale;
m_fLODRatio = fLODRatio;
if( FAILED( _BuildHeightMap( lpBMPFilename ) ) ) { _Destroy(); return E_FAIL; }
if( FAILED( _LoadTextures( lpTEXFilename ) ) ) { _Destroy(); return E_FAIL; }
if( FAILED( _CreateVIB() ) ) { _Destroy(); return E_FAIL; }
m_pQuadTree = new ZQuadTree( m_cxDIB, m_czDIB );
if( FAILED( _BuildQuadTree() ) ) { _Destroy(); return E_FAIL; }
return S_OK;
}
ZQuadTree.cpp 수정
int ZQuadTree::_GenTriIndex( int nTris, LPVOID pIndex, TERRAINVERTEX* pHeightMap, ZFrustum* pFrustum, float fLODRatio )
{
// 컬링된 노드라면 그냥 리턴
if( m_bCulled )
{
m_bCulled = FALSE;
return nTris;
}
// 현재 노드가 출력되어야 하는가?
if( _IsVisible( pHeightMap, pFrustum->GetPos(), fLODRatio ) )
{
#ifdef _USE_INDEX16
LPWORD p = ((LPWORD)pIndex) + nTris * 3;
#else
LPDWORD p = ((LPDWORD)pIndex) + nTris * 3;
#endif
*p++ = m_nCorner[0];
*p++ = m_nCorner[1];
*p++ = m_nCorner[2];
nTris++;
*p++ = m_nCorner[2];
*p++ = m_nCorner[1];
*p++ = m_nCorner[3];
nTris++;
return nTris;
}
// 자식 노드들 검색
if( m_pChild[CORNER_TL] ) nTris = m_pChild[CORNER_TL]->_GenTriIndex( nTris, pIndex, pHeightMap, pFrustum, fLODRatio );
if( m_pChild[CORNER_TR] ) nTris = m_pChild[CORNER_TR]->_GenTriIndex( nTris, pIndex, pHeightMap, pFrustum, fLODRatio );
if( m_pChild[CORNER_BL] ) nTris = m_pChild[CORNER_BL]->_GenTriIndex( nTris, pIndex, pHeightMap, pFrustum, fLODRatio );
if( m_pChild[CORNER_BR] ) nTris = m_pChild[CORNER_BR]->_GenTriIndex( nTris, pIndex, pHeightMap, pFrustum, fLODRatio );
return nTris;
}
// 삼각형의 인덱스를 만들고, 출력할 삼각형의 개수를 반환한다.
int ZQuadTree::GenerateIndex( LPVOID pIndex, TERRAINVERTEX* pHeightMap, ZFrustum* pFrustum, float fLODRatio )
{
// 먼저 프러스텀 컬링을 해서 컬링될 노드들을 배제한다.
_FrustumCull( pHeightMap, pFrustum );
// 출력할 폴리곤의 인덱스를 생성한뒤, 폴리곤의 개수를 리턴한다.
return _GenTriIndex( 0, pIndex, pHeightMap, pFrustum, fLODRatio );
}
HeightMap.cpp 수정
HRESULT InitObjects()
{
LPSTR tex[4] = { "tile2.tga", "", "", "" };
D3DXVECTOR3 vScale;
vScale.x = vScale.z = 1.0f; vScale.y = 0.1f;
g_pLog = new ZFLog( ZF_LOG_TARGET_WINDOW );
g_pCamera = new ZCamera;
g_pFrustum = new ZFrustum;
g_pTerrain = new ZTerrain;
g_pTerrain->Create( g_pd3dDevice, &vScale, 0.1f, BMP_HEIGHTMAP, tex );
return S_OK;
}
결과
와이어프레임으로 본 지형의 시야
카메라와 가까운곳과 먼곳의 차이가 느껴지죠?
ㅇㅋㅇㅋ
'Graphics > DirectX' 카테고리의 다른 글
Direct X - 애니메이션 기법 (0) | 2014.09.03 |
---|---|
Direct X - 균열 방지 (0) | 2014.08.27 |
Direct X - 쿼드트리 컬링 (0) | 2014.08.16 |
Direct X - 쿼드트리 (0) | 2014.08.14 |
Direct X - 절두체 컬링 (0) | 2014.08.11 |