2023-05-01 13:13:35 +00:00
|
|
|
#include "util/model_loader.h"
|
2023-01-05 13:21:33 +00:00
|
|
|
|
2023-05-01 13:13:35 +00:00
|
|
|
#include "log.h"
|
2023-01-05 13:21:33 +00:00
|
|
|
|
2023-05-01 13:13:35 +00:00
|
|
|
#include "application.h"
|
2023-01-05 13:21:33 +00:00
|
|
|
|
2023-05-01 13:13:35 +00:00
|
|
|
#include "components/transform.h"
|
|
|
|
#include "components/renderable.h"
|
2023-01-05 13:21:33 +00:00
|
|
|
|
2023-05-01 13:13:35 +00:00
|
|
|
#include "resources/texture.h"
|
|
|
|
#include "resources/material.h"
|
|
|
|
#include "resources/shader.h"
|
|
|
|
#include "resources/mesh.h"
|
2023-01-05 13:21:33 +00:00
|
|
|
|
|
|
|
#include <assimp/Importer.hpp>
|
|
|
|
#include <assimp/LogStream.hpp>
|
|
|
|
#include <assimp/Logger.hpp>
|
|
|
|
#include <assimp/DefaultLogger.hpp>
|
|
|
|
#include <assimp/postprocess.h>
|
|
|
|
#include <assimp/mesh.h>
|
|
|
|
#include <assimp/scene.h>
|
|
|
|
|
|
|
|
#include <glm/gtc/quaternion.hpp>
|
|
|
|
|
|
|
|
#include <map>
|
|
|
|
#include <filesystem>
|
|
|
|
|
|
|
|
namespace engine::util {
|
|
|
|
|
|
|
|
static void buildGraph(
|
|
|
|
const std::map<int, std::shared_ptr<resources::Texture>>& textures,
|
|
|
|
const std::vector<std::shared_ptr<resources::Mesh>>& meshes,
|
|
|
|
const std::vector<unsigned int>& meshTextureIndices,
|
|
|
|
aiNode* parentNode, Scene* scene, uint32_t parentObj)
|
|
|
|
{
|
|
|
|
|
|
|
|
// convert to glm column major
|
2023-03-15 01:49:03 +00:00
|
|
|
glm::mat4 transform{};
|
2023-01-05 13:21:33 +00:00
|
|
|
for (int i = 0; i < 4; i++) {
|
|
|
|
for (int j = 0; j < 4; j++) {
|
|
|
|
transform[i][j] = parentNode->mTransformation[j][i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// get position
|
|
|
|
glm::vec3 position{ transform[3][0], transform[3][1], transform[3][2] };
|
|
|
|
|
|
|
|
// remove position from matrix
|
|
|
|
transform[3][0] = 0.0f;
|
|
|
|
transform[3][1] = 0.0f;
|
|
|
|
transform[3][2] = 0.0f;
|
|
|
|
|
|
|
|
// get scale
|
|
|
|
glm::vec3 scale{};
|
|
|
|
scale.x = sqrt(transform[0][0] * transform[0][0] + transform[0][1] * transform[0][1] + transform[0][2] * transform[0][2]);
|
|
|
|
scale.y = sqrt(transform[1][0] * transform[1][0] + transform[1][1] * transform[1][1] + transform[1][2] * transform[1][2]);
|
|
|
|
scale.z = sqrt(transform[2][0] * transform[2][0] + transform[2][1] * transform[2][1] + transform[2][2] * transform[2][2]);
|
|
|
|
|
|
|
|
// remove scaling from matrix
|
|
|
|
for (int row = 0; row < 3; row++) {
|
|
|
|
transform[0][row] /= scale.x;
|
|
|
|
transform[1][row] /= scale.y;
|
|
|
|
transform[2][row] /= scale.z;
|
|
|
|
}
|
|
|
|
|
|
|
|
// get rotation
|
|
|
|
glm::quat rotation = glm::quat_cast(transform);
|
|
|
|
|
|
|
|
// update position, scale, rotation
|
2023-04-29 14:22:25 +00:00
|
|
|
auto parentTransform = scene->GetComponent<TransformComponent>(parentObj);
|
2023-01-05 13:21:33 +00:00
|
|
|
parentTransform->position = position;
|
|
|
|
parentTransform->scale = scale;
|
|
|
|
parentTransform->rotation = rotation;
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < parentNode->mNumMeshes; i++) {
|
|
|
|
// create child node for each mesh
|
2023-04-29 14:22:25 +00:00
|
|
|
auto child = scene->CreateEntity("_mesh" + std::to_string(i), parentObj);
|
|
|
|
auto childRenderer = scene->AddComponent<RenderableComponent>(child);
|
2023-01-05 13:21:33 +00:00
|
|
|
childRenderer->mesh = meshes[parentNode->mMeshes[i]];
|
2023-04-29 14:22:25 +00:00
|
|
|
childRenderer->material = std::make_shared<resources::Material>(scene->app()->GetResource<resources::Shader>("builtin.standard"));
|
2023-01-05 13:21:33 +00:00
|
|
|
if (textures.contains(meshTextureIndices[parentNode->mMeshes[i]])) {
|
2023-05-01 12:55:49 +00:00
|
|
|
childRenderer->material->texture_ = textures.at(meshTextureIndices[parentNode->mMeshes[i]]);
|
2023-01-05 13:21:33 +00:00
|
|
|
} else {
|
2023-05-01 12:55:49 +00:00
|
|
|
childRenderer->material->texture_ = scene->app()->GetResource<resources::Texture>("builtin.white");
|
2023-01-05 13:21:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < parentNode->mNumChildren; i++) {
|
|
|
|
buildGraph(
|
|
|
|
textures,
|
|
|
|
meshes,
|
|
|
|
meshTextureIndices,
|
|
|
|
parentNode->mChildren[i],
|
|
|
|
scene,
|
2023-04-29 14:22:25 +00:00
|
|
|
scene->CreateEntity("child" + std::to_string(i), parentObj)
|
2023-01-05 13:21:33 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-01 12:55:49 +00:00
|
|
|
uint32_t LoadMeshFromFile(Scene* parent, const std::string& path)
|
2023-01-05 13:21:33 +00:00
|
|
|
{
|
|
|
|
Assimp::Importer importer;
|
|
|
|
|
|
|
|
class myStream : public Assimp::LogStream {
|
|
|
|
public:
|
|
|
|
void write(const char* message) override {
|
|
|
|
(void)message;
|
2023-03-12 16:14:55 +00:00
|
|
|
LOG_TRACE("ASSIMP: {}", message);
|
2023-01-05 13:21:33 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const unsigned int severity = Assimp::Logger::Debugging | Assimp::Logger::Info | Assimp::Logger::Err | Assimp::Logger::Warn;
|
|
|
|
Assimp::DefaultLogger::get()->attachStream(new myStream, severity);
|
|
|
|
|
|
|
|
// remove everything but texcoords, normals, meshes, materials
|
|
|
|
importer.SetPropertyInteger(AI_CONFIG_PP_RVC_FLAGS,
|
|
|
|
aiComponent_ANIMATIONS |
|
|
|
|
aiComponent_BONEWEIGHTS |
|
|
|
|
aiComponent_CAMERAS |
|
|
|
|
aiComponent_COLORS |
|
|
|
|
aiComponent_LIGHTS |
|
|
|
|
aiComponent_TANGENTS_AND_BITANGENTS |
|
|
|
|
aiComponent_TEXTURES |
|
|
|
|
0
|
|
|
|
);
|
|
|
|
importer.SetPropertyInteger(AI_CONFIG_PP_SBP_REMOVE,
|
|
|
|
aiPrimitiveType_POINT |
|
|
|
|
aiPrimitiveType_LINE |
|
|
|
|
aiPrimitiveType_POLYGON
|
|
|
|
);
|
|
|
|
|
|
|
|
const aiScene* scene = importer.ReadFile(path,
|
|
|
|
aiProcess_JoinIdenticalVertices |
|
|
|
|
aiProcess_Triangulate |
|
|
|
|
aiProcess_SortByPType |
|
|
|
|
aiProcess_RemoveComponent |
|
|
|
|
aiProcess_SplitLargeMeshes | // leave at default maximum
|
|
|
|
aiProcess_ValidateDataStructure | // make sure to log the output
|
|
|
|
aiProcess_ImproveCacheLocality |
|
|
|
|
aiProcess_RemoveRedundantMaterials |
|
|
|
|
aiProcess_FindInvalidData |
|
|
|
|
aiProcess_GenSmoothNormals |
|
|
|
|
aiProcess_GenUVCoords |
|
|
|
|
aiProcess_TransformUVCoords |
|
|
|
|
aiProcess_FlipUVs | // Maybe?
|
|
|
|
0
|
|
|
|
);
|
|
|
|
|
|
|
|
const char* errString = importer.GetErrorString();
|
|
|
|
if (errString[0] != '\0' || scene == nullptr) {
|
2023-01-26 21:17:07 +00:00
|
|
|
throw std::runtime_error("assimp error: " + std::string(errString));
|
2023-01-05 13:21:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE) {
|
2023-01-26 21:17:07 +00:00
|
|
|
throw std::runtime_error("assimp error (incomplete): " + std::string(errString));
|
2023-01-05 13:21:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
assert(scene->HasAnimations() == false);
|
|
|
|
assert(scene->HasCameras() == false);
|
|
|
|
assert(scene->HasLights() == false);
|
|
|
|
assert(scene->hasSkeletons() == false);
|
|
|
|
|
2023-03-12 16:14:55 +00:00
|
|
|
LOG_TRACE("material count: {}, mesh count: {}", scene->mNumMaterials, scene->mNumMeshes);
|
2023-01-05 13:21:33 +00:00
|
|
|
|
|
|
|
std::map<int, std::shared_ptr<resources::Texture>> textures{};
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < scene->mNumMaterials; i++) {
|
|
|
|
const aiMaterial* m = scene->mMaterials[i];
|
2023-03-12 16:14:55 +00:00
|
|
|
LOG_TRACE("Material {}:", i);
|
|
|
|
LOG_TRACE(" Name: {}", m->GetName().C_Str());
|
2023-01-05 13:21:33 +00:00
|
|
|
for (uint32_t j = 0; j < m->mNumProperties; j++) {
|
2023-01-06 16:45:39 +00:00
|
|
|
[[maybe_unused]] const aiMaterialProperty* p = m->mProperties[j];
|
2023-03-12 16:14:55 +00:00
|
|
|
LOG_TRACE(" prop {}, key: {}", j, p->mKey.C_Str());
|
2023-01-05 13:21:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (aiGetMaterialTextureCount(m, aiTextureType_DIFFUSE) >= 1) {
|
|
|
|
aiString texPath{};
|
|
|
|
aiGetMaterialTexture(m, aiTextureType_DIFFUSE, 0, &texPath);
|
2023-03-12 16:14:55 +00:00
|
|
|
LOG_TRACE(" Diffuse tex: {}", texPath.C_Str());
|
2023-01-05 13:21:33 +00:00
|
|
|
std::filesystem::path absPath = path;
|
|
|
|
absPath = absPath.parent_path();
|
|
|
|
absPath /= texPath.C_Str();
|
|
|
|
try {
|
2023-01-26 21:17:07 +00:00
|
|
|
textures[i] = std::make_shared<resources::Texture>(
|
2023-04-29 14:22:25 +00:00
|
|
|
&parent->app()->render_data_, absPath.string(),
|
2023-05-01 12:55:49 +00:00
|
|
|
resources::Texture::Filtering::kTrilinear);
|
2023-01-08 15:22:44 +00:00
|
|
|
} catch (const std::runtime_error&) {
|
2023-04-29 14:22:25 +00:00
|
|
|
textures[i] = parent->app()->GetResource<resources::Texture>("builtin.white");
|
2023-01-05 13:21:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<std::shared_ptr<resources::Mesh>> meshes{};
|
|
|
|
std::vector<unsigned int> meshMaterialIndices{};
|
|
|
|
for (uint32_t i = 0; i < scene->mNumMeshes; i++) {
|
|
|
|
const aiMesh* m = scene->mMeshes[i];
|
|
|
|
meshMaterialIndices.push_back(m->mMaterialIndex);
|
|
|
|
std::vector<Vertex> vertices(m->mNumVertices);
|
2023-03-15 01:49:03 +00:00
|
|
|
std::vector<uint32_t> indices((size_t)m->mNumFaces * 3);
|
2023-03-12 16:14:55 +00:00
|
|
|
LOG_TRACE("Mesh {}: vertex count {}", i, vertices.size());
|
|
|
|
LOG_TRACE("Mesh {}: index count {}", i, indices.size());
|
2023-01-05 13:21:33 +00:00
|
|
|
|
|
|
|
for (uint32_t j = 0; j < vertices.size(); j++) {
|
|
|
|
Vertex v{};
|
|
|
|
v.pos.x = m->mVertices[j].x;
|
|
|
|
v.pos.y = m->mVertices[j].y;
|
|
|
|
v.pos.z = m->mVertices[j].z;
|
|
|
|
v.norm.x = m->mNormals[j].x;
|
|
|
|
v.norm.y = m->mNormals[j].y;
|
|
|
|
v.norm.z = m->mNormals[j].z;
|
|
|
|
vertices[j] = v;
|
|
|
|
}
|
|
|
|
if (m->mNumUVComponents[0] >= 2) {
|
|
|
|
for (uint32_t j = 0; j < vertices.size(); j++) {
|
|
|
|
vertices[j].uv.x = m->mTextureCoords[0][j].x;
|
|
|
|
vertices[j].uv.y = m->mTextureCoords[0][j].y;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (uint32_t j = 0; j < indices.size() / 3; j++) {
|
2023-03-15 01:49:03 +00:00
|
|
|
indices[(size_t)j * 3 + 0] = m->mFaces[j].mIndices[0];
|
|
|
|
indices[(size_t)j * 3 + 1] = m->mFaces[j].mIndices[1];
|
|
|
|
indices[(size_t)j * 3 + 2] = m->mFaces[j].mIndices[2];
|
2023-01-05 13:21:33 +00:00
|
|
|
}
|
2023-04-29 14:22:25 +00:00
|
|
|
meshes.push_back(std::make_shared<resources::Mesh>(parent->app()->gfxdev(), vertices, indices));
|
2023-01-05 13:21:33 +00:00
|
|
|
}
|
|
|
|
|
2023-04-29 14:22:25 +00:00
|
|
|
uint32_t obj = parent->CreateEntity(scene->GetShortFilename(path.c_str()));
|
2023-01-05 13:21:33 +00:00
|
|
|
|
|
|
|
buildGraph(textures, meshes, meshMaterialIndices, scene->mRootNode, parent, obj);
|
|
|
|
|
2023-03-12 16:14:55 +00:00
|
|
|
LOG_INFO("Loaded model: {}, meshes: {}, textures: {}", scene->GetShortFilename(path.c_str()), meshes.size(), textures.size());
|
2023-01-06 16:45:39 +00:00
|
|
|
|
2023-01-05 13:21:33 +00:00
|
|
|
Assimp::DefaultLogger::kill();
|
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|