From b25bc3cc32c5a9057c66ad282fa1cdfe0ed6094a Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Mon, 10 Apr 2023 18:45:13 +0100 Subject: First cut loading assets using assimp This is far from perfect, specifically the created texture atlas is not compatibile with wrapping texture UVs --- assetFactory/assimp.cpp | 119 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 assetFactory/assimp.cpp (limited to 'assetFactory/assimp.cpp') diff --git a/assetFactory/assimp.cpp b/assetFactory/assimp.cpp new file mode 100644 index 0000000..55090f4 --- /dev/null +++ b/assetFactory/assimp.cpp @@ -0,0 +1,119 @@ +#include "assimp.h" +#include "assetFactory.h" +#include "collections.hpp" +#include "ptr.hpp" +#include "resource.h" +#include +#include +#include +#include + +template +glm::vec<3, T> +operator*(const aiVector3t & v) +{ + return {v.x, v.y, v.z}; +} + +template +glm::vec<2, T> +operator!(const aiVector3t & v) +{ + return {v.x, v.y}; +} + +#define AIRANGE(parent, member) \ + std::span \ + { \ + (parent)->m##member, (parent)->mNum##member \ + } + +using ScemeCPtr = std::shared_ptr; +class AssImpNode : public Shape { +public: + AssImpNode(ScemeCPtr scene, const aiNode * node) : scene(std::move(scene)), node(node) { } + + ScemeCPtr scene; + const aiNode * node; + + CreatedFaces + createMesh(ModelFactoryMesh & mesh, float) const + { + CreatedFaces faces; + addMesh(faces, mesh, node); + return faces; + } + + void + addMesh(CreatedFaces & faces, ModelFactoryMesh & mesh, const aiNode * node) const + { + for (const auto & m : AIRANGE(node, Meshes)) { + addMesh(faces, mesh, scene->mMeshes[m]); + } + for (const auto & n : AIRANGE(node, Children)) { + addMesh(faces, mesh, n); + } + } + + void + addMesh(CreatedFaces & faces, ModelFactoryMesh & mesh, const aiMesh * amesh) const + { + const auto vhs = AIRANGE(amesh, Vertices) * [&mesh](auto && v) { + return mesh.add_vertex(*v); + }; + const auto & m = *scene->mMaterials[amesh->mMaterialIndex]; + + AssetFactory::TextureFragmentCoords tfc; + if (auto mf = Persistence::ParseBase::getShared("assetFactory")) { + aiString path; + m.Get(AI_MATKEY_TEXTURE_DIFFUSE(0), path); + tfc = mf->getTextureCoords(path.C_Str()); + } + + for (const auto & f : AIRANGE(amesh, Faces)) { + const auto fvhs = AIRANGE(&f, Indices) * [&vhs](auto && i) { + return vhs[i]; + }; + const auto fh = faces.emplace(mesh.add_namedFace(amesh->mName.C_Str(), fvhs))->second; + if (amesh->HasTextureCoords(0)) { + for (auto idx = f.mIndices; const auto fheh : mesh.fh_range(fh)) { + const auto ouv = !amesh->mTextureCoords[0][*idx++]; + const auto uv = glm::mix(tfc[0], tfc[2], ouv); + mesh.set_texcoord2D(fheh, uv); + } + } + } + } +}; + +void +AssImp::postLoad() +{ + ScemeCPtr scene { + aiImportFile(Resource::mapPath(path).c_str(), aiProcess_RemoveRedundantMaterials), &aiReleaseImport}; + if (!scene) { + throw std::runtime_error("Failed to load asset library: " + path); + } + if (auto mf = Persistence::ParseBase::getShared("assetFactory")) { + const auto root = AIRANGE(scene->mRootNode, Children); + std::transform( + root.begin(), root.end(), std::inserter(mf->shapes, mf->shapes.end()), [&scene](const aiNode * m) { + return AssetFactory::Shapes::value_type {m->mName.C_Str(), std::make_shared(scene, m)}; + }); + const auto textures = AIRANGE(scene, Textures); + std::transform(textures.begin(), textures.end(), + std::inserter(mf->textureFragments, mf->textureFragments.end()), [](const aiTexture * t) { + auto texture = std::make_shared(); + texture->id = texture->path = t->mFilename.C_Str(); + texture->image = std::make_unique( + std::span {reinterpret_cast(t->pcData), t->mWidth}, STBI_rgb_alpha); + return AssetFactory::TextureFragments::value_type {texture->id, texture}; + }); + } +} + +bool +AssImp::persist(Persistence::PersistenceStore & store) +{ + return STORE_TYPE && STORE_MEMBER(path); +} -- cgit v1.2.3 From 3cd6bc2d9eebbdd575164816110717241d9e22db Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Mon, 10 Apr 2023 19:48:07 +0100 Subject: Load assimp textures in parallel --- assetFactory/assimp.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'assetFactory/assimp.cpp') diff --git a/assetFactory/assimp.cpp b/assetFactory/assimp.cpp index 55090f4..0c6cb86 100644 --- a/assetFactory/assimp.cpp +++ b/assetFactory/assimp.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include template @@ -101,12 +102,18 @@ AssImp::postLoad() return AssetFactory::Shapes::value_type {m->mName.C_Str(), std::make_shared(scene, m)}; }); const auto textures = AIRANGE(scene, Textures); - std::transform(textures.begin(), textures.end(), - std::inserter(mf->textureFragments, mf->textureFragments.end()), [](const aiTexture * t) { - auto texture = std::make_shared(); - texture->id = texture->path = t->mFilename.C_Str(); - texture->image = std::make_unique( - std::span {reinterpret_cast(t->pcData), t->mWidth}, STBI_rgb_alpha); + auto textureFutures = textures * [](const aiTexture * t) { + return std::async(std::launch::async, [t]() { + auto texture = std::make_shared(); + texture->id = texture->path = t->mFilename.C_Str(); + texture->image = std::make_unique( + std::span {reinterpret_cast(t->pcData), t->mWidth}, STBI_rgb_alpha); + return texture; + }); + }; + std::transform(textureFutures.begin(), textureFutures.end(), + std::inserter(mf->textureFragments, mf->textureFragments.end()), [](auto && textureFuture) { + auto texture = textureFuture.get(); return AssetFactory::TextureFragments::value_type {texture->id, texture}; }); } -- cgit v1.2.3 From 1b97b7b4cb126c8b60ac1acbd7e72274f0ddf21f Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Thu, 13 Apr 2023 02:20:50 +0100 Subject: Use texture atlas for asset factory --- assetFactory/assimp.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'assetFactory/assimp.cpp') diff --git a/assetFactory/assimp.cpp b/assetFactory/assimp.cpp index 0c6cb86..dd82105 100644 --- a/assetFactory/assimp.cpp +++ b/assetFactory/assimp.cpp @@ -64,11 +64,11 @@ public: }; const auto & m = *scene->mMaterials[amesh->mMaterialIndex]; - AssetFactory::TextureFragmentCoords tfc; + GLuint material {}; if (auto mf = Persistence::ParseBase::getShared("assetFactory")) { aiString path; m.Get(AI_MATKEY_TEXTURE_DIFFUSE(0), path); - tfc = mf->getTextureCoords(path.C_Str()); + material = mf->getMaterialIndex(path.C_Str()); } for (const auto & f : AIRANGE(amesh, Faces)) { @@ -79,8 +79,8 @@ public: if (amesh->HasTextureCoords(0)) { for (auto idx = f.mIndices; const auto fheh : mesh.fh_range(fh)) { const auto ouv = !amesh->mTextureCoords[0][*idx++]; - const auto uv = glm::mix(tfc[0], tfc[2], ouv); - mesh.set_texcoord2D(fheh, uv); + mesh.set_texcoord2D(fheh, ouv); + mesh.property(mesh.materialFaceProperty, fh) = material; } } } -- cgit v1.2.3 From c51c4c0ca3b19e47d6e75ce4be247a28d412a04c Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Thu, 13 Apr 2023 20:03:13 +0100 Subject: Fix typo in name SceneCPtr --- assetFactory/assimp.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'assetFactory/assimp.cpp') diff --git a/assetFactory/assimp.cpp b/assetFactory/assimp.cpp index dd82105..878e7e7 100644 --- a/assetFactory/assimp.cpp +++ b/assetFactory/assimp.cpp @@ -29,12 +29,12 @@ operator!(const aiVector3t & v) (parent)->m##member, (parent)->mNum##member \ } -using ScemeCPtr = std::shared_ptr; +using SceneCPtr = std::shared_ptr; class AssImpNode : public Shape { public: - AssImpNode(ScemeCPtr scene, const aiNode * node) : scene(std::move(scene)), node(node) { } + AssImpNode(SceneCPtr scene, const aiNode * node) : scene(std::move(scene)), node(node) { } - ScemeCPtr scene; + SceneCPtr scene; const aiNode * node; CreatedFaces @@ -90,7 +90,7 @@ public: void AssImp::postLoad() { - ScemeCPtr scene { + SceneCPtr scene { aiImportFile(Resource::mapPath(path).c_str(), aiProcess_RemoveRedundantMaterials), &aiReleaseImport}; if (!scene) { throw std::runtime_error("Failed to load asset library: " + path); -- cgit v1.2.3 From 1cdd7753d37bcf8f626298c3df97a02cc73f266c Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Fri, 14 Apr 2023 14:48:59 +0100 Subject: Load texture images in Worker --- assetFactory/assimp.cpp | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) (limited to 'assetFactory/assimp.cpp') diff --git a/assetFactory/assimp.cpp b/assetFactory/assimp.cpp index 878e7e7..bab052e 100644 --- a/assetFactory/assimp.cpp +++ b/assetFactory/assimp.cpp @@ -102,18 +102,14 @@ AssImp::postLoad() return AssetFactory::Shapes::value_type {m->mName.C_Str(), std::make_shared(scene, m)}; }); const auto textures = AIRANGE(scene, Textures); - auto textureFutures = textures * [](const aiTexture * t) { - return std::async(std::launch::async, [t]() { - auto texture = std::make_shared(); - texture->id = texture->path = t->mFilename.C_Str(); - texture->image = std::make_unique( - std::span {reinterpret_cast(t->pcData), t->mWidth}, STBI_rgb_alpha); - return texture; - }); - }; - std::transform(textureFutures.begin(), textureFutures.end(), - std::inserter(mf->textureFragments, mf->textureFragments.end()), [](auto && textureFuture) { - auto texture = textureFuture.get(); + std::transform(textures.begin(), textures.end(), + std::inserter(mf->textureFragments, mf->textureFragments.end()), [](auto && t) { + auto texture = std::make_shared(); + texture->id = texture->path = t->mFilename.C_Str(); + texture->image = Worker::addWork([t]() { + return std::make_unique( + std::span {reinterpret_cast(t->pcData), t->mWidth}, STBI_rgb_alpha); + }); return AssetFactory::TextureFragments::value_type {texture->id, texture}; }); } -- cgit v1.2.3 From 3e97b30a194907cede7a230e618f82ffb516b329 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Fri, 14 Apr 2023 15:25:38 +0100 Subject: Create texture fragments from materials --- assetFactory/assimp.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'assetFactory/assimp.cpp') diff --git a/assetFactory/assimp.cpp b/assetFactory/assimp.cpp index bab052e..9a49717 100644 --- a/assetFactory/assimp.cpp +++ b/assetFactory/assimp.cpp @@ -62,13 +62,11 @@ public: const auto vhs = AIRANGE(amesh, Vertices) * [&mesh](auto && v) { return mesh.add_vertex(*v); }; - const auto & m = *scene->mMaterials[amesh->mMaterialIndex]; + const auto & m = scene->mMaterials[amesh->mMaterialIndex]->GetName(); GLuint material {}; if (auto mf = Persistence::ParseBase::getShared("assetFactory")) { - aiString path; - m.Get(AI_MATKEY_TEXTURE_DIFFUSE(0), path); - material = mf->getMaterialIndex(path.C_Str()); + material = mf->getMaterialIndex(m.C_Str()); } for (const auto & f : AIRANGE(amesh, Faces)) { @@ -101,12 +99,15 @@ AssImp::postLoad() root.begin(), root.end(), std::inserter(mf->shapes, mf->shapes.end()), [&scene](const aiNode * m) { return AssetFactory::Shapes::value_type {m->mName.C_Str(), std::make_shared(scene, m)}; }); - const auto textures = AIRANGE(scene, Textures); - std::transform(textures.begin(), textures.end(), - std::inserter(mf->textureFragments, mf->textureFragments.end()), [](auto && t) { + const auto materials = AIRANGE(scene, Materials); + std::transform(materials.begin(), materials.end(), + std::inserter(mf->textureFragments, mf->textureFragments.end()), [&scene](const aiMaterial * m) { + aiString path; + m->Get(AI_MATKEY_TEXTURE_DIFFUSE(0), path); auto texture = std::make_shared(); - texture->id = texture->path = t->mFilename.C_Str(); - texture->image = Worker::addWork([t]() { + texture->id = m->GetName().C_Str(); + texture->path = path.C_Str(); + texture->image = Worker::addWork([t = scene->GetEmbeddedTexture(path.C_Str())]() { return std::make_unique( std::span {reinterpret_cast(t->pcData), t->mWidth}, STBI_rgb_alpha); }); -- cgit v1.2.3 From 32a2da41e0946c1d6d364b7763d1829bfa8b74db Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Fri, 14 Apr 2023 16:36:22 +0100 Subject: Configure texture fragment mapmode from material --- assetFactory/assimp.cpp | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'assetFactory/assimp.cpp') diff --git a/assetFactory/assimp.cpp b/assetFactory/assimp.cpp index 9a49717..840c5a9 100644 --- a/assetFactory/assimp.cpp +++ b/assetFactory/assimp.cpp @@ -85,6 +85,11 @@ public: } }; +static_assert(TextureOptions::MapMode::Repeat == static_cast(aiTextureMapMode_Wrap)); +static_assert(TextureOptions::MapMode::Clamp == static_cast(aiTextureMapMode_Clamp)); +static_assert(TextureOptions::MapMode::Decal == static_cast(aiTextureMapMode_Decal)); +static_assert(TextureOptions::MapMode::Mirror == static_cast(aiTextureMapMode_Mirror)); + void AssImp::postLoad() { @@ -107,6 +112,8 @@ AssImp::postLoad() auto texture = std::make_shared(); texture->id = m->GetName().C_Str(); texture->path = path.C_Str(); + m->Get(AI_MATKEY_MAPPINGMODE_U_DIFFUSE(0), texture->mapmodeU); + m->Get(AI_MATKEY_MAPPINGMODE_V_DIFFUSE(0), texture->mapmodeV); texture->image = Worker::addWork([t = scene->GetEmbeddedTexture(path.C_Str())]() { return std::make_unique( std::span {reinterpret_cast(t->pcData), t->mWidth}, STBI_rgb_alpha); -- cgit v1.2.3