Merge pull request #2741 from muxanickms/fbx_orphant_embedded_textures
FBX orphan embedded textures fixpull/2728/head^2
commit
ef06cabe6c
|
@ -47,6 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#define INCLUDED_AI_FBX_COMPILECONFIG_H
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
//
|
||||
#if _MSC_VER > 1500 || (defined __GNUC___)
|
||||
|
@ -54,16 +55,23 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
# else
|
||||
# define fbx_unordered_map map
|
||||
# define fbx_unordered_multimap multimap
|
||||
# define fbx_unordered_set set
|
||||
# define fbx_unordered_multiset multiset
|
||||
#endif
|
||||
|
||||
#ifdef ASSIMP_FBX_USE_UNORDERED_MULTIMAP
|
||||
# include <unordered_map>
|
||||
# include <unordered_set>
|
||||
# if _MSC_VER > 1600
|
||||
# define fbx_unordered_map unordered_map
|
||||
# define fbx_unordered_multimap unordered_multimap
|
||||
# define fbx_unordered_set unordered_set
|
||||
# define fbx_unordered_multiset unordered_multiset
|
||||
# else
|
||||
# define fbx_unordered_map tr1::unordered_map
|
||||
# define fbx_unordered_multimap tr1::unordered_multimap
|
||||
# define fbx_unordered_set tr1::unordered_set
|
||||
# define fbx_unordered_multiset tr1::unordered_multiset
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
|
|
@ -97,6 +97,14 @@ namespace Assimp {
|
|||
// populate the node_anim_chain_bits map, which is needed
|
||||
// to determine which nodes need to be generated.
|
||||
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();
|
||||
|
||||
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)
|
||||
unsigned int index;
|
||||
|
||||
VideoMap::const_iterator it = textures_converted.find(media);
|
||||
VideoMap::const_iterator it = textures_converted.find(*media);
|
||||
if (it != textures_converted.end()) {
|
||||
index = (*it).second;
|
||||
textureReady = true;
|
||||
|
@ -1782,7 +1790,7 @@ namespace Assimp {
|
|||
else {
|
||||
if (media->ContentLength() > 0) {
|
||||
index = ConvertVideo(*media);
|
||||
textures_converted[media] = index;
|
||||
textures_converted[*media] = index;
|
||||
textureReady = true;
|
||||
}
|
||||
}
|
||||
|
@ -2306,13 +2314,13 @@ void FBXConverter::SetShadingPropertiesRaw(aiMaterial* out_mat, const PropertyTa
|
|||
if (media != nullptr && media->ContentLength() > 0) {
|
||||
unsigned int index;
|
||||
|
||||
VideoMap::const_iterator it = textures_converted.find(media);
|
||||
VideoMap::const_iterator it = textures_converted.find(*media);
|
||||
if (it != textures_converted.end()) {
|
||||
index = (*it).second;
|
||||
}
|
||||
else {
|
||||
index = ConvertVideo(*media);
|
||||
textures_converted[media] = index;
|
||||
textures_converted[*media] = index;
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
|
|
|
@ -427,6 +427,10 @@ private:
|
|||
// copy generated meshes, animations, lights, cameras and textures to the output scene
|
||||
void TransferDataToScene();
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// FBX file could have embedded textures not connected to anything
|
||||
void ConvertOrphantEmbeddedTextures();
|
||||
|
||||
private:
|
||||
// 0: not assigned yet, others: index is value - 1
|
||||
unsigned int defaultMaterialIndex;
|
||||
|
@ -438,21 +442,21 @@ private:
|
|||
std::vector<aiCamera*> cameras;
|
||||
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;
|
||||
|
||||
using VideoMap = std::map<const Video*, unsigned int>;
|
||||
using VideoMap = std::fbx_unordered_map<const Video, unsigned int>;
|
||||
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;
|
||||
|
||||
// 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;
|
||||
|
||||
// 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;
|
||||
|
||||
// Deformer name is not the same as a bone name - it does contain the bone name though :)
|
||||
|
|
|
@ -637,6 +637,20 @@ public:
|
|||
return ptr;
|
||||
}
|
||||
|
||||
bool operator==(const Video& other) const
|
||||
{
|
||||
return (
|
||||
type == other.type
|
||||
&& relativeFileName == other.relativeFileName
|
||||
&& fileName == other.fileName
|
||||
);
|
||||
}
|
||||
|
||||
bool operator<(const Video& other) const
|
||||
{
|
||||
return std::tie(type, relativeFileName, fileName) < std::tie(other.type, other.relativeFileName, other.fileName);
|
||||
}
|
||||
|
||||
private:
|
||||
std::string type;
|
||||
std::string relativeFileName;
|
||||
|
@ -1005,10 +1019,10 @@ public:
|
|||
// during their entire lifetime (Document). FBX files have
|
||||
// up to many thousands of objects (most of which we never use),
|
||||
// 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::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
|
||||
* be accessed via Document.Globals(). */
|
||||
|
@ -1177,4 +1191,25 @@ private:
|
|||
} // Namespace FBX
|
||||
} // 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
|
||||
|
|
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);
|
||||
//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