// // Created by Lenn on 2025/12/2. // #ifndef COORDINATE_SYSTEM_PROJECT_MESH_HH #define COORDINATE_SYSTEM_PROJECT_MESH_HH #include #include #include #include #include #include #include #include #include #include #include #include "myshader.hh" #include "stb_image.h" #define MAX_BONE_INFLUENCE 4 struct Vertex { glm::vec3 Position; glm::vec3 Normal; glm::vec2 TexCoords; glm::vec3 Tangent; glm::vec3 Bitangent; int BoneIDs[MAX_BONE_INFLUENCE]; float Weights[MAX_BONE_INFLUENCE]; }; struct Texture { unsigned int id; std::string type; std::string path; }; class Mesh { public: std::vector vertices; std::vector indices; std::vector textures; // unsigned int VAO; Mesh(std::vector vertices, std::vector indices, std::vector textures) { vertices_ = vertices; indices_ = indices; textures_ = textures; setup_mesh(); } void draw(Shader& shader) { unsigned int diffuse_nr = 1; unsigned int specular_nr = 1; for (unsigned int i = 0; i < textures.size(); i++) { glActiveTexture(GL_TEXTURE0 + i); std::string number; std::string name = textures[i].type; if (name == "texture_diffuse") number = std::to_string(diffuse_nr++); else if (name == "texture_specular") number = std::to_string(specular_nr++); shader.setInt(("material." + name + number).c_str(), i); glBindTexture(GL_TEXTURE_2D, textures[i].id); } glActiveTexture(GL_TEXTURE0); glBindVertexArray(VAO); glDrawElements(GL_TRIANGLES, static_cast(indices.size()), GL_UNSIGNED_INT, 0); glBindVertexArray(0); } private: unsigned int VAO, VBO, EBO; std::vector vertices_; std::vector indices_; std::vector textures_; void setup_mesh() { glGenVertexArrays(1, &VAO); glGenBuffers(1, &VBO); glGenBuffers(1, &EBO); glBindVertexArray(VAO); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), &vertices[0], GL_STATIC_DRAW); 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), (void*)offsetof(Vertex, TexCoords)); glEnableVertexAttribArray(3); glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Tangent)); glEnableVertexAttribArray(4); glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Bitangent)); glEnableVertexAttribArray(5); glVertexAttribPointer(5, 4, GL_INT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, BoneIDs)); glEnableVertexAttribArray(6); glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Weights)); glBindVertexArray(0); } }; unsigned int TextureFromFile(const char* path, const std::string& directory, bool gamma = false); class Model { public: Model(char* path) { } void draw(Shader shader) { for (unsigned int i = 0; i < meshes_.size(); i++) { meshes_[i].draw(shader); } } private: std::vector textures_; std::vector meshes_; std::string directory_; bool gamma_correction_; void loadModel(std::string path) { Assimp::Importer importer; const aiScene* scene = importer.ReadFile(path, aiProcess_Triangulate | aiProcess_GenSmoothNormals); if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) { std::cout << "ERROR:ASSIMP::" << importer.GetErrorString(); return; } directory_ = path.substr(0, path.find_last_of('/')); processNode(scene->mRootNode, scene); } void processNode(aiNode* node, const aiScene* scene) { // 处理节点所有的网格(如果有的话) for (unsigned int i = 0; i < node->mNumMeshes; i++) { aiMesh* mesh = scene->mMeshes[node->mMeshes[i]]; meshes_.push_back(processMesh(mesh, scene)); } // 接下来对它的子节点重复这一过程 for (unsigned int i = 0; i < node->mNumChildren; i++) { processNode(node->mChildren[i], scene); } } Mesh processMesh(aiMesh* mesh, const aiScene* scene) { std::vector vertices; std::vector indices; std::vector textures; for (unsigned int i = 0; i < mesh->mNumVertices; i++) { Vertex vertex; glm::vec3 vector; vector.x = mesh->mVertices[i].x; vector.y = mesh->mVertices[i].y; vector.z = mesh->mVertices[i].z; vertex.Position = vector; if (mesh->HasNormals()) { vector.x = mesh->mNormals[i].x; vector.y = mesh->mNormals[i].y; vector.z = mesh->mNormals[i].z; vertex.Normal = vector; } if (mesh->mTextureCoords[0]) { glm::vec2 vec; vec.x = mesh->mTextureCoords[0][i].x; vec.y = mesh->mTextureCoords[0][i].y; vertex.TexCoords = vec; vector.x = mesh->mTangents[i].x; vector.y = mesh->mTangents[i].y; vector.z = mesh->mTangents[i].z; vertex.Tangent = vector; vector.x = mesh->mBitangents[i].x; vector.y = mesh->mBitangents[i].y; vector.z = mesh->mBitangents[i].z; vertex.Bitangent = vector; } else vertex.TexCoords = glm::vec2(0.0f, 0.0f); vertices.push_back(vertex); } for (unsigned int i = 0; i < mesh->mNumFaces; i++) { aiFace face = mesh->mFaces[i]; for (unsigned int j = 0; j < face.mNumIndices; j++) { indices.push_back(face.mIndices[j]); } } aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex]; std::vector diffuseMaps = loadMaterialTextures(material, aiTextureType_DIFFUSE, "texture_diffuse"); textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end()); std::vector specularMaps = loadMaterialTextures(material, aiTextureType_SPECULAR, "texture_specular"); textures.insert(textures.end(), specularMaps.begin(), specularMaps.end()); std::vector normalMaps = loadMaterialTextures(material, aiTextureType_HEIGHT, "texture_normal"); textures.insert(textures.end(), normalMaps.begin(), normalMaps.end()); std::vector heightMaps = loadMaterialTextures(material, aiTextureType_AMBIENT, "texture_height"); textures.insert(textures.end(), textures.begin(), heightMaps.end()); return Mesh(vertices, indices, textures); } std::vector loadMaterialTextures(aiMaterial* mat, aiTextureType type, std::string type_name) { std::vector textures; for (unsigned int i = 0; i < mat->GetTextureCount(type); i++) { aiString str; mat->GetTexture(type, i, &str); bool skip = false; for (unsigned int j = 0; j < textures_.size(); j++) { if (std::strcmp(textures_[j].path.data(), str.C_Str()) == 0) { textures.push_back(textures_[j]); skip = true; break; } } if (!skip) { Texture texture; texture.id = textureFromFile(str.C_Str(), this->directory_, false); texture.type = type_name; texture.path = str.C_Str(); textures.push_back(texture); textures_.push_back(texture); } } return textures; } unsigned int textureFromFile(const char* path, const std::string& directory, bool gamma) { std::string filename = std::string(path); filename = directory + '/' + filename; unsigned int textureID; glGenTextures(1, &textureID); int width, height, nrComponents; unsigned char* data = stbi_load(filename.c_str(), &width, &height, &nrComponents, 0); if (data) { GLenum fromat; if (nrComponents == 1) { fromat = GL_RED; } else if (nrComponents == 3) { fromat = GL_RGB; } else if (nrComponents == 4) { fromat = GL_RGBA; } glBindTexture(GL_TEXTURE_2D, textureID); glTexImage2D(GL_TEXTURE_2D, 0, fromat, width, height, 0, fromat, 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; } }; #endif // COORDINATE_SYSTEM_PROJECT_MESH_HH