实验报告学生姓名:学号:专业班级:实验类型:□验证□综合□设计□创新实验日期:2018.11 实验成绩:一、实验名称实验七模型加载二、实验内容1.设计并实现Mesh类,利用该类实现模型网格的解析、加载、管理与渲染。
2.设计并实现Model类,利用该类实现几何模型的解析、加载、管理与渲染。
3.基于Mesh类和Model类,利用Assimp模型加载库,加载并渲染三维几何模型。
三、实验目的1.掌握3D模型网格数据的组织与渲染方法。
2.掌握3D模型数据的结构与组织,以及模型数据的解析与渲染方法。
3.了解Assimp库中管理3D模型的数据结构,掌握Assimp库的使用方法。
四、实验步骤1.定义网格类结构,并初始化class Mesh{Public:vector<Vertex> vertices;vector<GLuint> indices;vector<Texture> textures;Mesh(vector<Vertex> vertices, vector<GLuint> indices, vector<Texture> texture);Void Draw(Shader shader);private:GLuint VAO, VBO, EBO;void setupMesh();}void setupMesh(){glGenVertexArrays(1, &this->VAO);glGenBuffers(1, &this->VBO);glGenBuffers(1, &this->EBO);glBindVertexArray(this->VAO);glBindBuffer(GL_ARRAY_BUFFER, this->VBO);glBufferData(GL_ARRAY_BUFFER, this->vertices.size() * sizeof(Vertex),&this->vertices[0], GL_STATIC_DRAW);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->EBO);glBufferData(GL_ELEMENT_ARRAY_BUFFER, this->indices.size() * sizeof(GLuint),&this->indices[0], GL_STATIC_DRAW);// 设置顶点坐标指针glEnableVertexAttribArray(0);glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),(GLvoid*)0);// 设置法线指针glEnableVertexAttribArray(1);glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),(GLvoid*)offsetof(Vertex, Normal));// 设置顶点的纹理坐标glEnableVertexAttribArray(2);glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex),(GLvoid*)offsetof(Vertex, TexCoords));glBindVertexArray(0);}2.定义用于渲染的函数:void Draw(Shader shader){GLuint diffuseNr = 1;GLuint specularNr = 1;for(GLuint i = 0; i < this->textures.size(); i++){glActiveTexture(GL_TEXTURE0 + i); // 在绑定纹理前需要激活适当的纹理单元// 检索纹理序列号(N in diffuse_textureN)stringstream ss;string number;string name = this->textures[i].type;if(name == "texture_diffuse")ss << diffuseNr++; // 将GLuin输入到string streamelse if(name == "texture_specular")ss << specularNr++; // 将GLuin输入到string streamnumber = ss.str();glUniform1f(glGetUniformLocation(shader.Program, ("material." + name + number).c_str()), i);glBindTexture(GL_TEXTURE_2D, this->textures[i].id);}glActiveTexture(GL_TEXTURE0);// 绘制MeshglBindVertexArray(this->VAO);glDrawElements(GL_TRIANGLES, this->indices.size(), GL_UNSIGNED_INT, 0);glBindVertexArray(0);3.编写顶点着色器和片段着色器的代码:#version 330 corelayout(location = 0) in vec3 position;layout(location = 1) in vec3 normal;layout(location = 2) in vec2 texCoords;out vec2 TexCoords;uniform mat4 model;uniform mat4 view;uniform mat4 projection;void main(){gl_Position = projection * view * model * vec4(position, 1.0f);TexCoords = texCoords;}#version 330 corein vec2 TexCoords;out vec4 color;uniform sampler2D texture_diffuse1;void main(){color = vec4(texture(texture_diffuse1, TexCoords));}4.把3D模型导入OpenGL:void loadModel(string path){Assimp::Importer import;const aiScene* scene = import.ReadFile(path, aiProcess_Triangulate | aiProcess_FlipUVs);if(!scene || scene->mFlags == AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode){cout << "ERROR::ASSIMP::" << import.GetErrorString() << endl;return;}this->directory = path.substr(0, path.find_last_of('/'));this->processNode(scene->mRootNode, scene);}void processNode(aiNode* node, const aiScene* scene){// 添加当前节点中的所有Meshfor(GLuint i = 0; i < node->mNumMeshes; i++){aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];this->meshes.push_back(this->processMesh(mesh, scene));}// 递归处理该节点的子孙节点for(GLuint i = 0; i < node->mNumChildren; i++){this->processNode(node->mChildren[i], scene);}}5.优化:vector<Texture> loadMaterialTextures(aiMaterial* mat, aiTextureType type, string typeName) {vector<Texture> textures;for(GLuint i = 0; i < mat->GetTextureCount(type); i++){aiString str;mat->GetTexture(type, i, &str);GLboolean skip = false;for(GLuint j = 0; j < textures_loaded.size(); j++){if(textures_loaded[j].path == str){textures.push_back(textures_loaded[j]);skip = true;break;}}if(!skip){ // 如果纹理没有被加载过,加载之Texture texture;texture.id = TextureFromFile(str.C_Str(), this->directory);texture.type = typeName;texture.path = str;textures.push_back(texture);this->textures_loaded.push_back(texture); // 添加到纹理列表textures}}return textures;}五、实验结果六、实验体会这次实验是做模型加载,在之前的实验中,我们通过在程序中指定的立方体数据,绘制立方体,看起来还是很乏味。
这次实验做模型加载,通过加载丰富的模型,能够丰富我们的场景,变得好玩。
当然它也比之前的实验更复杂,要理解Mesh网格、知道如何载入obj模型,实验代码虽然简洁,但是理解起来比较困难,需要反复看代码,才能真正理解透彻。