#pragmaonce#ifndefMODEL_H#defineMODEL_H#include<glad/glad.h>#include<glm/glm.hpp>#include<glm/gtc/matrix_transform.hpp>#include"stb_image.h"#include<assimp/Importer.hpp>#include<assimp/scene.h>#include<assimp/postprocess.h>#include"mesh.h"#include"Shader.h"#include<string>#include<fstream>#include<sstream>#include<iostream>#include<map>#include<vector>usingnamespace std;classModel{public:/* 函數 */Model(constchar* path){loadModel(path);//調用模型路徑加載函數}//渲染函數voidDraw(Shader shader){for(unsignedint i =0; i < meshes.size(); i++)meshes[i].Draw(shader);//調用mesh的draw函數 }private:/* 模型數據 */vector<Mesh> meshes;string directory;/* 加載模型函數 */voidloadModel(string path){// 讀取文件 via ASSIMPAssimp::Importer importer;const aiScene* scene = importer.ReadFile(path, aiProcess_Triangulate | aiProcess_FlipUVs);//用三角形|翻轉Y軸|還有一個切線空間暫時用不到// check for errorsif(!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE ||!scene->mRootNode)// if is Not Zero{cout <<"ERROR::ASSIMP:: "<< importer.GetErrorString()<< endl;return;}// retrieve the directory path of the filepathdirectory = path.substr(0, path.find_last_of('/'));// process ASSIMP's root node recursivelyprocessNode(scene->mRootNode, scene);//通過路徑尋找并且賦值}//遞歸去獲取這些網格索引,獲取每個網格,處理每個網格,接著對每個節點的子節點重復這一過程。//結構都放進meshes里邊voidprocessNode(aiNode* node,const aiScene* scene){// 處理節點所有的網格(如果有的話)for(unsignedint i =0; i < node->mNumMeshes; i++){aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];meshes.push_back(processMesh(mesh, scene));//函數將一個新的元素加到vector的最后面,位置為當前最后一個元素的下一個元素}// 接下來對它的子節點重復這一過程for(unsignedint i =0; i < node->mNumChildren; i++){processNode(node->mChildren[i], scene);}}//將構造mesh函數放到model類里邊Mesh processMesh(aiMesh* mesh,const aiScene* scene){vector<Vertex> vertices;vector<unsignedint> indices;vector<Texture> textures;for(unsignedint i =0; i < mesh->mNumVertices; i++){Vertex vertex;// 處理頂點位置、法線和紋理坐標glm::vec3 vector;// we declare a placeholder vector since assimp uses its own vector class that doesn't directly convert to glm's vec3 class so we transfer the data to this placeholder glm::vec3 first.// positionsvector.x = mesh->mVertices[i].x;vector.y = mesh->mVertices[i].y;vector.z = mesh->mVertices[i].z;vertex.Position = vector;// normalsvector.x = mesh->mNormals[i].x;vector.y = mesh->mNormals[i].y;vector.z = mesh->mNormals[i].z;vertex.Normal = vector;// texture coordinatesif(mesh->mTextureCoords[0])// does the mesh contain texture coordinates?{glm::vec2 vec;// a vertex can contain up to 8 different texture coordinates. We thus make the assumption that we won't // use models where a vertex can have multiple texture coordinates so we always take the first set (0).vec.x = mesh->mTextureCoords[0][i].x;vec.y = mesh->mTextureCoords[0][i].y;vertex.TexCoords = vec;}elsevertex.TexCoords = glm::vec2(0.0f,0.0f);//沒有紋理的情況vertices.push_back(vertex);}// 處理索引for(unsignedint i =0; i < mesh->mNumFaces; i++){aiFace face = mesh->mFaces[i];// retrieve all indices of the face and store them in the indices vectorfor(unsignedint j =0; j < face.mNumIndices; j++)indices.push_back(face.mIndices[j]);}//處理材質//把所有的材質按照類型分類放到向量里邊if(mesh->mMaterialIndex >=0){//注意這里是給材質對象賦值aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex];//分別構造兩個紋理數組存放漫反射和鏡面反射紋理vector<Texture> diffuseMaps =loadMaterialTextures(material,aiTextureType_DIFFUSE,"texture_diffuse");textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end());//填充vector<Texture> specularMaps =loadMaterialTextures(material,aiTextureType_SPECULAR,"texture_specular");textures.insert(textures.end(), specularMaps.begin(), specularMaps.end());}returnMesh(vertices, indices, textures);}//加載與存儲紋理vector<Texture>loadMaterialTextures(aiMaterial* mat, aiTextureType type,string typeName){vector<Texture> textures;for(unsignedint i =0; i < mat->GetTextureCount(type); i++){aiString str;mat->GetTexture(type, i,&str);Texture texture;texture.id =TextureFromFile(str.C_Str(), directory);texture.type = typeName;texture.path = str.C_Str();textures.push_back(texture);}return textures;}//讀取紋理文件unsignedintTextureFromFile(constchar* path,const string& directory){string filename =string(path);filename = directory +'/'+ filename;unsignedint textureID;glGenTextures(1,&textureID);int width, height, nrComponents;unsignedchar* data =stbi_load(filename.c_str(),&width,&height,&nrComponents,0);if(data){GLenum format;if(nrComponents ==1)format = GL_RED;elseif(nrComponents ==3)format = GL_RGB;elseif(nrComponents ==4)format = GL_RGBA;glBindTexture(GL_TEXTURE_2D, textureID);glTexImage2D(GL_TEXTURE_2D,0, format, width, height,0, format, GL_UNSIGNED_BYTE, data);glGenerateMipmap(GL_TEXTURE_2D);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);stbi_image_free(data);}else{std::cout <<"Texture failed to load at path: "<< path << std::endl;stbi_image_free(data);}return textureID;//返回textureID}};#endif