最爱午后红茶

从文件中加载模型

日期图标
2023-06-15

前面的几个例子都是通过直接计算出模型的顶点来创建几何体,但这只适用于一些简单的几何体(球、立方体、圆柱体等),如果是一些复杂的模型就无法通过简单的计算来获取顶点。通常复杂的模型是通过一些 3D 建模软件制作,按照一些存储标准把制作好的模型存储在文本文件里面,然后在程序中直接读取。比如下面这个头骨模型的例子(skull.txt):

VertexCount:31076
TriangleCount:60339
VertexList(pos, normal)
{
    0. 592978  1. 92413  -2. 62486  0. 572276  0. 816877  0. 0721907
    0. 571224  1. 94331  -2. 66948  0. 572276  0. 816877  0. 0721907
    0. 609047  1. 90942  -2. 58578  0. 572276  0. 816877  0. 0721907
}
TriangleList
{
    0  1  2
    3  4  5
    6  7  8
}

我们可以直接从文件中读取所有的顶点和索引。其中 VertexList 中每个元素有 6 个值,前 3 个表示位置(pos)的坐标,后 3 个表示法线向量(normal,暂时还没有使用到)。

void SkullApp::BuildGeometryBuffers() {
  std::ifstream fin("Models/skull.txt");

  if (!fin) {
    MessageBox(0, L"Models/skull.txt not found.", 0, 0);
    return;
  }

  UINT vcount = 0;
  UINT tcount = 0;
  std::string ignore;

  fin >> ignore >> vcount;
  fin >> ignore >> tcount;
  fin >> ignore >> ignore >> ignore >> ignore;

  float nx, ny, nz;
  XMFLOAT4 black(0.0f, 0.0f, 0.0f, 1.0f);

  std::vector<Vertex> vertices(vcount);
  for (UINT i = 0; i < vcount; ++i) {
    fin >> vertices[i].Pos.x >> vertices[i].Pos.y >> vertices[i].Pos.z;

    vertices[i].Color = black;

    // Normal not used in this demo.
    fin >> nx >> ny >> nz;
  }

  fin >> ignore;
  fin >> ignore;
  fin >> ignore;

  mSkullIndexCount = 3 * tcount;
  std::vector<UINT> indices(mSkullIndexCount);
  for (UINT i = 0; i < tcount; ++i) {
    fin >> indices[i * 3 + 0] >> indices[i * 3 + 1] >> indices[i * 3 + 2];
  }

  fin.close();

  D3D11_BUFFER_DESC vbd;
  vbd.Usage = D3D11_USAGE_IMMUTABLE;
  vbd.ByteWidth = sizeof(Vertex) * vcount;
  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) * mSkullIndexCount;
  ibd.BindFlags = D3D11_BIND_INDEX_BUFFER;
  ibd.CPUAccessFlags = 0;
  ibd.MiscFlags = 0;
  D3D11_SUBRESOURCE_DATA iinitData;
  iinitData.pSysMem = &indices[0];
  HR(md3dDevice->CreateBuffer(&ibd, &iinitData, &mIB));
}

头骨演示程序:

* 未经同意不得转载。