Implement model loading with assimp
This commit is contained in:
		
							
								
								
									
										4
									
								
								compile
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								compile
									
									
									
									
									
								
							| @@ -1,9 +1,9 @@ | ||||
| #!/bin/bash | ||||
|  | ||||
| CC=clang | ||||
| CFLAGS="-g -c -Wall -Isrc/glad/include" | ||||
| CFLAGS="-O3 -c -Wall -Isrc/glad/include" | ||||
| CXX=clang++ | ||||
| CXXFLAGS="-g -Wall -std=c++20 $(pkg-config --cflags sdl2) -Isrc/glad/include -Isrc/glm -Isrc/assimp/include -Isrc/assimp/build/include" | ||||
| CXXFLAGS="-O3 -Wall -std=c++20 $(pkg-config --cflags sdl2) -Isrc/glad/include -Isrc/glm -Isrc/assimp/include -Isrc/assimp/build/include" | ||||
| LIBS="$(pkg-config --libs sdl2) -ldl -lz -lminizip -Lsrc/assimp/build/lib/ -lassimp" | ||||
| GLAD_SRC="src/glad/src/glad.c" | ||||
| GLAD_OBJ="glad.o" | ||||
|   | ||||
							
								
								
									
										
											BIN
										
									
								
								models/backpack/ao.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								models/backpack/ao.jpg
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 1.8 MiB | 
							
								
								
									
										16
									
								
								models/backpack/backpack.mtl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								models/backpack/backpack.mtl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| # Blender MTL File: 'None' | ||||
| # Material Count: 1 | ||||
|  | ||||
| newmtl Scene_-_Root | ||||
| Ns 225.000000 | ||||
| Ka 1.000000 1.000000 1.000000 | ||||
| Kd 0.800000 0.800000 0.800000 | ||||
| Ks 0.500000 0.500000 0.500000 | ||||
| Ke 0.0 0.0 0.0 | ||||
| Ni 1.450000 | ||||
| d 1.000000 | ||||
| illum 2 | ||||
| map_Kd diffuse.jpg | ||||
| map_Bump normal.png | ||||
| map_Ks specular.jpg | ||||
|  | ||||
							
								
								
									
										199481
									
								
								models/backpack/backpack.obj
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										199481
									
								
								models/backpack/backpack.obj
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								models/backpack/diffuse.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								models/backpack/diffuse.jpg
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 5.8 MiB | 
							
								
								
									
										
											BIN
										
									
								
								models/backpack/normal.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								models/backpack/normal.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 14 MiB | 
							
								
								
									
										
											BIN
										
									
								
								models/backpack/roughness.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								models/backpack/roughness.jpg
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 4.2 MiB | 
							
								
								
									
										3
									
								
								models/backpack/source_attribution.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								models/backpack/source_attribution.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| Model by Berk Gedik, from: https://sketchfab.com/3d-models/survival-guitar-backpack-low-poly-799f8c4511f84fab8c3f12887f7e6b36 | ||||
