// Assuming the metallic-roughness material model of models loaded with GLTF. std::pair<ID, std::vector<std::pair<Texture::Type, std::string>>> MeshManager::load_mesh(const std::string& directory, const std::string& file) { MeshInformation mesh_info; mesh_info.loaded_from_filepath = directory + file; Assimp::Importer importer; auto scene = importer.ReadFile(mesh_info.loaded_from_filepath.c_str(), aiProcess_Triangulate | aiProcess_JoinIdenticalVertices); if (scene == nullptr || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE) { Log::error(std::string(importer.GetErrorString())); return {0, {}}; } std::vector<std::pair<Texture::Type, std::string>> texture_info; if (scene->HasMaterials()) { Log::info("Number of materials: " + std::to_string(scene->mNumMaterials)); for (size_t i = 0; i < scene->mNumMaterials; i++) { auto material = scene->mMaterials[i]; aiString material_name; material->Get(AI_MATKEY_NAME, material_name); Log::info("Material name: " + std::string(material_name.C_Str())); aiString diffuse_filepath; if (material->GetTexture(aiTextureType_DIFFUSE, 0, &diffuse_filepath) == AI_SUCCESS) { Log::info("Diffuse texture name: " + std::string(directory.c_str()) + std::string(diffuse_filepath.data)); std::string texture_filepath(diffuse_filepath.data); texture_filepath.insert(0, directory); texture_info.push_back({Texture::Type::Diffuse, texture_filepath}); } aiString specular_filepath; if (material->GetTexture(aiTextureType_SPECULAR, 0, &specular_filepath) == AI_SUCCESS) { Log::info("Specular texture name: " + std::string(directory.c_str()) + std::string(specular_filepath.data)); } aiString ambient_filepath; if (material->GetTexture(aiTextureType_AMBIENT, 0, &ambient_filepath) == AI_SUCCESS) { Log::info("Ambient occlusion texture name: " + std::string(directory.c_str()) + std::string(ambient_filepath.data)); } aiString shininess_filepath; if (material->GetTexture(aiTextureType_SHININESS, 0, &shininess_filepath) == AI_SUCCESS) { Log::info("Shininess texture name: " + std::string(directory.c_str()) + std::string(shininess_filepath.data)); } aiString emissive_filepath; if (material->GetTexture(aiTextureType_EMISSIVE, 0, &emissive_filepath) == AI_SUCCESS) { Log::info("Emissive texture name: " + std::string(directory.c_str()) + std::string(emissive_filepath.data)); std::string texture_filepath(emissive_filepath.data); texture_filepath.insert(0, directory); texture_info.push_back({Texture::Type::Emissive, texture_filepath}); // TODO: Fetch emissive factor as well } aiString displacement_filepath; if (material->GetTexture(aiTextureType_DISPLACEMENT, 0, &displacement_filepath) == AI_SUCCESS) { Log::info("Displacement texture name: " + std::string(directory.c_str()) + std::string(displacement_filepath.data)); } aiString height_filepath; if (material->GetTexture(aiTextureType_HEIGHT, 0, &height_filepath) == AI_SUCCESS) { Log::info("Bumpmap texture name: " + std::string(directory.c_str()) + std::string(height_filepath.data)); } // Lightmap is usually the ambient occlusion map ... aiString lightmap_filepath; if (material->GetTexture(aiTextureType_LIGHTMAP, 0, &lightmap_filepath) == AI_SUCCESS) { Log::info("Lightmap texture name: " + std::string(directory.c_str()) + std::string(lightmap_filepath.data)); std::string texture_filepath(lightmap_filepath.data); texture_filepath.insert(0, directory); texture_info.push_back({Texture::Type::AmbientOcclusion, texture_filepath}); } aiString normals_filepath; if (material->GetTexture(aiTextureType_NORMALS, 0, &normals_filepath) == AI_SUCCESS) { Log::info("Normals texture name: " + std::string(directory.c_str()) + std::string(normals_filepath.data)); } aiString reflection_filepath; if (material->GetTexture(aiTextureType_REFLECTION, 0, &reflection_filepath) == AI_SUCCESS) { Log::info("Reflection texture name: " + std::string(directory.c_str()) + std::string(reflection_filepath.data)); } aiString opacity_filepath; if (material->GetTexture(aiTextureType_OPACITY, 0, &opacity_filepath) == AI_SUCCESS) { Log::info("Opacity texture name: " + std::string(directory.c_str()) + std::string(opacity_filepath.data)); } // NOTE: Roughness metallic textures are not detected so here we are assuming this is the unknown texture of the material. aiString unknown_filepath; if (material->GetTexture(aiTextureType_UNKNOWN, 0, &unknown_filepath) == AI_SUCCESS) { Log::info("Unknown texture name: " + std::string(directory.c_str()) + std::string(unknown_filepath.data)); std::string texture_filepath(normals_filepath.data); texture_filepath.insert(0, directory); texture_info.push_back({Texture::Type::MetallicRoughness, texture_filepath}); } } } if (scene->HasMeshes()) { // FIXME: Assumes the mesh is a single mesh and not a hierarchy Log::info("Scene: # meshes " + std::to_string(scene->mNumMeshes)); for (size_t i = 0; i < scene->mNumMeshes; i++) { auto mesh = scene->mMeshes[i]; Log::info("Loading mesh with name: " + std::string(mesh->mName.data)); for (size_t j = 0; j < mesh->mNumVertices; j++) { Vertex vertex; auto pos = mesh->mVertices[j]; vertex.position = {pos.x, pos.y, pos.z}; if (mesh->HasTextureCoords(0)) { auto tex_coord = mesh->mTextureCoords[0][j]; vertex.tex_coord = {tex_coord.x, -tex_coord.y}; // glTF (& .obj) has a flipped texture coordinate system compared to OpenGL } if (mesh->HasNormals()) { auto normal = mesh->mNormals[j]; vertex.normal = {normal.x, normal.y, normal.z}; } mesh_info.mesh.vertices.push_back(vertex); } for (size_t j = 0; j < mesh->mNumFaces; j++) { auto face = &mesh->mFaces[j]; if (face->mNumIndices != 3) { Log::warn("Not 3 vertices per face in model."); return {0, {}}; } for (size_t k = 0; k < 3; k++) { auto index = face->mIndices[k]; mesh_info.mesh.indices.push_back(index); } } } } // FIXME: Mesh id is worthless since it does not change or anything ... loaded_meshes.push_back(mesh_info.mesh); return {loaded_meshes.size() - 1, texture_info}; }
std::vector<Vertex> ModelLoader::load(int& numTriangles, int& numTextures) { std::ifstream fileCheck(filename); Vertex tempVert; std::vector<Vertex> geometry; std::deque<aiVector3D> texCoord; numTriangles = 0; numTextures = 0; for(int i = 0; i < 3; i++) tempVert.color[i] = 1.0; if(!fileCheck) { std::cerr << "Error: Unable to open object file" << std::endl; exit(-1); } fileCheck.close(); Assimp::Importer importer; auto scene = importer.ReadFile(filename, aiProcessPreset_TargetRealtime_Fast); if(!scene) { std::cerr << "Error: " << importer.GetErrorString() << std::endl; exit(-1); } std::cout << "Material Count: " << scene->mNumMaterials << std::endl; if(scene->HasMaterials()) { const auto& material = scene->mMaterials[0]; aiColor3D color(0.0f,0.0f,0.0); material->Get(AI_MATKEY_COLOR_DIFFUSE, color); tempVert.color[0] = color.r; tempVert.color[1] = color.g; tempVert.color[2] = color.b; } for(unsigned int i = 0; i < scene->mNumMeshes; i++) { auto mesh = scene->mMeshes[i]; if(scene->mNumMaterials > i+1) { auto material = scene->mMaterials[i+1]; aiColor3D color(1.0f,1.0f,1.0f); material->Get(AI_MATKEY_COLOR_DIFFUSE, color); tempVert.color[0] = color.r; tempVert.color[1] = color.g; tempVert.color[2] = color.b; if(material->GetTextureCount(aiTextureType_DIFFUSE) > 0) { aiString path; if(material->GetTexture(aiTextureType_DIFFUSE, 0, &path, NULL, NULL, NULL, NULL, NULL) == AI_SUCCESS) { std::cout << "Texture Path: " << path.C_Str() << std::endl; numTextures++; loadTexture(path.C_Str()); /* for(unsigned int j = 0; j < mesh->mNumVertices; j++) { const auto textureCoords = mesh->HasTextureCoords(0) ? mesh->mTextureCoords[0][j] : aiVector3D(0.0f,0.0f,0.0f); //texCoord.emplace_back(textureCoords); } */ } } } numTriangles += mesh->mNumFaces; for(unsigned int j = 0; j < mesh->mNumFaces; j++) { const auto& face = mesh->mFaces[j]; for(unsigned int k = 0; k < face.mNumIndices; k++) { const auto& vertex = mesh->mVertices[face.mIndices[k]]; tempVert.position[0] = vertex.x; tempVert.position[1] = vertex.y; tempVert.position[2] = vertex.z; const auto& textureVertex = mesh->HasTextureCoords(0) ? mesh->mTextureCoords[0][face.mIndices[k]] : aiVector3D(0,0,0); tempVert.textCoord[0] = textureVertex[0]; tempVert.textCoord[1] = textureVertex[1]; geometry.push_back(tempVert); } } } //loadTexture("checkerboard.jpg"); std::cout << "size: " << geometry.size() << std::endl << "bytes: " << sizeof(tempVert) * geometry.size() << std::endl; return geometry; }