Kim Kulling преди 3 години
родител
ревизия
e5747dad9b

+ 10 - 6
code/AssetLib/FBX/FBXConverter.cpp

@@ -1435,6 +1435,16 @@ unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, co
     return static_cast<unsigned int>(mMeshes.size() - 1);
 }
 
+void ConvertWeightsToSkeleton(const MeshGeometry &geo, const aiMatrix4x4 &absolute_transform, aiNode *parent, unsigned int materialIndex,
+        std::vector<unsigned int> *outputVertStartIndices) {
+    ai_assert(geo.DeformerSkin() != nullptr);
+
+    const Skin &sk = *geo.DeformerSkin();
+    for (auto &cluster : sk.Clusters()) {
+        cluster->Transform();
+    }
+}
+
 void FBXConverter::ConvertWeights(aiMesh *out, const MeshGeometry &geo,
         const aiMatrix4x4 &absolute_transform,
         aiNode *parent, unsigned int materialIndex,
@@ -1529,12 +1539,6 @@ void FBXConverter::ConvertWeights(aiMesh *out, const MeshGeometry &geo,
     }
 }
 
-const aiNode *GetNodeByName(aiNode *current_node) {
-    aiNode *iter = current_node;
-    //printf("Child count: %d", iter->mNumChildren);
-    return iter;
-}
-
 void FBXConverter::ConvertCluster(std::vector<aiBone *> &local_mesh_bones, const Cluster *cl,
         std::vector<size_t> &out_indices, std::vector<size_t> &index_out_indices,
         std::vector<size_t> &count_out_indices, const aiMatrix4x4 &absolute_transform,

+ 6 - 0
code/AssetLib/FBX/FBXImportSettings.h

@@ -60,6 +60,7 @@ struct ImportSettings {
             readLights(true),
             readAnimations(true),
             readWeights(true),
+            useSkeleton(false),
             preservePivots(true),
             optimizeEmptyAnimationCurves(true),
             useLegacyEmbeddedTextureNaming(false),
@@ -112,6 +113,11 @@ struct ImportSettings {
      *  Default value is true. */
     bool readWeights;
 
+    /** will convert all animation data into a skeleton (experimental)
+     *  Default value is false.
+     */
+    bool useSkeleton;
+
     /** preserve transformation pivots and offsets. Since these can
      *  not directly be represented in assimp, additional dummy
      *  nodes will be generated. Note that settings this to false

+ 22 - 25
code/AssetLib/FBX/FBXImporter.cpp

@@ -90,12 +90,9 @@ static const aiImporterDesc desc = {
 
 // ------------------------------------------------------------------------------------------------
 // Constructor to be privately used by #Importer
-FBXImporter::FBXImporter() {
-}
-
-// ------------------------------------------------------------------------------------------------
-// Destructor, private as well
-FBXImporter::~FBXImporter() {
+FBXImporter::FBXImporter() :
+        mSettings() {
+    // empty
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -115,20 +112,21 @@ const aiImporterDesc *FBXImporter::GetInfo() const {
 // ------------------------------------------------------------------------------------------------
 // Setup configuration properties for the loader
 void FBXImporter::SetupProperties(const Importer *pImp) {
-	settings.readAllLayers = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_GEOMETRY_LAYERS, true);
-	settings.readAllMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_MATERIALS, false);
-	settings.readMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_MATERIALS, true);
-	settings.readTextures = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_TEXTURES, true);
-	settings.readCameras = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_CAMERAS, true);
-	settings.readLights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_LIGHTS, true);
-	settings.readAnimations = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ANIMATIONS, true);
-	settings.readWeights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_WEIGHTS, true);
-	settings.strictMode = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_STRICT_MODE, false);
-	settings.preservePivots = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, true);
-	settings.optimizeEmptyAnimationCurves = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES, true);
-	settings.useLegacyEmbeddedTextureNaming = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING, false);
-	settings.removeEmptyBones = pImp->GetPropertyBool(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, true);
-	settings.convertToMeters = pImp->GetPropertyBool(AI_CONFIG_FBX_CONVERT_TO_M, false);
+    mSettings.readAllLayers = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_GEOMETRY_LAYERS, true);
+    mSettings.readAllMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_MATERIALS, false);
+    mSettings.readMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_MATERIALS, true);
+    mSettings.readTextures = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_TEXTURES, true);
+    mSettings.readCameras = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_CAMERAS, true);
+    mSettings.readLights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_LIGHTS, true);
+    mSettings.readAnimations = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ANIMATIONS, true);
+    mSettings.readWeights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_WEIGHTS, true);
+    mSettings.strictMode = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_STRICT_MODE, false);
+    mSettings.preservePivots = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, true);
+    mSettings.optimizeEmptyAnimationCurves = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES, true);
+    mSettings.useLegacyEmbeddedTextureNaming = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING, false);
+    mSettings.removeEmptyBones = pImp->GetPropertyBool(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, true);
+    mSettings.convertToMeters = pImp->GetPropertyBool(AI_CONFIG_FBX_CONVERT_TO_M, false);
+    mSettings.useSkeleton = pImp->GetPropertyBool(AI_CONFIG_FBX_USE_SKELETON_BONE_CONTAINER, false);
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -155,7 +153,7 @@ void FBXImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
 	contents[contents.size() - 1] = 0;
 	const char *const begin = &*contents.begin();
 
-	// broadphase tokenizing pass in which we identify the core
+	// broad-phase tokenized pass in which we identify the core
 	// syntax elements of FBX (brackets, commas, key:value mappings)
 	TokenList tokens;
 	try {
@@ -173,15 +171,14 @@ void FBXImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
 		Parser parser(tokens, is_binary);
 
 		// take the raw parse-tree and convert it to a FBX DOM
-		Document doc(parser, settings);
+		Document doc(parser, mSettings);
 
 		// convert the FBX DOM to aiScene
-		ConvertToAssimpScene(pScene, doc, settings.removeEmptyBones);
+		ConvertToAssimpScene(pScene, doc, mSettings.removeEmptyBones);
 
 		// size relative to cm
 		float size_relative_to_cm = doc.GlobalSettings().UnitScaleFactor();
-        if (size_relative_to_cm == 0.0)
-        {
+        if (size_relative_to_cm == 0.0) {
 			// BaseImporter later asserts that fileScale is non-zero.
 			ThrowException("The UnitScaleFactor must be non-zero");
         }

+ 7 - 6
code/AssetLib/FBX/FBXImporter.h

@@ -69,13 +69,14 @@ typedef class basic_formatter<char, std::char_traits<char>, std::allocator<char>
 // -------------------------------------------------------------------------------------------
 class FBXImporter : public BaseImporter, public LogFunctions<FBXImporter> {
 public:
+    /// @brief The class constructor.
     FBXImporter();
-    ~FBXImporter() override;
 
-    // --------------------
-    bool CanRead(const std::string &pFile,
-            IOSystem *pIOHandler,
-            bool checkSig) const override;
+    ///	@brief The class destructor, default implementation.
+    ~FBXImporter() override = default;
+
+    /// @brief Will check the file for readability.
+    bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const override;
 
 protected:
     // --------------------
@@ -90,7 +91,7 @@ protected:
             IOSystem *pIOHandler) override;
 
 private:
-    FBX::ImportSettings settings;
+    FBX::ImportSettings mSettings;
 }; // !class FBXImporter
 
 } // end of namespace Assimp

+ 8 - 6
code/Common/SkeletonMeshBuilder.cpp

@@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
 
 Copyright (c) 2006-2022, assimp team
 
-
 All rights reserved.
 
 Redistribution and use of this software in source and binary forms,
@@ -97,13 +96,14 @@ void SkeletonMeshBuilder::CreateGeometry(const aiNode *pNode) {
             const aiMatrix4x4 &childTransform = pNode->mChildren[a]->mTransformation;
             aiVector3D childpos(childTransform.a4, childTransform.b4, childTransform.c4);
             ai_real distanceToChild = childpos.Length();
-            if (distanceToChild < 0.0001)
+            if (distanceToChild < ai_epsilon) {
                 continue;
+            }
             aiVector3D up = aiVector3D(childpos).Normalize();
-
             aiVector3D orth(1.0, 0.0, 0.0);
-            if (std::fabs(orth * up) > 0.99)
+            if (std::fabs(orth * up) > 0.99) {
                 orth.Set(0.0, 1.0, 0.0);
+            }
 
             aiVector3D front = (up ^ orth).Normalize();
             aiVector3D side = (front ^ up).Normalize();
@@ -183,8 +183,9 @@ void SkeletonMeshBuilder::CreateGeometry(const aiNode *pNode) {
         // add all the vertices to the bone's influences
         bone->mNumWeights = numVertices;
         bone->mWeights = new aiVertexWeight[numVertices];
-        for (unsigned int a = 0; a < numVertices; a++)
+        for (unsigned int a = 0; a < numVertices; ++a) {
             bone->mWeights[a] = aiVertexWeight(vertexStartIndex + a, 1.0);
+        }
 
         // HACK: (thom) transform all vertices to the bone's local space. Should be done before adding
         // them to the array, but I'm tired now and I'm annoyed.
@@ -194,8 +195,9 @@ void SkeletonMeshBuilder::CreateGeometry(const aiNode *pNode) {
     }
 
     // and finally recurse into the children list
-    for (unsigned int a = 0; a < pNode->mNumChildren; a++)
+    for (unsigned int a = 0; a < pNode->mNumChildren; ++a) {
         CreateGeometry(pNode->mChildren[a]);
+    }
 }
 
 // ------------------------------------------------------------------------------------------------

+ 9 - 0
include/assimp/config.h.in

@@ -691,6 +691,15 @@ enum aiComponent
 #define AI_CONFIG_FBX_CONVERT_TO_M \
     "AI_CONFIG_FBX_CONVERT_TO_M"
 
+// ---------------------------------------------------------------------------
+/** @brief  Will enable the skeleton structo to store bone data.
+ *
+ *  This will decouple the bone coupling to the mesh. This feature is
+ *  experimental.
+ */
+#define AI_CONFIG_FBX_USE_SKELETON_BONE_CONTAINER \
+    "AI_CONFIG_FBX_USE_SKELETON_BONE_CONTAINER"
+
 // ---------------------------------------------------------------------------
 /** @brief  Set the vertex animation keyframe to be imported
  *

+ 105 - 25
include/assimp/mesh.h

@@ -120,7 +120,7 @@ extern "C" {
  * primitive are actually present in a mesh. The #aiProcess_SortByPType flag
  * executes a special post-processing algorithm which splits meshes with
  * *different* primitive types mixed up (e.g. lines and triangles) in several
- * 'clean' submeshes. Furthermore there is a configuration option (
+ * 'clean' sub-meshes. Furthermore there is a configuration option (
  * #AI_CONFIG_PP_SBP_REMOVE) to force #aiProcess_SortByPType to remove
  * specific kinds of primitives from the imported scene, completely and forever.
  * In many cases you'll probably want to set this setting to
@@ -269,12 +269,12 @@ struct aiBone {
     unsigned int mNumWeights;
 
 #ifndef ASSIMP_BUILD_NO_ARMATUREPOPULATE_PROCESS
-    // The bone armature node - used for skeleton conversion
-    // you must enable aiProcess_PopulateArmatureData to populate this
+    /// The bone armature node - used for skeleton conversion
+    /// you must enable aiProcess_PopulateArmatureData to populate this
     C_STRUCT aiNode *mArmature;
 
-    // The bone node in the scene - used for skeleton conversion
-    // you must enable aiProcess_PopulateArmatureData to populate this
+    /// The bone node in the scene - used for skeleton conversion
+    /// you must enable aiProcess_PopulateArmatureData to populate this
     C_STRUCT aiNode *mNode;
 
 #endif
@@ -296,7 +296,7 @@ struct aiBone {
 
 #ifdef __cplusplus
 
-    //! Default constructor
+    ///	@brief  Default constructor
     aiBone() AI_NO_EXCEPT
             : mName(),
               mNumWeights(0),
@@ -309,7 +309,7 @@ struct aiBone {
         // empty
     }
 
-    //! Copy constructor
+    /// @brief  Copy constructor
     aiBone(const aiBone &other) :
             mName(other.mName),
             mNumWeights(other.mNumWeights),
@@ -319,14 +319,27 @@ struct aiBone {
 #endif
             mWeights(nullptr),
             mOffsetMatrix(other.mOffsetMatrix) {
-        if (other.mWeights && other.mNumWeights) {
-            mWeights = new aiVertexWeight[mNumWeights];
-            ::memcpy(mWeights, other.mWeights, mNumWeights * sizeof(aiVertexWeight));
+        copyVertexWeights(other);
+    }
+
+    void copyVertexWeights( const aiBone &other ) {
+        if (other.mWeights == nullptr || other.mNumWeights == 0) {
+            mWeights = nullptr;
+            mNumWeights = 0;
+            return;
         }
+
+        mNumWeights = other.mNumWeights;
+        if (mWeights) {
+            delete[] mWeights;
+        }
+
+        mWeights = new aiVertexWeight[mNumWeights];
+        ::memcpy(mWeights, other.mWeights, mNumWeights * sizeof(aiVertexWeight));
     }
 
     //! Assignment operator
-    aiBone &operator=(const aiBone &other) {
+    aiBone &operator = (const aiBone &other) {
         if (this == &other) {
             return *this;
         }
@@ -334,21 +347,13 @@ struct aiBone {
         mName = other.mName;
         mNumWeights = other.mNumWeights;
         mOffsetMatrix = other.mOffsetMatrix;
-
-        if (other.mWeights && other.mNumWeights) {
-            if (mWeights) {
-                delete[] mWeights;
-            }
-
-            mWeights = new aiVertexWeight[mNumWeights];
-            ::memcpy(mWeights, other.mWeights, mNumWeights * sizeof(aiVertexWeight));
-        }
+        copyVertexWeights(other);
 
         return *this;
     }
 
     bool operator==(const aiBone &rhs) const {
-        if (mName != rhs.mName || mNumWeights != rhs.mNumWeights) {
+        if (mName != rhs.mName || mNumWeights != rhs.mNumWeights ) {
             return false;
         }
 
@@ -937,17 +942,92 @@ struct aiMesh {
 #endif // __cplusplus
 };
 
+struct aiSkeletonBone {
+    /// The parent bone index, is -1 one if this bone represents the root bone.
+    int mParent;
+
+#ifndef ASSIMP_BUILD_NO_ARMATUREPOPULATE_PROCESS
+    /// The bone armature node - used for skeleton conversion
+    /// you must enable aiProcess_PopulateArmatureData to populate this
+    C_STRUCT aiNode *mArmature;
+
+    /// The bone node in the scene - used for skeleton conversion
+    /// you must enable aiProcess_PopulateArmatureData to populate this
+    C_STRUCT aiNode *mNode;
+
+#endif
+    /// @brief The number of weights
+    unsigned int mNumnWeights;
+
+    /// The influence weights of this bone, by vertex index.
+    C_STRUCT aiVertexWeight *mWeights;
+
+    /** Matrix that transforms from bone space to mesh space in bind pose.
+     *
+     * This matrix describes the position of the mesh
+     * in the local space of this bone when the skeleton was bound.
+     * Thus it can be used directly to determine a desired vertex position,
+     * given the world-space transform of the bone when animated,
+     * and the position of the vertex in mesh space.
+     *
+     * It is sometimes called an inverse-bind matrix,
+     * or inverse bind pose matrix.
+     */
+    C_STRUCT aiMatrix4x4 mOffsetMatrix;
+
+    /// Matrix that transforms the locale bone in bind pose.
+    C_STRUCT aiMatrix4x4 mLocalMatrix;
+
+#ifdef __cplusplus
+    aiSkeletonBone() :
+            mParent(-1),
+            mArmature(nullptr),
+            mNode(nullptr),
+            mNumnWeights(0),
+            mWeights(nullptr),
+            mOffsetMatrix(),
+            mLocalMatrix() {
+        // empty
+    }
+
+    ~aiSkeletonBone() {
+        delete[] mWeights;
+        mWeights = nullptr;
+    }
+#endif // __cplusplus
+};
+/**
+ *  @brief  
+ */
 struct aiSkeleton {
+    /**
+     *
+     */
     C_STRUCT aiString mName;
-    unsigned int mNumWeights;
-    C_STRUCT aiVertexWeight *mWeights;
+
+    /**
+     *
+     */
+    unsigned int mNumBones;
+
+    /**
+     *
+     */
+    C_STRUCT aiSkeletonBone *mBones;
 
 #ifdef __cplusplus
-    aiSkeleton() AI_NO_EXCEPT : mName(), mNumWeights(0), mWeights(nullptr) {
+    /**
+     *
+     */
+    aiSkeleton() AI_NO_EXCEPT : mName(), mNumBones(0), mBones(nullptr) {
         // empty
     }
-    ~aiSkeleton() {
 
+    /**
+     *
+     */
+    ~aiSkeleton() {
+        delete[] mBones;
     }
 #endif // __cplusplus
 };

+ 14 - 0
include/assimp/scene.h

@@ -343,6 +343,16 @@ struct aiScene
      */
     C_STRUCT aiString mName;
 
+    /**
+     *
+     */
+    unsigned int mNumSkeletons;
+
+    /**
+     *
+     */
+    C_STRUCT aiSkeleton **mSkeletons;
+
 #ifdef __cplusplus
 
     //! Default constructor - set everything to 0/nullptr
@@ -383,6 +393,10 @@ struct aiScene
         return mAnimations != nullptr && mNumAnimations > 0;
     }
 
+    bool hasSkeletons() const {
+        return mSkeletons != nullptr && mNumSkeletons > 0;
+    }
+
     //! Returns a short filename from a full path
     static const char* GetShortFilename(const char* filename) {
         const char* lastSlash = strrchr(filename, '/');