原文地址: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;
}