Skip to content

Commit f2c60f4

Browse files
hook up external loaders to Mitsuba XML
1 parent a66f3af commit f2c60f4

2 files changed

Lines changed: 83 additions & 48 deletions

File tree

include/nbl/ext/MitsubaLoader/SContext.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,23 @@
1414

1515
namespace nbl::ext::MitsubaLoader
1616
{
17+
class CMitsubaLoader;
1718

1819
struct SContext final
1920
{
2021
public:
22+
using interm_getAssetInHierarchy_t = asset::SAssetBundle(const char*, const uint16_t);
23+
2124
SContext(
2225
const asset::IAssetLoader::SAssetLoadContext& _params,
2326
asset::IAssetLoader::IAssetLoaderOverride* _override,
2427
CMitsubaMetadata* _metadata
2528
);
2629

2730
using shape_ass_type = core::smart_refctd_ptr<const asset::ICPUGeometryCollection>;
28-
shape_ass_type loadBasicShape(const uint32_t hierarchyLevel, const CElementShape* shape);
31+
shape_ass_type loadBasicShape(const CElementShape* shape);
2932
// the `shape` will have to be `Type::SHAPEGROUP`
30-
shape_ass_type loadShapeGroup(const uint32_t hierarchyLevel, const CElementShape* shape);
33+
shape_ass_type loadShapeGroup(const CElementShape* shape);
3134

3235
inline void transferMetadata()
3336
{
@@ -37,6 +40,7 @@ struct SContext final
3740

3841
const asset::IAssetLoader::SAssetLoadContext inner;
3942
asset::IAssetLoader::IAssetLoaderOverride* override_;
43+
std::function<interm_getAssetInHierarchy_t> interm_getAssetInHierarchy;
4044
CMitsubaMetadata* meta;
4145
core::smart_refctd_ptr<asset::ICPUScene> scene;
4246

src/nbl/ext/MitsubaLoader/CMitsubaLoader.cpp

Lines changed: 77 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,18 @@
22
// This file is part of the "Nabla Engine".
33
// For conditions of distribution and use, see copyright notice in nabla.h
44

5+
56
#include "nbl/builtin/hlsl/math/linalg/basic.hlsl"
67
#include "nbl/builtin/hlsl/math/linalg/fast_affine.hlsl"
78

89
#include "nbl/ext/MitsubaLoader/CMitsubaLoader.h"
910
#include "nbl/ext/MitsubaLoader/ParserUtil.h"
11+
#include "nbl/ext/MitsubaLoader/CMitsubaSerializedMetadata.h"
1012

1113
#include <cwchar>
1214

13-
#if 0
14-
#include "nbl/asset/utils/CDerivativeMapCreator.h"
15+
//#include "nbl/asset/utils/CDerivativeMapCreator.h"
1516

16-
#include "nbl/ext/MitsubaLoader/CMitsubaSerializedMetadata.h"
17-
#endif
1817

1918

2019
#if defined(_NBL_DEBUG) || defined(_NBL_RELWITHDEBINFO)
@@ -220,6 +219,10 @@ SAssetBundle CMitsubaLoader::loadAsset(system::IFile* _file, const IAssetLoader:
220219
_override,
221220
result.metadata.get()
222221
);
222+
ctx.interm_getAssetInHierarchy = [&](const char* filename, const uint16_t hierarchyOffset)->SAssetBundle
223+
{
224+
return this->interm_getAssetInHierarchy(filename,ctx.inner.params,_hierarchyLevel+hierarchyOffset,ctx.override_);
225+
};
223226
//
224227
ctx.scene->m_ambientLight = result.ambient;
225228

@@ -289,14 +292,14 @@ SAssetBundle CMitsubaLoader::loadAsset(system::IFile* _file, const IAssetLoader:
289292
continue;
290293

291294
if (shapedef->type!=CElementShape::Type::INSTANCE)
292-
addToScene(shapedef,ctx.loadBasicShape(_hierarchyLevel,shapedef));
295+
addToScene(shapedef,ctx.loadBasicShape(shapedef));
293296
else // mitsuba is weird and lists instances under a shapegroup instead of having instances reference the shapegroup
294297
{
295298
// get group reference
296299
const CElementShape* parent = shapedef->instance.parent;
297300
if (!parent) // we should probably assert this
298301
continue;
299-
addToScene(shapedef,ctx.loadShapeGroup(_hierarchyLevel,parent));
302+
addToScene(shapedef,ctx.loadShapeGroup(parent));
300303
}
301304
}
302305
result.shapegroups.clear();
@@ -625,7 +628,7 @@ SContext::SContext(
625628
frontIR = material_compiler3::CFrontendIR::create();
626629
}
627630

628-
auto SContext::loadShapeGroup(const uint32_t hierarchyLevel, const CElementShape* shape) -> SContext::shape_ass_type
631+
auto SContext::loadShapeGroup(const CElementShape* shape) -> SContext::shape_ass_type
629632
{
630633
assert(shape->type==CElementShape::Type::SHAPEGROUP);
631634
const auto* const shapegroup = &shape->shapegroup;
@@ -650,9 +653,9 @@ auto SContext::loadShapeGroup(const uint32_t hierarchyLevel, const CElementShape
650653

651654
shape_ass_type nestedCollection;
652655
if (child->type!=CElementShape::Type::SHAPEGROUP)
653-
nestedCollection = loadBasicShape(hierarchyLevel,child);
656+
nestedCollection = loadBasicShape(child);
654657
else
655-
nestedCollection = loadShapeGroup(hierarchyLevel,child);
658+
nestedCollection = loadShapeGroup(child);
656659
if (!nestedCollection)
657660
continue;
658661

@@ -673,7 +676,7 @@ auto SContext::loadShapeGroup(const uint32_t hierarchyLevel, const CElementShape
673676
return collection;
674677
}
675678

676-
auto SContext::loadBasicShape(const uint32_t hierarchyLevel, const CElementShape* shape) -> SContext::shape_ass_type
679+
auto SContext::loadBasicShape(const CElementShape* shape) -> SContext::shape_ass_type
677680
{
678681
auto found = shapeCache.find(shape);
679682
if (found!=shapeCache.end())
@@ -697,69 +700,97 @@ auto SContext::loadBasicShape(const uint32_t hierarchyLevel, const CElementShape
697700

698701
auto loadModel = [&](const char* filename, int64_t index=-1) -> void
699702
{
700-
#if 0
701-
auto retval = interm_getAssetInHierarchy(filename,inner.params,hierarchyLevel+/*ICPUScene::GEOMETRY_COLLECTION_HIERARCHY_LEVELS_BELOW*/1,override_);
702-
if (retval.getContents().empty())
703+
auto retval = interm_getAssetInHierarchy(filename,/*ICPUScene::GEOMETRY_COLLECTION_HIERARCHY_LEVELS_BELOW*/1);
704+
auto contentRange = retval.getContents();
705+
if (contentRange.empty())
703706
{
704-
os::Printer::log(std::string("[ERROR] Could Not Find Mesh: ") + filename.svalue, ELL_ERROR);
707+
inner.params.logger.log("Could Not Load Shape : %s",LoggerError,filename);
705708
return;
706709
}
710+
711+
// we used to load with the IAssetLoader::ELPF_RIGHT_HANDED_MESHES flag, this means flipping the mesh x-axis
712+
auto transform = math::linalg::diagonal<float32_t3x4>(1.f);
713+
transform[0][0] = -1.f;
714+
715+
//
716+
auto addCollectionGeometries = [&](const ICPUGeometryCollection* col)->void
717+
{
718+
if (col)
719+
for (auto ref : col->getGeometries())
720+
{
721+
if (ref.hasTransform())
722+
ref.transform = math::linalg::promoted_mul(ref.transform,transform);
723+
else
724+
ref.transform = transform;
725+
addGeometry(std::move(ref));
726+
}
727+
};
728+
729+
// take first target and replace the collection
730+
auto addFirstTargetGeometries = [&](const ICPUMorphTargets* morph)->void
731+
{
732+
if (const auto& targets=morph->getTargets(); !targets.empty())
733+
addCollectionGeometries(targets.front().geoCollection.get());
734+
};
707735

708-
uint32_t actualIndex = 0;
709736
switch (retval.getAssetType())
710737
{
711738
case IAsset::ET_GEOMETRY:
712739
{
713-
auto contentRange = retval.getContents();
740+
// only add one geometry, if we meant to add a whole collection, the file would load a collection
741+
const IGeometry<ICPUBuffer>* geo = nullptr;
714742
auto serializedMeta = retval.getMetadata()->selfCast<CMitsubaSerializedMetadata>();
715-
//
716-
if (index>=0ll && serializedMeta)
717743
for (auto it=contentRange.begin(); it!=contentRange.end(); it++)
718744
{
719-
auto meshMeta = static_cast<const CMitsubaSerializedMetadata::CMesh*>(serializedMeta->getAssetSpecificMetadata(IAsset::castDown<ICPUMesh>(*it).get()));
720-
if (meshMeta->m_id!=static_cast<uint32_t>(index))
721-
continue;
722-
actualIndex = it-contentRange.begin();
723-
break;
724-
}
725-
//
726-
if (contentRange.begin()+actualIndex < contentRange.end())
727-
{
728-
auto asset = contentRange.begin()[actualIndex];
729-
if (!asset)
730-
{
731-
return;
732-
}
733-
addGeometry(asset);
745+
geo = IAsset::castDown<const ICPUPolygonGeometry>(*it).get();
746+
assert(geo);
747+
if (!serializedMeta || index<0ll || index>numeric_limits<uint32_t>::max) // not Misuba serialized or shape index not specialized
748+
break;
749+
auto* const meta = serializedMeta->getAssetSpecificMetadata(static_cast<const ICPUPolygonGeometry*>(geo));
750+
assert(meta);
751+
auto* const polygonMeta = static_cast<const CMitsubaSerializedMetadata::CPolygonGeometry*>(meta);
752+
if (polygonMeta->m_id==static_cast<uint32_t>(index))
753+
break;
734754
}
755+
if (auto* const mg=const_cast<IGeometry<ICPUBuffer>*>(geo); mg)
756+
addGeometry({.transform=transform,.geometry=core::smart_refctd_ptr<IGeometry<ICPUBuffer>>(mg)});
757+
break;
735758
}
736759
case IAsset::ET_GEOMETRY_COLLECTION:
737760
{
738-
// TODO: replace the collection
761+
// only add the first collection's geometries
762+
addCollectionGeometries(IAsset::castDown<const ICPUGeometryCollection>(contentRange[0]).get());
739763
break;
740764
}
741765
case IAsset::ET_MORPH_TARGETS:
742766
{
743-
// TODO: take first target and replace the collection
744-
_NBL_DEBUG_BREAK_IF(true); // we have no such loaders right now
767+
addFirstTargetGeometries(IAsset::castDown<const ICPUMorphTargets>(contentRange[0]).get());
745768
break;
746769
}
747770
case IAsset::ET_SCENE:
748771
{
749-
// TODO: flatten the scene into a single instance, this is path for OBJ loading
750-
// NOTE: also need to preserve/forward the materials somehow (need to chape the `shape_ass_type` to have a default Material Binding Table)
772+
// flatten the scene into a single instance, this is path for OBJ loading
773+
const auto& instances = IAsset::castDown<const ICPUScene>(contentRange[0])->getInstances();
774+
const auto instanceTforms = instances.getInitialTransforms();
775+
for (auto i=0u; i<instances.size(); i++)
776+
{
777+
auto* const targets = instances.getMorphTargets()[i].get();
778+
const auto oldGeoBegin = pGeometries->size();
779+
addFirstTargetGeometries(targets);
780+
if (!instanceTforms.empty())
781+
for (auto geoIx=oldGeoBegin; geoIx<pGeometries->size(); geoIx++)
782+
{
783+
auto& ref = pGeometries->operator[](geoIx);
784+
ref.transform = math::linalg::promoted_mul(instanceTforms[i],ref.transform);
785+
}
786+
// NOTE: also need to preserve/forward the materials somehow (need to chape the `shape_ass_type` to have a default Material Binding Table)
787+
}
788+
break;
751789
}
752790
default:
753-
os::Printer::log("[ERROR] Loaded an Asset but it wasn't a mesh, was E_ASSET_TYPE " + std::to_string(retval.getAssetType()), ELL_ERROR);
791+
inner.params.logger.log("Loaded an Asset but it didn't contain any geometry, was %s",LoggerError,system::to_string(retval.getAssetType()));
754792
break;
755793
}
756-
#endif
757-
// we used to load with the IAssetLoader::ELPF_RIGHT_HANDED_MESHES flag, this means flipping the mesh x-axis
758-
for (auto& ref : *pGeometries)
759-
{
760-
ref.transform = math::linalg::diagonal<float32_t3x4>(1.f);
761-
ref.transform[0][0] = -1.f;
762-
}
763794
};
764795

765796
bool flipNormals = false;

0 commit comments

Comments
 (0)