通常我們在xz平面定義一個二維的網格,然后y的值根據一定的函數計算得到,比如正弦、余弦函數的組合等等,可以得到一個看似不錯的地形或者水面的效果。 在本教程中我們修改ModelClass.h和ModelClass.cpp,得到一個近似的地形。
在本章代碼中,我們定義300*300=90000個頂點,共(300-1)(300-1)*2個三角形,每個網格的大小都為1.
我們得到y值的函數為:
float ModelClass::getHeight(float x, float z) const
{
return 0.3f*( z*sinf(0.1f*x) + x*cosf(0.1f*z) );
}
ModelClass.h主要代碼如下:
#pragma once
#include <d3d11.h>
#include <d3dx10math.h>
#include "common.h"
class ModelClass
{
…
int GetIndexCount();
//根據頂點的x值和z值,計算出y值
float getHeight(float x, float z)const;
private:
bool InitializeBuffers(ID3D11Device*, int, int, float);
void ShutdownBuffers();
void RenderBuffers(ID3D11DeviceContext*);
//頂點緩沖和頂點索引緩沖
ID3D11Buffer *m_vertexBuffer, *m_indexBuffer;
int m_vertexCount, m_indexCount;
};
ModelClass.cpp主要代碼如下:
bool ModelClass::Initialize(ID3D11Device* device, int m, int n, float dx){
bool result;
// 初始化頂點緩沖和頂點索引緩沖.
result = InitializeBuffers(device, m, n, dx);
if(!result)
{
return false;
}
return true;
}
void ModelClass::Shutdown()
{
// 釋放頂點和索引緩沖.
ShutdownBuffers();
return;
}
float ModelClass::getHeight(float x, float z) const
{
return 0.3f*( z*sinf(0.1f*x) + x*cosf(0.1f*z) );
}
void ModelClass::Render(ID3D11DeviceContext* deviceContext)
{
// 把頂點和索引緩沖放入圖形管線,准備渲染.
RenderBuffers(deviceContext);
return;
}
int ModelClass::GetIndexCount()
{
//返回索引頂點計數
return m_indexCount;
}
bool ModelClass::InitializeBuffers(ID3D11Device* device, int m, int n, float dx)
{
VertexType* vertices;
unsigned long* indices;
D3D11_BUFFER_DESC vertexBufferDesc, indexBufferDesc;
D3D11_SUBRESOURCE_DATA vertexData, indexData;
HRESULT result;
//計算得到頂點和索引頂點數目
//首先得到三角形的數目,然后乘以3就是頂點索引數目
m_vertexCount = m*n;
m_indexCount = (m-1)*(n-1)*2*3;
// 創建頂點臨時緩沖.
vertices = new VertexType[m_vertexCount];
if(!vertices)
{
return false;
}
float halfWidth = (n-1)*dx*0.5f;
float halfDepth = (m-1)*dx*0.5f;
for(int i = 0; i < m; ++i)
{
float z = halfDepth - i*dx;
for(int j = 0; j < n; ++j)
{
float x = -halfWidth + j*dx;
// 計算得到z值.
float y = getHeight(x,z);
vertices[i*n+j].position = D3DXVECTOR3(x, y, z);
// 根據高度來定義顏色
if( y < -10.0f )
vertices[i*n+j].color = BEACH_SAND;
else if( y < 5.0f )
vertices[i*n+j].color = LIGHT_YELLOW_GREEN;
else if( y < 12.0f )
vertices[i*n+j].color = DARK_YELLOW_GREEN;
else if( y < 20.0f )
vertices[i*n+j].color = DARKBROWN;
else
vertices[i*n+j].color = WHITE;
}
}
// 創建索引緩沖.
indices = new unsigned long[m_indexCount];
if(!indices)
{
return false;
}
// 迭代每個grid,計算得出索引.
int k = 0;
for(int i = 0; i < m-1; ++i)
{
for(int j = 0; j < n-1; ++j)
{
indices[k] = i*n+j;
indices[k+1] = i*n+j+1;
indices[k+2] = (i+1)*n+j;
indices[k+3] = (i+1)*n+j;
indices[k+4] = i*n+j+1;
indices[k+5] = (i+1)*n+j+1;
k += 6; //下一個grid
}
}
// 設置頂點緩沖描述
…
return true;
}
// 初始化模型對象.
result = m_Model->Initialize(m_D3D->GetDevice(), 300, 300, 1.0f);
if(!result)
{
MessageBox(hwnd, L"Could not initialize the model object.", L"Error", MB_OK);
return false;
}
運行程序后,效果如下,我們還可以用a/s/d/w鍵來移動攝像機看看地形的效果。
我們還可以修改D3DClass.cpp中,渲染狀態Fillmode設置,修改為線框模式后的效果如下:
D3DClass.cpp中修改代碼如下:
// 設置光柵化描述,指定多邊形如何被渲染.
rasterDesc.AntialiasedLineEnable = false;
rasterDesc.CullMode = D3D11_CULL_BACK;
rasterDesc.DepthBias = 0;
rasterDesc.DepthBiasClamp = 0.0f;
rasterDesc.DepthClipEnable = true;
rasterDesc.FillMode = D3D11_FILL_WIREFRAME;
rasterDesc.FrontCounterClockwise = false;
rasterDesc.MultisampleEnable = false;
rasterDesc.ScissorEnable = false;
rasterDesc.SlopeScaledDepthBias = 0.0f;
完整的代碼請參考:
工程文件myTutorialD3D11_13
代碼下載: