기존에 Terrain 코드를 작성하면서 느낀 점으로 높이 맵 파일을 구하기가 어렵다는 것이었다. 툴에 익숙한 고수들은 Maya나 Max 로 제작한다는 것 같기도 한데, 그 부분은 내가 잘 모르겠어서 스스로 높이 맵 제작 툴을 만들어 보기로 계획했다.
우선 목표 기능으로
- X by Y 의 격자 생성과,
- 격자내의 한 점의 높이를 수정하는 기능,
- 마지막으로 해당 높이정보와 계산된 법선벡터를 비트맵으로 저장하는 기능까지다.
오늘은 그 첫 번째로 X by Y 격자 생성 부분까지 완료된 내용에 대한 포스팅이다.
결과물부터 보자.
오…단순한UI
마우스 휠을 통하여 카메라의 Z 값을 조절할 수 있다.
View 는 이전 포스팅에서 언급한 CD3DX9Wnd 클래스를 약간 수정하여 사용하였다.
(결국은 상속이 답인듯?)
이번엔 다른 부분 보다 Terrain의 격자 생성 부분을 보도록 하자.
terrain.h
#pragma once #include#include #include struct Terrain_Vertex { float x, y, z; float nx, ny, nz; float tu, tv; enum { FVF = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1 }; }; class Terrain { public: Terrain(void); ~Terrain(void); LPD3DXMESH GetMesh(){ return m_pTerrainMesh; }; void CreateTerrain(LPDIRECT3DDEVICE9 device, DWORD dwWidth, DWORD dwHeight); private: UINT m_dwTerrainVertices; UINT m_dwTerrainPrimitives; UINT m_uiTerrainX; UINT m_uiTerrainY; LPD3DXMESH m_pTerrainMesh; };
terrain.cpp
D3DVERTEXELEMENT9 VERTEX_DECL[] = { { 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, { 0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0}, { 0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0}, D3DDECL_END() }; void Terrain::CreateTerrain(LPDIRECT3DDEVICE9 device, DWORD dwWidth, DWORD dwHeight) { assert(device != NULL); assert(dwWidth != 0); assert(dwHeight!= 0); ////////////////////////////////////////////////////////////////////////// m_uiTerrainX = dwWidth; m_uiTerrainY = dwHeight; m_dwTerrainVertices = (m_uiTerrainX + 1) * (m_uiTerrainY + 1); m_dwTerrainPrimitives = m_uiTerrainX * m_uiTerrainY * 2; ////////////////////////////////////////////////////////////////////////// Terrain_Vertex* pVertexData = NULL; DWORD* pIndexData = NULL; LPVOID pData = NULL; ////////////////////////////////////////////////////////////////////////// pVertexData = new Terrain_Vertex[m_dwTerrainVertices]; for(unsigned int y = 0;y < (m_uiTerrainY + 1);++y) { for(unsigned int x = 0;x < (m_uiTerrainX + 1);++x) { pVertexData[x + y * (m_uiTerrainX + 1)].x = (float)x - m_uiTerrainX / 2; pVertexData[x + y * (m_uiTerrainX + 1)].y = 0; pVertexData[x + y * (m_uiTerrainX + 1)].z = (float)y - m_uiTerrainY / 2; // 노말 정보는 아래에서계산 pVertexData[x + y * (m_uiTerrainX + 1)].nx = 0.0f; pVertexData[x + y * (m_uiTerrainX + 1)].ny = 1.0f; pVertexData[x + y * (m_uiTerrainX + 1)].nz = 0.0f; pVertexData[x + y * (m_uiTerrainX + 1)].tu = (float)x / (float)m_uiTerrainX; pVertexData[x + y * (m_uiTerrainX + 1)].tv = (float)y / (float)m_uiTerrainX; } } ////////////////////////////////////////////////////////////////////////// pIndexData = new DWORD[m_dwTerrainPrimitives * 3]; for(unsigned int y = 0;y < m_uiTerrainY;++y) { for(unsigned int x = 0;x < m_uiTerrainX;++x) { unsigned int index = (x + y * m_uiTerrainY) * 6; pIndexData[index + 0] = x + y * (m_uiTerrainX + 1); pIndexData[index + 1] = x + 1 + y * (m_uiTerrainX + 1); pIndexData[index + 2] = x + 1 + (y + 1) * (m_uiTerrainX + 1); pIndexData[index + 3] = x + y * (m_uiTerrainX + 1); pIndexData[index + 4] = x + 1 + (y + 1) * (m_uiTerrainX + 1); pIndexData[index + 5] = x + (y + 1) * (m_uiTerrainX + 1); } } ////////////////////////////////////////////////////////////////////////// // Normal Calc : step 1, per face D3DXVECTOR3* pFaceNorm = new D3DXVECTOR3[m_dwTerrainPrimitives]; ZeroMemory(pFaceNorm, sizeof(D3DXVECTOR3)* m_dwTerrainPrimitives); unsigned int idx = 0; for ( unsigned int i=0; i< m_dwTerrainPrimitives*3; i+=6) { D3DXVECTOR3 p1, p2, p3, p4, p5, p6, norm; p1.x=pVertexData[pIndexData[i+0]].x; p1.y=pVertexData[pIndexData[i+0]].y; p1.z=pVertexData[pIndexData[i+0]].z; p2.x=pVertexData[pIndexData[i+1]].x; p2.y=pVertexData[pIndexData[i+1]].y; p2.z=pVertexData[pIndexData[i+1]].z; p3.x=pVertexData[pIndexData[i+2]].x; p3.y=pVertexData[pIndexData[i+2]].y; p3.z=pVertexData[pIndexData[i+2]].z; p4.x=pVertexData[pIndexData[i+3]].x; p4.y=pVertexData[pIndexData[i+3]].y; p4.z=pVertexData[pIndexData[i+3]].z; p5.x=pVertexData[pIndexData[i+4]].x; p5.y=pVertexData[pIndexData[i+4]].y; p5.z=pVertexData[pIndexData[i+4]].z; p6.x=pVertexData[pIndexData[i+5]].x; p6.y=pVertexData[pIndexData[i+5]].y; p6.z=pVertexData[pIndexData[i+5]].z; // vector calc D3DXVECTOR3 v1 = p2 - p1; D3DXVECTOR3 v2 = p2 - p3; D3DXVec3Cross(&pFaceNorm[idx], &v1, &v2); D3DXVec3Normalize(&pFaceNorm[idx], &pFaceNorm[idx]); idx++; D3DXVECTOR3 v3 = p6 - p5; D3DXVECTOR3 v4 = p6 - p4; D3DXVec3Cross(&pFaceNorm[idx], &v3, &v4); D3DXVec3Normalize(&pFaceNorm[idx], &pFaceNorm[idx]); idx++; } ////////////////////////////////////////////////////////////////////////// // Normal Calc : step 2, per vertex // 자신(점)을 참조하는 모든 페이스를 (최대 6개) 찾아서 노말을 평균낸다 for (unsigned int i=0; i< m_dwTerrainVertices; i++) { D3DXVECTOR3 sum; ZeroMemory(&sum, sizeof(D3DXVECTOR3)); for (unsigned int j=0; j< m_dwTerrainPrimitives * 3; j++) { if (i == pIndexData[j]) { sum += pFaceNorm[(int)j/3]; } } D3DXVec3Normalize(&sum, &sum); pVertexData[i].nx = sum.x; pVertexData[i].ny = sum.y; pVertexData[i].nz = sum.z; } ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// LPD3DXMESH pMesh; D3DXCreateMesh( m_dwTerrainPrimitives * 3, m_dwTerrainVertices, D3DXMESH_MANAGED | D3DXMESH_32BIT, VERTEX_DECL, device, &pMesh); pMesh->LockVertexBuffer( 0, (void**)&pData); memcpy(pData, pVertexData, sizeof(Terrain_Vertex) * m_dwTerrainVertices); pMesh->UnlockVertexBuffer(); pMesh->LockIndexBuffer(0, (void**)&pData ); memcpy( pData, pIndexData, sizeof(DWORD) * m_dwTerrainPrimitives * 3 ); pMesh->UnlockIndexBuffer(); DWORD* pSubset; pMesh->LockAttributeBuffer(0, &pSubset); memset( pSubset, 0, sizeof(DWORD) * m_dwTerrainPrimitives); pMesh->UnlockAttributeBuffer(); DWORD* aAdjacency = new DWORD[pMesh->GetNumFaces() * 3]; pMesh->GenerateAdjacency( 1e-6f, aAdjacency ); pMesh->OptimizeInplace( D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_VERTEXCACHE, aAdjacency, NULL, NULL, NULL ); delete aAdjacency; if (m_pTerrainMesh != NULL) { m_pTerrainMesh->Release(); m_pTerrainMesh = NULL; } m_pTerrainMesh = pMesh; ////////////////////////////////////////////////////////////////////////// // pointer free delete[] pVertexData; delete[] pIndexData; delete[] pFaceNorm; }
'Dev.Write' 카테고리의 다른 글
My Simple Camera (0) | 2010.02.14 |
---|---|
높이 맵 제작 툴 만들기(2) (0) | 2010.01.20 |
MFC 기반의 Direct3DX Window (0) | 2010.01.15 |
MFC Custom_Control 연습 (0) | 2010.01.15 |
DX로 만든 첫번째 게임 프로젝트 (0) | 2010.01.08 |