FBX orphant embedded textures
parent
aa4c9fb5fa
commit
55c2a3edb9
|
@ -47,6 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#define INCLUDED_AI_FBX_COMPILECONFIG_H
|
#define INCLUDED_AI_FBX_COMPILECONFIG_H
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
//
|
//
|
||||||
#if _MSC_VER > 1500 || (defined __GNUC___)
|
#if _MSC_VER > 1500 || (defined __GNUC___)
|
||||||
|
@ -54,16 +55,23 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
# else
|
# else
|
||||||
# define fbx_unordered_map map
|
# define fbx_unordered_map map
|
||||||
# define fbx_unordered_multimap multimap
|
# define fbx_unordered_multimap multimap
|
||||||
|
# define fbx_unordered_set set
|
||||||
|
# define fbx_unordered_multiset multiset
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ASSIMP_FBX_USE_UNORDERED_MULTIMAP
|
#ifdef ASSIMP_FBX_USE_UNORDERED_MULTIMAP
|
||||||
# include <unordered_map>
|
# include <unordered_map>
|
||||||
|
# include <unordered_set>
|
||||||
# if _MSC_VER > 1600
|
# if _MSC_VER > 1600
|
||||||
# define fbx_unordered_map unordered_map
|
# define fbx_unordered_map unordered_map
|
||||||
# define fbx_unordered_multimap unordered_multimap
|
# define fbx_unordered_multimap unordered_multimap
|
||||||
|
# define fbx_unordered_set unordered_set
|
||||||
|
# define fbx_unordered_multiset unordered_multiset
|
||||||
# else
|
# else
|
||||||
# define fbx_unordered_map tr1::unordered_map
|
# define fbx_unordered_map tr1::unordered_map
|
||||||
# define fbx_unordered_multimap tr1::unordered_multimap
|
# define fbx_unordered_multimap tr1::unordered_multimap
|
||||||
|
# define fbx_unordered_set tr1::unordered_set
|
||||||
|
# define fbx_unordered_multiset tr1::unordered_multiset
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -97,6 +97,14 @@ namespace Assimp {
|
||||||
// populate the node_anim_chain_bits map, which is needed
|
// populate the node_anim_chain_bits map, which is needed
|
||||||
// to determine which nodes need to be generated.
|
// to determine which nodes need to be generated.
|
||||||
ConvertAnimations();
|
ConvertAnimations();
|
||||||
|
// Embedded textures in FBX could be connected to nothing but to itself,
|
||||||
|
// for instance Texture -> Video connection only but not to the main graph,
|
||||||
|
// The idea here is to traverse all objects to find these Textures and convert them,
|
||||||
|
// so later during material conversion it will find converted texture in the textures_converted array.
|
||||||
|
if (doc.Settings().readTextures)
|
||||||
|
{
|
||||||
|
ConvertOrphantEmbeddedTextures();
|
||||||
|
}
|
||||||
ConvertRootNode();
|
ConvertRootNode();
|
||||||
|
|
||||||
if (doc.Settings().readAllMaterials) {
|
if (doc.Settings().readAllMaterials) {
|
||||||
|
@ -1774,7 +1782,7 @@ namespace Assimp {
|
||||||
bool textureReady = false; //tells if our texture is ready (if it was loaded or if it was found)
|
bool textureReady = false; //tells if our texture is ready (if it was loaded or if it was found)
|
||||||
unsigned int index;
|
unsigned int index;
|
||||||
|
|
||||||
VideoMap::const_iterator it = textures_converted.find(media);
|
VideoMap::const_iterator it = textures_converted.find(*media);
|
||||||
if (it != textures_converted.end()) {
|
if (it != textures_converted.end()) {
|
||||||
index = (*it).second;
|
index = (*it).second;
|
||||||
textureReady = true;
|
textureReady = true;
|
||||||
|
@ -1782,7 +1790,7 @@ namespace Assimp {
|
||||||
else {
|
else {
|
||||||
if (media->ContentLength() > 0) {
|
if (media->ContentLength() > 0) {
|
||||||
index = ConvertVideo(*media);
|
index = ConvertVideo(*media);
|
||||||
textures_converted[media] = index;
|
textures_converted[*media] = index;
|
||||||
textureReady = true;
|
textureReady = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2306,13 +2314,13 @@ void FBXConverter::SetShadingPropertiesRaw(aiMaterial* out_mat, const PropertyTa
|
||||||
if (media != nullptr && media->ContentLength() > 0) {
|
if (media != nullptr && media->ContentLength() > 0) {
|
||||||
unsigned int index;
|
unsigned int index;
|
||||||
|
|
||||||
VideoMap::const_iterator it = textures_converted.find(media);
|
VideoMap::const_iterator it = textures_converted.find(*media);
|
||||||
if (it != textures_converted.end()) {
|
if (it != textures_converted.end()) {
|
||||||
index = (*it).second;
|
index = (*it).second;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
index = ConvertVideo(*media);
|
index = ConvertVideo(*media);
|
||||||
textures_converted[media] = index;
|
textures_converted[*media] = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
// setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture)
|
// setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture)
|
||||||
|
@ -3666,6 +3674,47 @@ void FBXConverter::SetShadingPropertiesRaw(aiMaterial* out_mat, const PropertyTa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FBXConverter::ConvertOrphantEmbeddedTextures()
|
||||||
|
{
|
||||||
|
// in C++14 it could be:
|
||||||
|
// for (auto&& [id, object] : objects)
|
||||||
|
for (auto&& id_and_object : doc.Objects())
|
||||||
|
{
|
||||||
|
auto&& id = std::get<0>(id_and_object);
|
||||||
|
auto&& object = std::get<1>(id_and_object);
|
||||||
|
// If an object doesn't have parent
|
||||||
|
if (doc.ConnectionsBySource().count(id) == 0)
|
||||||
|
{
|
||||||
|
const Texture* realTexture = nullptr;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
const auto& element = object->GetElement();
|
||||||
|
const Token& key = element.KeyToken();
|
||||||
|
const char* obtype = key.begin();
|
||||||
|
const size_t length = static_cast<size_t>(key.end() - key.begin());
|
||||||
|
if (strncmp(obtype, "Texture", length) == 0)
|
||||||
|
{
|
||||||
|
const Texture* texture = static_cast<const Texture*>(object->Get());
|
||||||
|
if (texture->Media() && texture->Media()->ContentLength() > 0)
|
||||||
|
{
|
||||||
|
realTexture = texture;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
if (realTexture)
|
||||||
|
{
|
||||||
|
const Video* media = realTexture->Media();
|
||||||
|
unsigned int index = ConvertVideo(*media);
|
||||||
|
textures_converted[*media] = index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void ConvertToAssimpScene(aiScene* out, const Document& doc, bool removeEmptyBones)
|
void ConvertToAssimpScene(aiScene* out, const Document& doc, bool removeEmptyBones)
|
||||||
{
|
{
|
||||||
|
|
|
@ -427,6 +427,10 @@ private:
|
||||||
// copy generated meshes, animations, lights, cameras and textures to the output scene
|
// copy generated meshes, animations, lights, cameras and textures to the output scene
|
||||||
void TransferDataToScene();
|
void TransferDataToScene();
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// FBX file could have embedded textures not connected to anything
|
||||||
|
void ConvertOrphantEmbeddedTextures();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// 0: not assigned yet, others: index is value - 1
|
// 0: not assigned yet, others: index is value - 1
|
||||||
unsigned int defaultMaterialIndex;
|
unsigned int defaultMaterialIndex;
|
||||||
|
@ -438,21 +442,21 @@ private:
|
||||||
std::vector<aiCamera*> cameras;
|
std::vector<aiCamera*> cameras;
|
||||||
std::vector<aiTexture*> textures;
|
std::vector<aiTexture*> textures;
|
||||||
|
|
||||||
using MaterialMap = std::map<const Material*, unsigned int>;
|
using MaterialMap = std::fbx_unordered_map<const Material*, unsigned int>;
|
||||||
MaterialMap materials_converted;
|
MaterialMap materials_converted;
|
||||||
|
|
||||||
using VideoMap = std::map<const Video*, unsigned int>;
|
using VideoMap = std::fbx_unordered_map<const Video, unsigned int>;
|
||||||
VideoMap textures_converted;
|
VideoMap textures_converted;
|
||||||
|
|
||||||
using MeshMap = std::map<const Geometry*, std::vector<unsigned int> >;
|
using MeshMap = std::fbx_unordered_map<const Geometry*, std::vector<unsigned int> >;
|
||||||
MeshMap meshes_converted;
|
MeshMap meshes_converted;
|
||||||
|
|
||||||
// fixed node name -> which trafo chain components have animations?
|
// fixed node name -> which trafo chain components have animations?
|
||||||
using NodeAnimBitMap = std::map<std::string, unsigned int> ;
|
using NodeAnimBitMap = std::fbx_unordered_map<std::string, unsigned int> ;
|
||||||
NodeAnimBitMap node_anim_chain_bits;
|
NodeAnimBitMap node_anim_chain_bits;
|
||||||
|
|
||||||
// number of nodes with the same name
|
// number of nodes with the same name
|
||||||
using NodeNameCache = std::unordered_map<std::string, unsigned int>;
|
using NodeNameCache = std::fbx_unordered_map<std::string, unsigned int>;
|
||||||
NodeNameCache mNodeNames;
|
NodeNameCache mNodeNames;
|
||||||
|
|
||||||
// Deformer name is not the same as a bone name - it does contain the bone name though :)
|
// Deformer name is not the same as a bone name - it does contain the bone name though :)
|
||||||
|
|
|
@ -637,6 +637,15 @@ public:
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool operator==(const Video& other) const
|
||||||
|
{
|
||||||
|
return (
|
||||||
|
type == other.type
|
||||||
|
&& relativeFileName == other.relativeFileName
|
||||||
|
&& fileName == other.fileName
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string type;
|
std::string type;
|
||||||
std::string relativeFileName;
|
std::string relativeFileName;
|
||||||
|
@ -1005,10 +1014,10 @@ public:
|
||||||
// during their entire lifetime (Document). FBX files have
|
// during their entire lifetime (Document). FBX files have
|
||||||
// up to many thousands of objects (most of which we never use),
|
// up to many thousands of objects (most of which we never use),
|
||||||
// so the memory overhead for them should be kept at a minimum.
|
// so the memory overhead for them should be kept at a minimum.
|
||||||
typedef std::map<uint64_t, LazyObject*> ObjectMap;
|
typedef std::fbx_unordered_map<uint64_t, LazyObject*> ObjectMap;
|
||||||
typedef std::fbx_unordered_map<std::string, std::shared_ptr<const PropertyTable> > PropertyTemplateMap;
|
typedef std::fbx_unordered_map<std::string, std::shared_ptr<const PropertyTable> > PropertyTemplateMap;
|
||||||
|
|
||||||
typedef std::multimap<uint64_t, const Connection*> ConnectionMap;
|
typedef std::fbx_unordered_multimap<uint64_t, const Connection*> ConnectionMap;
|
||||||
|
|
||||||
/** DOM class for global document settings, a single instance per document can
|
/** DOM class for global document settings, a single instance per document can
|
||||||
* be accessed via Document.Globals(). */
|
* be accessed via Document.Globals(). */
|
||||||
|
@ -1177,4 +1186,25 @@ private:
|
||||||
} // Namespace FBX
|
} // Namespace FBX
|
||||||
} // Namespace Assimp
|
} // Namespace Assimp
|
||||||
|
|
||||||
|
namespace std
|
||||||
|
{
|
||||||
|
template <>
|
||||||
|
struct hash<const Assimp::FBX::Video>
|
||||||
|
{
|
||||||
|
std::size_t operator()(const Assimp::FBX::Video& video) const
|
||||||
|
{
|
||||||
|
using std::size_t;
|
||||||
|
using std::hash;
|
||||||
|
using std::string;
|
||||||
|
|
||||||
|
size_t res = 17;
|
||||||
|
res = res * 31 + hash<string>()(video.Name());
|
||||||
|
res = res * 31 + hash<string>()(video.RelativeFilename());
|
||||||
|
res = res * 31 + hash<string>()(video.Type());
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
#endif // INCLUDED_AI_FBX_DOCUMENT_H
|
#endif // INCLUDED_AI_FBX_DOCUMENT_H
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -263,3 +263,23 @@ TEST_F(utFBXImporterExporter, fbxTokenizeTestTest) {
|
||||||
//const aiScene* scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/FBX/transparentTest2.fbx", aiProcess_ValidateDataStructure);
|
//const aiScene* scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/FBX/transparentTest2.fbx", aiProcess_ValidateDataStructure);
|
||||||
//EXPECT_NE(nullptr, scene);
|
//EXPECT_NE(nullptr, scene);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(utFBXImporterExporter, importOrphantEmbeddedTextureTest) {
|
||||||
|
// see https://github.com/assimp/assimp/issues/1957
|
||||||
|
Assimp::Importer importer;
|
||||||
|
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/FBX/box_orphant_embedded_texture.fbx", aiProcess_ValidateDataStructure);
|
||||||
|
EXPECT_NE(nullptr, scene);
|
||||||
|
|
||||||
|
EXPECT_EQ(1u, scene->mNumMaterials);
|
||||||
|
aiMaterial *mat = scene->mMaterials[0];
|
||||||
|
ASSERT_NE(nullptr, mat);
|
||||||
|
|
||||||
|
aiString path;
|
||||||
|
aiTextureMapMode modes[2];
|
||||||
|
ASSERT_EQ(aiReturn_SUCCESS, mat->GetTexture(aiTextureType_DIFFUSE, 0, &path, nullptr, nullptr, nullptr, nullptr, modes));
|
||||||
|
ASSERT_STREQ(path.C_Str(), "..\\Primitives\\GridGrey.tga");
|
||||||
|
|
||||||
|
ASSERT_EQ(1u, scene->mNumTextures);
|
||||||
|
ASSERT_TRUE(scene->mTextures[0]->pcData);
|
||||||
|
ASSERT_EQ(9026u, scene->mTextures[0]->mWidth) << "FBX ASCII base64 compression used for a texture.";
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue