From 08bcb56a5f6b027bd949e33afb33180ec0174a55 Mon Sep 17 00:00:00 2001 From: SeanOMik Date: Thu, 22 Sep 2022 00:11:12 -0400 Subject: [PATCH] Read diffuse textures from 3d models --- examples/dev_testing/src/main.cpp | 9 ++- include/simpleengine/gfx/material.h | 9 +-- include/simpleengine/gfx/mesh.h | 7 --- include/simpleengine/gfx/model.h | 2 +- include/simpleengine/gfx/texture.h | 19 ++----- src/gfx/mesh.cpp | 88 ----------------------------- src/gfx/model.cpp | 60 ++++++++++++-------- src/gfx/renderer.cpp | 15 ++++- src/gfx/texture.cpp | 10 ++-- 9 files changed, 71 insertions(+), 148 deletions(-) diff --git a/examples/dev_testing/src/main.cpp b/examples/dev_testing/src/main.cpp index b85b390..632a488 100644 --- a/examples/dev_testing/src/main.cpp +++ b/examples/dev_testing/src/main.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -80,7 +81,7 @@ int main(int argc, char *argv[]) { auto light = std::make_shared(core_shader, glm::vec3(0.f, 1.f, -10.f), glm::vec3(1.f, 1.f, 1.f)); game.add_event(light); - se::gfx::Texture white_texture("examples/dev_testing/resources/white_texture.png"); + auto white_texture = se::gfx::Texture::white_texture(); // white_texture.shine_damper = 10; //white_texture.reflectivity = 1; /* auto dragon = std::make_shared(game.get_window(), core_shader, white_texture, "examples/dev_testing/resources/dragon.obj"); @@ -165,11 +166,13 @@ int main(int argc, char *argv[]) { 5, 6, 12, 12, 6, 13 }; - se::gfx::Material material(white_texture, 1.f, 0.f, 0.f, 0.f, 0.f); + std::unordered_map> textures; + textures.emplace(white_texture.type, std::vector{ white_texture }); + se::gfx::Material white_material(textures, 1.f, 0.f, 0.f, 0.f, 0.f); // Create the entity and add the model component to it. /* auto entity = std::make_shared(); - entity->add_component(cube_vertices, cube_indicies, material, true); + entity->add_component(cube_vertices, cube_indicies, white_material, true); entity->translate(3.5f, 0.f, 0.f); */ auto entity = std::make_shared(); diff --git a/include/simpleengine/gfx/material.h b/include/simpleengine/gfx/material.h index e28b496..8dd3817 100644 --- a/include/simpleengine/gfx/material.h +++ b/include/simpleengine/gfx/material.h @@ -2,12 +2,13 @@ #include "texture.h" -#include +#include +#include namespace simpleengine::gfx { class Material { public: - Texture texture; + std::unordered_map> textures; float ambient_scalar; float diffuse_scalar; @@ -15,8 +16,8 @@ namespace simpleengine::gfx { float shine; float reflectivity; - Material(Texture texture, float shine = 1.f, float reflectivity = 0.f, float specular_scalar = 0.f, float ambient_scalar = 0.f, float diffuse_scalar = 0.f) : - texture(texture), ambient_scalar(ambient_scalar), diffuse_scalar(diffuse_scalar), specular_scalar(specular_scalar), + Material(std::unordered_map> textures, float shine = 1.f, float reflectivity = 0.f, float specular_scalar = 0.f, float ambient_scalar = 0.f, float diffuse_scalar = 0.f) : + textures(textures), ambient_scalar(ambient_scalar), diffuse_scalar(diffuse_scalar), specular_scalar(specular_scalar), shine(shine), reflectivity(reflectivity) { } diff --git a/include/simpleengine/gfx/mesh.h b/include/simpleengine/gfx/mesh.h index a96ddc8..45a82ba 100644 --- a/include/simpleengine/gfx/mesh.h +++ b/include/simpleengine/gfx/mesh.h @@ -30,8 +30,6 @@ namespace simpleengine::gfx { Mesh(std::vector vertices, std::vector indicies, Material material); Mesh(std::vector vertices, std::vector indicies = std::vector(), std::optional material = std::nullopt); Mesh(std::vector vertices, std::vector indicies, Material material, gfx::VBO ebo, gfx::VBO vbo, gfx::VAO vao); - Mesh(Material material, std::string filename); - Mesh(Material material, std::ifstream file_stream); virtual void destroy() override; @@ -46,10 +44,5 @@ namespace simpleengine::gfx { * */ void calculate_normals(); - - private: - void process_vertex(const std::vector& vertex_data, const std::vector& in_textures, - const std::vector& in_normals, std::vector& out_indicies, - std::vector& out_textures, std::vector& out_normals); }; } \ No newline at end of file diff --git a/include/simpleengine/gfx/model.h b/include/simpleengine/gfx/model.h index 377cd24..13535ca 100644 --- a/include/simpleengine/gfx/model.h +++ b/include/simpleengine/gfx/model.h @@ -28,6 +28,6 @@ namespace simpleengine::gfx { void load_model(std::string path); void process_node(aiNode* node, const aiScene* scene); gfx::Mesh process_mesh(aiMesh* mesh, const aiScene* scene); - std::vector load_material_textures(aiMaterial* material, aiTextureType* type, std::string type_name); + std::vector load_material_textures(aiMaterial* material, aiTextureType type); }; } \ No newline at end of file diff --git a/include/simpleengine/gfx/texture.h b/include/simpleengine/gfx/texture.h index c956d38..b7a8289 100644 --- a/include/simpleengine/gfx/texture.h +++ b/include/simpleengine/gfx/texture.h @@ -8,7 +8,7 @@ #include #endif -#include +#include #include @@ -26,19 +26,10 @@ namespace simpleengine::gfx { Texture() = default; public: - /** - * @brief The type of the texture - * - */ - enum Type { - TexT_DIFFUSE, - TexT_SPECULAR - }; - int height; int width; int channels; - Type type; + aiTextureType type; /** * @brief Construct a new Texture object from a path. @@ -47,7 +38,7 @@ namespace simpleengine::gfx { * @param img_2d Whether or not the texture is 2D. * @param mipmap Whether or not to generate mipmaps for this texture. */ - Texture(const char* path, Type type = Type::TexT_DIFFUSE, bool img_2d = true, bool mipmap = true); + Texture(const char* path, aiTextureType type = aiTextureType::aiTextureType_DIFFUSE, bool img_2d = true, bool mipmap = true); /** * @brief Construct a new Texture object from the loaded file buffer. @@ -57,7 +48,7 @@ namespace simpleengine::gfx { * @param img_2d Whether or not the texture is 2D. * @param mipmap Whether or not to generate mipmaps for this texture. */ - Texture(const unsigned char *const buffer, int buffer_length, Type type = Type::TexT_DIFFUSE, bool img_2d = true, bool mipmap = true); + Texture(const unsigned char *const buffer, int buffer_length, aiTextureType type = aiTextureType::aiTextureType_DIFFUSE, bool img_2d = true, bool mipmap = true); /** * @brief Construct a new Texture object from the loaded file buffer. @@ -66,7 +57,7 @@ namespace simpleengine::gfx { * @param img_2d Whether or not the texture is 2D. * @param mipmap Whether or not to generate mipmaps for this texture. */ - Texture(std::vector buffer, Type type = Type::TexT_DIFFUSE, bool img_2d = true, bool mipmap = true); + Texture(std::vector buffer, aiTextureType type = aiTextureType::aiTextureType_DIFFUSE, bool img_2d = true, bool mipmap = true); static Texture white_texture(); diff --git a/src/gfx/mesh.cpp b/src/gfx/mesh.cpp index 0119e15..ba48518 100644 --- a/src/gfx/mesh.cpp +++ b/src/gfx/mesh.cpp @@ -21,10 +21,6 @@ namespace simpleengine::gfx { } - Mesh::Mesh(Material material, std::string filename) : - Mesh(material, std::ifstream(filename, std::ios::in | std::ios::binary)) { - } - std::vector split_string(std::string str, const char delim) { std::istringstream ss(str); @@ -41,90 +37,6 @@ namespace simpleengine::gfx { return tokens; } - Mesh::Mesh(Material material, std::ifstream file_stream) : - vbo(gfx::VBO::init(GL_ARRAY_BUFFER, false)), ebo(gfx::VBO::init(GL_ELEMENT_ARRAY_BUFFER, false)), - vao(gfx::VAO::init()), material(material) { - - if (!file_stream.is_open()) { - std::cerr << "File stream that was given to ObjModel::ObjModel is not open!" << std::endl; - throw std::runtime_error("Failed to open ObjModel model file"); - } - - // The vertices, texture coords, and normals that were read from the obj file - // these are not in a particular order. - std::vector obj_vertices; - std::vector obj_textures; - std::vector obj_normals; - - // The texture coords and normals that have been sorted. - std::vector textures; - std::vector normals; - - // Read the vertices, texture coords, and normals. Break when run into indices - std::string line; - while (std::getline(file_stream, line)) { - std::vector line_tokens = split_string(line, ' '); - - if (line_tokens.front() == "v") { - //glm::vec3 vertex(stof(line_tokens[1]), stof(line_tokens[2]), stof(line_tokens[3])); - obj_vertices.emplace_back(stof(line_tokens[1]), stof(line_tokens[2]), stof(line_tokens[3])); - } else if (line_tokens.front() == "vt") { - obj_textures.emplace_back(stof(line_tokens[1]), stof(line_tokens[2])); - } else if (line_tokens.front() == "vn") { - obj_normals.emplace_back(stof(line_tokens[1]), stof(line_tokens[2]), stof(line_tokens[3])); - } else if (line_tokens.front() == "f") { - auto size = obj_vertices.size(); - textures.resize(size); - normals.resize(size); - break; - } - } - - // Process the indicies. This will sort everything for storing inside of the Vertex list. - do { - if (!line.starts_with("f")) { - continue; - } - std::vector line_tokens = split_string(line, ' '); - std::vector vertex1 = split_string(line_tokens[1], '/'); - std::vector vertex2 = split_string(line_tokens[2], '/'); - std::vector vertex3 = split_string(line_tokens[3], '/'); - - process_vertex(vertex1, obj_textures, obj_normals, indicies, textures, normals); - process_vertex(vertex2, obj_textures, obj_normals, indicies, textures, normals); - process_vertex(vertex3, obj_textures, obj_normals, indicies, textures, normals); - } while (std::getline(file_stream, line)); - - file_stream.close(); - - const int texture_id = 0; - - std::cout << "Texture ID: " << texture_id << std::endl; - - // Insert everything into lit_vertices. - for (int i = 0; i < obj_vertices.size(); i++) { - vertices.emplace_back(simpleengine::Vectorf(obj_vertices.at(i)), glm::vec3(1.f), textures.at(i), normals.at(i), texture_id); - } - } - - void Mesh::process_vertex(const std::vector& vertex_data, const std::vector& in_textures, - const std::vector& in_normals, std::vector& out_indicies, - std::vector& out_textures, std::vector& out_normals) { - - // Get the index the current vertex and put it in indicies - int currentVertexIndex = stoi(vertex_data[0]) - 1; - out_indicies.push_back(currentVertexIndex); - - // Read texture coords - glm::vec2 current_tex = in_textures.at(stoi(vertex_data[1]) - 1); - current_tex.y = 1 - current_tex.y; - out_textures.at(currentVertexIndex) = current_tex; - - // Read normals - glm::vec3 current_norm = in_normals.at(stoi(vertex_data[2]) - 1); - out_normals.at(currentVertexIndex) = current_norm; - } - void Mesh::destroy() { this->ebo.destroy(); this->vbo.destroy(); diff --git a/src/gfx/model.cpp b/src/gfx/model.cpp index 38ac258..c749bb5 100644 --- a/src/gfx/model.cpp +++ b/src/gfx/model.cpp @@ -7,7 +7,11 @@ #include #include #include + #include +#include +#include +#include namespace simpleengine::gfx { Model::Model(std::string file_path) { @@ -77,38 +81,48 @@ namespace simpleengine::gfx { } } - std::optional op_mat; + // Create a default material and white texture. + auto white_texture = gfx::Texture::white_texture(); + std::unordered_map> default_textures; + default_textures.emplace(white_texture.type, std::vector{ white_texture }); + gfx::Material mat(default_textures, 1.f, 0.f, 0.f, 0.f, 0.f); - // TODO: Process material if(mesh->mMaterialIndex >= 0) { std::cout << "TODO: Process model materials!" << std::endl; - /* aiMaterial *material = scene->mMaterials[mesh->mMaterialIndex]; - std::vector diffuseMaps = load_material_textures(material, - aiTextureType_DIFFUSE, "texture_diffuse"); + std::unordered_map> textures; + aiMaterial *material = scene->mMaterials[mesh->mMaterialIndex]; - textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end()); - - std::vector specularMaps = load_material_textures(material, - aiTextureType_SPECULAR, "texture_specular"); - textures.insert(textures.end(), specularMaps.begin(), specularMaps.end()); */ + // Load Diffuse texture maps + std::vector diffuse_maps = load_material_textures(material, aiTextureType_DIFFUSE); + if (!diffuse_maps.empty()) textures.emplace(aiTextureType_DIFFUSE, diffuse_maps); + + // TODO Handle other types of texture maps + + if (!textures.empty()) { + // TODO: Find a way to let the user set the scalars. + mat = Material(textures, 1.f, 0.f, 0.f, 0.f, 0.f); + } } - // TODO: After we start processing materials, this can be put in the else statement as a fallback. - - auto white_texture = gfx::Texture::white_texture(); - //gfx::Material mat(white_texture); - - //gfx::Texture white_texture("examples/dev_testing/resources/white_texture.png"); - gfx::Material mat(white_texture, 1.f, 0.f, 0.f, 0.f, 0.f); - - op_mat = std::optional(mat); - - //return Mesh(vertices, indices, textures); - return Mesh(vertices, indices, op_mat); + return Mesh(vertices, indices, mat); } - std::vector Model::load_material_textures(aiMaterial* material, aiTextureType* type, std::string type_name) { + std::vector Model::load_material_textures(aiMaterial* material, aiTextureType type) { + std::vector textures; + for(int i = 0; i < material->GetTextureCount(type); i++) { + aiString texture_path; + material->GetTexture(type, i, &texture_path); + + std::stringstream ss; + ss << model_directory << "/" << texture_path.C_Str(); + std::string full_path = ss.str(); + + Texture texture(full_path.c_str(), type); + textures.emplace_back(texture); + } + + return textures; } } // namespace simpleengine::gfx \ No newline at end of file diff --git a/src/gfx/renderer.cpp b/src/gfx/renderer.cpp index 8b2627b..6ad4644 100644 --- a/src/gfx/renderer.cpp +++ b/src/gfx/renderer.cpp @@ -9,6 +9,7 @@ #include "ecs/component/model_component.h" #include +#include namespace simpleengine::gfx { void create_mesh_buffers(std::shared_ptr comp, simpleengine::gfx::Mesh& mesh); @@ -99,9 +100,17 @@ namespace simpleengine::gfx { shader.set_uniform_float("u_texture_shine", material->shine, false); shader.set_uniform_float("u_texture_reflectivity", material->reflectivity, false); - glActiveTexture(GL_TEXTURE0); - glBindTextureUnit(0, material->texture.get_texture_id()); - material->texture.bind(); + int texture_count = 0; + auto diffuse_maps = material->textures.find(aiTextureType_DIFFUSE); + for (const auto& texture : diffuse_maps->second) { + // We can only bind to 16 textures at a time (indexes are 0-15) + if (texture_count >= 16) break; + + glActiveTexture(GL_TEXTURE0 + texture_count); + glBindTextureUnit(texture_count, texture.get_texture_id()); + + texture_count++; + } } model.vao.bind(); diff --git a/src/gfx/texture.cpp b/src/gfx/texture.cpp index dd119dc..6c0f0e2 100644 --- a/src/gfx/texture.cpp +++ b/src/gfx/texture.cpp @@ -4,7 +4,7 @@ #include namespace simpleengine::gfx { - Texture::Texture(const char* path, Type type, bool img_2d, bool mipmap): type(type) { + Texture::Texture(const char* path, aiTextureType type, bool img_2d, bool mipmap): type(type) { image_type_gl = img_2d ? GL_TEXTURE_2D : GL_TEXTURE_3D; glGenTextures(1, &texture_id); @@ -12,7 +12,7 @@ namespace simpleengine::gfx { int linear_param = mipmap ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR; - glTexParameteri(image_type_gl, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(image_type_gl, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(image_type_gl, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(image_type_gl, GL_TEXTURE_MIN_FILTER, linear_param); glTexParameteri(image_type_gl, GL_TEXTURE_MAG_FILTER, linear_param); @@ -35,7 +35,7 @@ namespace simpleengine::gfx { unbind(); } - Texture::Texture(const unsigned char *const buffer, int buffer_length, Type type, bool img_2d, bool mipmap): type(type) { + Texture::Texture(const unsigned char *const buffer, int buffer_length, aiTextureType type, bool img_2d, bool mipmap): type(type) { image_type_gl = img_2d ? GL_TEXTURE_2D : GL_TEXTURE_3D; glGenTextures(1, &texture_id); @@ -66,7 +66,7 @@ namespace simpleengine::gfx { unbind(); } - Texture::Texture(std::vector buffer, Type type, bool img_2d, bool mipmap) : + Texture::Texture(std::vector buffer, aiTextureType type, bool img_2d, bool mipmap) : Texture(buffer.data(), buffer.size(), type, img_2d, mipmap) { } @@ -86,7 +86,7 @@ namespace simpleengine::gfx { texture.width = width; texture.height = height; texture.channels = 4; - texture.type = Texture::Type::TexT_DIFFUSE; + texture.type = aiTextureType::aiTextureType_DIFFUSE; texture.img_data = data; glGenTextures(1, &texture.texture_id);