12
24

 

'LOD ?'

LOD는 Level Of Detail으로 단계에 따라서

메시의 모델링 데이터의 정밀도를 조절하는 것이다.

게임에서 최적화를 위해서 거리에 대응해 LOD를 사용한다.

 

'LOD의 종류(정적 LOD 동적LOD)'

첫번째, 정적 LOD는 처음부터 메시의 정밀도가 정해져 있고

이를 카메라와의 거리에 따라서 단계별로

버퍼의 교체를 통해 출력하는 것이다.

이미 메시의 정밀도가 이미 정해져 있어서

연산이 간단해 속도가 빠르다

. 하지만 메시를 추가적인 메모리를 가지고

있어야 하며 단계가 급격히 변화해 튀는 현상이 있다.

 

두 번째, 동적 LOD는 실시간으로 메시의 정밀도를 변화시키는 기법이다.

자연스럽게 LOD가 이루어지기 때문에 튀는 현상이 적고,

낭비되는 메모리도 없지만 계속해서 연산을 해야 되기 때문에

상대적으로 속도가 느리다는 단점이 있다.

 

방사형 정적LOD 결과물

 

카메라가 멀어져 있을때 최상단의 패치를 보여준다.

 

거리에 따라서 두개의 패치(각 16개의 정점버퍼)가 포함된 외부파일과

공유되는 인덱스 버퍼로 총 3단계의 LOD를 보여주고 있음

 

"지형이 더 가까울 수록 정밀하게 표현되는 것을 볼 수가 있다."

 

앞서 패치라고 말을 했는데 패치란 단계별 메시의 단위를 패치라고 한다.

패치는 카메라로부터의 거리를 기반으로 적용되기 때문에

이웃 노드들과의 LOD레벨이 다를 수밖에 없다.

이웃 정점들과 패치의 정점이 공유되지 못하면서 "균열"이 일어나게 된다.

 

이를 방지하기 위해서 균열이 일어날 경우의 수를 알아야 한다.

총 16개의 경우의 수가 있다. 한 개의 정수형 변수에 저장하기 위해서 8421코드를 사용하였다.

8421 코드는 4비트의 2진수로 0000~1111로 최대 16개의 경우의 수를 표현해주는 역할이다.

 

해당 노드의 LOD 레벨이 이웃레벨의 LOD레벨보다 크다면

각 방향에 해당하는 8421코드를 더해서 조합을 한다.

그리고 해당하는 버퍼에 넣어주는 알고리즘이다.

 

BCD(Binary-Coded Decimal) 코드: 8421 코드

 

더보기
bool	KQuadtree::Render(ID3D11DeviceContext* pContext, KVector3* vCamera)
{		
	for (int iNode = 0; iNode < m_pLeafList.size(); iNode++)
	{
		int iLodLevel = 0;
		float fDistance = (m_pLeafList[iNode]->m_vCenter - *vCamera).Length();
		if (fDistance < 50.0f)
		{
			m_pLeafList[iNode]->m_iLodLevel = 2;
		}
		else if (fDistance < 100.0f)
		{
			m_pLeafList[iNode]->m_iLodLevel = 1;
		}		
		else
			m_pLeafList[iNode]->m_iLodLevel = 0;
	}
	for (int iNode = 0; iNode < m_pLeafList.size(); iNode++)
	{
		int iRenderCode = 0;
		// 동서남북
		if (m_pLeafList[iNode]->m_NeighborList[0] &&
			m_pLeafList[iNode]->m_iLodLevel < m_pLeafList[iNode]->m_NeighborList[0]->m_iLodLevel)
		{
			iRenderCode += 2;
		}
		if (m_pLeafList[iNode]->m_NeighborList[1] && 
			m_pLeafList[iNode]->m_iLodLevel < m_pLeafList[iNode]->m_NeighborList[1]->m_iLodLevel)
		{
			iRenderCode += 8;
		}
		if (m_pLeafList[iNode]->m_NeighborList[2] && 
			m_pLeafList[iNode]->m_iLodLevel < m_pLeafList[iNode]->m_NeighborList[2]->m_iLodLevel)
		{
			iRenderCode += 4;
		}
		if (m_pLeafList[iNode]->m_NeighborList[3] && 
			m_pLeafList[iNode]->m_iLodLevel < m_pLeafList[iNode]->m_NeighborList[3]->m_iLodLevel)
		{
			iRenderCode += 1;
		}
		UINT iNumIndex = 0;
		ID3D11Buffer * pRenderBuffer = nullptr;
		UINT iLodLevel = m_pLeafList[iNode]->m_iLodLevel;
		if (m_pLeafList[iNode]->m_iLodLevel ==  0)
		{
			iNumIndex = m_LodPatchList[iLodLevel].IndexList[iRenderCode].size();
			pRenderBuffer = m_LodPatchList[iLodLevel].IndexBufferList[iRenderCode];
		}
		else if (m_pLeafList[iNode]->m_iLodLevel == 1)
		{
			iNumIndex = m_LodPatchList[iLodLevel].IndexList[iRenderCode].size();
			pRenderBuffer = m_LodPatchList[iLodLevel].IndexBufferList[iRenderCode];
		}
		else
		{
			iNumIndex = m_IndexList.size();
			pRenderBuffer = m_pIndexBuffer;
		}
	}
	return true;
}

 

COMMENT