Merge branch 'master' into allow_empty_slots_in_mTextureCoords

pull/5636/head
Kim Kulling 2024-07-02 21:55:13 +02:00 committed by GitHub
commit b078bbdf66
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 55 additions and 42 deletions

View File

@ -1868,33 +1868,26 @@ void FBXExporter::WriteObjects ()
// one sticky point is that the number of vertices may not match, // one sticky point is that the number of vertices may not match,
// because assimp splits vertices by normal, uv, etc. // because assimp splits vertices by normal, uv, etc.
// functor for aiNode sorting
struct SortNodeByName
{
bool operator()(const aiNode *lhs, const aiNode *rhs) const
{
return strcmp(lhs->mName.C_Str(), rhs->mName.C_Str()) < 0;
}
};
// first we should mark the skeleton for each mesh. // first we should mark the skeleton for each mesh.
// the skeleton must include not only the aiBones, // the skeleton must include not only the aiBones,
// but also all their parent nodes. // but also all their parent nodes.
// anything that affects the position of any bone node must be included. // anything that affects the position of any bone node must be included.
// Use SorNodeByName to make sure the exported result will be the same across all systems
// Otherwise the aiNodes of the skeleton would be sorted based on the pointer address, which isn't consistent // note that we want to preserve input order as much as possible here.
std::vector<std::set<const aiNode*, SortNodeByName>> skeleton_by_mesh(mScene->mNumMeshes); // previously, sorting by name lead to consistent output across systems, but was not
// suitable for downstream consumption by some applications.
std::vector<std::vector<const aiNode*>> skeleton_by_mesh(mScene->mNumMeshes);
// at the same time we can build a list of all the skeleton nodes, // at the same time we can build a list of all the skeleton nodes,
// which will be used later to mark them as type "limbNode". // which will be used later to mark them as type "limbNode".
std::unordered_set<const aiNode*> limbnodes; std::unordered_set<const aiNode*> limbnodes;
//actual bone nodes in fbx, without parenting-up //actual bone nodes in fbx, without parenting-up
std::unordered_set<std::string> setAllBoneNamesInScene; std::vector<std::string> allBoneNames;
for(unsigned int m = 0; m < mScene->mNumMeshes; ++ m) for(unsigned int m = 0; m < mScene->mNumMeshes; ++ m) {
{
aiMesh* pMesh = mScene->mMeshes[m]; aiMesh* pMesh = mScene->mMeshes[m];
for(unsigned int b = 0; b < pMesh->mNumBones; ++ b) for(unsigned int b = 0; b < pMesh->mNumBones; ++ b)
setAllBoneNamesInScene.insert(pMesh->mBones[b]->mName.data); allBoneNames.push_back(pMesh->mBones[b]->mName.data);
} }
aiMatrix4x4 mxTransIdentity; aiMatrix4x4 mxTransIdentity;
@ -1902,7 +1895,7 @@ void FBXExporter::WriteObjects ()
std::map<std::string,aiNode*> node_by_bone; std::map<std::string,aiNode*> node_by_bone;
for (size_t mi = 0; mi < mScene->mNumMeshes; ++mi) { for (size_t mi = 0; mi < mScene->mNumMeshes; ++mi) {
const aiMesh* m = mScene->mMeshes[mi]; const aiMesh* m = mScene->mMeshes[mi];
std::set<const aiNode*, SortNodeByName> skeleton; std::vector<const aiNode*> skeleton;
for (size_t bi =0; bi < m->mNumBones; ++bi) { for (size_t bi =0; bi < m->mNumBones; ++bi) {
const aiBone* b = m->mBones[bi]; const aiBone* b = m->mBones[bi];
const std::string name(b->mName.C_Str()); const std::string name(b->mName.C_Str());
@ -1921,7 +1914,7 @@ void FBXExporter::WriteObjects ()
node_by_bone[name] = n; node_by_bone[name] = n;
limbnodes.insert(n); limbnodes.insert(n);
} }
skeleton.insert(n); skeleton.push_back(n);
// mark all parent nodes as skeleton as well, // mark all parent nodes as skeleton as well,
// up until we find the root node, // up until we find the root node,
// or else the node containing the mesh, // or else the node containing the mesh,
@ -1932,7 +1925,7 @@ void FBXExporter::WriteObjects ()
parent = parent->mParent parent = parent->mParent
) { ) {
// if we've already done this node we can skip it all // if we've already done this node we can skip it all
if (skeleton.count(parent)) { if (std::find(skeleton.begin(), skeleton.end(), parent) != skeleton.end()) {
break; break;
} }
// ignore fbx transform nodes as these will be collapsed later // ignore fbx transform nodes as these will be collapsed later
@ -1942,7 +1935,7 @@ void FBXExporter::WriteObjects ()
continue; continue;
} }
//not a bone in scene && no effect in transform //not a bone in scene && no effect in transform
if(setAllBoneNamesInScene.find(node_name)==setAllBoneNamesInScene.end() if (std::find(allBoneNames.begin(), allBoneNames.end(), node_name) == allBoneNames.end()
&& parent->mTransformation == mxTransIdentity) { && parent->mTransformation == mxTransIdentity) {
continue; continue;
} }
@ -2027,7 +2020,7 @@ void FBXExporter::WriteObjects ()
aiMatrix4x4 mesh_xform = get_world_transform(mesh_node, mScene); aiMatrix4x4 mesh_xform = get_world_transform(mesh_node, mScene);
// now make a subdeformer for each bone in the skeleton // now make a subdeformer for each bone in the skeleton
const std::set<const aiNode*, SortNodeByName> skeleton= skeleton_by_mesh[mi]; const auto & skeleton= skeleton_by_mesh[mi];
for (const aiNode* bone_node : skeleton) { for (const aiNode* bone_node : skeleton) {
// if there's a bone for this node, find it // if there's a bone for this node, find it
const aiBone* b = nullptr; const aiBone* b = nullptr;

View File

@ -193,7 +193,7 @@ void ObjFileImporter::CreateDataFromImport(const ObjFile::Model *pModel, aiScene
pScene->mRootNode->mChildren = new aiNode *[childCount]; pScene->mRootNode->mChildren = new aiNode *[childCount];
// Create nodes for the whole scene // Create nodes for the whole scene
std::vector<aiMesh *> MeshArray; std::vector<std::unique_ptr<aiMesh>> MeshArray;
MeshArray.reserve(meshCount); MeshArray.reserve(meshCount);
for (size_t index = 0; index < pModel->mObjects.size(); ++index) { for (size_t index = 0; index < pModel->mObjects.size(); ++index) {
createNodes(pModel, pModel->mObjects[index], pScene->mRootNode, pScene, MeshArray); createNodes(pModel, pModel->mObjects[index], pScene->mRootNode, pScene, MeshArray);
@ -205,7 +205,7 @@ void ObjFileImporter::CreateDataFromImport(const ObjFile::Model *pModel, aiScene
if (pScene->mNumMeshes > 0) { if (pScene->mNumMeshes > 0) {
pScene->mMeshes = new aiMesh *[MeshArray.size()]; pScene->mMeshes = new aiMesh *[MeshArray.size()];
for (size_t index = 0; index < MeshArray.size(); ++index) { for (size_t index = 0; index < MeshArray.size(); ++index) {
pScene->mMeshes[index] = MeshArray[index]; pScene->mMeshes[index] = MeshArray[index].release();
} }
} }
@ -257,7 +257,7 @@ void ObjFileImporter::CreateDataFromImport(const ObjFile::Model *pModel, aiScene
// Creates all nodes of the model // Creates all nodes of the model
aiNode *ObjFileImporter::createNodes(const ObjFile::Model *pModel, const ObjFile::Object *pObject, aiNode *ObjFileImporter::createNodes(const ObjFile::Model *pModel, const ObjFile::Object *pObject,
aiNode *pParent, aiScene *pScene, aiNode *pParent, aiScene *pScene,
std::vector<aiMesh *> &MeshArray) { std::vector<std::unique_ptr<aiMesh>> &MeshArray) {
ai_assert(nullptr != pModel); ai_assert(nullptr != pModel);
if (nullptr == pObject) { if (nullptr == pObject) {
return nullptr; return nullptr;
@ -275,12 +275,10 @@ aiNode *ObjFileImporter::createNodes(const ObjFile::Model *pModel, const ObjFile
for (size_t i = 0; i < pObject->m_Meshes.size(); ++i) { for (size_t i = 0; i < pObject->m_Meshes.size(); ++i) {
unsigned int meshId = pObject->m_Meshes[i]; unsigned int meshId = pObject->m_Meshes[i];
aiMesh *pMesh = createTopology(pModel, pObject, meshId); std::unique_ptr<aiMesh> pMesh = createTopology(pModel, pObject, meshId);
if (pMesh != nullptr) { if (pMesh != nullptr) {
if (pMesh->mNumFaces > 0) { if (pMesh->mNumFaces > 0) {
MeshArray.push_back(pMesh); MeshArray.push_back(std::move(pMesh));
} else {
delete pMesh;
} }
} }
} }
@ -312,7 +310,7 @@ aiNode *ObjFileImporter::createNodes(const ObjFile::Model *pModel, const ObjFile
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Create topology data // Create topology data
aiMesh *ObjFileImporter::createTopology(const ObjFile::Model *pModel, const ObjFile::Object *pData, unsigned int meshIndex) { std::unique_ptr<aiMesh> ObjFileImporter::createTopology(const ObjFile::Model *pModel, const ObjFile::Object *pData, unsigned int meshIndex) {
// Checking preconditions // Checking preconditions
ai_assert(nullptr != pModel); ai_assert(nullptr != pModel);
@ -394,7 +392,7 @@ aiMesh *ObjFileImporter::createTopology(const ObjFile::Model *pModel, const ObjF
// Create mesh vertices // Create mesh vertices
createVertexArray(pModel, pData, meshIndex, pMesh.get(), uiIdxCount); createVertexArray(pModel, pData, meshIndex, pMesh.get(), uiIdxCount);
return pMesh.release(); return pMesh;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -44,6 +44,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/BaseImporter.h> #include <assimp/BaseImporter.h>
#include <assimp/material.h> #include <assimp/material.h>
#include <memory>
#include <vector> #include <vector>
struct aiMesh; struct aiMesh;
@ -84,10 +85,10 @@ protected:
//! \brief Creates all nodes stored in imported content. //! \brief Creates all nodes stored in imported content.
aiNode *createNodes(const ObjFile::Model *pModel, const ObjFile::Object *pData, aiNode *createNodes(const ObjFile::Model *pModel, const ObjFile::Object *pData,
aiNode *pParent, aiScene *pScene, std::vector<aiMesh *> &MeshArray); aiNode *pParent, aiScene *pScene, std::vector<std::unique_ptr<aiMesh>> &MeshArray);
//! \brief Creates topology data like faces and meshes for the geometry. //! \brief Creates topology data like faces and meshes for the geometry.
aiMesh *createTopology(const ObjFile::Model *pModel, const ObjFile::Object *pData, std::unique_ptr<aiMesh> createTopology(const ObjFile::Model *pModel, const ObjFile::Object *pData,
unsigned int uiMeshIndex); unsigned int uiMeshIndex);
//! \brief Creates vertices from model. //! \brief Creates vertices from model.

View File

@ -53,7 +53,8 @@ namespace Assimp {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer // Constructor to be privately used by Importer
LimitBoneWeightsProcess::LimitBoneWeightsProcess() : mMaxWeights(AI_LMW_MAX_WEIGHTS) { LimitBoneWeightsProcess::LimitBoneWeightsProcess() :
mMaxWeights(AI_LMW_MAX_WEIGHTS), mRemoveEmptyBones(true) {
// empty // empty
} }

View File

@ -13,10 +13,14 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <time.h> #include <time.h>
#if defined(_MSC_VER)
/* For Visual Studio only, NOT MinGW (GCC) -- ThatOSDev */
#pragma warning( disable : 4706 )
#endif
#if defined(_WIN32) || defined(__WIN32__) || defined(_MSC_VER) || \ #if defined(_WIN32) || defined(__WIN32__) || defined(_MSC_VER) || \
defined(__MINGW32__) defined(__MINGW32__)
/* Win32, DOS, MSVC, MSVS */ /* Win32, DOS, MSVC, MSVS, MinGW(GCC for windows) */
#pragma warning( disable : 4706 )
#include <direct.h> #include <direct.h>
#define STRCLONE(STR) ((STR) ? _strdup(STR) : NULL) #define STRCLONE(STR) ((STR) ? _strdup(STR) : NULL)

View File

@ -113,19 +113,19 @@ struct aiMetadata;
*/ */
// ------------------------------------------------------------------------------- // -------------------------------------------------------------------------------
inline aiMetadataType GetAiType(bool) { inline aiMetadataType GetAiType(const bool &) {
return AI_BOOL; return AI_BOOL;
} }
inline aiMetadataType GetAiType(int32_t) { inline aiMetadataType GetAiType(int32_t) {
return AI_INT32; return AI_INT32;
} }
inline aiMetadataType GetAiType(uint64_t) { inline aiMetadataType GetAiType(const uint64_t &) {
return AI_UINT64; return AI_UINT64;
} }
inline aiMetadataType GetAiType(float) { inline aiMetadataType GetAiType(const float &) {
return AI_FLOAT; return AI_FLOAT;
} }
inline aiMetadataType GetAiType(double) { inline aiMetadataType GetAiType(const double &) {
return AI_DOUBLE; return AI_DOUBLE;
} }
inline aiMetadataType GetAiType(const aiString &) { inline aiMetadataType GetAiType(const aiString &) {
@ -137,10 +137,10 @@ inline aiMetadataType GetAiType(const aiVector3D &) {
inline aiMetadataType GetAiType(const aiMetadata &) { inline aiMetadataType GetAiType(const aiMetadata &) {
return AI_AIMETADATA; return AI_AIMETADATA;
} }
inline aiMetadataType GetAiType(int64_t) { inline aiMetadataType GetAiType(const int64_t &) {
return AI_INT64; return AI_INT64;
} }
inline aiMetadataType GetAiType(uint32_t) { inline aiMetadataType GetAiType(const uint32_t &) {
return AI_UINT32; return AI_UINT32;
} }

View File

@ -242,6 +242,22 @@ TEST_F( utMetadata, copy_test ) {
EXPECT_EQ( i32v, v ); EXPECT_EQ( i32v, v );
} }
// uint32_t test
{
uint32_t v = 0;
bool ok = copy.Get("uint32_t", v);
EXPECT_TRUE(ok);
EXPECT_EQ( ui32, v );
}
// int64_t test
{
int64_t v = -1;
bool ok = copy.Get("int64_t", v);
EXPECT_TRUE(ok);
EXPECT_EQ( i64, v );
}
// uint64_t test // uint64_t test
{ {
uint64_t v = 255; uint64_t v = 255;
@ -264,14 +280,14 @@ TEST_F( utMetadata, copy_test ) {
EXPECT_EQ( dv, v ); EXPECT_EQ( dv, v );
} }
// bool test // string test
{ {
aiString v; aiString v;
EXPECT_TRUE( copy.Get( "aiString", v ) ); EXPECT_TRUE( copy.Get( "aiString", v ) );
EXPECT_EQ( strVal, v ); EXPECT_EQ( strVal, v );
} }
// bool test // vector test
{ {
aiVector3D v; aiVector3D v;
EXPECT_TRUE( copy.Get( "aiVector3D", v ) ); EXPECT_TRUE( copy.Get( "aiVector3D", v ) );