Merge pull request #4193 from PencilAmazing/BlenderCollections
Update blender importer to work with Blender 2.8+ filespull/4211/head^2
commit
745f5e7e65
|
@ -318,42 +318,81 @@ void BlenderImporter::ExtractScene(Scene &out, const FileDatabase &file) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
void BlenderImporter::ParseSubCollection(const Blender::Scene &in, aiNode *root, std::shared_ptr<Collection> collection, ConversionData &conv_data) {
|
||||||
|
|
||||||
|
std::deque<Object *> root_objects;
|
||||||
|
// Count number of objects
|
||||||
|
for (std::shared_ptr<CollectionObject> cur = std::static_pointer_cast<CollectionObject>(collection->gobject.first); cur; cur = cur->next) {
|
||||||
|
if (cur->ob) {
|
||||||
|
root_objects.push_back(cur->ob);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::deque<Collection *> root_children;
|
||||||
|
// Count number of child nodes
|
||||||
|
for (std::shared_ptr<CollectionChild> cur = std::static_pointer_cast<CollectionChild>(collection->children.first); cur; cur = cur->next) {
|
||||||
|
if (cur->collection) {
|
||||||
|
root_children.push_back(cur->collection.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
root->mNumChildren = static_cast<unsigned int>(root_objects.size() + root_children.size());
|
||||||
|
root->mChildren = new aiNode *[root->mNumChildren]();
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < static_cast<unsigned int>(root_objects.size()); ++i) {
|
||||||
|
root->mChildren[i] = ConvertNode(in, root_objects[i], conv_data, aiMatrix4x4());
|
||||||
|
root->mChildren[i]->mParent = root;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For each subcollection create a new node to represent it
|
||||||
|
unsigned int iterator = static_cast<unsigned int>(root_objects.size());
|
||||||
|
for (std::shared_ptr<CollectionChild> cur = std::static_pointer_cast<CollectionChild>(collection->children.first); cur; cur = cur->next) {
|
||||||
|
if (cur->collection) {
|
||||||
|
root->mChildren[iterator] = new aiNode(cur->collection->id.name + 2); // skip over the name prefix 'OB'
|
||||||
|
root->mChildren[iterator]->mParent = root;
|
||||||
|
ParseSubCollection(in, root->mChildren[iterator], cur->collection, conv_data);
|
||||||
|
}
|
||||||
|
iterator += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void BlenderImporter::ConvertBlendFile(aiScene *out, const Scene &in, const FileDatabase &file) {
|
void BlenderImporter::ConvertBlendFile(aiScene *out, const Scene &in, const FileDatabase &file) {
|
||||||
ConversionData conv(file);
|
ConversionData conv(file);
|
||||||
|
|
||||||
// FIXME it must be possible to take the hierarchy directly from
|
|
||||||
// the file. This is terrible. Here, we're first looking for
|
|
||||||
// all objects which don't have parent objects at all -
|
|
||||||
std::deque<const Object *> no_parents;
|
|
||||||
for (std::shared_ptr<Base> cur = std::static_pointer_cast<Base>(in.base.first); cur; cur = cur->next) {
|
|
||||||
if (cur->object) {
|
|
||||||
if (!cur->object->parent) {
|
|
||||||
no_parents.push_back(cur->object.get());
|
|
||||||
} else {
|
|
||||||
conv.objects.insert(cur->object.get());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (std::shared_ptr<Base> cur = in.basact; cur; cur = cur->next) {
|
|
||||||
if (cur->object) {
|
|
||||||
if (cur->object->parent) {
|
|
||||||
conv.objects.insert(cur->object.get());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (no_parents.empty()) {
|
|
||||||
ThrowException("Expected at least one object with no parent");
|
|
||||||
}
|
|
||||||
|
|
||||||
aiNode *root = out->mRootNode = new aiNode("<BlenderRoot>");
|
aiNode *root = out->mRootNode = new aiNode("<BlenderRoot>");
|
||||||
|
// Iterate over all objects directly under master_collection,
|
||||||
|
// If in.master_collection == null, then we're parsing something older.
|
||||||
|
if (in.master_collection) {
|
||||||
|
ParseSubCollection(in, root, in.master_collection, conv);
|
||||||
|
} else {
|
||||||
|
std::deque<const Object *> no_parents;
|
||||||
|
for (std::shared_ptr<Base> cur = std::static_pointer_cast<Base>(in.base.first); cur; cur = cur->next) {
|
||||||
|
if (cur->object) {
|
||||||
|
if (!cur->object->parent) {
|
||||||
|
no_parents.push_back(cur->object.get());
|
||||||
|
} else {
|
||||||
|
conv.objects.insert(cur->object.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (std::shared_ptr<Base> cur = in.basact; cur; cur = cur->next) {
|
||||||
|
if (cur->object) {
|
||||||
|
if (cur->object->parent) {
|
||||||
|
conv.objects.insert(cur->object.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
root->mNumChildren = static_cast<unsigned int>(no_parents.size());
|
if (no_parents.empty()) {
|
||||||
root->mChildren = new aiNode *[root->mNumChildren]();
|
ThrowException("Expected at least one object with no parent");
|
||||||
for (unsigned int i = 0; i < root->mNumChildren; ++i) {
|
}
|
||||||
root->mChildren[i] = ConvertNode(in, no_parents[i], conv, aiMatrix4x4());
|
|
||||||
root->mChildren[i]->mParent = root;
|
root->mNumChildren = static_cast<unsigned int>(no_parents.size());
|
||||||
|
root->mChildren = new aiNode *[root->mNumChildren]();
|
||||||
|
for (unsigned int i = 0; i < root->mNumChildren; ++i) {
|
||||||
|
root->mChildren[i] = ConvertNode(in, no_parents[i], conv, aiMatrix4x4());
|
||||||
|
root->mChildren[i]->mParent = root;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BuildMaterials(conv);
|
BuildMaterials(conv);
|
||||||
|
|
|
@ -78,6 +78,7 @@ struct ElemBase;
|
||||||
namespace Blender {
|
namespace Blender {
|
||||||
struct Scene;
|
struct Scene;
|
||||||
struct Object;
|
struct Object;
|
||||||
|
struct Collection;
|
||||||
struct Mesh;
|
struct Mesh;
|
||||||
struct Camera;
|
struct Camera;
|
||||||
struct Lamp;
|
struct Lamp;
|
||||||
|
@ -116,6 +117,7 @@ protected:
|
||||||
void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) override;
|
void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) override;
|
||||||
void ParseBlendFile(Blender::FileDatabase &out, std::shared_ptr<IOStream> stream);
|
void ParseBlendFile(Blender::FileDatabase &out, std::shared_ptr<IOStream> stream);
|
||||||
void ExtractScene(Blender::Scene &out, const Blender::FileDatabase &file);
|
void ExtractScene(Blender::Scene &out, const Blender::FileDatabase &file);
|
||||||
|
void ParseSubCollection(const Blender::Scene &in, aiNode *root, std::shared_ptr<Blender::Collection> collection, Blender::ConversionData &conv_data);
|
||||||
void ConvertBlendFile(aiScene *out, const Blender::Scene &in, const Blender::FileDatabase &file);
|
void ConvertBlendFile(aiScene *out, const Blender::Scene &in, const Blender::FileDatabase &file);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -94,6 +94,52 @@ void Structure ::Convert<Group>(
|
||||||
db.reader->IncPtr(size);
|
db.reader->IncPtr(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------
|
||||||
|
template <>
|
||||||
|
void Structure::Convert<CollectionObject>(
|
||||||
|
CollectionObject &dest,
|
||||||
|
const FileDatabase &db) const {
|
||||||
|
|
||||||
|
ReadFieldPtr<ErrorPolicy_Fail>(dest.next, "*next", db);
|
||||||
|
{
|
||||||
|
//std::shared_ptr<CollectionObject> prev;
|
||||||
|
//ReadFieldPtr<ErrorPolicy_Fail>(prev, "*prev", db);
|
||||||
|
//dest.prev = prev.get();
|
||||||
|
|
||||||
|
std::shared_ptr<Object> ob;
|
||||||
|
ReadFieldPtr<ErrorPolicy_Igno>(ob, "*ob", db);
|
||||||
|
dest.ob = ob.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
db.reader->IncPtr(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------
|
||||||
|
template <>
|
||||||
|
void Structure::Convert<CollectionChild>(
|
||||||
|
CollectionChild &dest,
|
||||||
|
const FileDatabase &db) const {
|
||||||
|
|
||||||
|
ReadFieldPtr<ErrorPolicy_Fail>(dest.prev, "*prev", db);
|
||||||
|
ReadFieldPtr<ErrorPolicy_Fail>(dest.next, "*next", db);
|
||||||
|
ReadFieldPtr<ErrorPolicy_Igno>(dest.collection, "*collection", db);
|
||||||
|
|
||||||
|
db.reader->IncPtr(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------
|
||||||
|
template <>
|
||||||
|
void Structure::Convert<Collection>(
|
||||||
|
Collection &dest,
|
||||||
|
const FileDatabase &db) const {
|
||||||
|
|
||||||
|
ReadField<ErrorPolicy_Fail>(dest.id, "id", db);
|
||||||
|
ReadField<ErrorPolicy_Fail>(dest.gobject, "gobject", db);
|
||||||
|
ReadField<ErrorPolicy_Fail>(dest.children, "children", db);
|
||||||
|
|
||||||
|
db.reader->IncPtr(size);
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------
|
||||||
template <>
|
template <>
|
||||||
void Structure ::Convert<MTex>(
|
void Structure ::Convert<MTex>(
|
||||||
|
@ -660,6 +706,7 @@ void Structure ::Convert<Scene>(
|
||||||
ReadFieldPtr<ErrorPolicy_Warn>(dest.camera, "*camera", db);
|
ReadFieldPtr<ErrorPolicy_Warn>(dest.camera, "*camera", db);
|
||||||
ReadFieldPtr<ErrorPolicy_Warn>(dest.world, "*world", db);
|
ReadFieldPtr<ErrorPolicy_Warn>(dest.world, "*world", db);
|
||||||
ReadFieldPtr<ErrorPolicy_Warn>(dest.basact, "*basact", db);
|
ReadFieldPtr<ErrorPolicy_Warn>(dest.basact, "*basact", db);
|
||||||
|
ReadFieldPtr<ErrorPolicy_Warn>(dest.master_collection, "*master_collection", db);
|
||||||
ReadField<ErrorPolicy_Igno>(dest.base, "base", db);
|
ReadField<ErrorPolicy_Igno>(dest.base, "base", db);
|
||||||
|
|
||||||
db.reader->IncPtr(size);
|
db.reader->IncPtr(size);
|
||||||
|
@ -833,6 +880,9 @@ void DNA::RegisterConverters() {
|
||||||
converters["Image"] = DNA::FactoryPair(&Structure::Allocate<Image>, &Structure::Convert<Image>);
|
converters["Image"] = DNA::FactoryPair(&Structure::Allocate<Image>, &Structure::Convert<Image>);
|
||||||
converters["CustomData"] = DNA::FactoryPair(&Structure::Allocate<CustomData>, &Structure::Convert<CustomData>);
|
converters["CustomData"] = DNA::FactoryPair(&Structure::Allocate<CustomData>, &Structure::Convert<CustomData>);
|
||||||
converters["CustomDataLayer"] = DNA::FactoryPair(&Structure::Allocate<CustomDataLayer>, &Structure::Convert<CustomDataLayer>);
|
converters["CustomDataLayer"] = DNA::FactoryPair(&Structure::Allocate<CustomDataLayer>, &Structure::Convert<CustomDataLayer>);
|
||||||
|
converters["Collection"] = DNA::FactoryPair(&Structure::Allocate<Collection>, &Structure::Convert<Collection>);
|
||||||
|
converters["CollectionChild"] = DNA::FactoryPair(&Structure::Allocate<CollectionChild>, &Structure::Convert<CollectionChild>);
|
||||||
|
converters["CollectionObject"] = DNA::FactoryPair(&Structure::Allocate<CollectionObject>, &Structure::Convert<CollectionObject>);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // ASSIMP_BUILD_NO_BLEND_IMPORTER
|
#endif // ASSIMP_BUILD_NO_BLEND_IMPORTER
|
||||||
|
|
|
@ -107,6 +107,7 @@ namespace Blender {
|
||||||
struct Object;
|
struct Object;
|
||||||
struct MTex;
|
struct MTex;
|
||||||
struct Image;
|
struct Image;
|
||||||
|
struct Collection;
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
@ -147,6 +148,26 @@ struct Group : ElemBase {
|
||||||
std::shared_ptr<GroupObject> gobject;
|
std::shared_ptr<GroupObject> gobject;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------
|
||||||
|
struct CollectionObject : ElemBase {
|
||||||
|
//CollectionObject* prev;
|
||||||
|
std::shared_ptr<CollectionObject> next;
|
||||||
|
Object *ob;
|
||||||
|
};
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------
|
||||||
|
struct CollectionChild : ElemBase {
|
||||||
|
std::shared_ptr<CollectionChild> next, prev;
|
||||||
|
std::shared_ptr<Collection> collection;
|
||||||
|
};
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------
|
||||||
|
struct Collection : ElemBase {
|
||||||
|
ID id FAIL;
|
||||||
|
ListBase gobject; // CollectionObject
|
||||||
|
ListBase children; // CollectionChild
|
||||||
|
};
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
struct World : ElemBase {
|
struct World : ElemBase {
|
||||||
ID id FAIL;
|
ID id FAIL;
|
||||||
|
@ -729,11 +750,12 @@ struct Scene : ElemBase {
|
||||||
std::shared_ptr<Object> camera WARN;
|
std::shared_ptr<Object> camera WARN;
|
||||||
std::shared_ptr<World> world WARN;
|
std::shared_ptr<World> world WARN;
|
||||||
std::shared_ptr<Base> basact WARN;
|
std::shared_ptr<Base> basact WARN;
|
||||||
|
std::shared_ptr<Collection> master_collection WARN;
|
||||||
|
|
||||||
ListBase base;
|
ListBase base;
|
||||||
|
|
||||||
Scene() :
|
Scene() :
|
||||||
ElemBase(), camera(), world(), basact() {
|
ElemBase(), camera(), world(), basact(), master_collection() {
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -62,6 +62,12 @@ template <> void Structure :: Convert<Group> (
|
||||||
) const
|
) const
|
||||||
;
|
;
|
||||||
|
|
||||||
|
template <> void Structure::Convert<Collection>(
|
||||||
|
Collection& dest,
|
||||||
|
const FileDatabase& db
|
||||||
|
) const
|
||||||
|
;
|
||||||
|
|
||||||
template <> void Structure :: Convert<MTex> (
|
template <> void Structure :: Convert<MTex> (
|
||||||
MTex& dest,
|
MTex& dest,
|
||||||
const FileDatabase& db
|
const FileDatabase& db
|
||||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -114,6 +114,12 @@ TEST(utBlenderImporter, importBlenderDefault271) {
|
||||||
ASSERT_NE(nullptr, scene);
|
ASSERT_NE(nullptr, scene);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(utBlenderImporter, importBlenderDefault293) {
|
||||||
|
Assimp::Importer importer;
|
||||||
|
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/BLEND/BlenderDefault_276.blend", aiProcess_ValidateDataStructure);
|
||||||
|
ASSERT_NE(nullptr, scene);
|
||||||
|
}
|
||||||
|
|
||||||
TEST(utBlenderImporter, importCubeHierarchy_248) {
|
TEST(utBlenderImporter, importCubeHierarchy_248) {
|
||||||
Assimp::Importer importer;
|
Assimp::Importer importer;
|
||||||
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/BLEND/CubeHierarchy_248.blend", aiProcess_ValidateDataStructure);
|
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/BLEND/CubeHierarchy_248.blend", aiProcess_ValidateDataStructure);
|
||||||
|
|
Loading…
Reference in New Issue