首页 > 代码库 > Directx11学习笔记【二十二】 用高度图实现地形

Directx11学习笔记【二十二】 用高度图实现地形

本文由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::vector<BYTE> inData(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 * n43     //因此总索引数量: 6 * m * n44     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 #include <vector> 4 #include "Dx11Base.h" 5 #include "Camera.h" 6 #include "Input.h" 7 #include "Utility.h" 8 #include "LightHelper.h" 9 10 class TerrainDemo : public Dx11Base11 {12 public:13     TerrainDemo(HINSTANCE hInst, std::wstring title = L"TerrainDemo", int width = 800, int height = 640);14     ~TerrainDemo();15 16     //顶点结构 位置、法线、uv坐标17     struct Vertex18     {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<Vertex>        m_vertices;        //顶点集合54     std::vector<UINT>          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 #include <fstream>  2 #include <memory>  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<BYTE> 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 * n317     //因此总索引数量: 6 * m * n318     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<Dx11Base> bd(new TerrainDemo(hInstance));368     if (!bd->Init())369         return -1;370     return bd->Run();371 }

 

Directx11学习笔记【二十二】 用高度图实现地形