서적 정리/DirectX11을 이용한 3D 게임 프로그래밍 입문
52.언덕 예제
민돌이2
2022. 2. 15. 04:02
1.격자 정점 만들기
xz평면에 격자를 만들때, 정점이 m × n개인 격자는 (m - 1) × (n - 1)개의 칸(cell)으로 이뤄진다.
각 칸은 두 개의 삼각형으로 구성되므로 총 2 · (m - 1) × (n - 1)개의 삼각형이 필요하다. 격자의 너비가 w이고 깊이가 d라고 하면 칸의 x축 간격은 dx = w / (n - 1)이고 z축 간격은 dz = d / (m - 1)이다.
xz평면에서 ij번째 격자 정점의 좌표는 아래와 같다.
격자 정점들의 좌표를 계산하는 코드는 아래와 같다.
void GeometryGenerator::CreateGrid(float width, float depth, UINT m, UINT n, MeshData& meshData)
{
UINT vertexCount = m*n;
UINT faceCount = (m-1)*(n-1)*2;
//
// Create the vertices.
//
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);
// Stretch texture over grid.
meshData.Vertices[i*n+j].TexC.x = j*du;
meshData.Vertices[i*n+j].TexC.y = i*dv;
}
}
...
}
2.격자 인덱스 만들기
격자의 정점들을 모두 계산했다면 격자 각 칸의 삼각형들을 구성하는 인덱스들을 정의해야 한다.
m x n 정점 격자의 경우 한 칸의 두 삼각형의 선형 배열 인덱스들은 아래와 같다.
격자 인덱스를 정의하는 코드는 아래와 같다.
void GeometryGenerator::CreateGrid(float width, float depth, UINT m, UINT n, MeshData& meshData)
{
...
//
// Create the indices.
//
meshData.Indices.resize(faceCount*3); // 3 indices per face
// Iterate over each quad and compute indices.
UINT k = 0;
for(UINT i = 0; i < m-1; ++i)
{
for(UINT j = 0; j < n-1; ++j)
{
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; // next quad
}
}
}
3.높이 함수의 적용
xz평면을 구현했다면 높이 함수를 적용해서 높이값인 y축을 설정한다. 또한 정점의 높이에 따라 색상도 설정한다.
void HillsApp::BuildGeometryBuffers()
{
GeometryGenerator::MeshData grid;
GeometryGenerator geoGen;
geoGen.CreateGrid(160.0f, 160.0f, 50, 50, grid);
mGridIndexCount = grid.Indices.size();
//
// Extract the vertex elements we are interested and apply the height function to
// each vertex. In addition, color the vertices based on their height so we have
// sandy looking beaches, grassy low hills, and snow mountain peaks.
//
std::vector<Vertex> vertices(grid.Vertices.size());
for(size_t i = 0; i < grid.Vertices.size(); ++i)
{
XMFLOAT3 p = grid.Vertices[i].Position;
p.y = GetHeight(p.x, p.z);
vertices[i].Pos = p;
// Color the vertex based on its height.
if( p.y < -10.0f )
{
// Sandy beach color.
vertices[i].Color = XMFLOAT4(1.0f, 0.96f, 0.62f, 1.0f);
}
else if( p.y < 5.0f )
{
// Light yellow-green.
vertices[i].Color = XMFLOAT4(0.48f, 0.77f, 0.46f, 1.0f);
}
else if( p.y < 12.0f )
{
// Dark yellow-green.
vertices[i].Color = XMFLOAT4(0.1f, 0.48f, 0.19f, 1.0f);
}
else if( p.y < 20.0f )
{
// Dark brown.
vertices[i].Color = XMFLOAT4(0.45f, 0.39f, 0.34f, 1.0f);
}
else
{
// White snow.
vertices[i].Color = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);
}
}
D3D11_BUFFER_DESC vbd;
vbd.Usage = D3D11_USAGE_IMMUTABLE;
vbd.ByteWidth = sizeof(Vertex) * grid.Vertices.size();
vbd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
vbd.CPUAccessFlags = 0;
vbd.MiscFlags = 0;
D3D11_SUBRESOURCE_DATA vinitData;
vinitData.pSysMem = &vertices[0];
HR(md3dDevice->CreateBuffer(&vbd, &vinitData, &mVB));
//
// Pack the indices of all the meshes into one index buffer.
//
D3D11_BUFFER_DESC ibd;
ibd.Usage = D3D11_USAGE_IMMUTABLE;
ibd.ByteWidth = sizeof(UINT) * mGridIndexCount;
ibd.BindFlags = D3D11_BIND_INDEX_BUFFER;
ibd.CPUAccessFlags = 0;
ibd.MiscFlags = 0;
D3D11_SUBRESOURCE_DATA iinitData;
iinitData.pSysMem = &grid.Indices[0];
HR(md3dDevice->CreateBuffer(&ibd, &iinitData, &mIB));
}
728x90