diff --git a/.vscode/settings.json b/.vscode/settings.json index 98bbebb..d7f31e6 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,12 +4,43 @@ "iosfwd": "cpp", "map": "cpp", "atomic": "cpp", - "iostream": "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", - "new": "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/Scene.h b/include/Scene.h index 07638e9..0639c13 100644 --- a/include/Scene.h +++ b/include/Scene.h @@ -6,6 +6,9 @@ #include "Model.h" #include "Camera.h" +#define DEFAULT_MTL_DIR "./" +class Scene loadOBJtoScene(const char* filename, const char* mtl_directory = DEFAULT_MTL_DIR, const char* texture_directory = DEFAULT_MTL_DIR); + // Класс сцены class Scene { diff --git a/src/Scene.cpp b/src/Scene.cpp index 222efc8..701c261 100644 --- a/src/Scene.cpp +++ b/src/Scene.cpp @@ -87,3 +87,127 @@ void Scene::rebuld_tree(const Scene& from) rebuild_Nodes_list(models, from); rebuild_Nodes_list(cameras, from); } + +#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...); +} + +Scene loadOBJtoScene(const char* filename, const char* mtl_directory, const char* texture_directory) +{ + Scene result; + Model model; + // Все модели образованные на основании этой модели будут иметь общего родителя + model.setParent(&result.root); + + 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++) + { + result.models.push_back(model); // Создание копии с общим VAO + auto s = --result.models.end(); + s->set_index_range(materials_range[i]*sizeof(GLuint), materials_range[i+1]-materials_range[i]); + + Texture diffuse(TEX_DIFFUSE, texture_directory + materials[materials_ids[i]].diffuse_texname); + s->set_texture(diffuse); + } + + return result; +} diff --git a/src/main.cpp b/src/main.cpp index 4675026..1d6a82c 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -5,9 +5,7 @@ #include -#include "Camera.h" -#include "Model.h" -#include "Texture.h" +#include "Scene.h" #define WINDOW_WIDTH 800 #define WINDOW_HEIGHT 600 @@ -184,44 +182,9 @@ int main(void) // Установим значения текстур Texture::init_textures(shaderProgram); - // Вершины прямоугольника - 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 файла + Scene scene = loadOBJtoScene("../resources/models/cubes.obj", "../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.e_position().y = -1; - rectangle.e_position().z = 3; - rectangle.e_rotation() = {0.707f, 0.707f, 0.0f, 0.0f}; - rectangle.e_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); @@ -241,7 +204,7 @@ int main(void) glClear(GL_COLOR_BUFFER_BIT); // Тут производится рендер - rectangle.render(model_uniform); + scene.render(model_uniform); // Представление содержимого буфера цепочки показа на окно glfwSwapBuffers(window);