环境:VS2017 语言:C++
总起:
红龙书的第六章Demo练习很多,我们一个个来。
工程,X_Jun96大佬建议放到Github上,现在的地址:https://github.com/anguangzhihen/Dx11。
以上一篇的基础来做渲染山地的Demo还是比较轻松的,山地或者水之类的东西实际上就是一个面片,使用顶点构建出面片之后,赋值高低的y坐标基本就完成了。Buffer绑定、Shader和上一章一模一样。
渲染山地:
首先来看看效果:
似乎比盒子的Demo进步了一大截,但并没有,只是顶点数量变多了,“模型”更加精细了而已。
构建面片的工作由GeometryGenerator类的CreateGrid方法完成:
void GeometryGenerator::CreateGrid(float width, float depth, UINT m, UINT n, MeshData& meshData)
{
UINT vertexCount = m * n; // 顶点数量
UINT faceCount = (m - 1)*(n - 1) * 2; // 三角数量
float halfWidth = 0.5f*width;
float halfDepth = 0.5f*depth;
// 计算一格的宽高
float dx = width / (n - 1);
float dz = depth / (m - 1);
float du = 1.0f / (n - 1);
float dv = 1.0f / (m - 1);
// 创建顶点
meshData.Vertices.resize(vertexCount);
for (UINT i = 0; i < m; ++i)
{
float z = halfDepth - i * dz;
for (UINT j = 0; j < n; ++j)
{
float x = -halfWidth + j * dx;
meshData.Vertices[i * n + j].Position = XMFLOAT3(x, 0.0f, z); // 顶点的位置
meshData.Vertices[i * n + j].Normal = XMFLOAT3(0.0f, 1.0f, 0.0f);
meshData.Vertices[i * n + j].TangentU = XMFLOAT3(1.0f, 0.0f, 0.0f);
// 当前点与00点的xy距离
meshData.Vertices[i*n + j].TexC.x = j * du;
meshData.Vertices[i*n + j].TexC.y = i * dv;
}
}
// 创建索引
meshData.Indices.resize(faceCount * 3);
UINT k = 0;
for (UINT i = 0; i < m - 1; ++i)
{
for (UINT j = 0; j < n - 1; ++j)
{
// 一个Quad
meshData.Indices[k] = i * n + j;
meshData.Indices[k + 1] = i * n + j + 1;
meshData.Indices[k + 2] = (i + 1) * n + j;
meshData.Indices[k + 3] = (i + 1) * n + j;
meshData.Indices[k + 4] = i * n + j + 1;
meshData.Indices[k + 5] = (i + 1) * n + j + 1;
k += 6;
}
}
}
现在一个顶点数据Vertex由Position位置、Normal法线坐标、TangentU切线、TexC纹理坐标组成,该Demo中只用到了Position。
而Vertex的集合与索引数据统称为Mesh,这边的数据结构便是MeshData。
有了面片的数据,接下来就是赋值高度和添加颜色了:
// HillsDemo::BuildGeometryBuffers方法
GeometryGenerator::MeshData grid;
GeometryGenerator::CreateGrid(160.f, 160.0f, 50, 50, grid); // 创建160x160大小的格子数为49的Mesh
mGridIndexCount = grid.Indices.size();
// 提取每个顶点
std::vector<Vertex> vertices(grid.Vertices.size());
for (size_t i = 0; i < grid.Vertices.size(); i++)
{
// 这边只用到Position信息,所以不对其他信息做处理(等到使用光照模型时会使用法线等信息)
XMFLOAT3 p = grid.Vertices[i].Position;
p.y = GetHeight(p.x, p.z); // 赋值高度
vertices[i].Pos = p;
// 以不同的颜色表示沙滩、山地、山峰(不同的高度对应不同的颜色)
if (p.y < -10.f)
{
// 沙滩的颜色
vertices[i].Color = XMFLOAT4(1.0f, 0.96f, 0.62f, 1.0f);
}
else if (p.y < 5.0f)
{
// 黄绿色
vertices[i].Color = XMFLOAT4(0.48f, 0.77f, 0.46f, 1.0f);
}
else if (p.y < 12.0f)
{
// 深黄绿色
vertices[i].Color = XMFLOAT4(0.1f, 0.48f, 0.19f, 1.0f);
}
else if (p.y < 20.0f)
{
// 深棕色
vertices[i].Color = XMFLOAT4(0.45f, 0.39f, 0.34f, 1.0f);
}
else
{
// 白色
vertices[i].Color = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);
}
}
GetHeight的内容如下:
// 根据x、z坐标获取高度
float HillsDemo::GetHeight(float x, float z) const
{
return 0.3f*(z*sinf(0.1f*x) + x * cosf(0.1f*z));
}
如果你愿意的话,可以做一张高度图,读取高度图的信息对y坐标进行赋值。
以上就是全部内容了。