diff options
author | Dan Goodliffe <dan@randomdan.homeip.net> | 2023-04-10 18:45:13 +0100 |
---|---|---|
committer | Dan Goodliffe <dan@randomdan.homeip.net> | 2023-04-10 18:45:13 +0100 |
commit | b25bc3cc32c5a9057c66ad282fa1cdfe0ed6094a (patch) | |
tree | 469ffd495b9114ff7f7a7ccca75e4a1977c1f662 | |
parent | Support loading textures from an in memory buffer (diff) | |
download | ilt-b25bc3cc32c5a9057c66ad282fa1cdfe0ed6094a.tar.bz2 ilt-b25bc3cc32c5a9057c66ad282fa1cdfe0ed6094a.tar.xz ilt-b25bc3cc32c5a9057c66ad282fa1cdfe0ed6094a.zip |
First cut loading assets using assimp
This is far from perfect, specifically the created texture atlas is not compatibile with wrapping texture UVs
-rw-r--r-- | assetFactory/assetFactory.cpp | 5 | ||||
-rw-r--r-- | assetFactory/assetFactory.h | 3 | ||||
-rw-r--r-- | assetFactory/assimp.cpp | 119 | ||||
-rw-r--r-- | assetFactory/assimp.h | 14 | ||||
-rw-r--r-- | res/foliage.xml | 9 | ||||
-rw-r--r-- | test/perf-assetFactory.cpp | 11 | ||||
-rw-r--r-- | test/test-assetFactory.cpp | 17 |
7 files changed, 176 insertions, 2 deletions
diff --git a/assetFactory/assetFactory.cpp b/assetFactory/assetFactory.cpp index ec0e19f..917edfe 100644 --- a/assetFactory/assetFactory.cpp +++ b/assetFactory/assetFactory.cpp @@ -109,7 +109,7 @@ AssetFactory::createTexutre() const std::transform( textureFragments.begin(), textureFragments.end(), std::back_inserter(imageSizes), [](const auto & tf) { return TexturePacker::Image {tf.second->image->width, tf.second->image->height}; - }); + }); const auto [layout, outSize] = TexturePacker {imageSizes}.pack(); // * create texture texture = std::make_shared<Texture>(outSize.x, outSize.y, TextureOptions {.wrap = GL_CLAMP_TO_EDGE}); @@ -134,7 +134,8 @@ AssetFactory::persist(Persistence::PersistenceStore & store) using MapObjects = Persistence::MapByMember<Shapes, std::shared_ptr<Object>>; using MapAssets = Persistence::MapByMember<Assets>; using MapTextureFragments = Persistence::MapByMember<TextureFragments>; + using MapAssImp = Persistence::MapByMember<AssImps, std::shared_ptr<AssImp>, &AssImp::path>; return STORE_TYPE && STORE_NAME_HELPER("object", shapes, MapObjects) && STORE_NAME_HELPER("textureFragment", textureFragments, MapTextureFragments) - && STORE_NAME_HELPER("asset", assets, MapAssets); + && STORE_NAME_HELPER("assimp", assimps, MapAssImp) && STORE_NAME_HELPER("asset", assets, MapAssets); } diff --git a/assetFactory/assetFactory.h b/assetFactory/assetFactory.h index 52692c4..7843d44 100644 --- a/assetFactory/assetFactory.h +++ b/assetFactory/assetFactory.h @@ -1,6 +1,7 @@ #pragma once #include "asset.h" +#include "assimp.h" #include "persistence.h" #include "shape.h" #include "textureFragment.h" @@ -12,6 +13,7 @@ class AssetFactory : public Persistence::Persistable { public: using Shapes = std::map<std::string, Shape::Ptr, std::less<>>; using Assets = std::map<std::string, Asset::Ptr, std::less<>>; + using AssImps = std::map<std::string, AssImp::Ptr, std::less<>>; using TextureFragments = std::map<std::string, TextureFragment::Ptr, std::less<>>; using Colour = glm::vec3; using ColourAlpha = glm::vec4; @@ -26,6 +28,7 @@ public: Shapes shapes; Assets assets; + AssImps assimps; Colours colours; TextureFragments textureFragments; 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 <assimp/cimport.h> +#include <assimp/postprocess.h> +#include <assimp/scene.h> +#include <stb/stb_image.h> + +template<typename T> +glm::vec<3, T> +operator*(const aiVector3t<T> & v) +{ + return {v.x, v.y, v.z}; +} + +template<typename T> +glm::vec<2, T> +operator!(const aiVector3t<T> & v) +{ + return {v.x, v.y}; +} + +#define AIRANGE(parent, member) \ + std::span \ + { \ + (parent)->m##member, (parent)->mNum##member \ + } + +using ScemeCPtr = std::shared_ptr<const aiScene>; +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>("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>("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<AssImpNode>(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<TextureFragment>(); + texture->id = texture->path = t->mFilename.C_Str(); + texture->image = std::make_unique<Image>( + std::span {reinterpret_cast<unsigned char *>(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); +} diff --git a/assetFactory/assimp.h b/assetFactory/assimp.h new file mode 100644 index 0000000..55b551d --- /dev/null +++ b/assetFactory/assimp.h @@ -0,0 +1,14 @@ +#pragma once + +#include "persistence.h" + +class AssImp : public Persistence::Persistable { +public: + using Ptr = std::shared_ptr<AssImp>; + + void postLoad() override; + + bool persist(Persistence::PersistenceStore & store) override; + + std::string path; +}; diff --git a/res/foliage.xml b/res/foliage.xml new file mode 100644 index 0000000..1b0a1aa --- /dev/null +++ b/res/foliage.xml @@ -0,0 +1,9 @@ +<?xml version="1.0"?> +<ilt p.id="assetFactory"> + <assimp path="shapespark-low-poly-plants-kit.fbx"/> + <asset p.typeid="Foliage" id="Tree-01-1" name="Tree-01-1"> + <bodyMesh id="body"> + <use type="Tree-01-1"/> + </bodyMesh> + </asset> +</ilt> diff --git a/test/perf-assetFactory.cpp b/test/perf-assetFactory.cpp index c90ac52..147e4ba 100644 --- a/test/perf-assetFactory.cpp +++ b/test/perf-assetFactory.cpp @@ -14,6 +14,17 @@ brush47xml_load(benchmark::State & state) } } +static void +foliagexml_load(benchmark::State & state) +{ + TestMainWindow window; + + for (auto _ : state) { + benchmark::DoNotOptimize(AssetFactory::loadXML(RESDIR "/foliage.xml")); + } +} + BENCHMARK(brush47xml_load); +BENCHMARK(foliagexml_load); BENCHMARK_MAIN(); diff --git a/test/test-assetFactory.cpp b/test/test-assetFactory.cpp index 54168aa..dd458ca 100644 --- a/test/test-assetFactory.cpp +++ b/test/test-assetFactory.cpp @@ -8,6 +8,8 @@ #include "assetFactory/assetFactory.h" #include "assetFactory/object.h" #include "assetFactory/texturePacker.h" +#include "game/scenary/foliage.h" +#include "game/scenary/plant.h" #include "game/vehicles/railVehicle.h" #include "game/vehicles/railVehicleClass.h" #include "gfx/gl/sceneRenderer.h" @@ -96,6 +98,21 @@ BOOST_AUTO_TEST_CASE(brush47xml, *boost::unit_test::timeout(5)) render(); } + +BOOST_AUTO_TEST_CASE(foliage, *boost::unit_test::timeout(5)) +{ + auto mf = AssetFactory::loadXML(RESDIR "/foliage.xml"); + BOOST_REQUIRE(mf); + auto tree_01_1 = mf->assets.at("Tree-01-1"); + BOOST_REQUIRE(tree_01_1); + auto tree_01_1_f = std::dynamic_pointer_cast<Foliage>(tree_01_1); + BOOST_REQUIRE(tree_01_1_f); + + auto plant = std::make_shared<Plant>(tree_01_1_f, Location {}); + objects.objects.push_back(plant); + + render(); +} BOOST_AUTO_TEST_SUITE_END(); template<typename T> using InOut = std::tuple<T, T>; |