图形学笔记 -- OpenGL 图形学 / 模型加载

不同 3D 引擎实现千差万别,但模型都是由非常多的三角形拼接组成。解析模型数据,然后得到所有三角形并完成绘制。

OpenGL 模型加载。解析模型文件,得到一堆三角形数据,把这些三角形绘制出来,就是这个样子了。

本文源码 LearnOpenGL-Model

Assimp

一个非常流行的模型导入库是 Assimp,它是 Open Asset Import Library(开放的资产导入库)的缩写。 Assimp 能够导入很多种不同的模型文件格式(并也能够导出部分的格式),它会将所有的模型数据加载至 Assimp 的通用数据结构中。

一个 Mesh 对象本身包含了渲染所需要的所有相关数据,像是顶点位置、法向量、纹理坐标、面 (Face) 和物体的材质。

一个网格包含了多个面。Face 代表的是物体的渲染图元 (Primitive)(三角形、方形、点)。一个面包含了组成图元的顶点的索引。由于顶点和索引是分开的,使用一个索引缓冲来渲染是非常简单的。

网格 Mesh

我们定义 Vertex:

struct Vertex {
    glm::vec3 Position; // 顶点位置
    glm::vec3 Normal; // 法线
    glm::vec2 TexCoords; // 纹理坐标
};

定义一个纹理:

struct Texture {
    unsigned int id; // 对应的 glGenTextures ID。
    string type; // 和 glsl shader 对应,根据这个名字完成参数传递。
    string path; // 图片文件路径。
};

#define TEXTURE_TYPE_DIFFUSE  "texture_diffuse"
#define TEXTURE_TYPE_SPECULAR "texture_specular"

相应的 glsl 就是:

uniform sampler2D texture_diffuse1;

那么一个网格(Mesh)可以定义为:

class Mesh {
    vector<Vertex> vertices;
    vector<unsigned int> indices;
    vector<Texture> textures;
    unsigned int VAO, VBO, EBO;
};

// 绘制就是:
void Draw(Shader& shader)
{
    glBindVertexArray(VAO);
    glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);
}

模型 Model

一个模型由非常多的 Mesh 组成,可以定义为:

class Model {
    vector<Mesh> meshes;
};

// 绘制就是:
void Draw(Shader& shader)
{
    for (unsigned int i = 0; i < meshes.size(); i++)
        meshes[i].Draw(shader);
}

最终效果


参考资料快照
参考资料快照

本文短链接:
If you have any questions or feedback, please reach out .