|
유튜브 동영상 강의 주소
(1) https://youtu.be/FUSxIU1vpsU (2) https://youtu.be/O3fC-qDeUKc (3) https://youtu.be/8xUspUahdFw
소스는 자료실에 다운로드 하시면 됩니다. ^^
삼각형을 연결하여 사각형을 만들 듯이 삼각형으로 다음과 같은 지면을 만들 수 있다.
|
|
[그림 11-1] 지면
위의 지면 격자는 지형을 표현할 때 아래 [그림 11-2]와 같이 사용된다.
[그림 11-2] 지형
11.1 지면 생성
지면을 만들기 위한 여러 가지 방법이 있지만 여기서는 삼각형을 연결한 Triangle List를 사용한다.
Triangle List로 출력하기 위해 정점 버퍼와 인덱스 버퍼를 사용하며 행과 열로 나열된 정점을 인덱스로 연결하여
격자를 만들면 된다.
지면 생성에서 가장 핵심은 삼각형 인덱스를 만드는 것이며 격자가 행과 열 단위이므로 격자의 정점 인덱스를 설정하는
규칙을 식으로 만들어 설정하는 것이 가장 중요하다.
1) 정점 개수
예로 가로 3개의 격자와 세로 2개의 격자로 이루어진 지면을 만든다고 한다면 총 정점의 개수는
‘총 정점 개수 = ( 가로 개수 + 1 ) ☓ ( 세로 개수 + 1)’ 로 구할 수 있다.
[그림 11-3] 정점
2) 정점의 위치 설정
정점마다 일정한 간격이 있으므로 이 간격을 이용하여 시작 위치에서부터 일정 거리만큼 떨어진 위치를 계산하면 된다.
[그림 11-4] 정점 위치 규칙
위 [그림 11-4]과 같이 좌측 상단에서 우측 하단으로 정점을 설정하려면 최초 시작 위치는 아래 [식 11-1]에 의해
구할 수 있다.
시작위치 = -1.0f * 격자 가로 개수 * 정점 간격 * 0.5f |
[식 11-1] 시작 위치 식
위의 식에서 0.5f는 과 같다.
3) 정점과 정점 버퍼 생성
[식 11-1]의 식을 이용하여 행과 열의 개수 그리고 간격을 입력받아 정점을 생성하여 정점 버퍼에 저장하는 소스는
다음과 같다.
struct GROUNDVERTEX { D3DXVECTOR3 vPos; DWORD dwDiffuse; };
#define D3DFVF_GROUNDVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE)
void CGround::Create( LPDIRECT3DDEVICE9 pd3dDevice, int nRow, int nCol, float fSize ) { m_nCol = nCol; m_nRow = nRow;
m_dwNumVertices = (m_nCol + 1)*(m_nRow + 1); m_dwNumIndices = m_nCol * m_nRow * 6; m_pd3dDevice = pd3dDevice;
GROUNDVERTEX *pGroundVertex = new GROUNDVERTEX[m_dwNumVertices];
// Note: 시작 위치 int nIndex = 0; D3DXVECTOR3 vPos0( -1.0f * m_nCol * fSize * 0.5f, 0.0f, m_nRow * fSize * 0.5f); for( int z = 0 ; z <= m_nRow ; z++ ) { for( int x = 0 ; x <= m_nCol ; x++ ) { pGroundVertex[nIndex].vPos.x = vPos0.x + ( fSize * x ); pGroundVertex[nIndex].vPos.y = 0.0f; pGroundVertex[nIndex].vPos.z = vPos0.z + -1.0f*( fSize * z ); pGroundVertex[nIndex].dwDiffuse = D3DCOLOR_RGBA( 255, 50, 255, 255); nIndex++; } }
//Note: 버텍스 버퍼 생성 if(m_pd3dDevice->CreateVertexBuffer( m_dwNumVertices*sizeof(GROUNDVERTEX), 0, D3DFVF_GROUNDVERTEX, D3DPOOL_DEFAULT, &m_pVB, 0 ) != D3D_OK ) { MessageBox( NULL, "정정 버퍼 생성 Error", "Error", MB_OK ); return ; }
void *pVertices; if( m_pVB->Lock( 0, 0, &pVertices, NULL ) != D3D_OK ) { MessageBox( NULL, "정정 버퍼 lock Error", "Error", MB_OK ); return ; } memcpy( pVertices, pGroundVertex, m_dwNumVertices*sizeof(GROUNDVERTEX)); m_pVB->Unlock(); |
[소스 11-1] 정점과 정점 버퍼 생성
4) 인덱스와 인덱스 버퍼 생성
인덱스 버퍼를 생성하기 위해서 먼저 설정할 인덱스의 개수를 구해야 한다.
아래 [그림 11-5]과 같이 두 개의 삼각형으로 이뤄지는 정사각형 하나는 6개의 인덱스로 구성되므로 [식 11-2]와 같이 만들 수 있다.
[그림 11-5] 사각형의 구조
인덱스의 총 개수 = 행 * 열 * 6 |
[식 11-2]
이제 인덱스를 생성해 보자.
먼저 정점은 좌상단에서 우하단의 방향으로 나열되어 있음을 생각하고 시계방향으로 인덱스를 지정할 수 있도록 규칙을 찾아야 한다.
한 격자에 대한 인덱스를 설정하는 순서는 [그림 11-6] 과 같이 정하였으며 삼각형의 인덱스는 (1, 2, 3), (4, 5, 6) 이 된다.
그리고 전체 격자를 사각형 단위로 행과 열로 나열하면 [그림 11-7]과 같으며 지면은 2행 3열로 구성되어 있다.
[그림 11-6] 정점의 인덱스 순서
[그림 11-7] 2행 3열의 정점
행과 열이라는 이차원의 개념을 일차원으로 변환하여 사각형을 한 단위로 인덱스를 설정하면 아래와 같다.
z : 행 인덱스 , x : 열 인덱스 col : 열의 개수
① 번 인덱스 = z * ( col + 1 ) + x = 0 * ( 3 + 1 ) + 0 = 0 ② 번 인덱스 = ( z + 1 )* ( col + 1 ) + x + 1 = 0 * ( 3 + 1 ) + 0 + 1 = 5 ③ 번 인덱스 = ( z + 1 )*( col + 1 ) + x = ( 0 + 1 )*( 3 + 1 ) + 0 = 4 ④ 번 인덱스 = z * ( col + 1 ) + x = 0 * ( 3 + 1 ) + 0 = 0 ⑤ 번 인덱스 = z * ( col + 1 ) + x + 1 = 0 * ( 3 + 1 ) + 0 + 1 = 1 ⑥ 번 인덱스 = ( z + 1 )*( col + 1 ) + x + 1 = ( 0 + 1 )*( 3 + 1 ) + 0 + 1 = 5 |
|
이제까지의 내용을 기반으로 코드를 작성하면 아래와 같다.
//Note: 인덱스 버퍼 생성 WORD *pIndex = new WORD[m_dwNumIndices]; nIndex = 0; for( int z = 0 ; z < m_nRow ; z++ ) { for( int x = 0 ; x < m_nCol ; x++ ) { pIndex[ nIndex++ ] = WORD( z * ( m_nCol + 1 ) + x ); pIndex[ nIndex++ ] = WORD( ( z + 1 )*( m_nCol + 1 ) + x + 1); pIndex[ nIndex++ ] = WORD( ( z + 1 )*( m_nCol + 1 ) + x );
pIndex[ nIndex++ ] = WORD( z * ( m_nCol + 1 ) + x ); pIndex[ nIndex++ ] = WORD( z * ( m_nCol + 1 ) + x + 1); pIndex[ nIndex++ ] = WORD( ( z + 1 )*( m_nCol + 1 ) + x + 1); } }
void *pIndices; m_pd3dDevice->CreateIndexBuffer( m_dwNumIndices*sizeof(WORD), 0, D3DFMT_INDEX16, D3DPOOL_DEFAULT, &m_pIB, NULL ); m_pIB->Lock( 0, 0, (void**)&pIndices, 0 ); memcpy( pIndices, pIndex, sizeof(WORD)*m_dwNumIndices ); m_pIB->Unlock();
delete [] pIndex; delete [] pGroundVertex; } |
[소스 11-2] 인덱스와 인덱스 버퍼 생성
11.2 출력
지면은 정점과 인덱스의 생성이 조금 까다로울 뿐이지 정점 버퍼와 인덱스 버퍼를 이용한 출력은 앞서 살펴본
일반적인 출력과 같다.
void CGround::OnRender() { D3DXMATRIX matWorld; D3DXMatrixIdentity( &matWorld );
m_pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE ); m_pd3dDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_WIREFRAME );
m_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld); m_pd3dDevice->SetStreamSource( 0, m_pVB, 0, sizeof( GROUNDVERTEX ) ); m_pd3dDevice->SetIndices( m_pIB ); m_pd3dDevice->SetFVF( D3DFVF_GROUNDVERTEX ); m_pd3dDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, 0, 0, m_dwNumVertices, 0, m_dwNumIndices/3 ); m_pd3dDevice->SetRenderState( D3DRS_LIGHTING, TRUE ); } |
[소스 11-3] 출력
첫댓글 지면에다 텍스쳐나 그림은 어떻게 붙이는거죠??