#define GLM_ENABLE_EXPERIMENTAL #include #include #include "Mesh.h" #include #include #include #include #include #include #include /** * Constructor, loading the specified aiMesh **/ Mesh::MeshEntry::MeshEntry(Dataset &set, Mesh *m) { renderType = NO_INDEX; parent = m; shininessStrength = 0; vbo[VERTEX_BUFFER] = NULL; vbo[NORMAL_BUFFER] = NULL; vbo[TEXCOORD_BUFFER] = NULL; vbo[COLOR_BUFFER] = NULL; vbo[INDEX_BUFFER] = NULL; vbo[TANGENTS_BUFFER] = NULL; vbo[BITTANGENTS_BUFFER] = NULL; glGenVertexArrays(1, &vao); glBindVertexArray(vao); //Copy Mesh vertices to VBO glGenBuffers(1, &vbo[VERTEX_BUFFER]); glBindBuffer(GL_ARRAY_BUFFER, vbo[VERTEX_BUFFER]); glBufferData(GL_ARRAY_BUFFER, set.vertices.size() * 3 * sizeof(GLfloat), set.vertices.data(), GL_STATIC_DRAW); glVertexAttribPointer(VERTEX_BUFFER, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 3, NULL); glEnableVertexAttribArray(VERTEX_BUFFER); //Copy Normals to VBO glGenBuffers(1, &vbo[NORMAL_BUFFER]); glBindBuffer(GL_ARRAY_BUFFER, vbo[NORMAL_BUFFER]); glBufferData(GL_ARRAY_BUFFER, set.normals.size() * 3 * sizeof(GLfloat), set.normals.data(), GL_STATIC_DRAW); glVertexAttribPointer(NORMAL_BUFFER, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 3, NULL); glEnableVertexAttribArray(NORMAL_BUFFER); //Copy texture mapping to VBO if (set.tex_mapping.size() > 0) { glGenBuffers(1, &vbo[TEXCOORD_BUFFER]); glBindBuffer(GL_ARRAY_BUFFER, vbo[TEXCOORD_BUFFER]); glBufferData(GL_ARRAY_BUFFER, 2 * set.tex_mapping.size() * sizeof(GLfloat), set.tex_mapping.data(), GL_STATIC_DRAW); glVertexAttribPointer(TEXCOORD_BUFFER, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 2, NULL); glEnableVertexAttribArray(TEXCOORD_BUFFER); } //Copy vertice color to VBO if (set.colors.size() > 0) { glGenBuffers(1, &vbo[COLOR_BUFFER]); glBindBuffer(GL_ARRAY_BUFFER, vbo[COLOR_BUFFER]); glBufferData(GL_ARRAY_BUFFER, set.colors.size() * 3 * sizeof(GLfloat), set.colors.data(), GL_STATIC_DRAW); glVertexAttribPointer(COLOR_BUFFER, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 3, NULL); glEnableVertexAttribArray(COLOR_BUFFER); } //Copy indexes to VBO if (set.indexes.size() > 0) { renderType = OBJ; glGenBuffers(1, &vbo[INDEX_BUFFER]); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo[INDEX_BUFFER]); glBufferData(GL_ELEMENT_ARRAY_BUFFER, set.indexes.size() * sizeof(GLuint), set.indexes.data(), GL_STATIC_DRAW); glVertexAttribPointer(INDEX_BUFFER, 3, GL_FLOAT, GL_FALSE, 0, NULL); glEnableVertexAttribArray(INDEX_BUFFER); } dset_size = set.vertices.size(); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); } Mesh::MeshEntry::MeshEntry(aiMesh *mesh, const aiScene* scene, Mesh * m) { renderType = OBJ; parent = m; vbo[VERTEX_BUFFER] = NULL; vbo[TEXCOORD_BUFFER] = NULL; vbo[NORMAL_BUFFER] = NULL; vbo[COLOR_BUFFER] = NULL; vbo[INDEX_BUFFER] = NULL; vbo[TANGENTS_BUFFER] = NULL; vbo[BITTANGENTS_BUFFER] = NULL; glGenVertexArrays(1, &vao); glBindVertexArray(vao); elementCount = mesh->mNumFaces * 3; if (mesh->HasPositions()) { float *vertices = new float[mesh->mNumVertices * 3]; for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { vertices[i * 3] = mesh->mVertices[i].x; vertices[i * 3 + 1] = mesh->mVertices[i].y; vertices[i * 3 + 2] = mesh->mVertices[i].z; } glGenBuffers(1, &vbo[VERTEX_BUFFER]); glBindBuffer(GL_ARRAY_BUFFER, vbo[VERTEX_BUFFER]); glBufferData(GL_ARRAY_BUFFER, 3 * mesh->mNumVertices * sizeof(GLfloat), vertices, GL_STATIC_DRAW); glVertexAttribPointer(VERTEX_BUFFER, 3, GL_FLOAT, GL_FALSE, 0, NULL); glEnableVertexAttribArray(VERTEX_BUFFER); delete[] vertices; } if (mesh->HasNormals()) { float *normals = new float[mesh->mNumVertices * 3]; for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { normals[i * 3] = mesh->mNormals[i].x; normals[i * 3 + 1] = mesh->mNormals[i].y; normals[i * 3 + 2] = mesh->mNormals[i].z; } glGenBuffers(1, &vbo[NORMAL_BUFFER]); glBindBuffer(GL_ARRAY_BUFFER, vbo[NORMAL_BUFFER]); glBufferData(GL_ARRAY_BUFFER, 3 * mesh->mNumVertices * sizeof(GLfloat), normals, GL_STATIC_DRAW); glVertexAttribPointer(NORMAL_BUFFER, 3, GL_FLOAT, GL_FALSE, 0, NULL); glEnableVertexAttribArray(NORMAL_BUFFER); delete[] normals; } if (mesh->HasTextureCoords(0)) { float *texCoords = new float[mesh->mNumVertices * 2]; for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { texCoords[i * 2] = mesh->mTextureCoords[0][i].x; texCoords[i * 2 + 1] = mesh->mTextureCoords[0][i].y; } glGenBuffers(1, &vbo[TEXCOORD_BUFFER]); glBindBuffer(GL_ARRAY_BUFFER, vbo[TEXCOORD_BUFFER]); glBufferData(GL_ARRAY_BUFFER, 2 * mesh->mNumVertices * sizeof(GLfloat), texCoords, GL_STATIC_DRAW); glVertexAttribPointer(TEXCOORD_BUFFER, 2, GL_FLOAT, GL_FALSE, 0, NULL); glEnableVertexAttribArray(TEXCOORD_BUFFER); delete[] texCoords; } if (mesh->HasFaces()) { unsigned int *indices = new unsigned int[mesh->mNumFaces * 3]; for (unsigned int i = 0; i < mesh->mNumFaces; ++i) { indices[i * 3] = mesh->mFaces[i].mIndices[0]; indices[i * 3 + 1] = mesh->mFaces[i].mIndices[1]; indices[i * 3 + 2] = mesh->mFaces[i].mIndices[2]; } glGenBuffers(1, &vbo[INDEX_BUFFER]); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo[INDEX_BUFFER]); glBufferData(GL_ELEMENT_ARRAY_BUFFER, 3 * mesh->mNumFaces * sizeof(GLuint), indices, GL_STATIC_DRAW); glVertexAttribPointer(INDEX_BUFFER, 3, GL_FLOAT, GL_FALSE, 0, NULL); glEnableVertexAttribArray(INDEX_BUFFER); delete[] indices; } if (mesh->HasTangentsAndBitangents()) { float *tangents = new float[mesh->mNumVertices * 3]; float *bittangents = new float[mesh->mNumVertices * 3]; for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { tangents[i * 3] = mesh->mTangents[i].x; tangents[i * 3 + 1] = mesh->mTangents[i].y; tangents[i * 3 + 2] = mesh->mTangents[i].z; bittangents[i * 3] = mesh->mBitangents[i].x; bittangents[i * 3 + 1] = mesh->mBitangents[i].y; bittangents[i * 3 + 2] = mesh->mBitangents[i].z; } glGenBuffers(1, &vbo[TANGENTS_BUFFER]); glBindBuffer(GL_ARRAY_BUFFER, vbo[TANGENTS_BUFFER]); glBufferData(GL_ARRAY_BUFFER, 3 * mesh->mNumVertices * sizeof(GLfloat), tangents, GL_STATIC_DRAW); glVertexAttribPointer(TANGENTS_BUFFER, 3, GL_FLOAT, GL_FALSE, 0, NULL); glEnableVertexAttribArray(TANGENTS_BUFFER); glGenBuffers(1, &vbo[BITTANGENTS_BUFFER]); glBindBuffer(GL_ARRAY_BUFFER, vbo[BITTANGENTS_BUFFER]); glBufferData(GL_ARRAY_BUFFER, 3 * mesh->mNumVertices * sizeof(GLfloat), bittangents, GL_STATIC_DRAW); glVertexAttribPointer(BITTANGENTS_BUFFER, 3, GL_FLOAT, GL_FALSE, 0, NULL); glEnableVertexAttribArray(BITTANGENTS_BUFFER); delete[] tangents; delete[] bittangents; } if (mesh->mMaterialIndex >= 0) { aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex]; material->Get(AI_MATKEY_SHININESS, shininessStrength); material->Get(AI_MATKEY_COLOR_DIFFUSE, dcolor); material->Get(AI_MATKEY_COLOR_AMBIENT, acolor); material->Get(AI_MATKEY_COLOR_SPECULAR, scolor); if (material->GetTextureCount(aiTextureType_DIFFUSE) > 0) { //we only care diffuse texture aiString Path; if (material->GetTexture(aiTextureType_DIFFUSE, 0, &Path, NULL, NULL, NULL, NULL, NULL) == AI_SUCCESS) { std::string FullPath = parent->directory + Path.data; //texture file textures.push_back(parent->textures[FullPath]); } } } glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); } /** * Deletes the allocated OpenGL buffers **/ Mesh::MeshEntry::~MeshEntry() { if (vbo[VERTEX_BUFFER]) { glDeleteBuffers(1, &vbo[VERTEX_BUFFER]); } if (vbo[TEXCOORD_BUFFER]) { glDeleteBuffers(1, &vbo[TEXCOORD_BUFFER]); } if (vbo[NORMAL_BUFFER]) { glDeleteBuffers(1, &vbo[NORMAL_BUFFER]); } if (vbo[INDEX_BUFFER]) { glDeleteBuffers(1, &vbo[INDEX_BUFFER]); } if (vbo[COLOR_BUFFER]) { glDeleteBuffers(1, &vbo[COLOR_BUFFER]); } if (vbo[BITTANGENTS_BUFFER]) { glDeleteBuffers(1, &vbo[BITTANGENTS_BUFFER]); } if (vbo[TANGENTS_BUFFER]) { glDeleteBuffers(1, &vbo[TANGENTS_BUFFER]); } glDeleteVertexArrays(1, &vao); } /** * Renders this MeshEntry **/ void Mesh::MeshEntry::render(SceneContext &ctx, Shader &shd) { glBindVertexArray(vao); if (renderType == NO_INDEX) { glDrawArrays(GL_TRIANGLES, 0, dset_size); } else { int size; glGetBufferParameteriv(GL_ELEMENT_ARRAY_BUFFER, GL_BUFFER_SIZE, &size); glDrawElements(GL_TRIANGLES, size / sizeof(unsigned int), GL_UNSIGNED_INT, NULL); } glBindVertexArray(0); } /** * Mesh constructor, loads the specified filename if supported by Assimp **/ Mesh::Mesh(const char *filename, std::string vert_shd, std::string frag_shd) { shader = std::make_shared(vert_shd, frag_shd); std::string fullname; fullname = std::string("./Models/")+ std::string(filename); directory = fullname; directory.resize(fullname.find_last_of('/') + 1); Assimp::Importer importer; //aiProcessPreset_TargetRealtime_Fast const aiScene* scene = importer.ReadFile(fullname.c_str(), aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_GenSmoothNormals | aiProcess_OptimizeMeshes | aiProcess_CalcTangentSpace); // Check for errors if (!scene || scene->mFlags == AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) // if is Not Zero { std::cout << "ERROR::ASSIMP:: " << importer.GetErrorString() << std::endl; throw new std::exception(("Error loading mesh at the following location : " + fullname).c_str()); } for (unsigned int i = 0; i < scene->mNumMeshes; ++i) { meshEntries.push_back(new Mesh::MeshEntry(scene->mMeshes[i], scene, this)); for (unsigned int i = 0; i < scene->mNumMaterials; i++) { aiMaterial* material = scene->mMaterials[i]; if (material->GetTextureCount(aiTextureType_DIFFUSE) > 0) { aiString Path; if (material->GetTexture(aiTextureType_DIFFUSE, 0, &Path, NULL, NULL, NULL, NULL, NULL) == AI_SUCCESS) { std::string FullPath = directory + Path.data; //texture file textures.emplace("0", Texture(FullPath)); } } } } } Mesh::Mesh(Dataset &set, std::string vert_shd, std::string frag_shd) { shader = std::make_shared(vert_shd, frag_shd); meshEntries.push_back(new Mesh::MeshEntry(set, this)); } /** * Clears all loaded MeshEntries **/ Mesh::~Mesh(void) { for (unsigned int i = 0; i < meshEntries.size(); ++i) { delete meshEntries.at(i); } meshEntries.clear(); } void Mesh::draw(SceneContext &ctx) { shader->enable(); for (unsigned int i = 0; i < meshEntries.size(); ++i) { MeshEntry * m = meshEntries[i]; // Moving the object to his set position model.glPushMatrix(); effectTransformations(); // Setting the space matrixes uniques to the object ctx.modelMatrix = model.getMatrix(); ctx.mvpMatrix = ctx.projectionMatrix * ctx.viewMatrix * ctx.modelMatrix; //ctx.modelViewMatrix = ctx.viewMatrix * ctx.modelMatrix; ctx.normalMatrix = glm::transpose(glm::inverse(glm::mat3(ctx.modelMatrix))); shader->addUniform("mvp", ctx.mvpMatrix); shader->addUniform("NormalMatrix", ctx.normalMatrix); shader->addUniform("ModelMatrix", ctx.modelMatrix); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, textures["0"].tex_ref); meshEntries.at(i)->render(ctx, *shader); glBindTexture(GL_TEXTURE_2D, 0); model.glPopMatrix(); } shader->disable(); } void Mesh::effectTransformations() { for (auto pair : _transformations) { switch (pair.second) { case(Rotation): model.glRotate(pair.first.w, pair.first.x, pair.first.y, pair.first.z); break; case(Translation): model.glTranslate(pair.first.x, pair.first.y, pair.first.z); break; case(Scaling): model.glScale(pair.first.x, pair.first.y, pair.first.z); break; } } } void Mesh::addStartRotation(glm::vec4 vec) { model.glRotate(vec.w, vec.x, vec.y, vec.z); } void Mesh::addStartTranslation(glm::vec4 vec) { model.glTranslate(vec.x, vec.y, vec.z); } void Mesh::addStartScaling(glm::vec4 vec) { model.glScale(vec.x, vec.y, vec.z); } void Mesh::addRotation(glm::vec4 vec) { _transformations.emplace_back(vec, Rotation); } void Mesh::addTranslation(glm::vec4 vec) { _transformations.emplace_back(vec, Translation); } void Mesh::addScaling(glm::vec4 vec) { _transformations.emplace_back(vec, Scaling); } glm::vec4 Mesh::translateToPivot(glm::vec3 pivot) { glm::vec4 curr_pos = { 0, 0, 0, 0 }; glm::vec4 h_pivot = { pivot.x, pivot.y, pivot.z, 0 }; for (auto pair : _transformations) { if (pair.second == Translation) curr_pos += pair.first; } addTranslation(h_pivot - curr_pos); return curr_pos - h_pivot; } void Mesh::removeLastTransformations(int n = 1) { for (int i = 0; i < n; i++) _transformations.pop_back(); } glm::vec3 Mesh::getPosition() { glm::vec4 curr_pos = { 0, 0, 0, 0 }; for (auto pair : _transformations) { if (pair.second == Translation) curr_pos += pair.first; } return curr_pos; }