diff --git a/.vscode/settings.json b/.vscode/settings.json index 1ab0c10..e7216c1 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,6 +4,45 @@ "iosfwd": "cpp", "map": "cpp", "atomic": "cpp", - "new": "cpp" + "new": "cpp", + "array": "cpp", + "*.tcc": "cpp", + "cctype": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "deque": "cpp", + "unordered_map": "cpp", + "vector": "cpp", + "exception": "cpp", + "algorithm": "cpp", + "functional": "cpp", + "iterator": "cpp", + "memory": "cpp", + "memory_resource": "cpp", + "numeric": "cpp", + "random": "cpp", + "string": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "utility": "cpp", + "initializer_list": "cpp", + "iostream": "cpp", + "istream": "cpp", + "limits": "cpp", + "ostream": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "streambuf": "cpp", + "cinttypes": "cpp", + "typeinfo": "cpp" } } \ No newline at end of file diff --git a/include/Model.h b/include/Model.h index 2219e29..3d12152 100644 --- a/include/Model.h +++ b/include/Model.h @@ -6,6 +6,11 @@ #include +#include + +#define DEFAULT_MTL_DIR "./" +void loadOBJtoVector(const char* filename, std::vector& scene, const char* mtl_directory = DEFAULT_MTL_DIR, const char* texture_directory = DEFAULT_MTL_DIR); + class Model { public: diff --git a/src/Model.cpp b/src/Model.cpp index 8cff3a2..6ab861d 100644 --- a/src/Model.cpp +++ b/src/Model.cpp @@ -183,3 +183,122 @@ void Model::set_index_range(GLuint beg, GLuint count) first_index = beg; indices_count = count; } + +#define TINYOBJLOADER_IMPLEMENTATION +#include "tiny_obj_loader.h" + +#include + +inline void hash_combine(std::size_t& seed) { } + +template +inline void hash_combine(std::size_t& seed, const T& v, Rest... rest) { + std::hash hasher; + seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2); + hash_combine(seed, rest...); +} + +void loadOBJtoVector(const char* filename, std::vector& scene, const char* mtl_directory, const char* texture_directory) +{ + Model model; + + tinyobj::attrib_t attrib; + std::vector shapes; + std::vector materials; + + std::string err; + + // Если в процессе загрузки возникли ошибки - выдадим исключение + if (!tinyobj::LoadObj(&attrib, &shapes, &materials, &err, filename, mtl_directory)) + throw std::runtime_error(err); + + std::vector indices; // индексы модели + std::vector verteces; // вершины + std::vector normals; // нормали + std::vector texCords; // текстурные координаты + size_t hash; // Для уникальных вершин + std::map uniqueVerteces; // словарь для уникальных вершин: ключ - хеш, значение - индекс вершины + + int last_material_index = 0; // индекс последнего материала (для группировки моделей) + int count = 0, offset; // для индексов начала и конца в индексном буфере + std::vector materials_range; // хранилище индексов + std::vector materials_ids; // индексы материалов + + materials_range.push_back(count); // Закидываем начало отрезка в индексном буфере + // Цикл по считанным моделям + for (const auto& shape : shapes) + { + offset = count; // Переменная для + last_material_index = shape.mesh.material_ids[(count - offset)/3]; // Запоминаем индекс материала + + // Цикл по индексам модели + for (const auto& index : shape.mesh.indices) + { + hash = 0; + hash_combine( hash + , attrib.vertices[3 * index.vertex_index + 0], attrib.vertices[3 * index.vertex_index + 1], attrib.vertices[3 * index.vertex_index + 2] + , attrib.normals[3 * index.normal_index + 0], attrib.normals[3 * index.normal_index + 1], attrib.normals[3 * index.normal_index + 2] + , attrib.texcoords[2 * index.texcoord_index + 0], attrib.texcoords[2 * index.texcoord_index + 1]); + + if (!uniqueVerteces.count(hash)) + { + uniqueVerteces[hash] = verteces.size(); + + // группируем вершины в массив на основании индексов + verteces.push_back({ attrib.vertices[3 * index.vertex_index + 0] + , attrib.vertices[3 * index.vertex_index + 1] + , attrib.vertices[3 * index.vertex_index + 2] + }); + // группируем нормали в массив на основании индексов + normals.push_back({ attrib.normals[3 * index.normal_index + 0] + , attrib.normals[3 * index.normal_index + 1] + , attrib.normals[3 * index.normal_index + 2] + }); + // группируем текстурные координаты в массив на основании индексов + texCords.push_back({ attrib.texcoords[2 * index.texcoord_index + 0] + , 1-attrib.texcoords[2 * index.texcoord_index + 1] + }); + } + // Сохраняем индекс в массив + indices.push_back(uniqueVerteces[hash]); + + // Если индекс последнего материала изменился, то необходимо сохранить его + if (last_material_index != shape.mesh.material_ids[(count - offset)/3]) + { + materials_range.push_back(count); // как конец отрезка + materials_ids.push_back(last_material_index); // как используемый материал + last_material_index = shape.mesh.material_ids[(count - offset)/3]; + } + count++; + } // for (const auto& index : shape.mesh.indices) + + // Если последний материал не загружен - загружаем его + if (materials_range[materials_range.size()-1] != count-1) + { + materials_range.push_back(count); // последний конец отрезка + materials_ids.push_back(last_material_index); // последний используемый материал + } + } // for (const auto& shape : shapes) + + + + // Загрузка в буферы + model.load_verteces (&verteces[0], verteces.size()); + model.load_normals (&normals[0], normals.size()); + model.load_texCoords(&texCords[0], texCords.size()); + // Загрузка индексного буфера + model.load_indices (&indices[0], indices.size()); + + + // Создаем копии модели, которые будут рендериться в заданном диапазоне + // И присваиваем текстуры копиям на основании материала + for (int i = 0; i < materials_range.size()-1; i++) + { + scene.push_back(model); // Создание копии с общим VAO + auto s = --scene.end(); + s->set_index_range(materials_range[i], materials_range[i+1]-materials_range[i]); + + Texture diffuse(TEX_DIFFUSE, texture_directory + materials[materials_ids[i]].diffuse_texname); + s->set_texture(diffuse); + } +} diff --git a/src/main.cpp b/src/main.cpp index fc86f78..a6d748b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -184,45 +184,12 @@ int main(void) glUseProgram(shaderProgram); // Установим значения текстур Texture::init_textures(shaderProgram); + // camera.move({0,0,-20}); - // Вершины прямоугольника - glm::vec3 verticies[] = { {-0.5f, -0.5f, 0.0f} - , { 0.5f, -0.5f, 0.0f} - , { 0.5f, 0.5f, 0.0f} - , {-0.5f, 0.5f, 0.0f} - }; - // Модель прямоугольника - Model rectangle; + // Загрузка сцены из obj файла + std::vector scene; + loadOBJtoVector("../resources/models/cubes.obj", scene, "../resources/models/", "../resources/textures/"); - // Загрузка вершин модели - rectangle.load_verteces(verticies, sizeof(verticies)/sizeof(glm::vec3)); - - // индексы вершин - GLuint indices[] = {0, 1, 2, 2, 3, 0}; - - // Загрузка индексов модели - rectangle.load_indices(indices, sizeof(indices)); - - // Текстурные координаты - glm::vec2 texCoords[] = { {0.0f, 0.0f} - , {1.0f, 0.0f} - , {1.0f, 1.0f} - , {0.0f, 1.0f} - }; - - // Загрузка текстурных координат модели - rectangle.load_texCoords(texCoords, sizeof(texCoords)/sizeof(glm::vec2)); - - // Зададим горизонтальное положение перед камерой - rectangle.position.y = -1; - rectangle.position.z = 3; - rectangle.rotation.x = 90; - rectangle.scale = glm::vec3(3); - - // Текстура травы - Texture grass(TEX_DIFFUSE, "../resources/textures/grass.png"); - rectangle.set_texture(grass); - // Установка цвета очистки буфера цвета glClearColor(0.0f, 0.0f, 0.0f, 1.0f); @@ -238,7 +205,10 @@ int main(void) glClear(GL_COLOR_BUFFER_BIT); // Тут производится рендер - rectangle.render(mvp_uniform); + for (auto& model : scene) + { + model.render(mvp_uniform); + } // Представление содержимого буфера цепочки показа на окно glfwSwapBuffers(window);