|  | ||||
| Modified material assignment (Joey de Vries) for easier load in OpenGL model loading chapter, and renamed albedo to diffuse and metallic to specular to match non-PBR lighting setup. | ||||
							
								
								
									
										
											BIN
										
									
								
								models/backpack/specular.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								models/backpack/specular.jpg
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 6.4 MiB | 
| @@ -3,8 +3,8 @@ | ||||
| #define POINT_LIGHT_COUNT 4 | ||||
|  | ||||
| struct Material { | ||||
|   sampler2D diffuse; | ||||
|   sampler2D specular; | ||||
|   sampler2D diffuse1; | ||||
|   sampler2D specular1; | ||||
|   float shininess; | ||||
| }; | ||||
|  | ||||
| @@ -70,11 +70,11 @@ vec3 calc_dir_light(DirLight light, vec3 normal, vec3 view_direction) { | ||||
|   vec3 light_direction     = normalize(-light.direction); | ||||
|   vec3  reflect_direction  = reflect(-light_direction, normal); | ||||
|   float diff               = max(dot(normal, light_direction), 0.0); | ||||
|   vec3  diff_tex           = vec3(texture(material.diffuse, uv_coords)); | ||||
|   vec3  diff_tex           = vec3(texture(material.diffuse1, uv_coords)); | ||||
|   float spec               = pow(max(dot(reflect_direction, view_direction), 0.0), material.shininess); | ||||
|   vec3  ambient            = light.ambient * diff_tex; | ||||
|   vec3  diffuse            = light.diffuse * (diff * diff_tex); | ||||
|   vec3  specular           = light.specular * (spec * vec3(texture(material.specular, uv_coords))); | ||||
|   vec3  specular           = light.specular * (spec * vec3(texture(material.specular1, uv_coords))); | ||||
|  | ||||
|   return ambient + diffuse + specular; | ||||
| } | ||||
| @@ -85,11 +85,11 @@ vec3 calc_point_light(PointLight light, vec3 normal, vec3 frag_position, vec3 vi | ||||
|   float distance           = length(light.position - frag_position); | ||||
|   float attenuation        = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance)); | ||||
|   float diff               = max(dot(normal, light_direction), 0.0); | ||||
|   vec3  diff_tex           = vec3(texture(material.diffuse, uv_coords)); | ||||
|   vec3  diff_tex           = vec3(texture(material.diffuse1, uv_coords)); | ||||
|   float spec               = pow(max(dot(reflect_direction, view_direction), 0.0), material.shininess); | ||||
|   vec3  ambient            = light.ambient * diff_tex * attenuation; | ||||
|   vec3  diffuse            = light.diffuse * (diff * diff_tex) * attenuation; | ||||
|   vec3  specular           = light.specular * (spec * vec3(texture(material.specular, uv_coords))) * attenuation; | ||||
|   vec3  specular           = light.specular * (spec * vec3(texture(material.specular1, uv_coords))) * attenuation; | ||||
|  | ||||
|   return ambient + diffuse + specular; | ||||
| } | ||||
| @@ -102,10 +102,10 @@ vec3 calc_spot_light(SpotLight light, vec3 normal, vec3 frag_position, vec3 view | ||||
|   float intensity          = clamp((theta - light.outer_cutoff) / epsilon, 0.0, 1.0); | ||||
|   float diff               = max(dot(normal, light_direction), 0.0); | ||||
|   float spec               = pow(max(dot(reflect_direction, view_direction), 0.0), material.shininess); | ||||
|   vec3  diff_tex           = vec3(texture(material.diffuse, uv_coords)); | ||||
|   vec3  diff_tex           = vec3(texture(material.diffuse1, uv_coords)); | ||||
|   vec3  ambient            = light.ambient * diff_tex; | ||||
|   vec3  diffuse            = light.diffuse * (diff * diff_tex) * intensity; | ||||
|   vec3  specular           = light.specular * (spec * vec3(texture(material.specular, uv_coords))) * intensity; | ||||
|   vec3  specular           = light.specular * (spec * vec3(texture(material.specular1, uv_coords))) * intensity; | ||||
|  | ||||
|   return ambient + diffuse + specular; | ||||
| } | ||||
|   | ||||
							
								
								
									
										186
									
								
								src/main.cc
									
									
									
									
									
								
							
							
						
						
									
										186
									
								
								src/main.cc
									
									
									
									
									
								
							| @@ -14,6 +14,14 @@ | ||||
