// // Created by sebastian on 07.02.26. // #include "OBJLoader.h" #define TINYOBJLOADER_IMPLEMENTATION #include #include #include #include "TextureLoader.h" #include "tiny_obj_loader.h" #include "async/RawModelData.h" std::shared_ptr OBJLoader::loadModel(const std::string &modelPath, const std::string& texturePath, Loader &loader) { tinyobj::attrib_t attrib; std::vector shapes; std::vector materials; std::string warn, err; std::string baseDir = std::filesystem::path(modelPath).parent_path().string(); bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err, modelPath.c_str(), baseDir.c_str()); if (!warn.empty()) { std::cout << "OBJ Loader warning: " << warn << std::endl; } if (!err.empty()) { std::cerr << "OBJ Loader error: " << err << std::endl; } if (!ret) { throw std::runtime_error("Failed to load OBJ"); } std::vector subModels; for (const auto& shape : shapes) { std::vector vertices; std::vector normals; std::vector uvs; std::vector indices; int indexOffset = 0; for (const auto& index : shape.mesh.indices) { // Vertex-Position vertices.push_back(attrib.vertices[3*index.vertex_index + 0]); vertices.push_back(attrib.vertices[3*index.vertex_index + 1]); vertices.push_back(attrib.vertices[3*index.vertex_index + 2]); // UV-Koordinaten if (!attrib.texcoords.empty()) { uvs.push_back(attrib.texcoords[2*index.texcoord_index + 0]); uvs.push_back(1.0f - attrib.texcoords[2*index.texcoord_index + 1]); } else { uvs.push_back(0.0f); uvs.push_back(0.0f); } normals.push_back(attrib.normals[3*index.normal_index + 0]); normals.push_back(attrib.normals[3*index.normal_index + 1]); normals.push_back(attrib.normals[3*index.normal_index + 2]); // Index indices.push_back(indexOffset); indexOffset++; } RawModel rawModel = loader.loadToVAO(vertices, normals, uvs, indices); std::shared_ptr texture = nullptr; if (!materials.empty() && !shape.mesh.material_ids.empty()) { int matID = shape.mesh.material_ids[0]; if (matID >= 0 && matID < static_cast(materials.size())) { tinyobj::material_t &mat = materials[matID]; if (!mat.diffuse_texname.empty()) { std::string texFile = mat.diffuse_texname; std::filesystem::path fullTexPath = std::filesystem::path(baseDir) / std::filesystem::path(texFile); texture = std::make_shared(loader.loadTextureFromFile(fullTexPath.string(), false)); } } } if (!texture) { texture = std::make_shared(loader.loadTextureFromFile(texturePath, false)); } subModels.emplace_back( std::make_shared(rawModel), texture ); } return std::make_shared(subModels); } RawModelData OBJLoader::loadModel(const std::string &modelPath) { tinyobj::attrib_t attrib; std::vector shapes; std::vector materials; std::string warn, err; std::string baseDir = std::filesystem::path(modelPath).parent_path().string(); bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err, modelPath.c_str(), baseDir.c_str()); if (!warn.empty()) { std::cout << "OBJ Loader warning: " << warn << std::endl; } if (!err.empty()) { std::cerr << "OBJ Loader error: " << err << std::endl; } if (!ret) { throw std::runtime_error("Failed to load OBJ"); } std::vector subModels; for (const auto& shape : shapes) { std::vector vertices; std::vector normals; std::vector uvs; std::vector indices; int indexOffset = 0; for (const auto& index : shape.mesh.indices) { // Vertex-Position vertices.push_back(attrib.vertices[3*index.vertex_index + 0]); vertices.push_back(attrib.vertices[3*index.vertex_index + 1]); vertices.push_back(attrib.vertices[3*index.vertex_index + 2]); // UV-Koordinaten if (!attrib.texcoords.empty()) { uvs.push_back(attrib.texcoords[2*index.texcoord_index + 0]); uvs.push_back(1.0f - attrib.texcoords[2*index.texcoord_index + 1]); } else { uvs.push_back(0.0f); uvs.push_back(0.0f); } normals.push_back(attrib.normals[3*index.normal_index + 0]); normals.push_back(attrib.normals[3*index.normal_index + 1]); normals.push_back(attrib.normals[3*index.normal_index + 2]); // Index indices.push_back(indexOffset); indexOffset++; } std::vector textures; if (!materials.empty() && !shape.mesh.material_ids.empty()) { int matID = shape.mesh.material_ids[0]; if (matID >= 0 && matID < static_cast(materials.size())) { tinyobj::material_t &mat = materials[matID]; if (!mat.diffuse_texname.empty()) { std::string texFile = mat.diffuse_texname; std::filesystem::path fullTexPath = std::filesystem::path(baseDir) / std::filesystem::path(texFile); textures.push_back(TextureLoader::loadTextureData(fullTexPath.string(), false, TextureType::Diffuse)); } } } RawSubModelData subModelData = {vertices, normals, uvs, indices, textures}; subModels.push_back(subModelData); } return {"", subModels}; }