原文地址:http://ogldev.atspace.co.uk/www/tutorial22/tutorial22.html
背景知识:
我们不能手动的创建复杂的模型。正如你所想象的,为每个顶点指定位置和其他的属性,并且要在缩放的时候保持正确是不现实的。一个盒子、金字塔或者是简单的表面是ok的,但是对于人脸这种复杂的网格结构就不可行了。现实的世界或者是商业的应用,处理的网格模型都是通过设计师设计的模型,他们使用Blender、Maya、3ds Max来设计。这些应用为设计师提供高级的工具来来创建复杂的模型。但模型被设计好之后,他会保存成多种格式的文件。每个文件都包含了整个几何体的定义。它可以被加载到游戏的引擎,前提是这个引擎能够识别文件的格式。文件的内容被用来填充顶点和索引缓冲。如何解析模型文件的内容,对于正确加载模型至关重要。
开发你自己的解析器是非常耗时的。如果你要加载各种各样的模型,你需要对每个格式的文件写一个解析器。有些格式是很简单的,但是有些格式很复杂,如果每个都实现,这个很耗时,而且这些不是3D编程的核心内容。因此,本节引入第三方的加载模型的库,他能为我们加载各种各样的模型。
这个开源的库叫做Open Asset Import Library,简称assimp。它能够加载很多3D格式的文件,包括流行的格式文件。对于windows和linux都是可以用的,它能够很好的和C++整合。
(mesh.h:50)
class Mesh
{
public:
Mesh();
~Mesh();
bool LoadMesh(const std::string& Filename);
void Render();
private:
bool InitFromScene(const aiScene* pScene, const std::string& Filename);
void InitMesh(unsigned int Index, const aiMesh* paiMesh);
bool InitMaterials(const aiScene* pScene, const std::string& Filename);
void Clear();
#define INVALID_MATERIAL 0xFFFFFFFF
struct MeshEntry {
MeshEntry();
~MeshEntry();
bool Init(const std::vector& Vertices,
const std::vector& Indices);
GLuint VB;
GLuint IB;
unsigned int NumIndices;
unsigned int MaterialIndex;
};
std::vector m_Entries;
std::vector m_Textures;
};
Mesh类代表了Assimp和OpenGL之间的接口。这个类中的方法LoadMesh()方法,需要传递文件的名字,使用Assimp加载模型,然后创建顶点缓冲,索引缓冲,还有贴图对象,这些贴图对象包含了模型的数据。为了能够渲染网格,我们使用函数Render()。Mesh类的内部会选择对于的方法来加载模型。Assimp使用aiScene对象来代表加载好的网格。aiScene包含了网格结构。aiScene对象至少包含一个网格结构。复杂的模型包含多个网格结构。Mesh类的m_Entries成员是MeshEntry的向量,其中每个值都是对应一个aiScene对象。这个结果包含顶点缓冲、索引缓冲、还有材质索引。从现在开始,一个材质就是一盏贴图,由于网格实体可以共享材质,我们使用一个向量m_Textures记录贴图。MeshEntry::MaterialIndex指向m_Textures中的某个。
(mesh.cpp:77)
bool Mesh::LoadMesh(const std::string& Filename)
{
// Release the previously loaded mesh (if it exists)
Clear();
bool Ret = false;
Assimp::Importer Importer;
const aiScene* pScene = Importer.ReadFile(Filename.c_str(), aiProcess_Triangulate | aiProcess_GenSmoothNormals | aiProcess_FlipUVs | aiProcess_JoinIdenticalVertices);
if (pScene) {
Ret = InitFromScene(pScene, Filename);
}
else {
printf("Error parsing '%s': '%s'\n", Filename.c_str(), Importer.GetErrorString());
}
return Ret;
}