diff --git a/compile b/compile index 299b413..1e5aaf7 100755 --- a/compile +++ b/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" @@ -14,5 +14,5 @@ OUT=main (set -x ; $CXX $CXXFLAGS $SRC $LIBS -o $OUT) if [[ -f $GLAD_OBJ ]]; then - rm $GLAD_OBJ + rm $GLAD_OBJ fi diff --git a/shaders/frag.glsl b/shaders/frag.glsl index f433323..0b63227 100644 --- a/shaders/frag.glsl +++ b/shaders/frag.glsl @@ -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; } diff --git a/src/main.cc b/src/main.cc index 0d9226f..865c5f9 100644 --- a/src/main.cc +++ b/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 #include @@ -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 loaded_textures; + std::vector 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 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 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 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 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)); - 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); - } + 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); + 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 vertices, std::vector indices, std::vector 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 vertices; + std::vector indices; + std::vector 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 diffuse_maps = load_material_textures(material, aiTextureType_DIFFUSE); + textures.insert(textures.end(), diffuse_maps.begin(), diffuse_maps.end()); + + std::vector 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 Model::load_material_textures(aiMaterial *material, aiTextureType type) { + std::vector 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; +}