2026-05-01 20:06:54 -05:00
|
|
|
//
|
|
|
|
|
// Created by lbmas on 4/29/2026.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
#include <spdlog/spdlog.h>
|
|
|
|
|
|
|
|
|
|
#include "ModelLoader.h"
|
|
|
|
|
|
|
|
|
|
#include <assimp/Importer.hpp>
|
|
|
|
|
#include <assimp/postprocess.h>
|
|
|
|
|
#include <assimp/scene.h>
|
|
|
|
|
|
2026-05-02 21:24:21 -04:00
|
|
|
#include <cstring>
|
|
|
|
|
|
2026-05-03 00:08:13 -05:00
|
|
|
#include "glm/ext/matrix_transform.hpp"
|
|
|
|
|
|
2026-05-02 21:24:21 -04:00
|
|
|
std::unordered_map<std::string, std::shared_ptr<Model>> ModelLoader::models;
|
|
|
|
|
|
2026-05-03 00:08:13 -05:00
|
|
|
Mesh process_ai_mesh(aiMesh* aiMesh);
|
2026-05-01 20:06:54 -05:00
|
|
|
void process_ai_node(aiNode* node, const aiScene* scene, Model* model);
|
2026-05-02 21:24:21 -04:00
|
|
|
|
|
|
|
|
Material process_ai_material(aiMaterial* mat);
|
2026-05-01 20:06:54 -05:00
|
|
|
|
|
|
|
|
std::shared_ptr<Model> ModelLoader::load_from_file(std::string_view _path)
|
|
|
|
|
{
|
|
|
|
|
Assimp::Importer importer;
|
|
|
|
|
|
|
|
|
|
const aiScene* scene = importer.ReadFile(_path.data(),
|
2026-05-02 21:24:21 -04:00
|
|
|
aiProcess_Triangulate |
|
2026-05-03 00:08:13 -05:00
|
|
|
aiProcess_GenNormals |
|
|
|
|
|
aiProcess_FlipUVs);
|
2026-05-01 20:06:54 -05:00
|
|
|
|
|
|
|
|
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<Model>();
|
|
|
|
|
|
2026-05-03 00:08:13 -05:00
|
|
|
process_ai_node(scene->mRootNode, scene, model.get());
|
2026-05-01 20:06:54 -05:00
|
|
|
|
|
|
|
|
return model;
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-03 00:08:13 -05:00
|
|
|
void process_ai_node(aiNode* node, const aiScene* scene, glm::mat4 transform, Model* model)
|
2026-05-01 20:06:54 -05:00
|
|
|
{
|
2026-05-03 00:08:13 -05:00
|
|
|
auto t = node->mTransformation;
|
|
|
|
|
transform = transform * glm::mat4(nTransform)
|
2026-05-02 21:24:21 -04:00
|
|
|
|
2026-05-03 00:08:13 -05:00
|
|
|
for (unsigned int i = 0; i < node->mNumMeshes; i++)
|
|
|
|
|
{
|
|
|
|
|
aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];
|
|
|
|
|
model->meshes.push_back(std::make_shared<Mesh>(process_ai_mesh(mesh)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (unsigned int i = 0; i < node->mNumChildren; i++)
|
|
|
|
|
{
|
|
|
|
|
process_ai_node(node->mChildren[i], scene, model);
|
2026-05-01 20:06:54 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-03 00:08:13 -05:00
|
|
|
Mesh process_ai_mesh(aiMesh* aiMesh)
|
2026-05-01 20:06:54 -05:00
|
|
|
{
|
|
|
|
|
auto positions = std::vector<float>(aiMesh->mNumVertices * 3);
|
|
|
|
|
auto uvs = std::vector<float>(aiMesh->mNumVertices * 2);
|
|
|
|
|
auto normals = std::vector<float>(aiMesh->mNumVertices * 3);
|
2026-05-03 00:08:13 -05:00
|
|
|
auto indices = std::vector<unsigned int>();
|
2026-05-01 20:06:54 -05:00
|
|
|
|
|
|
|
|
for (unsigned int i = 0; i < aiMesh->mNumVertices; i++)
|
|
|
|
|
{
|
|
|
|
|
auto position = aiMesh->mVertices[i];
|
2026-05-03 00:08:13 -05:00
|
|
|
positions[3 * i] = position.x;
|
|
|
|
|
positions[3 * i + 1] = position.y;
|
|
|
|
|
positions[3 * i + 2] = position.z;
|
2026-05-01 20:06:54 -05:00
|
|
|
|
|
|
|
|
if (aiMesh->HasNormals())
|
|
|
|
|
{
|
2026-05-03 00:08:13 -05:00
|
|
|
aiVector3D norm = aiMesh->mNormals[i];
|
|
|
|
|
normals[3 * i] = norm.x;
|
|
|
|
|
normals[3 * i + 1] = norm.y;
|
|
|
|
|
normals[3 * i + 2] = norm.z;
|
2026-05-01 20:06:54 -05:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2026-05-03 00:08:13 -05:00
|
|
|
normals[3 * i] = 0;
|
|
|
|
|
normals[3 * i + 1] = 0;
|
|
|
|
|
normals[3 * i + 2] = 0;
|
2026-05-01 20:06:54 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (aiMesh->HasTextureCoords(0))
|
|
|
|
|
{
|
2026-05-03 00:08:13 -05:00
|
|
|
uvs[2 * i] = aiMesh->mTextureCoords[0][i].x;
|
|
|
|
|
uvs[2 * i + 1] = aiMesh->mTextureCoords[0][i].y;
|
2026-05-01 20:06:54 -05:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2026-05-03 00:08:13 -05:00
|
|
|
uvs[2 * i] = 0;
|
|
|
|
|
uvs[2 * i + 1] = 0;
|
2026-05-01 20:06:54 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return {positions, uvs, normals, indices};
|
|
|
|
|
}
|
2026-05-02 21:24:21 -04:00
|
|
|
|
|
|
|
|
Material process_ai_material(aiMaterial *mat) {
|
|
|
|
|
aiString matName;
|
|
|
|
|
aiReturn ret = mat->Get(AI_MATKEY_NAME, matName);
|
|
|
|
|
if (ret != AI_SUCCESS) {
|
|
|
|
|
spdlog::error("Could not find material name");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
aiColor3D ambientColor {0.f, 0.f, 0.f};
|
|
|
|
|
ret = mat->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 = mat->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 = mat->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 = mat->Get(AI_MATKEY_SHININESS, shininess);
|
|
|
|
|
if (ret != AI_SUCCESS) {
|
|
|
|
|
spdlog::error("Could not find shininess for material: {}", matName.C_Str());
|
|
|
|
|
shininess = 32.f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Material material;
|
|
|
|
|
material.name = matName.C_Str();
|
|
|
|
|
material.phong.ambient = glm::vec3{ambientColor.r, ambientColor.g, ambientColor.b};
|
|
|
|
|
material.phong.diffuse = glm::vec3{diffuseColor.r, diffuseColor.g, diffuseColor.b};
|
|
|
|
|
material.phong.specular = glm::vec3{specularColor.r, specularColor.g, specularColor.b};
|
|
|
|
|
material.phong.shininess = shininess;
|
|
|
|
|
|
|
|
|
|
return material;
|
|
|
|
|
}
|