本文由zhangbaochong原创,转载请注明出处http://www.cnblogs.com/zhangbaochong/p/5827714.html
在前面我们曾经实现过简单的地形(Directx11学习笔记【十三】 实现一个简单地形),只不过原来使用一个固定的函数获得地形高度,这样跟真实的地形差距比较大。接下来让我们学习使用高度图来进行三维地形模拟。
1.高度图
高度图其实就是一组连续的数组,这个数组中的元素与地形网格中的顶点一一对应,且每一个元素都指定了地形网格的某个顶点的高度值。高度图最常用的使用灰度图实现,灰度图中亮度越大对应的地形高度越高。下面就是一幅灰度图:
灰度图格式通常为.raw,google一下高度图保存图片改为raw格式就可以了。高度图每个元素通常只分配一个字节,即数值在0~255之间。但在实际使用的时候经常要对高度进行比例变换,因此需要将byte转为float,然后通过一个缩放系数进行缩放,这样就不必拘泥于0~255这么一个范围了。
2.读取高度图
读取高度图很简单,用二进制读取文件就好了。
1 //读取高度图信息 2 bool TerrainDemo::ReadRawFile(std::string filePath) 3 { 4 std::ifstream inFile; 5 //二进制方式打开文件 6 inFile.open(filePath.c_str(), std::ios::binary); 7 //文件指针移动到末尾 8 inFile.seekg(0, std::ios::end); 9 //大小为当前缓冲区大小 10 std::vectorinData(inFile.tellg()); 11 //文件指针移动到开头 12 inFile.seekg(std::ios::beg); 13 //读取高度信息 14 inFile.read((char*)&inData[0], inData.size()); 15 inFile.close(); 16 17 m_heightInfos.resize(inData.size()); 18 for (int i = 0; i < inData.size(); ++i) 19 { 20 m_heightInfos[i] = inData[i]; 21 } 22 23 return true; 24 }
3.顶点和索引的计算
顶点和索引的计算同Directx11学习笔记【十三】 实现一个简单地形类似,这里就不再详细说明了。不一样的由于采用了纹理光照渲染,所以需要得到法线,在计算索引的同时需要把顶点法线计算出来:
1 //计算法线 2 void TerrainDemo::ComputeNomal(Vertex& v1, Vertex& v2, Vertex& v3, XMFLOAT3& normal) 3 { 4 XMFLOAT3 f1(v2.pos.x - v1.pos.x, v2.pos.y - v1.pos.y, v2.pos.z - v1.pos.z); 5 XMFLOAT3 f2(v3.pos.x - v1.pos.x, v3.pos.y - v1.pos.y, v3.pos.z - v1.pos.z); 6 XMVECTOR vec1 = XMLoadFloat3(&f1); 7 XMVECTOR vec2 = XMLoadFloat3(&f2); 8 XMVECTOR temp = XMVector3Normalize(XMVector3Cross(vec1, vec2)); 9 XMStoreFloat3(&normal, temp); 10 }
计算顶点和索引:
1 bool TerrainDemo::InitTerrain(float width, float height, UINT m, UINT n,float scale) 2 { 3 m_cellsPerRow = m; 4 m_cellsPerCol = n; 5 m_verticesPerRow = m + 1; 6 m_verticesPerCol = n + 1; 7 m_numsVertices = m_verticesPerRow*m_verticesPerCol; 8 m_width = width; 9 m_height = height; 10 m_heightScale = scale; 11 12 //得到缩放后的高度 13 for (auto& item : m_heightInfos) 14 { 15 item *= m_heightScale; 16 } 17 18 //起始x z坐标 19 float oX = -width * 0.5f; 20 float oZ = height * 0.5f; 21 //每一格坐标变化 22 float dx = width / m; 23 float dz = height / n; 24 25 m_vertices.resize(m_numsVertices); 26 //计算顶点 27 for (UINT i = 0; i < m_verticesPerCol; ++i) 28 { 29 float tempZ = oZ - dz * i; 30 for (UINT j = 0; j < m_verticesPerRow; ++j) 31 { 32 UINT index = m_verticesPerRow * i + j; 33 m_vertices[index].pos.x = oX + dx * j; 34 m_vertices[index].pos.y = m_heightInfos[index]; 35 m_vertices[index].pos.z = tempZ; 36 37 m_vertices[index].tex = XMFLOAT2(dx*i, dx*j); 38 } 39 } 40 41 //计算索引和法线 42 //总格子数量:m * n 43 //因此总索引数量: 6 * m * n 44 UINT nIndices = m * n * 6; 45 m_indices.resize(nIndices); 46 UINT tmp = 0; 47 for (UINT i = 0; i < n; ++i) 48 { 49 for (UINT j = 0; j < m; ++j) 50 { 51 m_indices[tmp] = i * m_verticesPerRow + j; 52 m_indices[tmp + 1] = i * m_verticesPerRow + j + 1; 53 m_indices[tmp + 2] = (i + 1) * m_verticesPerRow + j; 54 55 //计算法线 56 XMFLOAT3 temp; 57 ComputeNomal(m_vertices[m_indices[tmp]], m_vertices[m_indices[tmp + 1]], 58 m_vertices[m_indices[tmp + 2]], temp); 59 m_vertices[m_indices[tmp]].normal = temp; 60 m_vertices[m_indices[tmp + 1]].normal = temp; 61 m_vertices[m_indices[tmp + 2]].normal = temp; 62 63 m_indices[tmp + 3] = i * m_verticesPerRow + j + 1; 64 m_indices[tmp + 4] = (i + 1) * m_verticesPerRow + j + 1; 65 m_indices[tmp + 5] = (i + 1) * m_verticesPerRow + j; 66 67 ComputeNomal(m_vertices[m_indices[tmp + 3]], m_vertices[m_indices[tmp + 4]], 68 m_vertices[m_indices[tmp + 5]], temp); 69 m_vertices[m_indices[tmp + 3]].normal = temp; 70 m_vertices[m_indices[tmp + 4]].normal = temp; 71 m_vertices[m_indices[tmp + 5]].normal = temp; 72 73 tmp += 6; 74 } 75 } 76 77 return true; 78 }
4.效果截图
5.详细源码
TerrainDemo.h
1 #pragma once 2 #include <string> 3 #include4 #include "Dx11Base.h" 5 #include "Camera.h" 6 #include "Input.h" 7 #include "Utility.h" 8 #include "LightHelper.h" 9 10 class TerrainDemo : public Dx11Base 11 { 12 public: 13 TerrainDemo(HINSTANCE hInst, std::wstring title = L"TerrainDemo", int width = 800, int height = 640); 14 ~TerrainDemo(); 15 16 //顶点结构 位置、法线、uv坐标 17 struct Vertex 18 { 19 Vertex() {} 20 Vertex(const XMFLOAT3 _pos, XMFLOAT3 _normal, XMFLOAT2 _tex) : 21 pos(_pos), normal(_normal), tex(_tex) {} 22 23 XMFLOAT3 pos; 24 XMFLOAT3 normal; 25 XMFLOAT2 tex; 26 }; 27 28 bool Init() override; 29 void Update(float dt); 30 void Render(); 31 32 bool OnResize() override; 33 private: 34 bool BuildBuffers(); 35 bool BuildSRVs(); 36 bool BuildInputLayouts(); 37 void UpdateCamera(float dt); 38 private: 39 bool ReadRawFile(std::string filePath); //从高度图读取高度信息 40 bool InitTerrain(float width, float height, UINT m, UINT n, float scale); //初始化地形 41 void ComputeNomal(Vertex& v1, Vertex& v2, Vertex& v3, XMFLOAT3& normal); //计算法线 42 private: 43 std::vector<float> m_heightInfos; //高度图高度信息 44 int m_cellsPerRow; //每行单元格数 45 int m_cellsPerCol; //每列单元格数 46 int m_verticesPerRow; //每行顶点数 47 int m_verticesPerCol; //每列顶点数 48 int m_numsVertices; //顶点总数 49 float m_width; //地形宽度 50 float m_height; //地形高度 51 float m_heightScale; //高度缩放系数 52 53 std::vector m_vertices; //顶点集合 54 std::vector m_indices; //索引集合 55 56 private: 57 ID3D11Buffer* m_pVertexBuffer; 58 ID3D11Buffer* m_pIndexBuffer; 59 ID3D11InputLayout* m_pInputLayout; 60 ID3D11ShaderResourceView* m_pSRVTerrain; 61 62 Lights::DirectionalLight m_dirLights[3]; //3个平行光源 63 Lights::Material m_materialTerrain; //材质 64 65 Camera m_camera; 66 67 XMFLOAT4X4 m_world; //世界变换矩阵 68 XMFLOAT4X4 m_worldViewProj; //世界视角投影矩阵 69 XMFLOAT4X4 m_worldInvTranspose; //世界逆矩阵的转置,用于法线变换 70 XMFLOAT4X4 m_texTrans; //纹理坐标变换矩阵 71 72 POINT m_lastMousePos; 73 };
TerrainDemo.cpp
1 #include2 #include 3 #include "TerrainDemo.h" 4 #include "Utility.h" 5 #include "WICTextureLoader.h" 6 #include "d3dx11effect.h" 7 #include "Effects.h" 8 9 TerrainDemo::TerrainDemo(HINSTANCE hInst, std::wstring title, int width, int height) 10 :Dx11Base(hInst, title, width, height) 11 { 12 //"三点式"照明 13 //主光源 14 m_dirLights[0].ambient = XMFLOAT4(0.3f, 0.3f, 0.3f, 1.0f); 15 m_dirLights[0].diffuse = XMFLOAT4(0.5f, 0.5f, 0.5f, 1.0f); 16 m_dirLights[0].specular = XMFLOAT4(0.5f, 0.5f, 0.5f, 1.0f); 17 m_dirLights[0].direction = XMFLOAT3(0.57735f, -0.57735f, 0.57735f); 18 //侧光源 19 m_dirLights[1].ambient = XMFLOAT4(0.0f, 0.0f, 0.0f, 1.0f); 20 m_dirLights[1].diffuse = XMFLOAT4(0.20f, 0.20f, 0.20f, 1.0f); 21 m_dirLights[1].specular = XMFLOAT4(0.25f, 0.25f, 0.25f, 1.0f); 22 m_dirLights[1].direction = XMFLOAT3(-0.57735f, -0.57735f, 0.57735f); 23 //背光源 24 m_dirLights[2].ambient = XMFLOAT4(0.0f, 0.0f, 0.0f, 1.0f); 25 m_dirLights[2].diffuse = XMFLOAT4(0.2f, 0.2f, 0.2f, 1.0f); 26 m_dirLights[2].specular = XMFLOAT4(0.0f, 0.0f, 0.0f, 1.0f); 27 m_dirLights[2].direction = XMFLOAT3(0.0f, -0.707f, -0.707f); 28 29 //材质 30 m_materialTerrain.ambient = XMFLOAT4(0.5f, 0.5f, 0.5f, 1.0f); 31 m_materialTerrain.diffuse = XMFLOAT4(1.f, 1.f, 1.f, 1.0f); 32 m_materialTerrain.specular = XMFLOAT4(0.3f, 0.3f, 0.3f, 16.0f); 33 34 //设置相机 35 m_lastMousePos = { 0,0 }; 36 XMVECTOR Eye = XMVectorSet(0.0f, 50.0f, 0.1f, 0.0f); 37 XMVECTOR At = XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f); 38 XMVECTOR Up = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f); 39 m_camera.LookAtXM(Eye, At, Up); 40 //设置投影矩阵 41 m_camera.SetLens(XM_PIDIV4, AspectRatio(), 0.1f, 1000.f); 42 43 //初始化世界矩阵 逆转置矩阵 及纹理坐标矩阵 44 //这些每一帧不改变 45 XMMATRIX I = XMMatrixIdentity(); 46 XMStoreFloat4x4(&m_world, I); 47 XMVECTOR det = XMMatrixDeterminant(I); 48 XMMATRIX worldInvTranspose = XMMatrixTranspose(XMMatrixInverse(&det,I)); 49 XMStoreFloat4x4(&m_worldInvTranspose, worldInvTranspose); 50 XMStoreFloat4x4(&m_texTrans, I); 51 } 52 53 TerrainDemo::~TerrainDemo() 54 { 55 SafeRelease(m_pVertexBuffer); 56 SafeRelease(m_pIndexBuffer); 57 SafeRelease(m_pInputLayout); 58 SafeRelease(m_pSRVTerrain); 59 Effects::ReleaseAll(); 60 } 61 62 bool TerrainDemo::Init() 63 { 64 if (!Dx11Base::Init()) 65 return false; 66 if (!Effects::InitAll(m_pd3dDevice)) 67 return false; 68 if (!ReadRawFile("Texture\\heightmap.raw")) 69 return false; 70 if (!InitTerrain(500, 500, 255, 255, 0.2f)) 71 return false; 72 if (!BuildBuffers()) 73 return false; 74 if (!BuildSRVs()) 75 return false; 76 if (!BuildInputLayouts()) 77 return false; 78 } 79 80 void TerrainDemo::Update(float dt) 81 { 82 UpdateCamera(dt); 83 XMMATRIX world = XMLoadFloat4x4(&m_world); 84 XMMATRIX worldViewProj = world * m_camera.GetViewProj(); 85 XMStoreFloat4x4(&m_worldViewProj, worldViewProj); 86 87 //设置灯光 88 Effects::ms_pBasicEffect->m_pFxDirLights->SetRawValue(&m_dirLights, 0, 89 3 * sizeof(Lights::DirectionalLight)); 90 Effects::ms_pBasicEffect->m_pFxEyePos->SetRawValue(&m_camera.GetPosition(), 0, 91 sizeof(m_camera.GetPosition())); 92 } 93 94 void TerrainDemo::Render() 95 { 96 m_pImmediateContext->ClearRenderTargetView(m_pRenderTargetView, Colors::Silver); 97 m_pImmediateContext->ClearDepthStencilView(m_pDepthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0); 98 m_pImmediateContext->IASetInputLayout(m_pInputLayout); 99 100 UINT stride = sizeof(Vertex); 101 UINT offset = 0; 102 m_pImmediateContext->IASetVertexBuffers(0, 1, &m_pVertexBuffer, &stride, &offset); 103 m_pImmediateContext->IASetIndexBuffer(m_pIndexBuffer, DXGI_FORMAT_R32_UINT, offset); 104 m_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); 105 106 D3DX11_TECHNIQUE_DESC desc; 107 ID3DX11EffectTechnique* tech = Effects::ms_pBasicEffect->m_pFxLight3TexTech; 108 tech->GetDesc(&desc); 109 110 for (UINT i = 0; i < desc.Passes; ++i) 111 { 112 //设置着色器变量 113 Effects::ms_pBasicEffect->m_pFxWorld->SetMatrix(reinterpret_cast<const float*>(&m_world)); 114 Effects::ms_pBasicEffect->m_pFxWorldViewProj->SetMatrix(reinterpret_cast<const float*>( 115 &m_worldViewProj)); 116 Effects::ms_pBasicEffect->m_pFxWorldInvTranspose->SetMatrix(reinterpret_cast<const float*>( 117 &m_worldInvTranspose)); 118 Effects::ms_pBasicEffect->m_pFxTexTrans->SetMatrix(reinterpret_cast<const float*>( 119 &m_texTrans)); 120 Effects::ms_pBasicEffect->m_pFxMaterial->SetRawValue(&m_materialTerrain, 0, sizeof(m_materialTerrain)); 121 Effects::ms_pBasicEffect->m_pFxSR->SetResource(m_pSRVTerrain); 122 tech->GetPassByIndex(i)->Apply(0, m_pImmediateContext); 123 m_pImmediateContext->DrawIndexed(m_indices.size(), 0, 0); 124 } 125 126 m_pSwapChain->Present(0, 0); 127 } 128 129 bool TerrainDemo::OnResize() 130 { 131 if (!Dx11Base::OnResize()) 132 return false; 133 //更新camera参数 134 m_camera.SetLens(XM_PIDIV4, AspectRatio(), 1.f, 1000.f); 135 136 return true; 137 } 138 139 bool TerrainDemo::BuildBuffers() 140 { 141 //创建顶点缓冲区 142 D3D11_BUFFER_DESC vertexDesc; 143 ZeroMemory(&vertexDesc, sizeof(vertexDesc)); 144 vertexDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; 145 vertexDesc.ByteWidth = sizeof(Vertex) * m_numsVertices; 146 vertexDesc.Usage = D3D11_USAGE_IMMUTABLE; 147 148 D3D11_SUBRESOURCE_DATA vertexData; 149 vertexData.pSysMem = &m_vertices[0]; 150 vertexData.SysMemPitch = 0; 151 vertexData.SysMemSlicePitch = 0; 152 if (FAILED(m_pd3dDevice->CreateBuffer(&vertexDesc, &vertexData, &m_pVertexBuffer))) 153 { 154 MessageBox(nullptr, L"Create Vertex Buffer failed!", L"Error", MB_OK); 155 return false; 156 } 157 158 //创建索引缓冲区 159 D3D11_BUFFER_DESC indexDesc; 160 ZeroMemory(&indexDesc, sizeof(indexDesc)); 161 indexDesc.BindFlags = D3D11_BIND_INDEX_BUFFER; 162 indexDesc.ByteWidth = sizeof(UINT) * m_indices.size(); 163 indexDesc.Usage = D3D11_USAGE_IMMUTABLE; 164 165 D3D11_SUBRESOURCE_DATA indexData; 166 indexData.pSysMem = &m_indices[0]; 167 indexData.SysMemPitch = 0; 168 indexData.SysMemSlicePitch = 0; 169 if (FAILED(m_pd3dDevice->CreateBuffer(&indexDesc, &indexData, &m_pIndexBuffer))) 170 { 171 MessageBox(nullptr, L"Create Index Buffer failed!", L"Error", MB_OK); 172 return false; 173 } 174 175 return true; 176 } 177 178 bool TerrainDemo::BuildSRVs() 179 { 180 if (FAILED(CreateWICTextureFromFile(m_pd3dDevice, L"Texture\\desert.bmp", nullptr, &m_pSRVTerrain))) 181 { 182 MessageBox(nullptr, L"create texture failed!", L"error", MB_OK); 183 return false; 184 } 185 return true; 186 } 187 188 bool TerrainDemo::BuildInputLayouts() 189 { 190 D3D11_INPUT_ELEMENT_DESC layout[] = 191 { 192 { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, 193 { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12,D3D11_INPUT_PER_VERTEX_DATA, 0 }, 194 { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24,D3D11_INPUT_PER_VERTEX_DATA, 0 } 195 }; 196 197 UINT numLayoutElements = ARRAYSIZE(layout); 198 D3DX11_PASS_DESC passDesc; 199 Effects::ms_pBasicEffect->m_pFxLight3TexTech->GetPassByIndex(0)->GetDesc(&passDesc); 200 if (FAILED(m_pd3dDevice->CreateInputLayout(layout, numLayoutElements, passDesc.pIAInputSignature, 201 passDesc.IAInputSignatureSize, &m_pInputLayout))) 202 { 203 MessageBox(nullptr, L"create inputLayout failed!", L"error", MB_OK); 204 return false; 205 } 206 return true; 207 } 208 209 void TerrainDemo::UpdateCamera(float dt) 210 { 211 //前后左右行走 212 if (Input::GetInstance()->IsKeyDown('A')) 213 { 214 m_camera.Strafe(-60.f*dt); 215 } 216 else if (Input::GetInstance()->IsKeyDown('D')) 217 { 218 m_camera.Strafe(60.f*dt); 219 } 220 if (Input::GetInstance()->IsKeyDown('W')) 221 { 222 m_camera.Walk(60.f*dt); 223 } 224 else if (Input::GetInstance()->IsKeyDown('S')) 225 { 226 m_camera.Walk(-60.f*dt); 227 } 228 229 230 if (Input::GetInstance()->IsMouseMove()) 231 { 232 float mouseX = Input::GetInstance()->GetMouseX(); 233 float mouseY = Input::GetInstance()->GetMouseY(); 234 if (Input::GetInstance()->IsLMouseDown()) 235 { 236 float dx = XMConvertToRadians(0.25f*(mouseX - m_lastMousePos.x)); 237 float dy = XMConvertToRadians(0.25f*(mouseY - m_lastMousePos.y)); 238 239 OutputDebugString(L"left btn click"); 240 m_camera.Pitch(dy); 241 m_camera.RotateY(dx); 242 } 243 m_lastMousePos.x = mouseX; 244 m_lastMousePos.y = mouseY; 245 } 246 247 m_camera.UpdateViewMatrix(); 248 } 249 250 //读取高度图信息 251 bool TerrainDemo::ReadRawFile(std::string filePath) 252 { 253 std::ifstream inFile; 254 //二进制方式打开文件 255 inFile.open(filePath.c_str(), std::ios::binary); 256 //文件指针移动到末尾 257 inFile.seekg(0, std::ios::end); 258 //大小为当前缓冲区大小 259 std::vector inData(inFile.tellg()); 260 //文件指针移动到开头 261 inFile.seekg(std::ios::beg); 262 //读取高度信息 263 inFile.read((char*)&inData[0], inData.size()); 264 inFile.close(); 265 266 m_heightInfos.resize(inData.size()); 267 for (int i = 0; i < inData.size(); ++i) 268 { 269 m_heightInfos[i] = inData[i]; 270 } 271 272 return true; 273 } 274 275 bool TerrainDemo::InitTerrain(float width, float height, UINT m, UINT n,float scale) 276 { 277 m_cellsPerRow = m; 278 m_cellsPerCol = n; 279 m_verticesPerRow = m + 1; 280 m_verticesPerCol = n + 1; 281 m_numsVertices = m_verticesPerRow*m_verticesPerCol; 282 m_width = width; 283 m_height = height; 284 m_heightScale = scale; 285 286 //得到缩放后的高度 287 for (auto& item : m_heightInfos) 288 { 289 item *= m_heightScale; 290 } 291 292 //起始x z坐标 293 float oX = -width * 0.5f; 294 float oZ = height * 0.5f; 295 //每一格坐标变化 296 float dx = width / m; 297 float dz = height / n; 298 299 m_vertices.resize(m_numsVertices); 300 //计算顶点 301 for (UINT i = 0; i < m_verticesPerCol; ++i) 302 { 303 float tempZ = oZ - dz * i; 304 for (UINT j = 0; j < m_verticesPerRow; ++j) 305 { 306 UINT index = m_verticesPerRow * i + j; 307 m_vertices[index].pos.x = oX + dx * j; 308 m_vertices[index].pos.y = m_heightInfos[index]; 309 m_vertices[index].pos.z = tempZ; 310 311 m_vertices[index].tex = XMFLOAT2(dx*i, dx*j); 312 } 313 } 314 315 //计算索引和法线 316 //总格子数量:m * n 317 //因此总索引数量: 6 * m * n 318 UINT nIndices = m * n * 6; 319 m_indices.resize(nIndices); 320 UINT tmp = 0; 321 for (UINT i = 0; i < n; ++i) 322 { 323 for (UINT j = 0; j < m; ++j) 324 { 325 m_indices[tmp] = i * m_verticesPerRow + j; 326 m_indices[tmp + 1] = i * m_verticesPerRow + j + 1; 327 m_indices[tmp + 2] = (i + 1) * m_verticesPerRow + j; 328 329 //计算法线 330 XMFLOAT3 temp; 331 ComputeNomal(m_vertices[m_indices[tmp]], m_vertices[m_indices[tmp + 1]], 332 m_vertices[m_indices[tmp + 2]], temp); 333 m_vertices[m_indices[tmp]].normal = temp; 334 m_vertices[m_indices[tmp + 1]].normal = temp; 335 m_vertices[m_indices[tmp + 2]].normal = temp; 336 337 m_indices[tmp + 3] = i * m_verticesPerRow + j + 1; 338 m_indices[tmp + 4] = (i + 1) * m_verticesPerRow + j + 1; 339 m_indices[tmp + 5] = (i + 1) * m_verticesPerRow + j; 340 341 ComputeNomal(m_vertices[m_indices[tmp + 3]], m_vertices[m_indices[tmp + 4]], 342 m_vertices[m_indices[tmp + 5]], temp); 343 m_vertices[m_indices[tmp + 3]].normal = temp; 344 m_vertices[m_indices[tmp + 4]].normal = temp; 345 m_vertices[m_indices[tmp + 5]].normal = temp; 346 347 tmp += 6; 348 } 349 } 350 351 return true; 352 } 353 354 //计算法线 355 void TerrainDemo::ComputeNomal(Vertex& v1, Vertex& v2, Vertex& v3, XMFLOAT3& normal) 356 { 357 XMFLOAT3 f1(v2.pos.x - v1.pos.x, v2.pos.y - v1.pos.y, v2.pos.z - v1.pos.z); 358 XMFLOAT3 f2(v3.pos.x - v1.pos.x, v3.pos.y - v1.pos.y, v3.pos.z - v1.pos.z); 359 XMVECTOR vec1 = XMLoadFloat3(&f1); 360 XMVECTOR vec2 = XMLoadFloat3(&f2); 361 XMVECTOR temp = XMVector3Normalize(XMVector3Cross(vec1, vec2)); 362 XMStoreFloat3(&normal, temp); 363 } 364 365 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR cmdLine, int cmdShow) 366 { 367 std::shared_ptr bd(new TerrainDemo(hInstance)); 368 if (!bd->Init()) 369 return -1; 370 return bd->Run(); 371 }