// // Created by lbmas on 4/29/2026. // #include #include "ModelLoader.h" #include #include #include #include #include "TextureLoader.h" #include "glm/ext/matrix_transform.hpp" std::unordered_map> ModelLoader::models; void process_ai_mesh(aiMesh* aiMesh, const aiScene* scene, glm::mat4 transform, Mesh& mesh); void process_ai_node(aiNode* node, const aiScene* scene, glm::mat4 transform, Model* model); void process_ai_material(aiMaterial* aiMat, const aiScene* scene, Material& mat); auto zUpMatrix = glm::mat4( 1.0f, 0.0f, 0.0f, 0.0f, // Column 0 0.0f, 0.0f, 1.0f, 0.0f, // Column 1 0.0f, -1.0f, 0.0f, 0.0f, // Column 2 0.0f, 0.0f, 0.0f, 1.0f // Column 3 ); std::shared_ptr ModelLoader::load_from_file(std::string_view _path, bool zUp) { Assimp::Importer importer; const aiScene* scene = importer.ReadFile(_path.data(), aiProcess_Triangulate | aiProcess_GenSmoothNormals | aiProcess_FlipUVs); if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) { spdlog::error("failed to load model {}: {}", _path, importer.GetErrorString()); return nullptr; } auto model = std::make_shared(); auto transform = glm::identity(); if (zUp) { transform = zUpMatrix; } process_ai_node(scene->mRootNode, scene, transform, model.get()); return model; } void process_ai_node(aiNode* node, const aiScene* scene, glm::mat4 transform, Model* model) { auto m = node->mTransformation; transform = transform * glm::mat4(m.a1, m.a2, m.a3, m.a4, m.b1, m.b2, m.b3, m.b4, m.c1, m.c2, m.c3, m.c4, m.d1, m.d2, m.d3, m.d4); for (unsigned int i = 0; i < node->mNumMeshes; i++) { aiMesh* aiMesh = scene->mMeshes[node->mMeshes[i]]; Mesh mesh{}; process_ai_mesh(aiMesh, scene, transform, mesh); model->meshes.push_back(std::make_shared(mesh)); aiMaterial* aiMat = scene->mMaterials[aiMesh->mMaterialIndex]; Material mat{}; process_ai_material(aiMat, scene, mat); model->materials.push_back(std::make_shared(mat)); } for (unsigned int i = 0; i < node->mNumChildren; i++) { process_ai_node(node->mChildren[i], scene, transform, model); } } void process_ai_mesh(aiMesh* aiMesh, const aiScene* scene, glm::mat4 transform, Mesh& mesh) { auto positions = std::vector(aiMesh->mNumVertices * 3); auto uvs = std::vector(aiMesh->mNumVertices * 2); auto normals = std::vector(aiMesh->mNumVertices * 3); auto indices = std::vector(); for (unsigned int i = 0; i < aiMesh->mNumVertices; i++) { auto position = transform * glm::vec4(aiMesh->mVertices[i].x, aiMesh->mVertices[i].y, aiMesh->mVertices[i].z, 1.0f); positions[3 * i] = position.x; positions[3 * i + 1] = position.y; positions[3 * i + 2] = position.z; if (aiMesh->HasNormals()) { aiVector3D norm = aiMesh->mNormals[i]; normals[3 * i] = norm.x; normals[3 * i + 1] = norm.y; normals[3 * i + 2] = norm.z; } else { normals[3 * i] = 0; normals[3 * i + 1] = 0; normals[3 * i + 2] = 0; } if (aiMesh->HasTextureCoords(0)) { uvs[2 * i] = aiMesh->mTextureCoords[0][i].x; uvs[2 * i + 1] = aiMesh->mTextureCoords[0][i].y; } else { uvs[2 * i] = 0; uvs[2 * i + 1] = 0; } } for(unsigned int i = 0; i < aiMesh->mNumFaces; i++) { const aiFace face = aiMesh->mFaces[i]; for(unsigned int j = 0; j < face.mNumIndices; j++) indices.push_back(face.mIndices[j]); } mesh = {positions, uvs, normals, indices}; } void process_ai_material(aiMaterial* aiMat, const aiScene* scene, Material& mat) { aiString matName; aiReturn ret = aiMat->Get(AI_MATKEY_NAME, matName); if (ret != AI_SUCCESS) { spdlog::error("Could not find material name"); } // grab the phong stuff aiColor3D ambientColor {0.f, 0.f, 0.f}; ret = aiMat->Get(AI_MATKEY_COLOR_DIFFUSE, ambientColor); if (ret != AI_SUCCESS) { spdlog::error("Could not find ambient color for material: {}", matName.C_Str()); ambientColor = {.3f, .3f, .3f}; } aiColor3D diffuseColor {1.f, 1.f, 1.f}; ret = aiMat->Get(AI_MATKEY_COLOR_DIFFUSE, diffuseColor); if (ret != AI_SUCCESS) { spdlog::error("Could not find diffuse color for material: {}", matName.C_Str()); diffuseColor = {1.f, 1.f, 1.f}; } aiColor3D specularColor {1.f, 1.f, 1.f}; ret = aiMat->Get(AI_MATKEY_COLOR_SPECULAR, specularColor); if (ret != AI_SUCCESS) { spdlog::error("Could not find specular color for material: {}", matName.C_Str()); specularColor = {1.f, 1.f, 1.f}; } float shininess = 32.f; ret = aiMat->Get(AI_MATKEY_SHININESS, shininess); if (ret != AI_SUCCESS) { spdlog::error("Could not find shininess for material: {}", matName.C_Str()); shininess = 32.f; } // now grab the textures, first diffuse for (unsigned int i = 0; i < aiMat->GetTextureCount(aiTextureType_DIFFUSE); i++) { aiString textureName; aiMat->GetTexture(aiTextureType_DIFFUSE, i, &textureName); if (!TextureLoader::textures.contains(textureName.C_Str())) { TextureLoader::textures[textureName.C_Str()] = TextureLoader::load_from_file(textureName.C_Str()); } } mat.name = matName.C_Str(); mat.phong.ambient = glm::vec3{ambientColor.r, ambientColor.g, ambientColor.b}; mat.phong.diffuse = glm::vec3{diffuseColor.r, diffuseColor.g, diffuseColor.b}; mat.phong.specular = glm::vec3{specularColor.r, specularColor.g, specularColor.b}; mat.phong.shininess = shininess; }