From 70b789d3b939accf7fb565150b516a709f1512a8 Mon Sep 17 00:00:00 2001 From: Joey de Vries Date: Wed, 31 May 2017 19:02:05 +0200 Subject: [PATCH] Code re-work with content: model-loading. --- includes/learnopengl/mesh.h | 137 +++++++-------- includes/learnopengl/model.h | 163 +++++++++--------- .../1.model_loading/1.model_loading.vs | 2 +- .../1.model_loading/model_loading.cpp | 22 +-- 4 files changed, 162 insertions(+), 162 deletions(-) diff --git a/includes/learnopengl/mesh.h b/includes/learnopengl/mesh.h index dd9a322..a62304a 100644 --- a/includes/learnopengl/mesh.h +++ b/includes/learnopengl/mesh.h @@ -1,32 +1,33 @@ -#pragma once -// Std. Includes +#ifndef MESH_H +#define MESH_H + +#include // holds all OpenGL type declarations + +#include +#include + #include #include #include #include #include using namespace std; -// GL Includes -#include // Contains all the necessery OpenGL includes -#include -#include - struct Vertex { - // Position + // position glm::vec3 Position; - // Normal + // normal glm::vec3 Normal; - // TexCoords + // texCoords glm::vec2 TexCoords; - // Tangent + // tangent glm::vec3 Tangent; - // Bitangent + // bitangent glm::vec3 Bitangent; }; struct Texture { - GLuint id; + unsigned int id; string type; aiString path; }; @@ -35,109 +36,103 @@ class Mesh { public: /* Mesh Data */ vector vertices; - vector indices; + vector indices; vector textures; - GLuint VAO; + unsigned int VAO; /* Functions */ - // Constructor - Mesh(vector vertices, vector indices, vector textures) + // constructor + Mesh(vector vertices, vector indices, vector textures) { this->vertices = vertices; this->indices = indices; this->textures = textures; - // Now that we have all the required data, set the vertex buffers and its attribute pointers. - this->setupMesh(); + // now that we have all the required data, set the vertex buffers and its attribute pointers. + setupMesh(); } - // Render the mesh + // render the mesh void Draw(Shader shader) { - // Bind appropriate textures - GLuint diffuseNr = 1; - GLuint specularNr = 1; - GLuint normalNr = 1; - GLuint heightNr = 1; - for(GLuint i = 0; i < this->textures.size(); i++) + // bind appropriate textures + unsigned int diffuseNr = 1; + unsigned int specularNr = 1; + unsigned int normalNr = 1; + unsigned int heightNr = 1; + for(unsigned int i = 0; i < textures.size(); i++) { - glActiveTexture(GL_TEXTURE0 + i); // Active proper texture unit before binding - // Retrieve texture number (the N in diffuse_textureN) + glActiveTexture(GL_TEXTURE0 + i); // active proper texture unit before binding + // retrieve texture number (the N in diffuse_textureN) stringstream ss; string number; - string name = this->textures[i].type; + string name = textures[i].type; if(name == "texture_diffuse") - ss << diffuseNr++; // Transfer GLuint to stream + ss << diffuseNr++; // transfer unsigned int to stream else if(name == "texture_specular") - ss << specularNr++; // Transfer GLuint to stream + ss << specularNr++; // transfer unsigned int to stream else if(name == "texture_normal") - ss << normalNr++; // Transfer GLuint to stream + ss << normalNr++; // transfer unsigned int to stream else if(name == "texture_height") - ss << heightNr++; // Transfer GLuint to stream + ss << heightNr++; // transfer unsigned int to stream number = ss.str(); - // Now set the sampler to the correct texture unit + // now set the sampler to the correct texture unit glUniform1i(glGetUniformLocation(shader.ID, (name + number).c_str()), i); - // And finally bind the texture - glBindTexture(GL_TEXTURE_2D, this->textures[i].id); + // and finally bind the texture + glBindTexture(GL_TEXTURE_2D, textures[i].id); } - // Draw mesh - glBindVertexArray(this->VAO); - glDrawElements(GL_TRIANGLES, this->indices.size(), GL_UNSIGNED_INT, 0); + // draw mesh + glBindVertexArray(VAO); + glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0); glBindVertexArray(0); - // Always good practice to set everything back to defaults once configured. - for (GLuint i = 0; i < this->textures.size(); i++) - { - glActiveTexture(GL_TEXTURE0 + i); - glBindTexture(GL_TEXTURE_2D, 0); - } + // always good practice to set everything back to defaults once configured. + glActiveTexture(GL_TEXTURE0); } private: /* Render data */ - GLuint VBO, EBO; + unsigned int VBO, EBO; /* Functions */ - // Initializes all the buffer objects/arrays + // initializes all the buffer objects/arrays void setupMesh() { - // Create buffers/arrays - glGenVertexArrays(1, &this->VAO); - glGenBuffers(1, &this->VBO); - glGenBuffers(1, &this->EBO); + // create buffers/arrays + glGenVertexArrays(1, &VAO); + glGenBuffers(1, &VBO); + glGenBuffers(1, &EBO); - glBindVertexArray(this->VAO); - // Load data into vertex buffers - glBindBuffer(GL_ARRAY_BUFFER, this->VBO); + glBindVertexArray(VAO); + // load data into vertex buffers + glBindBuffer(GL_ARRAY_BUFFER, VBO); // A great thing about structs is that their memory layout is sequential for all its items. // The effect is that we can simply pass a pointer to the struct and it translates perfectly to a glm::vec3/2 array which // again translates to 3/2 floats which translates to a byte array. - glBufferData(GL_ARRAY_BUFFER, this->vertices.size() * sizeof(Vertex), &this->vertices[0], GL_STATIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), &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); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), &indices[0], GL_STATIC_DRAW); - // Set the vertex attribute pointers - // Vertex Positions + // set the vertex attribute pointers + // vertex Positions glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)0); - // Vertex Normals + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0); + // vertex normals glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, Normal)); - // Vertex Texture Coords + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Normal)); + // vertex texture coords glEnableVertexAttribArray(2); - glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, TexCoords)); - // Vertex Tangent + glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, TexCoords)); + // vertex tangent glEnableVertexAttribArray(3); - glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, Tangent)); - // Vertex Bitangent + glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Tangent)); + // vertex bitangent glEnableVertexAttribArray(4); - glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, Bitangent)); + glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Bitangent)); glBindVertexArray(0); } }; - - - +#endif \ No newline at end of file diff --git a/includes/learnopengl/model.h b/includes/learnopengl/model.h index 91e5d9a..ba1521e 100644 --- a/includes/learnopengl/model.h +++ b/includes/learnopengl/model.h @@ -1,14 +1,8 @@ -#pragma once -// Std. Includes -#include -#include -#include -#include -#include -#include -using namespace std; -// GL Includes -#include // Contains all the necessery OpenGL includes +#ifndef MODEL_H +#define MODEL_H + +#include + #include #include #include @@ -18,98 +12,106 @@ using namespace std; #include -unsigned int TextureFromFile(const char* path, string directory, bool gamma = false); +#include +#include +#include +#include +#include +#include +using namespace std; + +unsigned int TextureFromFile(const char *path, const string &directory, bool gamma = false); class Model { public: /* Model Data */ - vector textures_loaded; // Stores all the textures loaded so far, optimization to make sure textures aren't loaded more than once. + vector textures_loaded; // stores all the textures loaded so far, optimization to make sure textures aren't loaded more than once. vector meshes; string directory; bool gammaCorrection; /* Functions */ - // Constructor, expects a filepath to a 3D model. - Model(string const & path, bool gamma = false) : gammaCorrection(gamma) + // constructor, expects a filepath to a 3D model. + Model(string const &path, bool gamma = false) : gammaCorrection(gamma) { - this->loadModel(path); + loadModel(path); } - // Draws the model, and thus all its meshes + // draws the model, and thus all its meshes void Draw(Shader shader) { - for(GLuint i = 0; i < this->meshes.size(); i++) - this->meshes[i].Draw(shader); + for(unsigned int i = 0; i < meshes.size(); i++) + meshes[i].Draw(shader); } private: /* Functions */ - // Loads a model with supported ASSIMP extensions from file and stores the resulting meshes in the meshes vector. - void loadModel(string path) + // loads a model with supported ASSIMP extensions from file and stores the resulting meshes in the meshes vector. + void loadModel(string const &path) { - // Read file via ASSIMP + // read file via ASSIMP Assimp::Importer importer; const aiScene* scene = importer.ReadFile(path, aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_CalcTangentSpace); - // Check for errors + // check for errors if(!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 filepath - this->directory = path.substr(0, path.find_last_of('/')); + // retrieve the directory path of the filepath + directory = path.substr(0, path.find_last_of('/')); - // Process ASSIMP's root node recursively - this->processNode(scene->mRootNode, scene); + // process ASSIMP's root node recursively + processNode(scene->mRootNode, scene); } - // Processes a node in a recursive fashion. Processes each individual mesh located at the node and repeats this process on its children nodes (if any). - void processNode(aiNode* node, const aiScene* scene) + // processes a node in a recursive fashion. Processes each individual mesh located at the node and repeats this process on its children nodes (if any). + void processNode(aiNode *node, const aiScene *scene) { - // Process each mesh located at the current node - for(GLuint i = 0; i < node->mNumMeshes; i++) + // process each mesh located at the current node + for(unsigned int i = 0; i < node->mNumMeshes; i++) { - // The node object only contains indices to index the actual objects in the scene. - // The scene contains all the data, node is just to keep stuff organized (like relations between nodes). - aiMesh* mesh = scene->mMeshes[node->mMeshes[i]]; - this->meshes.push_back(this->processMesh(mesh, scene)); + // the node object only contains indices to index the actual objects in the scene. + // the scene contains all the data, node is just to keep stuff organized (like relations between nodes). + aiMesh* mesh = scene->mMeshes[node->mMeshes[i]]; + meshes.push_back(processMesh(mesh, scene)); } - // After we've processed all of the meshes (if any) we then recursively process each of the children nodes - for(GLuint i = 0; i < node->mNumChildren; i++) + // after we've processed all of the meshes (if any) we then recursively process each of the children nodes + for(unsigned int i = 0; i < node->mNumChildren; i++) { - this->processNode(node->mChildren[i], scene); + processNode(node->mChildren[i], scene); } } - Mesh processMesh(aiMesh* mesh, const aiScene* scene) + Mesh processMesh(aiMesh *mesh, const aiScene *scene) { - // Data to fill + // data to fill vector vertices; - vector indices; + vector indices; vector textures; // Walk through each of the mesh's vertices - for(GLuint i = 0; i < mesh->mNumVertices; i++) + for(unsigned int 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. - // Positions + 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. + // positions vector.x = mesh->mVertices[i].x; vector.y = mesh->mVertices[i].y; vector.z = mesh->mVertices[i].z; vertex.Position = vector; - // Normals + // normals vector.x = mesh->mNormals[i].x; vector.y = mesh->mNormals[i].y; vector.z = mesh->mNormals[i].z; vertex.Normal = vector; - // Texture Coordinates - if(mesh->mTextureCoords[0]) // Does the mesh contain texture coordinates? + // texture coordinates + if(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 + // 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; @@ -117,83 +119,83 @@ private: } else vertex.TexCoords = glm::vec2(0.0f, 0.0f); - // Tangent + // tangent vector.x = mesh->mTangents[i].x; vector.y = mesh->mTangents[i].y; vector.z = mesh->mTangents[i].z; vertex.Tangent = vector; - // Bitangent + // bitangent vector.x = mesh->mBitangents[i].x; vector.y = mesh->mBitangents[i].y; vector.z = mesh->mBitangents[i].z; vertex.Bitangent = vector; vertices.push_back(vertex); } - // Now wak through each of the mesh's faces (a face is a mesh its triangle) and retrieve the corresponding vertex indices. - for(GLuint i = 0; i < mesh->mNumFaces; i++) + // now wak through each of the mesh's faces (a face is a mesh its triangle) and retrieve the corresponding vertex indices. + for(unsigned int i = 0; i < mesh->mNumFaces; i++) { aiFace face = mesh->mFaces[i]; - // Retrieve all indices of the face and store them in the indices vector - for(GLuint j = 0; j < face.mNumIndices; j++) + // retrieve all indices of the face and store them in the indices vector + for(unsigned int j = 0; j < face.mNumIndices; j++) indices.push_back(face.mIndices[j]); } - // Process materials + // process materials if(mesh->mMaterialIndex >= 0) { aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex]; - // We assume a convention for sampler names in the shaders. Each diffuse texture should be named + // we assume a convention for sampler names in the shaders. Each diffuse texture should be named // as 'texture_diffuseN' where N is a sequential number ranging from 1 to MAX_SAMPLER_NUMBER. // Same applies to other texture as the following list summarizes: - // Diffuse: texture_diffuseN - // Specular: texture_specularN - // Normal: texture_normalN + // diffuse: texture_diffuseN + // specular: texture_specularN + // normal: texture_normalN - // 1. Diffuse maps - vector diffuseMaps = this->loadMaterialTextures(material, aiTextureType_DIFFUSE, "texture_diffuse"); + // 1. diffuse maps + vector diffuseMaps = loadMaterialTextures(material, aiTextureType_DIFFUSE, "texture_diffuse"); textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end()); - // 2. Specular maps - vector specularMaps = this->loadMaterialTextures(material, aiTextureType_SPECULAR, "texture_specular"); + // 2. specular maps + vector specularMaps = loadMaterialTextures(material, aiTextureType_SPECULAR, "texture_specular"); textures.insert(textures.end(), specularMaps.begin(), specularMaps.end()); - // 3. Normal maps - std::vector normalMaps = this->loadMaterialTextures(material, aiTextureType_HEIGHT, "texture_normal"); + // 3. normal maps + std::vector normalMaps = loadMaterialTextures(material, aiTextureType_HEIGHT, "texture_normal"); textures.insert(textures.end(), normalMaps.begin(), normalMaps.end()); - // 4. Height maps - std::vector heightMaps = this->loadMaterialTextures(material, aiTextureType_AMBIENT, "texture_height"); + // 4. height maps + std::vector heightMaps = loadMaterialTextures(material, aiTextureType_AMBIENT, "texture_height"); textures.insert(textures.end(), heightMaps.begin(), heightMaps.end()); } - // Return a mesh object created from the extracted mesh data + // return a mesh object created from the extracted mesh data return Mesh(vertices, indices, textures); } - // Checks all material textures of a given type and loads the textures if they're not loaded yet. - // The required info is returned as a Texture struct. - vector loadMaterialTextures(aiMaterial* mat, aiTextureType type, string typeName) + // checks all material textures of a given type and loads the textures if they're not loaded yet. + // the required info is returned as a Texture struct. + vector loadMaterialTextures(aiMaterial *mat, aiTextureType type, string typeName) { vector textures; - for(GLuint i = 0; i < mat->GetTextureCount(type); i++) + for(unsigned int i = 0; i < mat->GetTextureCount(type); i++) { aiString str; mat->GetTexture(type, i, &str); - // Check if texture was loaded before and if so, continue to next iteration: skip loading a new texture - GLboolean skip = false; - for(GLuint j = 0; j < textures_loaded.size(); j++) + // check if texture was loaded before and if so, continue to next iteration: skip loading a new texture + bool skip = false; + for(unsigned int j = 0; j < textures_loaded.size(); j++) { if(std::strcmp(textures_loaded[j].path.C_Str(), str.C_Str()) == 0) { textures.push_back(textures_loaded[j]); - skip = true; // A texture with the same filepath has already been loaded, continue to next one. (optimization) + skip = true; // a texture with the same filepath has already been loaded, continue to next one. (optimization) break; } } if(!skip) - { // If texture hasn't been loaded already, load it + { // if texture hasn't been loaded already, load it 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); // Store it as texture loaded for entire model, to ensure we won't unnecesery load duplicate textures. + textures_loaded.push_back(texture); // store it as texture loaded for entire model, to ensure we won't unnecesery load duplicate textures. } } return textures; @@ -201,7 +203,7 @@ private: }; -unsigned int TextureFromFile(const char* path, string directory, bool gamma) +unsigned int TextureFromFile(const char *path, const string &directory, bool gamma) { string filename = string(path); filename = directory + '/' + filename; @@ -239,4 +241,5 @@ unsigned int TextureFromFile(const char* path, string directory, bool gamma) } return textureID; -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/src/3.model_loading/1.model_loading/1.model_loading.vs b/src/3.model_loading/1.model_loading/1.model_loading.vs index f9203e8..253b79e 100644 --- a/src/3.model_loading/1.model_loading/1.model_loading.vs +++ b/src/3.model_loading/1.model_loading/1.model_loading.vs @@ -12,5 +12,5 @@ uniform mat4 projection; void main() { TexCoords = aTexCoords; - gl_Position = projection * view * model * vec4(aPos, 1.0f); + gl_Position = projection * view * model * vec4(aPos, 1.0); } \ No newline at end of file diff --git a/src/3.model_loading/1.model_loading/model_loading.cpp b/src/3.model_loading/1.model_loading/model_loading.cpp index 61f1ad4..53207c5 100644 --- a/src/3.model_loading/1.model_loading/model_loading.cpp +++ b/src/3.model_loading/1.model_loading/model_loading.cpp @@ -1,6 +1,5 @@ #include #include -#include #include #include @@ -18,13 +17,18 @@ void mouse_callback(GLFWwindow* window, double xpos, double ypos); void scroll_callback(GLFWwindow* window, double xoffset, double yoffset); void processInput(GLFWwindow *window); +// settings +const unsigned int SCR_WIDTH = 800; +const unsigned int SCR_HEIGHT = 600; + // camera Camera camera(glm::vec3(0.0f, 0.0f, 3.0f)); -float lastX = 800.0f / 2.0; -float lastY = 600.0 / 2.0; +float lastX = SCR_WIDTH / 2.0f; +float lastY = SCR_HEIGHT / 2.0f; bool firstMouse = true; -float deltaTime = 0.0f; // time between current frame and last frame +// timing +float deltaTime = 0.0f; float lastFrame = 0.0f; int main() @@ -38,14 +42,14 @@ int main() // glfw window creation // -------------------- - GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL); - glfwMakeContextCurrent(window); + GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL); if (window == NULL) { std::cout << "Failed to create GLFW window" << std::endl; glfwTerminate(); return -1; } + glfwMakeContextCurrent(window); glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); glfwSetCursorPosCallback(window, mouse_callback); glfwSetScrollCallback(window, scroll_callback); @@ -93,14 +97,14 @@ int main() // render // ------ - glClearColor(0.2f, 0.3f, 0.3f, 1.0f); + glClearColor(0.05f, 0.05f, 0.05f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // don't forget to enable shader before setting uniforms ourShader.use(); // view/projection transformations - glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), 800.0f / 600.0f, 0.1f, 100.0f); + glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f); glm::mat4 view = camera.GetViewMatrix(); ourShader.setMat4("projection", projection); ourShader.setMat4("view", view); @@ -132,7 +136,6 @@ void processInput(GLFWwindow *window) if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) glfwSetWindowShouldClose(window, true); - float cameraSpeed = 2.5 * deltaTime; if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) camera.ProcessKeyboard(FORWARD, deltaTime); if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) @@ -152,7 +155,6 @@ void framebuffer_size_callback(GLFWwindow* window, int width, int height) glViewport(0, 0, width, height); } - // glfw: whenever the mouse moves, this callback is called // ------------------------------------------------------- void mouse_callback(GLFWwindow* window, double xpos, double ypos)