| #include "glm/gtx/rotate_vector.hpp" | ||||
| #include "glm/gtx/string_cast.hpp" | ||||
|  | ||||
| // Assimp | ||||
| #include "assimp/Importer.hpp" | ||||
| #include "assimp/postprocess.h" | ||||
| #include "assimp/scene.h" | ||||
| #include "assimp/mesh.h" | ||||
| #include "assimp/material.h" | ||||
| #include "assimp/types.h" | ||||
|  | ||||
| // SDL | ||||
| #include <SDL2/SDL.h> | ||||
| #include <SDL2/SDL_timer.h> | ||||
| @@ -67,16 +75,23 @@ class Shader { | ||||
|     static const char *get_shader_type_string(GLenum shader_type); | ||||
| }; | ||||
|  | ||||
| enum TextureType : unsigned char { | ||||
|   TEXTURE_TYPE_DIFFUSE, | ||||
|   TEXTURE_TYPE_SPECULAR, | ||||
| }; | ||||
|  | ||||
| class Texture2D { | ||||
|   public: | ||||
|     Texture2D(const char *filename, GLint texture_unit, const char *name); | ||||
|     Texture2D(const char *filename, GLint texture_unit, TextureType type); | ||||
|     ~Texture2D(); | ||||
|     void activate() const; | ||||
|     std::string name(unsigned int index) const; | ||||
|     int width; | ||||
|     int height; | ||||
|     int channels; | ||||
|     const char *filename; | ||||
|     GLint texture_unit; | ||||
|     std::string name; | ||||
|     TextureType type; | ||||
|   private: | ||||
|     GLuint texture; | ||||
|     GLint format; | ||||
| @@ -101,6 +116,25 @@ class Mesh { | ||||
|     void setup_mesh(); | ||||
| }; | ||||
|  | ||||
| class Model { | ||||
|   public: | ||||
|     Model(const char *path) { | ||||
|       load_model(path); | ||||
|     } | ||||
|  | ||||
|     void draw(Shader &shader); | ||||
|   private: | ||||
|     std::vector<Texture2D> loaded_textures; | ||||
|     std::vector<Mesh> meshes; | ||||
|     std::string directory; | ||||
|     GLint texture_unit = GL_TEXTURE0; | ||||
|  | ||||
|     void load_model(std::string path); | ||||
|     void process_node(aiNode *node, const aiScene *scene); | ||||
|     Mesh process_mesh(aiMesh *mesh, const aiScene *scene); | ||||
|     std::vector<Texture2D> load_material_textures(aiMaterial *mat, aiTextureType type); | ||||
| }; | ||||
|  | ||||
| int main() { | ||||
|   if (SDL_Init(SDL_INIT_EVERYTHING) != 0) { | ||||
|     return EXIT_CODE_SDL_INIT_FAILED; | ||||
| @@ -179,12 +213,7 @@ int main() { | ||||
|     13, 15, 16 | ||||
|   }; | ||||
|  | ||||
|   std::vector<Texture2D> textures = { | ||||
|     Texture2D("images/container2.png", GL_TEXTURE0, "material.diffuse"), | ||||
|     Texture2D("images/container2_specular.png", GL_TEXTURE1, "material.specular"), | ||||
|   }; | ||||
|  | ||||
|   Mesh container = {vertices, indices, textures}; | ||||
|   Model backpack = {"models/backpack/backpack.obj"}; | ||||
|   Mesh light     = {vertices, indices, {}}; | ||||
|  | ||||
|   Shader main_shader  {"shaders/vert.glsl", "shaders/frag.glsl"}; | ||||
| @@ -207,24 +236,10 @@ int main() { | ||||
|   glm::mat3 normal_mat = glm::mat3(1.0f); | ||||
|  | ||||
|   main_shader.set_mat4 ("projection", projection); | ||||
|   main_shader.set_vec3 ("material.specular", glm::vec3(0.5f, 0.5f, 0.5f)); | ||||
|   main_shader.set_float("material.shininess", 32.0f); | ||||
|  | ||||
|   light_shader.set_mat4("projection", projection); | ||||
|  | ||||
|   std::vector<glm::vec3> cube_positions = { | ||||
|       glm::vec3( 0.0f,  0.0f,  0.0f), | ||||
|       glm::vec3( 4.0f,  6.0f, -15.0f), | ||||
|       glm::vec3(-3.5f, -3.2f, -2.5f), | ||||
|       glm::vec3(-5.8f, -3.0f, -12.3f), | ||||
|       glm::vec3( 4.4f, -1.4f, -3.5f), | ||||
|       glm::vec3(-3.7f,  4.0f, -7.5f), | ||||
|       glm::vec3( 3.3f, -3.0f, -2.5f), | ||||
|       glm::vec3( 3.5f,  3.0f, -2.5f), | ||||
|       glm::vec3( 3.5f,  1.2f, -1.5f), | ||||
|       glm::vec3(-3.3f,  2.0f, -1.5f) | ||||
|   }; | ||||
|  | ||||
|   std::vector<glm::vec3> point_light_positions = { | ||||
|     glm::vec3( 0.7f,  0.2f,  2.0f), | ||||
|     glm::vec3( 2.3f, -3.3f, -4.0f), | ||||
| @@ -364,15 +379,12 @@ int main() { | ||||
|     glClearColor(0.04f, 0.08f, 0.08f, 1.0f); | ||||
|     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | ||||
|  | ||||
|     for (int i = 0; i < cube_positions.size(); ++i) { | ||||
|       model = glm::translate(glm::mat4(1.0f), cube_positions[i]); | ||||
|       model = glm::rotate(model, glm::radians(10.0f * i), glm::vec3(1.0f, 0.3f, 0.5f)); | ||||
|     model = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, 0.0f)); | ||||
|     normal_mat = glm::transpose(glm::inverse(model)); | ||||
|     main_shader.activate(); | ||||
|     main_shader.set_mat4("model", model); | ||||
|     main_shader.set_mat3("normal_mat", normal_mat); | ||||
|       container.draw(main_shader); | ||||
|     } | ||||
|     backpack.draw(main_shader); | ||||
|  | ||||
|     // Draw light source | ||||
|     for (int i = 0; i < point_light_positions.size(); ++i) { | ||||
| @@ -531,7 +543,7 @@ const char *Shader::get_shader_type_string(GLenum shader_type) { | ||||
|   return output; | ||||
| } | ||||
|  | ||||
| Texture2D::Texture2D(const char *filename, GLint texture_unit, const char *name) : texture_unit(texture_unit), name(name) { | ||||
| Texture2D::Texture2D(const char *filename, GLint texture_unit, TextureType type) : filename(filename), texture_unit(texture_unit), type(type) { | ||||
|   uint8_t *image = stbi_load(filename, &width, &height, &channels, 0); | ||||
|   if (!image) { | ||||
|     return; | ||||
| @@ -562,6 +574,23 @@ void Texture2D::activate() const { | ||||
|   glBindTexture(GL_TEXTURE_2D, texture); | ||||
| } | ||||
|  | ||||
| std::string Texture2D::name(unsigned int index) const { | ||||
|   std::string output = "material."; | ||||
|  | ||||
|   switch (type) { | ||||
|     case TEXTURE_TYPE_DIFFUSE: | ||||
|       output += "diffuse"; | ||||
|       break; | ||||
|     case TEXTURE_TYPE_SPECULAR: | ||||
|       output += "specular"; | ||||
|       break; | ||||
|   } | ||||
|  | ||||
|   output += std::to_string(index); | ||||
|  | ||||
|   return output.c_str(); | ||||
| } | ||||
|  | ||||
| Mesh::Mesh(std::vector<Vertex> vertices, std::vector<GLuint> indices, std::vector<Texture2D> textures) | ||||
|   : vertices(vertices), indices(indices), textures(textures) { | ||||
|     setup_mesh(); | ||||
| @@ -589,9 +618,14 @@ void Mesh::setup_mesh() { | ||||
| } | ||||
|  | ||||
| void Mesh::draw(Shader &shader) { | ||||
|   unsigned int diffuse = 1; | ||||
|   unsigned int specular = 1; | ||||
|   unsigned int index; | ||||
|  | ||||
|   for (int i = 0; i < textures.size(); ++i) { | ||||
|     const Texture2D &texture = textures[i]; | ||||
|     shader.set_int(texture.name.c_str(), texture.texture_unit - GL_TEXTURE0); | ||||
|     index = texture.type == TEXTURE_TYPE_DIFFUSE ? diffuse++ : specular++; | ||||
|     shader.set_int(texture.name(index).c_str(), texture.texture_unit - GL_TEXTURE0); | ||||
|     texture.activate(); | ||||
|   } | ||||
|  | ||||
| @@ -599,3 +633,97 @@ void Mesh::draw(Shader &shader) { | ||||
|   glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, (void *)0); | ||||
|   glBindVertexArray(0); | ||||
| } | ||||
|  | ||||
| void Model::draw(Shader &shader) { | ||||
|   for (int i = 0; i < meshes.size(); ++i) { | ||||
|     meshes[i].draw(shader); | ||||
|   } | ||||
| } | ||||
|  | ||||
| void Model::load_model(std::string path) { | ||||
|   Assimp::Importer importer; | ||||
|   const aiScene *scene = importer.ReadFile(path, aiProcess_Triangulate | aiProcess_FlipUVs); | ||||
|   if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) { | ||||
|     printf("Failed to load model: %s. Error: %s\n", path.c_str(), importer.GetErrorString()); | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   directory = path.substr(0, path.find_last_of('/')); | ||||
|   process_node(scene->mRootNode, scene); | ||||
| } | ||||
|  | ||||
| void Model::process_node(aiNode *node, const aiScene *scene) { | ||||
|   for (unsigned int i = 0; i < node->mNumMeshes; ++i) { | ||||
|     aiMesh *mesh = scene->mMeshes[node->mMeshes[i]]; | ||||
|     meshes.push_back(process_mesh(mesh, scene)); | ||||
|   } | ||||
|  | ||||
|   for (unsigned int i = 0; i < node->mNumChildren; ++i) { | ||||
|     process_node(node->mChildren[i], scene); | ||||
|   } | ||||
| } | ||||
|  | ||||
| Mesh Model::process_mesh(aiMesh *mesh, const aiScene *scene) { | ||||
|   std::vector<Vertex> vertices; | ||||
|   std::vector<GLuint> indices; | ||||
|   std::vector<Texture2D> textures; | ||||
|  | ||||
|   for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { | ||||
|     Vertex vertex; | ||||
|  | ||||
|     vertex.position = glm::vec3(mesh->mVertices[i].x, mesh->mVertices[i].y, mesh->mVertices[i].z); | ||||
|     vertex.normal = glm::vec3(mesh->mNormals[i].x, mesh->mNormals[i].y, mesh->mNormals[i].z); | ||||
|     if (mesh->mTextureCoords[0]) { | ||||
|       vertex.tex_coord = glm::vec2(mesh->mTextureCoords[0][i].x, mesh->mTextureCoords[0][i].y); | ||||
|     } else { | ||||
|       vertex.tex_coord = 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]); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   if (mesh->mMaterialIndex >= 0) { | ||||
|     aiMaterial *material = scene->mMaterials[mesh->mMaterialIndex]; | ||||
|  | ||||
|     std::vector<Texture2D> diffuse_maps = load_material_textures(material, aiTextureType_DIFFUSE); | ||||
|     textures.insert(textures.end(), diffuse_maps.begin(), diffuse_maps.end()); | ||||
|  | ||||
|     std::vector<Texture2D> specular_maps = load_material_textures(material, aiTextureType_SPECULAR); | ||||
|     textures.insert(textures.end(), specular_maps.begin(), specular_maps.end()); | ||||
|   } | ||||
|  | ||||
|   return Mesh(vertices, indices, textures); | ||||
| } | ||||
|  | ||||
| std::vector<Texture2D> Model::load_material_textures(aiMaterial *material, aiTextureType type) { | ||||
|   std::vector<Texture2D> textures; | ||||
|   for (unsigned int i = 0; i < material->GetTextureCount(type); ++i) { | ||||
|     aiString path; | ||||
|     material->GetTexture(type, i, &path); | ||||
|     std::string absolute_path = directory + '/' + path.C_Str(); | ||||
|  | ||||
|     bool skip = false; | ||||
|     for (unsigned int j = 0; i < loaded_textures.size(); ++j) { | ||||
|       if (std::strcmp(loaded_textures[j].filename, absolute_path.c_str()) == 0) { | ||||
|         textures.push_back(loaded_textures[j]); | ||||
|         skip = true; | ||||
|         break; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     if (!skip) { | ||||
|       TextureType tex_type = type == aiTextureType_DIFFUSE ? TEXTURE_TYPE_DIFFUSE : TEXTURE_TYPE_SPECULAR; | ||||
|       Texture2D texture = {absolute_path.c_str(), texture_unit++, tex_type}; | ||||
|       textures.push_back(texture); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   return textures; | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user