第三章 模型加载
3.1 Assimp
1、Assimp能够导入多种模型文件格式,将所有的模型数据加载至Assimp的通用数据结构中,我们就能够从Assimp的数据结构中提取我们所需的所有数据了。
2、Assimp会将整个模型加载进一个场景对象,场景对象中包含一系列的节点,每个节点包含了场景对象中所储存数据的索引,每个节点都可以有任意数量的子节点。(图中左半边)
- 场景的根节点含子节点,子节点中有一系列指向场景对象中
mMeshes
数组中储存的网格数据的索引。 - 注意:
Scene
下的mMeshes
数组储存了真正的Mesh对象,节点中的mMeshes数组保存的只是场景中网格数组的索引
3.2 网格
3.2.1 网格类
1、通过Assimp加载模型数据到程序中后,需要将数据转换为OpenGL能够理解的格式。因此定义一个网格类,将模型数据读取到网格对象中,网格(Mesh)代表的是单个的可绘制实体。
2、一个网格应该需要一系列的顶点,每个顶点包含位置向量、法向量和纹理坐标向量;一个网格还应该包含用于索引绘制的索引以及纹理形式的材质数据(漫反射/镜面光贴图)。
struct Vertex
{
glm::vec3 Position;
glm::vec3 Normal;
glm::vec2 TexCoords;
};
struct Texture
{
unsigned int id;
std::string type;//diffuse or specular
std::string path;
};
3、在构造函数中,将所有数据赋予了网格,在setupMesh
函数中初始化缓冲,最终使用Draw
函数来绘制网格。注意将着色器传入了Draw函数中,可以让在绘制之前设置一些uniform
(像是链接采样器到纹理单元)。
class Mesh
{
public:
/* 网格数据 */
std::vector<Vertex> vertices;
std::vector<unsigned int>indices;//索引绘制的索引,EBO绘制时需要
std::vector<Texture> textures;
Mesh(std::vector<Vertex> vertices,std::vector<unsigned int>indices,std::vector<Texture> textures);//构造函数
void Draw(Shader* shader);//设置unform变量(如链接采样器到纹理单元),绘制网格
private:
unsigned int VAO, VBO, EBO;//缓冲对象
void SetupMesh();//初始化缓冲
};
Mesh::Mesh(std::vector<Vertex> vertices, std::vector<unsigned int> indices, std::vector<Texture> textures)
{
this->vertices = vertices;
this->indices = indices;
this->textures = textures;
SetupMesh();
}
3.2.2 初始化缓冲
1、现在有一大列的网格数据用于渲染,因此必须配置正确的缓冲,并通过顶点属性指针定义顶点着色器的布局(layout
)。
void Mesh::SetupMesh()
{
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), &vertices[0], GL_STATIC_DRAW);
glGenBuffers(1, &EBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), &indices[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Normal));
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex)