[DirectX11] Terrain 01 - 그리드 및 카메라 이동
Terrain 01 - 그리드 및 카메라 이동
원문 : http://www.rastertek.com/tertut01.html
이 튜토리얼은 DirectX 11을 사용하여 지형 그리드 렌더링의 기본 사항을 다룹니다. 이 튜토리얼의 목적은 고급 지형 개념을 익히기 전에 기본 격자 지형을 렌더링하고 좋은 카메라 기능을 사용할 수 있도록 하는 것입니다. 지형을 쉽게 이동할 수 있는 우수한 카메라를 사용하면 개발 중에 발생하는 문제를 디버깅하는 데 도움이 됩니다. 우수한 디버깅 도구를 갖추는 것이 개발 속도를 높이고 품질을 보장하는 핵심 요소입니다. 또한이 듀토리얼은 DirectX 11 Basic 듀토리얼의 지식과 프레임 워크를 기반으로 합니다. 만약 기본이 갖추어져 있지 않다면 DirectX 11 Basic 듀토리얼 강좌란으로 이동하여 필요한 부분을 선행학습 하신 다음 진행하시기 바랍니다.
이 듀토리얼의 격자는 기본 100x100 단위 평면 지형입니다. TerrainClass라는 새로운 클래스는 라인으로 만들어진 쿼드를 구성하기 위해 캡슐화 하였습니다. 카메라는 또한 PositionClass라는 새로운 클래스를 기반으로 합니다 (CameraClass는 여전히 뷰 매트릭스를 만드는 데 사용되며 기능을 분리했습니다). PositionClass는 카메라가 지형 주위를 부드럽게 움직일 수 있도록 카메라의 위치와 회전 및 가속과 감속을 유지합니다. 마지막으로 TextClass를 다시 사용하여 FPS, CPU 사용량, 비디오 카드 정보 및 카메라의 위치 / 회전을 표시합니다.
프레임워크
프레임 작업에는 새로운 TerrainClass 및 PositionClass가 포함됩니다. 나머지 클래스는 이미 DirectX 11 튜토리얼 섹션에서 다루었습니다.
지형 클래스는 100x100 선 그리기를 위한 모델 데이터 및 렌더링 기능을 캡슐화합니다. 이 튜토리얼은 매우 기본적인 지형을 먼저 얻는데 중점을 둡니다.
Terrainclass.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | #pragma once class TerrainClass { private: struct VertexType { XMFLOAT3 position; XMFLOAT4 color; }; public: TerrainClass(); TerrainClass(const TerrainClass&); ~TerrainClass(); bool Initialize(ID3D11Device*, int, int); void Shutdown(); void Render(ID3D11DeviceContext*); int GetIndexCount(); private: bool InitializeBuffers(ID3D11Device*); void ShutdownBuffers(); void RenderBuffers(ID3D11DeviceContext*); private: int m_terrainWidth = 0; int m_terrainHeight = 0; int m_vertexCount = 0; int m_indexCount = 0; ID3D11Buffer* m_vertexBuffer = nullptr; ID3D11Buffer* m_indexBuffer = nullptr; }; | cs |
Terrainclass.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 | #include "stdafx.h" #include "terrainclass.h" TerrainClass::TerrainClass() { } TerrainClass::TerrainClass(const TerrainClass& other) { } TerrainClass::~TerrainClass() { } bool TerrainClass::Initialize(ID3D11Device* device, int terrainWidth, int terrainHeight) { // 지형의 너비와 높이를 설정합니다. m_terrainWidth = terrainWidth; m_terrainHeight = terrainHeight; // 지형에 대한 지오 메트릭을 포함하는 정점 및 인덱스 버퍼를 초기화합니다. return InitializeBuffers(device); } void TerrainClass::Shutdown() { // 버텍스와 인덱스 버퍼를 해제합니다. ShutdownBuffers(); } void TerrainClass::Render(ID3D11DeviceContext* deviceContext) { // 그리기를 준비하기 위해 그래픽 파이프 라인에 꼭지점과 인덱스 버퍼를 놓습니다. RenderBuffers(deviceContext); } int TerrainClass::GetIndexCount() { return m_indexCount; } bool TerrainClass::InitializeBuffers(ID3D11Device* device) { // 지형 메쉬의 정점 수를 계산합니다. m_vertexCount = (m_terrainWidth - 1) * (m_terrainHeight - 1) * 8; // 인덱스 수를 꼭지점 수와 같게 설정합니다. m_indexCount = m_vertexCount; // 정점 배열을 만듭니다. VertexType* vertices = new VertexType[m_vertexCount]; if(!vertices) { return false; } // 인덱스 배열을 만듭니다. unsigned long* indices = new unsigned long[m_indexCount]; if(!indices) { return false; } // 정점 배열에 대한 인덱스를 초기화합니다. int index = 0; // 지형 데이터로 정점 및 인덱스 배열을 로드합니다. for(int j=0; j<(m_terrainHeight-1); j++) { for(int i=0; i<(m_terrainWidth-1); i++) { // LINE 1 // 왼쪽 위. float positionX = (float)i; float positionZ = (float)(j+1); vertices[index].position = XMFLOAT3(positionX, 0.0f, positionZ); vertices[index].color = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f); indices[index] = index; index++; // 오른쪽 위. positionX = (float)(i+1); positionZ = (float)(j+1); vertices[index].position = XMFLOAT3(positionX, 0.0f, positionZ); vertices[index].color = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f); indices[index] = index; index++; // LINE 2 // 오른쪽 위. positionX = (float)(i+1); positionZ = (float)(j+1); vertices[index].position = XMFLOAT3(positionX, 0.0f, positionZ); vertices[index].color = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f); indices[index] = index; index++; // 오른쪽 아래. positionX = (float)(i+1); positionZ = (float)j; vertices[index].position = XMFLOAT3(positionX, 0.0f, positionZ); vertices[index].color = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f); indices[index] = index; index++; // LINE 3 // 오른쪽 아래. positionX = (float)(i+1); positionZ = (float)j; vertices[index].position = XMFLOAT3(positionX, 0.0f, positionZ); vertices[index].color = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f); indices[index] = index; index++; // 왼쪽 아래. positionX = (float)i; positionZ = (float)j; vertices[index].position = XMFLOAT3(positionX, 0.0f, positionZ); vertices[index].color = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f); indices[index] = index; index++; // LINE 4 // 왼쪽 아래. positionX = (float)i; positionZ = (float)j; vertices[index].position = XMFLOAT3(positionX, 0.0f, positionZ); vertices[index].color = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f); indices[index] = index; index++; // 왼쪽 위. positionX = (float)i; positionZ = (float)(j+1); vertices[index].position = XMFLOAT3(positionX, 0.0f, positionZ); vertices[index].color = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f); indices[index] = index; index++; } } // 정적 정점 버퍼의 구조체를 설정한다. D3D11_BUFFER_DESC vertexBufferDesc; vertexBufferDesc.Usage = D3D11_USAGE_DEFAULT; vertexBufferDesc.ByteWidth = sizeof(VertexType) * m_vertexCount; vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; vertexBufferDesc.CPUAccessFlags = 0; vertexBufferDesc.MiscFlags = 0; vertexBufferDesc.StructureByteStride = 0; // subresource 구조에 정점 데이터에 대한 포인터를 제공합니다. D3D11_SUBRESOURCE_DATA vertexData; vertexData.pSysMem = vertices; vertexData.SysMemPitch = 0; vertexData.SysMemSlicePitch = 0; // 이제 정점 버퍼를 만듭니다. if(FAILED(device->CreateBuffer(&vertexBufferDesc, &vertexData, &m_vertexBuffer))) { return false; } // 정적 인덱스 버퍼의 구조체를 설정합니다. D3D11_BUFFER_DESC indexBufferDesc; indexBufferDesc.Usage = D3D11_USAGE_DEFAULT; indexBufferDesc.ByteWidth = sizeof(unsigned long) * m_indexCount; indexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER; indexBufferDesc.CPUAccessFlags = 0; indexBufferDesc.MiscFlags = 0; indexBufferDesc.StructureByteStride = 0; // 하위 리소스 구조에 인덱스 데이터에 대한 포인터를 제공합니다. D3D11_SUBRESOURCE_DATA indexData; indexData.pSysMem = indices; indexData.SysMemPitch = 0; indexData.SysMemSlicePitch = 0; // 인덱스 버퍼를 만듭니다. if(FAILED(device->CreateBuffer(&indexBufferDesc, &indexData, &m_indexBuffer))) { return false; } // 이제 버퍼가 생성되고 로드된 배열을 해제하십시오. delete [] vertices; vertices = 0; delete [] indices; indices = 0; return true; } void TerrainClass::ShutdownBuffers() { // 인덱스 버퍼를 해제합니다. if(m_indexBuffer) { m_indexBuffer->Release(); m_indexBuffer = 0; } // 버텍스 버퍼를 해제합니다. if(m_vertexBuffer) { m_vertexBuffer->Release(); m_vertexBuffer = 0; } } void TerrainClass::RenderBuffers(ID3D11DeviceContext* deviceContext) { // 정점 버퍼 보폭 및 오프셋을 설정합니다. unsigned int stride = sizeof(VertexType); unsigned int offset = 0; // 렌더링 할 수 있도록 입력 어셈블러에서 정점 버퍼를 활성으로 설정합니다. deviceContext->IASetVertexBuffers(0, 1, &m_vertexBuffer, &stride, &offset); // 렌더링 할 수 있도록 입력 어셈블러에서 인덱스 버퍼를 활성으로 설정합니다. deviceContext->IASetIndexBuffer(m_indexBuffer, DXGI_FORMAT_R32_UINT, 0); // 이 버텍스 버퍼에서 렌더링되어야하는 프리미티브의 타입을 설정한다.이 경우 라인리스트이다. deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST); } | cs |
PositionClass는 카메라 / 뷰어 위치와 카메라 이동 기능을 캡슐화하는 클래스입니다.
Positionclass.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | #pragma once class PositionClass { public: PositionClass(); PositionClass(const PositionClass&); ~PositionClass(); void SetPosition(XMFLOAT3); void SetRotation(XMFLOAT3); void GetPosition(XMFLOAT3&); void GetRotation(XMFLOAT3&); void SetFrameTime(float); void MoveForward(bool); void MoveBackward(bool); void MoveUpward(bool); void MoveDownward(bool); void TurnLeft(bool); void TurnRight(bool); void LookUpward(bool); void LookDownward(bool); private: XMFLOAT3 m_position = XMFLOAT3(0.0f, 0.0f, 0.0f); XMFLOAT3 m_rotation = XMFLOAT3(0.0f, 0.0f, 0.0f); float m_frameTime = 0; float m_forwardSpeed = 0; float m_backwardSpeed = 0; float m_upwardSpeed = 0; float m_downwardSpeed = 0; float m_leftTurnSpeed = 0; float m_rightTurnSpeed = 0; float m_lookUpSpeed = 0; float m_lookDownSpeed = 0; }; | cs |
Positionclass.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 | #include "stdafx.h" #include "PositionClass.h" PositionClass::PositionClass() { } PositionClass::PositionClass(const PositionClass& other) { } PositionClass::~PositionClass() { } void PositionClass::SetPosition(XMFLOAT3 pos) { m_position = pos; } void PositionClass::SetRotation(XMFLOAT3 rot) { m_rotation = rot; } void PositionClass::GetPosition(XMFLOAT3& p) { p = m_position; } void PositionClass::GetRotation(XMFLOAT3& p) { p = m_rotation; } void PositionClass::SetFrameTime(float time) { m_frameTime = time; } void PositionClass::MoveForward(bool keydown) { // 키를 누르면 카메라가 왼쪽으로 돌아는 속도가 증가합니다. 회전 속도를 늦추지 않으면. if (keydown) { m_forwardSpeed += m_frameTime * 0.001f; if(m_forwardSpeed > (m_frameTime * 0.03f)) { m_forwardSpeed = m_frameTime * 0.03f; } } else { m_forwardSpeed -= m_frameTime * 0.0007f; if(m_forwardSpeed < 0.0f) { m_forwardSpeed = 0.0f; } } // 값을 라디안으로 변환하십시오. float radians = m_rotation.y * 0.0174532925f; // 위치를 업데이트 합니다. m_position.x += sinf(radians) * m_forwardSpeed; m_position.z += cosf(radians) * m_forwardSpeed; } void PositionClass::MoveBackward(bool keydown) { // 키를 누르면 카메라가 오른쪽으로 회전하는 속도가 증가합니다. 회전 속도를 늦추지 않으면. if (keydown) { m_backwardSpeed += m_frameTime * 0.001f; if(m_backwardSpeed > (m_frameTime * 0.03f)) { m_backwardSpeed = m_frameTime * 0.03f; } } else { m_backwardSpeed -= m_frameTime * 0.0007f; if(m_backwardSpeed < 0.0f) { m_backwardSpeed = 0.0f; } } // 값을 라디안으로 변환하십시오. float radians = m_rotation.y * 0.0174532925f; // 위치를 업데이트 합니다. m_position.x -= sinf(radians) * m_backwardSpeed; m_position.z -= cosf(radians) * m_backwardSpeed; } void PositionClass::MoveUpward(bool keydown) { // 사용자가 키를 누르고 있는 프레임 시간에 따라 상향 이동 속도를 갱신합니다. if(keydown) { m_upwardSpeed += m_frameTime * 0.003f; if(m_upwardSpeed > (m_frameTime * 0.03f)) { m_upwardSpeed = m_frameTime * 0.03f; } } else { m_upwardSpeed -= m_frameTime * 0.002f; if(m_upwardSpeed < 0.0f) { m_upwardSpeed = 0.0f; } } // 높이 위치를 업데이트 합니다. m_position.y += m_upwardSpeed; } void PositionClass::MoveDownward(bool keydown) { // 사용자가 키를 누르고 있는 프레임 시간에 따라 하향 이동 속도를 갱신합니다. if(keydown) { m_downwardSpeed += m_frameTime * 0.003f; if(m_downwardSpeed > (m_frameTime * 0.03f)) { m_downwardSpeed = m_frameTime * 0.03f; } } else { m_downwardSpeed -= m_frameTime * 0.002f; if(m_downwardSpeed < 0.0f) { m_downwardSpeed = 0.0f; } } // 높이 위치를 업데이트 합니다. m_position.y -= m_downwardSpeed; } void PositionClass::TurnLeft(bool keydown) { // 사용자가 키를 누르고 있는 프레임 시간에 따라 왼쪽 회전 속도를 갱신합니다. if(keydown) { m_leftTurnSpeed += m_frameTime * 0.01f; if(m_leftTurnSpeed > (m_frameTime * 0.15f)) { m_leftTurnSpeed = m_frameTime * 0.15f; } } else { m_leftTurnSpeed -= m_frameTime* 0.005f; if(m_leftTurnSpeed < 0.0f) { m_leftTurnSpeed = 0.0f; } } // 회전을 업데이트 합니다. m_rotation.y -= m_leftTurnSpeed; // 회전값의 범위를 0 ~360 에서 유지합니다. if(m_rotation.y < 0.0f) { m_rotation.y += 360.0f; } } void PositionClass::TurnRight(bool keydown) { // 사용자가 키를 누르고 있는 프레임 시간에 따라 오른쪽 회전 속도를 갱신합니다. if(keydown) { m_rightTurnSpeed += m_frameTime * 0.01f; if(m_rightTurnSpeed > (m_frameTime * 0.15f)) { m_rightTurnSpeed = m_frameTime * 0.15f; } } else { m_rightTurnSpeed -= m_frameTime* 0.005f; if(m_rightTurnSpeed < 0.0f) { m_rightTurnSpeed = 0.0f; } } // 회전을 업데이트 합니다. m_rotation.y += m_rightTurnSpeed; // 회전값의 범위를 0 ~360 에서 유지합니다. if(m_rotation.y > 360.0f) { m_rotation.y -= 360.0f; } } void PositionClass::LookUpward(bool keydown) { // 사용자가 키를 누르고 있는 프레임 시간에 따라 위쪽 회전 속도를 갱신합니다. if(keydown) { m_lookUpSpeed += m_frameTime * 0.01f; if(m_lookUpSpeed > (m_frameTime * 0.15f)) { m_lookUpSpeed = m_frameTime * 0.15f; } } else { m_lookUpSpeed -= m_frameTime* 0.005f; if(m_lookUpSpeed < 0.0f) { m_lookUpSpeed = 0.0f; } } // 회전을 업데이트 합니다. m_rotation.x -= m_lookUpSpeed; // 회전은 최대 90 도로 유지 합니다. if(m_rotation.x > 90.0f) { m_rotation.x = 90.0f; } } void PositionClass::LookDownward(bool keydown) { // 사용자가 키를 누르고 있는 프레임 시간에 따라 아래쪽 회전 속도를 갱신합니다. if(keydown) { m_lookDownSpeed += m_frameTime * 0.01f; if(m_lookDownSpeed > (m_frameTime * 0.15f)) { m_lookDownSpeed = m_frameTime * 0.15f; } } else { m_lookDownSpeed -= m_frameTime* 0.005f; if(m_lookDownSpeed < 0.0f) { m_lookDownSpeed = 0.0f; } } // 회전을 업데이트 합니다. m_rotation.x += m_lookDownSpeed; //회전은 최대 90 도로 유지 합니다. if(m_rotation.x < -90.0f) { m_rotation.x = -90.0f; } } | cs |
SystemClass는 DirectX 튜토리얼 버전에서 약간 수정되었습니다. 이제는 Windows 초기화 및 새 ApplicationClass 만 포함됩니다.
Systemclass.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | #pragma once class ApplicationClass; class SystemClass { public: SystemClass(); SystemClass(const SystemClass&); ~SystemClass(); bool Initialize(); void Shutdown(); void Run(); LRESULT CALLBACK MessageHandler(HWND, UINT, WPARAM, LPARAM); private: bool Frame(); void InitializeWindows(int&, int&); void ShutdownWindows(); private: LPCWSTR m_applicationName; HINSTANCE m_hinstance; HWND m_hwnd; ApplicationClass* m_Application = nullptr; }; static LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); static SystemClass* ApplicationHandle = 0; | cs |
Systemclass.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 | #include "stdafx.h" #include "ApplicationClass.h" #include "systemclass.h" SystemClass::SystemClass() { } SystemClass::SystemClass(const SystemClass& other) { } SystemClass::~SystemClass() { } bool SystemClass::Initialize() { // 윈도우 창 가로, 세로 넓이 변수 초기화 int screenWidth = 0; int screenHeight = 0; // 윈도우 생성 초기화 InitializeWindows(screenWidth, screenHeight); // 응용 프로그램 객체를 생성합니다. m_Application = new ApplicationClass; if(!m_Application) { return false; } // 응용 프로그램 객체를 초기화 합니다. if(!m_Application->Initialize(m_hinstance, m_hwnd, screenWidth, screenHeight)) { MessageBox(m_hwnd, L"Could not initialize the application object.", L"Error", MB_OK); return false; } return true; } void SystemClass::Shutdown() { // 응용 프로그램 객체를 해제합니다. if(m_Application) { m_Application->Shutdown(); delete m_Application; m_Application = 0; } // 윈도우를 종료합니다. ShutdownWindows(); } void SystemClass::Run() { // 메시지 구조체 생성 및 초기화 MSG msg; ZeroMemory(&msg, sizeof(MSG)); // 사용자로부터 종료 메시지를 받을때까지 메시지루프를 돕니다 while (true) { // 윈도우 메시지를 처리합니다 if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { // 종료 메시지를 받을 경우 메시지 루프를 탈출합니다 if (msg.message == WM_QUIT) break; TranslateMessage(&msg); DispatchMessage(&msg); } else { // 그 외에는 Frame 함수를 처리합니다. if (!Frame()) break; } } } bool SystemClass::Frame() { // 응용 프로그램 개체에 대한 프레임 처리를 수행합니다. return m_Application->Frame(); } LRESULT CALLBACK SystemClass::MessageHandler(HWND hwnd, UINT umsg, WPARAM wparam, LPARAM lparam) { return DefWindowProc(hwnd, umsg, wparam, lparam); } void SystemClass::InitializeWindows(int& screenWidth, int& screenHeight) { // 외부 포인터를 이 객체로 지정합니다 ApplicationHandle = this; // 이 프로그램의 인스턴스를 가져옵니다 m_hinstance = GetModuleHandle(NULL); // 프로그램 이름을 지정합니다 m_applicationName = L"Dx11Terrain_01"; // windows 클래스를 아래와 같이 설정합니다. WNDCLASSEX wc; wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; wc.lpfnWndProc = WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = m_hinstance; wc.hIcon = LoadIcon(NULL, IDI_WINLOGO); wc.hIconSm = wc.hIcon; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); wc.lpszMenuName = NULL; wc.lpszClassName = m_applicationName; wc.cbSize = sizeof(WNDCLASSEX); // windows class를 등록합니다 RegisterClassEx(&wc); // 모니터 화면의 해상도를 읽어옵니다 screenWidth = GetSystemMetrics(SM_CXSCREEN); screenHeight = GetSystemMetrics(SM_CYSCREEN); int posX = 0; int posY = 0; // FULL_SCREEN 변수 값에 따라 화면을 설정합니다. if (FULL_SCREEN) { // 풀스크린 모드로 지정했다면 모니터 화면 해상도를 데스크톱 해상도로 지정하고 색상을 32bit로 지정합니다. DEVMODE dmScreenSettings; memset(&dmScreenSettings, 0, sizeof(dmScreenSettings)); dmScreenSettings.dmSize = sizeof(dmScreenSettings); dmScreenSettings.dmPelsWidth = (unsigned long)screenWidth; dmScreenSettings.dmPelsHeight = (unsigned long)screenHeight; dmScreenSettings.dmBitsPerPel = 32; dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; // 풀스크린으로 디스플레이 설정을 변경합니다. ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN); } else { // 윈도우 모드의 경우 800 * 600 크기를 지정합니다. screenWidth = 800; screenHeight = 600; // 윈도우 창을 가로, 세로의 정 가운데 오도록 합니다. posX = (GetSystemMetrics(SM_CXSCREEN) - screenWidth) / 2; posY = (GetSystemMetrics(SM_CYSCREEN) - screenHeight) / 2; } // 윈도우를 생성하고 핸들을 구합니다. m_hwnd = CreateWindowEx(WS_EX_APPWINDOW, m_applicationName, m_applicationName, WS_POPUP, posX, posY, screenWidth, screenHeight, NULL, NULL, m_hinstance, NULL); // 윈도우를 화면에 표시하고 포커스를 지정합니다 ShowWindow(m_hwnd, SW_SHOW); SetForegroundWindow(m_hwnd); SetFocus(m_hwnd); // Hide the mouse cursor. ShowCursor(false); } void SystemClass::ShutdownWindows() { // Show the mouse cursor. ShowCursor(true); // 풀스크린 모드였다면 디스플레이 설정을 초기화합니다. if (FULL_SCREEN) { ChangeDisplaySettings(NULL, 0); } // 창을 제거합니다 DestroyWindow(m_hwnd); m_hwnd = NULL; // 프로그램 인스턴스를 제거합니다 UnregisterClass(m_applicationName, m_hinstance); m_hinstance = NULL; // 외부포인터 참조를 초기화합니다 ApplicationHandle = NULL; } LRESULT CALLBACK WndProc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam) { switch (umessage) { // 윈도우 종료를 확인합니다 case WM_DESTROY: { PostQuitMessage(0); return 0; } // 윈도우가 닫히는지 확인합니다 case WM_CLOSE: { PostQuitMessage(0); return 0; } // 그 외의 모든 메시지들은 시스템 클래스의 메시지 처리로 넘깁니다. default: { return ApplicationHandle->MessageHandler(hwnd, umessage, wparam, lparam); } } } | cs |
ApplicationClass는 전체 지형 응용 프로그램의 기본 래퍼 클래스입니다. 그것은 모든 그래픽, 입력 및 처리를 처리합니다.
Applicationclass.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | #pragma once ///////////// // GLOBALS // ///////////// const bool FULL_SCREEN = false; const bool VSYNC_ENABLED = true; const float SCREEN_DEPTH = 1000.0f; const float SCREEN_NEAR = 0.1f; class D3DClass; class InputClass; class CameraClass; class TerrainClass; class ColorShaderClass; class TimerClass; class PositionClass; class FpsClass; class CpuClass; class FontShaderClass; class TextClass; class ApplicationClass { public: ApplicationClass(); ApplicationClass(const ApplicationClass&); ~ApplicationClass(); bool Initialize(HINSTANCE, HWND, int, int); void Shutdown(); bool Frame(); private: bool HandleInput(float); bool RenderGraphics(); private: InputClass* m_Input = nullptr; D3DClass* m_Direct3D = nullptr; CameraClass* m_Camera = nullptr; TerrainClass* m_Terrain = nullptr; ColorShaderClass* m_ColorShader = nullptr; TimerClass* m_Timer = nullptr; PositionClass* m_Position = nullptr; FpsClass* m_Fps = nullptr; CpuClass* m_Cpu = nullptr; FontShaderClass* m_FontShader = nullptr; TextClass* m_Text = nullptr; }; | cs |
Applicationclass.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 | #include "stdafx.h" #include "inputclass.h" #include "d3dclass.h" #include "cameraclass.h" #include "terrainclass.h" #include "colorshaderclass.h" #include "timerclass.h" #include "positionclass.h" #include "fpsclass.h" #include "cpuclass.h" #include "fontshaderclass.h" #include "textclass.h" #include "ApplicationClass.h" ApplicationClass::ApplicationClass() { } ApplicationClass::ApplicationClass(const ApplicationClass& other) { } ApplicationClass::~ApplicationClass() { } bool ApplicationClass::Initialize(HINSTANCE hinstance, HWND hwnd, int screenWidth, int screenHeight) { // 입력 개체를 생성합니다. m_Input = new InputClass; if(!m_Input) { return false; } // 입력 개체를 초기화합니다. bool result = m_Input->Initialize(hinstance, hwnd, screenWidth, screenHeight); if(!result) { MessageBox(hwnd, L"Could not initialize the input object.", L"Error", MB_OK); return false; } // Direct3D 개체를 생성합니다. m_Direct3D = new D3DClass; if(!m_Direct3D) { return false; } // Direct3D 개체를 초기화합니다. result = m_Direct3D->Initialize(screenWidth, screenHeight, VSYNC_ENABLED, hwnd, FULL_SCREEN, SCREEN_DEPTH, SCREEN_NEAR); if(!result) { MessageBox(hwnd, L"Could not initialize DirectX 11.", L"Error", MB_OK); return false; } // 카메라 객체를 생성합니다. m_Camera = new CameraClass; if(!m_Camera) { return false; } // 2D 사용자 인터페이스 렌더링을 위해 카메라로 기본 뷰 행렬을 초기화합니다. XMMATRIX baseViewMatrix; m_Camera->SetPosition(XMFLOAT3(0.0f, 0.0f, -1.0f)); m_Camera->Render(); m_Camera->GetViewMatrix(baseViewMatrix); // 카메라의 초기 위치를 설정합니다. XMFLOAT3 camera = XMFLOAT3(50.0f, 2.0f, -7.0f); m_Camera->SetPosition(camera); // 지형 객체를 생성합니다. m_Terrain = new TerrainClass; if(!m_Terrain) { return false; } // 지형 객체를 초기화 합니다. result = m_Terrain->Initialize(m_Direct3D->GetDevice(), 100, 100); if(!result) { MessageBox(hwnd, L"Could not initialize the terrain object.", L"Error", MB_OK); return false; } // 색상 쉐이더 객체를 생성합니다. m_ColorShader = new ColorShaderClass; if(!m_ColorShader) { return false; } // 색상 쉐이더 객체를 초기화합니다. result = m_ColorShader->Initialize(m_Direct3D->GetDevice(), hwnd); if(!result) { MessageBox(hwnd, L"Could not initialize the color shader object.", L"Error", MB_OK); return false; } // 타이머 객체를 생성합니다. m_Timer = new TimerClass; if(!m_Timer) { return false; } // 타이머 객체를 초기화 합니다. result = m_Timer->Initialize(); if(!result) { MessageBox(hwnd, L"Could not initialize the timer object.", L"Error", MB_OK); return false; } // 위치 개체를 생성합니다. m_Position = new PositionClass; if(!m_Position) { return false; } // 뷰어의 초기 위치를 초기 카메라 위치와 동일하게 설정합니다. m_Position->SetPosition(camera); // fps 객체를 생성합니다. m_Fps = new FpsClass; if(!m_Fps) { return false; } // fps 객체를 초기화합니다. m_Fps->Initialize(); // cpu 객체를 생성합니다. m_Cpu = new CpuClass; if(!m_Cpu) { return false; } // cpu 객체를 초기화 합니다. m_Cpu->Initialize(); // 폰트 셰이더 객체를 생성합니다. m_FontShader = new FontShaderClass; if(!m_FontShader) { return false; } // 폰트 셰이더 객체를 초기화합니다. result = m_FontShader->Initialize(m_Direct3D->GetDevice(), hwnd); if(!result) { MessageBox(hwnd, L"Could not initialize the font shader object.", L"Error", MB_OK); return false; } // 텍스트 객체를 생성합니다. m_Text = new TextClass; if(!m_Text) { return false; } // 텍스트 객체를 초기화합니다. result = m_Text->Initialize(m_Direct3D->GetDevice(), m_Direct3D->GetDeviceContext(), hwnd, screenWidth, screenHeight, baseViewMatrix); if(!result) { MessageBox(hwnd, L"Could not initialize the text object.", L"Error", MB_OK); return false; } // 비디오 카드 정보를 가져옵니다. char videoCard[128] = { 0, }; int videoMemory = 0; m_Direct3D->GetVideoCardInfo(videoCard, videoMemory); // 텍스트 객체에 비디오 카드 정보를 설정합니다. result = m_Text->SetVideoCardInfo(videoCard, videoMemory, m_Direct3D->GetDeviceContext()); if(!result) { MessageBox(hwnd, L"Could not set video card info in the text object.", L"Error", MB_OK); return false; } return true; } void ApplicationClass::Shutdown() { // 텍스트 객체를 해제합니다. if(m_Text) { m_Text->Shutdown(); delete m_Text; m_Text = 0; } // 폰트 쉐이더 객체를 해제합니다.. if(m_FontShader) { m_FontShader->Shutdown(); delete m_FontShader; m_FontShader = 0; } // cpu 객체를 해제합니다. if(m_Cpu) { m_Cpu->Shutdown(); delete m_Cpu; m_Cpu = 0; } // fps 객체를 해제합니다. if(m_Fps) { delete m_Fps; m_Fps = 0; } // 위치 객체를 해제합니다. if(m_Position) { delete m_Position; m_Position = 0; } // 타이머 객체를 해제합니다. if(m_Timer) { delete m_Timer; m_Timer = 0; } // 색상 셰이더 객체를 해제합니다. if(m_ColorShader) { m_ColorShader->Shutdown(); delete m_ColorShader; m_ColorShader = 0; } // 지형 객체를 해제합니다. if(m_Terrain) { m_Terrain->Shutdown(); delete m_Terrain; m_Terrain = 0; } // 카메라 객체를 해제합니다. if(m_Camera) { delete m_Camera; m_Camera = 0; } // D3D 객체를 해제합니다. if (m_Direct3D) { m_Direct3D->Shutdown(); delete m_Direct3D; m_Direct3D = 0; } // 입력 객체를 해제합니다. if(m_Input) { m_Input->Shutdown(); delete m_Input; m_Input = 0; } } bool ApplicationClass::Frame() { // 사용자 입력을 읽습니다. bool result = m_Input->Frame(); if(!result) { return false; } // 사용자가 ESC를 눌렀을 때 응용 프로그램을 종료 할 것인지 확인합니다. if(m_Input->IsEscapePressed() == true) { return false; } // 시스템 통계를 업데이트 합니다. m_Timer->Frame(); m_Fps->Frame(); m_Cpu->Frame(); // 텍스트 개체에서 FPS 값을 업데이트 합니다. result = m_Text->SetFps(m_Fps->GetFps(), m_Direct3D->GetDeviceContext()); if(!result) { return false; } // 텍스트 개체의 CPU 사용값을 업데이트 합니다. result = m_Text->SetCpu(m_Cpu->GetCpuPercentage(), m_Direct3D->GetDeviceContext()); if(!result) { return false; } // 프레임 입력 처리를 수행합니다. result = HandleInput(m_Timer->GetTime()); if(!result) { return false; } // 그래픽을 렌더링 합니다. result = RenderGraphics(); if(!result) { return false; } return result; } bool ApplicationClass::HandleInput(float frameTime) { XMFLOAT3 pos = XMFLOAT3(0.0f, 0.0f, 0.0f); XMFLOAT3 rot = XMFLOAT3(0.0f, 0.0f, 0.0f); // 갱신된 위치를 계산하기 위한 프레임 시간을 설정합니다. m_Position->SetFrameTime(frameTime); // 입력을 처리합니다. m_Position->TurnLeft(m_Input->IsLeftPressed()); m_Position->TurnRight(m_Input->IsRightPressed()); m_Position->MoveForward(m_Input->IsUpPressed()); m_Position->MoveBackward(m_Input->IsDownPressed()); m_Position->MoveUpward(m_Input->IsAPressed()); m_Position->MoveDownward(m_Input->IsZPressed()); m_Position->LookUpward(m_Input->IsPgUpPressed()); m_Position->LookDownward(m_Input->IsPgDownPressed()); // 시점 위치 / 회전을 가져옵니다. m_Position->GetPosition(pos); m_Position->GetRotation(rot); // 카메라의 위치를 설정합니다. m_Camera->SetPosition(pos); m_Camera->SetRotation(rot); // 텍스트 개체의 위치 값을 업데이트 합니다. if(!m_Text->SetCameraPosition(pos, m_Direct3D->GetDeviceContext())) { return false; } // 텍스트 객체의 회전 값을 업데이트 합니다. if(!m_Text->SetCameraRotation(rot, m_Direct3D->GetDeviceContext())) { return false; } return true; } bool ApplicationClass::RenderGraphics() { XMMATRIX worldMatrix, viewMatrix, projectionMatrix, orthoMatrix; // 장면을 지웁니다. m_Direct3D->BeginScene(0.0f, 0.0f, 0.0f, 1.0f); // 카메라의 위치에 따라 뷰 행렬을 생성합니다. m_Camera->Render(); // 카메라 및 Direct3D 객체에서 월드, 뷰, 투영 및 ortho 행렬을 가져옵니다. m_Direct3D->GetWorldMatrix(worldMatrix); m_Camera->GetViewMatrix(viewMatrix); m_Direct3D->GetProjectionMatrix(projectionMatrix); m_Direct3D->GetOrthoMatrix(orthoMatrix); // 지형 버퍼를 렌더링 합니다. m_Terrain->Render(m_Direct3D->GetDeviceContext()); // 색상 쉐이더를 사용하여 모델을 렌더링 합니다. if(!m_ColorShader->Render(m_Direct3D->GetDeviceContext(), m_Terrain->GetIndexCount(), worldMatrix, viewMatrix, projectionMatrix)) { return false; } // 모든 2D 렌더링을 시작하려면 Z 버퍼를 끕니다. m_Direct3D->TurnZBufferOff(); // 텍스트를 렌더링하기 전에 알파 블렌딩을 켭니다. m_Direct3D->TurnOnAlphaBlending(); // 텍스트 사용자 인터페이스 요소를 렌더링 합니다. if(!m_Text->Render(m_Direct3D->GetDeviceContext(), m_FontShader, worldMatrix, orthoMatrix)) { return false; } // 텍스트를 렌더링 한 후 알파 블렌딩을 끕니다. m_Direct3D->TurnOffAlphaBlending(); // 모든 2D 렌더링이 완료되었으므로 Z 버퍼를 다시 켭니다. m_Direct3D->TurnZBufferOn(); // 렌더링 된 장면을 화면에 표시합니다. m_Direct3D->EndScene(); return true; } | cs |
출력 화면
마치면서
이제 100x100 사이즈의 지형 그리드를 움직이는 매우 반응이 빠른 카메라를 갖게되었습니다. 또한 디버깅을 위해 사용자 인터페이스에 위치 및 회전이 표시됩니다.
연습문제
1. 코드를 다시 컴파일하고 지형 그리드를 따라 이동하십시오. 화살표 키와 A 및 Z 키를 사용하여 위아래로 이동하십시오. PgUp 및 PgDn을 사용하여 뷰를 위아래로 회전합니다.
2. 입력 키를 원하는 설정으로 변경하십시오.
3. strafing 기능을 포지션 클래스에 추가하십시오.
소스코드
소스코드 : Dx11Terrain_01.zip
'DirectX 11 > Terrain' 카테고리의 다른 글
[DirectX 11] Terrain 06 - 높이 기반 이동 (0) | 2018.02.06 |
---|---|
[DirectX 11] Terrain 05 - 쿼드 트리 (0) | 2018.02.05 |
[DirectX11] Terrain 04 - 지형 텍스처 (0) | 2018.02.04 |
[DirectX11] Terrain 03 - 지형 조명 (0) | 2018.02.04 |
[DirectX11] Terrain 02 - 높이 맵 (1) | 2018.02.02 |