Просмотр исходного кода

Added ArmaturePopulate scale process for all formats

RevoluPowered 5 лет назад
Родитель
Сommit
46cdd81d75

+ 2 - 0
code/CMakeLists.txt

@@ -670,6 +670,8 @@ SET( PostProcessing_SRCS
   PostProcessing/MakeVerboseFormat.h
   PostProcessing/MakeVerboseFormat.h
   PostProcessing/ScaleProcess.cpp
   PostProcessing/ScaleProcess.cpp
   PostProcessing/ScaleProcess.h
   PostProcessing/ScaleProcess.h
+  PostProcessing/ArmaturePopulate.cpp
+  PostProcessing/ArmaturePopulate.h
   PostProcessing/GenBoundingBoxesProcess.cpp
   PostProcessing/GenBoundingBoxesProcess.cpp
   PostProcessing/GenBoundingBoxesProcess.h
   PostProcessing/GenBoundingBoxesProcess.h
 )
 )

+ 0 - 194
code/FBX/FBXConverter.cpp

@@ -121,39 +121,6 @@ namespace Assimp {
             ConvertGlobalSettings();
             ConvertGlobalSettings();
             TransferDataToScene();
             TransferDataToScene();
 
 
-            // Now convert all bone positions to the correct mOffsetMatrix
-            std::vector<aiBone*> bones;
-            std::vector<aiNode*> nodes;
-            std::map<aiBone*, aiNode*> bone_stack;
-            BuildBoneList(out->mRootNode, out->mRootNode, out, bones);
-            BuildNodeList(out->mRootNode, nodes );
-
-
-            BuildBoneStack(out->mRootNode, out->mRootNode, out, bones, bone_stack, nodes);
-
-            std::cout << "Bone stack size: " << bone_stack.size() << std::endl;
-
-            for( std::pair<aiBone*, aiNode*> kvp : bone_stack )
-            {
-                aiBone *bone = kvp.first;
-                aiNode *bone_node = kvp.second;
-                std::cout << "active node lookup: " << bone->mName.C_Str() << std::endl;
-                // lcl transform grab - done in generate_nodes :)
-
-                //bone->mOffsetMatrix = bone_node->mTransformation;
-                aiNode * armature = GetArmatureRoot(bone_node, bones);
-
-                ai_assert(armature);
-
-                // set up bone armature id
-                bone->mArmature = armature;
-
-                // set this bone node to be referenced properly
-                ai_assert(bone_node);
-                bone->mNode = bone_node;
-            }
-
-
             // if we didn't read any meshes set the AI_SCENE_FLAGS_INCOMPLETE
             // if we didn't read any meshes set the AI_SCENE_FLAGS_INCOMPLETE
             // to make sure the scene passes assimp's validation. FBX files
             // to make sure the scene passes assimp's validation. FBX files
             // need not contain geometry (i.e. camera animations, raw armatures).
             // need not contain geometry (i.e. camera animations, raw armatures).
@@ -172,167 +139,6 @@ namespace Assimp {
             std::for_each(textures.begin(), textures.end(), Util::delete_fun<aiTexture>());
             std::for_each(textures.begin(), textures.end(), Util::delete_fun<aiTexture>());
         }
         }
 
 
-        /* Returns the armature root node */
-        /* This is required to be detected for a bone initially, it will recurse up until it cannot find another
-         * bone and return the node
-         * No known failure points. (yet)
-         */
-        aiNode * FBXConverter::GetArmatureRoot(aiNode *bone_node, std::vector<aiBone*> &bone_list)
-        {
-            while(bone_node)
-            {
-                if(!IsBoneNode(bone_node->mName, bone_list))
-                {
-                    std::cout << "Found valid armature: " << bone_node->mName.C_Str() << std::endl;
-                    return bone_node;
-                }
-
-                bone_node = bone_node->mParent;
-            }
-
-            std::cout << "can't find armature! node: " << bone_node << std::endl;
-
-            return NULL;
-        }
-
-        /* Simple IsBoneNode check if this could be a bone */
-        bool FBXConverter::IsBoneNode(const aiString &bone_name, std::vector<aiBone*>& bones )
-        {
-            for( aiBone *bone : bones)
-            {
-                if(bone->mName == bone_name)
-                {
-                    return true;
-                }
-            }
-
-            return false;
-        }
-
-
-        /* Pop this node by name from the stack if found */
-        /* Used in multiple armature situations with duplicate node / bone names */
-        /* Known flaw: cannot have nodes with bone names, will be fixed in later release */
-        /* (serious to be fixed) Known flaw: nodes which have more than one bone could be prematurely dropped from stack */
-        aiNode* FBXConverter::GetNodeFromStack(const aiString &node_name, std::vector<aiNode*> &nodes)
-        {
-            std::vector<aiNode*>::iterator iter;
-            aiNode *found = NULL;
-            for( iter = nodes.begin(); iter < nodes.end(); ++iter )
-            {
-                aiNode *element = *iter;
-                ai_assert(element);
-                // node valid and node name matches
-                if(element->mName == node_name)
-                {
-                    found = element;
-                    break;
-                }
-            }
-
-            if(found != NULL) {
-                // now pop the element from the node list
-                nodes.erase(iter);
-
-                return found;
-            }
-            return NULL;
-        }
-
-        /* Prepare flat node list which can be used for non recursive lookups later */
-        void FBXConverter::BuildNodeList(aiNode *current_node, std::vector<aiNode *> &nodes)
-        {
-            ai_assert(current_node);
-
-            for( unsigned int nodeId = 0; nodeId < current_node->mNumChildren; ++nodeId)
-            {
-                aiNode *child = current_node->mChildren[nodeId];
-                ai_assert(child);
-
-                nodes.push_back(child);
-
-                BuildNodeList(child, nodes);
-            }
-        }
-
-        /* Reprocess all nodes to calculate bone transforms properly based on the REAL mOffsetMatrix not the local. */
-        /* Before this would use mesh transforms which is wrong for bone transforms */
-        /* Before this would work for simple character skeletons but not complex meshes with multiple origins */
-        /* Source: sketch fab log cutter fbx */
-        void FBXConverter::BuildBoneList(aiNode *current_node, const aiNode * root_node, const aiScene *scene, std::vector<aiBone*> &bones )
-        {
-            ai_assert(scene);
-            for( unsigned int nodeId = 0; nodeId < current_node->mNumChildren; ++nodeId)
-            {
-                aiNode *child = current_node->mChildren[nodeId];
-                ai_assert(child);
-
-                // check for bones
-                for( unsigned int meshId = 0; meshId < child->mNumMeshes; ++meshId)
-                {
-                    ai_assert(child->mMeshes);
-                    unsigned int mesh_index = child->mMeshes[meshId];
-                    aiMesh *mesh = scene->mMeshes[ mesh_index ];
-                    ai_assert(mesh);
-
-                    for( unsigned int boneId = 0; boneId < mesh->mNumBones; ++boneId)
-                    {
-                        aiBone *bone = mesh->mBones[boneId];
-                        ai_assert(bone);
-
-                        // duplicate meshes exist with the same bones sometimes :)
-                        // so this must be detected
-                        if( std::find(bones.begin(), bones.end(), bone) == bones.end() )
-                        {
-                            // add the element once
-                            bones.push_back(bone);
-                        }
-                    }
-
-                    // find mesh and get bones
-                    // then do recursive lookup for bones in root node hierarchy
-                }
-
-                BuildBoneList(child, root_node, scene, bones);
-            }
-        }
-
-        /* A bone stack allows us to have multiple armatures, with the same bone names
-         * A bone stack allows us also to retrieve bones true transform even with duplicate names :)
-         */
-        void FBXConverter::BuildBoneStack(aiNode *current_node, const aiNode *root_node, const aiScene *scene,
-                                          const std::vector<aiBone *> &bones,
-                                          std::map<aiBone *, aiNode *> &bone_stack,
-                                          std::vector<aiNode*> &node_stack )
-        {
-            ai_assert(scene);
-            ai_assert(root_node);
-            ai_assert(!node_stack.empty());
-
-            for( aiBone * bone : bones)
-            {
-                ai_assert(bone);
-                aiNode* node = GetNodeFromStack(bone->mName, node_stack);
-                if(node == NULL)
-                {
-                    node_stack.clear();
-                    BuildNodeList(out->mRootNode, node_stack );
-                    std::cout << "Resetting bone stack: null element " << bone->mName.C_Str() << std::endl;
-
-                    node = GetNodeFromStack(bone->mName, node_stack);
-
-                    if(!node) {
-                        std::cout << "serious import issue armature failed to be detected?" << std::endl;
-                        continue;
-                    }
-                }
-
-                std::cout << "Successfully added bone to stack and have valid armature: " << bone->mName.C_Str() << std::endl;
-
-                bone_stack.insert(std::pair<aiBone*, aiNode*>(bone, node));
-            }
-        }
-
         void FBXConverter::ConvertRootNode() {
         void FBXConverter::ConvertRootNode() {
             out->mRootNode = new aiNode();
             out->mRootNode = new aiNode();
             std::string unique_name;
             std::string unique_name;

+ 247 - 0
code/PostProcessing/ArmaturePopulate.cpp

@@ -0,0 +1,247 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2019, assimp team
+
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the
+following conditions are met:
+
+* Redistributions of source code must retain the above
+copyright notice, this list of conditions and the
+following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the
+following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+contributors may be used to endorse or promote products
+derived from this software without specific prior
+written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+*/
+#include "ArmaturePopulate.h"
+
+#include <assimp/BaseImporter.h>
+#include <assimp/DefaultLogger.hpp>
+#include <assimp/postprocess.h>
+#include <assimp/scene.h>
+
+namespace Assimp {
+
+bool ArmaturePopulate::IsActive(unsigned int pFlags) const {
+  return (pFlags & aiProcess_PopulateArmatureData) != 0;
+}
+
+void ArmaturePopulate::SetupProperties(const Importer *pImp) {
+  // do nothing
+}
+
+void ArmaturePopulate::Execute(aiScene *out) {
+
+  // Now convert all bone positions to the correct mOffsetMatrix
+  std::vector<aiBone *> bones;
+  std::vector<aiNode *> nodes;
+  std::map<aiBone *, aiNode *> bone_stack;
+  BuildBoneList(out->mRootNode, out->mRootNode, out, bones);
+  BuildNodeList(out->mRootNode, nodes);
+
+  BuildBoneStack(out->mRootNode, out->mRootNode, out, bones, bone_stack, nodes);
+
+  ASSIMP_LOG_DEBUG_F("Bone stack size: %ld\n", bone_stack.size());
+
+  for (std::pair<aiBone *, aiNode *> kvp : bone_stack) {
+    aiBone *bone = kvp.first;
+    aiNode *bone_node = kvp.second;
+    ASSIMP_LOG_DEBUG_F("active node lookup: %s\n", bone->mName.C_Str());
+    // lcl transform grab - done in generate_nodes :)
+
+    // bone->mOffsetMatrix = bone_node->mTransformation;
+    aiNode *armature = GetArmatureRoot(bone_node, bones);
+
+    ai_assert(armature);
+
+    // set up bone armature id
+    bone->mArmature = armature;
+
+    // set this bone node to be referenced properly
+    ai_assert(bone_node);
+    bone->mNode = bone_node;
+  }
+}
+
+/* Returns the armature root node */
+/* This is required to be detected for a bone initially, it will recurse up
+ * until it cannot find another bone and return the node No known failure
+ * points. (yet)
+ */
+aiNode *ArmaturePopulate::GetArmatureRoot(aiNode *bone_node,
+                                          std::vector<aiBone *> &bone_list) {
+  while (bone_node) {
+    if (!IsBoneNode(bone_node->mName, bone_list)) {
+      ASSIMP_LOG_DEBUG_F("Found valid armature: %s\n", bone_node->mName.C_Str());
+      return bone_node;
+    }
+
+    bone_node = bone_node->mParent;
+  }
+
+  ASSIMP_LOG_WARN_F("can't find armature! node: %s\n", bone_node->mName.C_Str());
+
+  return NULL;
+}
+
+/* Simple IsBoneNode check if this could be a bone */
+bool ArmaturePopulate::IsBoneNode(const aiString &bone_name,
+                                  std::vector<aiBone *> &bones) {
+  for (aiBone *bone : bones) {
+    if (bone->mName == bone_name) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+/* Pop this node by name from the stack if found */
+/* Used in multiple armature situations with duplicate node / bone names */
+/* Known flaw: cannot have nodes with bone names, will be fixed in later release
+ */
+/* (serious to be fixed) Known flaw: nodes which have more than one bone could
+ * be prematurely dropped from stack */
+aiNode *ArmaturePopulate::GetNodeFromStack(const aiString &node_name,
+                                           std::vector<aiNode *> &nodes) {
+  std::vector<aiNode *>::iterator iter;
+  aiNode *found = NULL;
+  for (iter = nodes.begin(); iter < nodes.end(); ++iter) {
+    aiNode *element = *iter;
+    ai_assert(element);
+    // node valid and node name matches
+    if (element->mName == node_name) {
+      found = element;
+      break;
+    }
+  }
+
+  if (found != NULL) {
+    // now pop the element from the node list
+    nodes.erase(iter);
+
+    return found;
+  }
+  return NULL;
+}
+
+/* Prepare flat node list which can be used for non recursive lookups later */
+void ArmaturePopulate::BuildNodeList(const aiNode *current_node,
+                                     std::vector<aiNode *> &nodes) {
+  ai_assert(current_node);
+
+  for (unsigned int nodeId = 0; nodeId < current_node->mNumChildren; ++nodeId) {
+    aiNode *child = current_node->mChildren[nodeId];
+    ai_assert(child);
+
+    nodes.push_back(child);
+
+    BuildNodeList(child, nodes);
+  }
+}
+
+/* Reprocess all nodes to calculate bone transforms properly based on the REAL
+ * mOffsetMatrix not the local. */
+/* Before this would use mesh transforms which is wrong for bone transforms */
+/* Before this would work for simple character skeletons but not complex meshes
+ * with multiple origins */
+/* Source: sketch fab log cutter fbx */
+void ArmaturePopulate::BuildBoneList(aiNode *current_node,
+                                     const aiNode *root_node,
+                                     const aiScene *scene,
+                                     std::vector<aiBone *> &bones) {
+  ai_assert(scene);
+  for (unsigned int nodeId = 0; nodeId < current_node->mNumChildren; ++nodeId) {
+    aiNode *child = current_node->mChildren[nodeId];
+    ai_assert(child);
+
+    // check for bones
+    for (unsigned int meshId = 0; meshId < child->mNumMeshes; ++meshId) {
+      ai_assert(child->mMeshes);
+      unsigned int mesh_index = child->mMeshes[meshId];
+      aiMesh *mesh = scene->mMeshes[mesh_index];
+      ai_assert(mesh);
+
+      for (unsigned int boneId = 0; boneId < mesh->mNumBones; ++boneId) {
+        aiBone *bone = mesh->mBones[boneId];
+        ai_assert(bone);
+
+        // duplicate meshes exist with the same bones sometimes :)
+        // so this must be detected
+        if (std::find(bones.begin(), bones.end(), bone) == bones.end()) {
+          // add the element once
+          bones.push_back(bone);
+        }
+      }
+
+      // find mesh and get bones
+      // then do recursive lookup for bones in root node hierarchy
+    }
+
+    BuildBoneList(child, root_node, scene, bones);
+  }
+}
+
+/* A bone stack allows us to have multiple armatures, with the same bone names
+ * A bone stack allows us also to retrieve bones true transform even with
+ * duplicate names :)
+ */
+void ArmaturePopulate::BuildBoneStack(aiNode *current_node,
+                                      const aiNode *root_node,
+                                      const aiScene *scene,
+                                      const std::vector<aiBone *> &bones,
+                                      std::map<aiBone *, aiNode *> &bone_stack,
+                                      std::vector<aiNode *> &node_stack) {
+  ai_assert(scene);
+  ai_assert(root_node);
+  ai_assert(!node_stack.empty());
+
+  for (aiBone *bone : bones) {
+    ai_assert(bone);
+    aiNode *node = GetNodeFromStack(bone->mName, node_stack);
+    if (node == NULL) {
+      node_stack.clear();
+      BuildNodeList(root_node, node_stack);
+      ASSIMP_LOG_DEBUG_F("Resetting bone stack: null element %s\n", bone->mName.C_Str());
+
+      node = GetNodeFromStack(bone->mName, node_stack);
+
+      if (!node) {
+        ASSIMP_LOG_ERROR("serious import issue armature failed to be detected");
+        continue;
+      }
+    }
+
+    ASSIMP_LOG_DEBUG_F("Successfully added bone to stack and have valid armature: %s\n", bone->mName.C_Str());
+
+    bone_stack.insert(std::pair<aiBone *, aiNode *>(bone, node));
+  }
+}
+
+} // Namespace Assimp

+ 111 - 0
code/PostProcessing/ArmaturePopulate.h

@@ -0,0 +1,111 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2019, assimp team
+
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the
+following conditions are met:
+
+* Redistributions of source code must retain the above
+copyright notice, this list of conditions and the
+following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the
+following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+contributors may be used to endorse or promote products
+derived from this software without specific prior
+written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+*/
+#ifndef SCALE_PROCESS_H_
+#define SCALE_PROCESS_H_
+
+#include "Common/BaseProcess.h"
+#include <vector>
+#include <map>
+
+struct aiNode;
+struct aiBone;
+
+#if (!defined AI_CONFIG_GLOBAL_SCALE_FACTOR_DEFAULT)
+#   define AI_CONFIG_GLOBAL_SCALE_FACTOR_DEFAULT  1.0f
+#endif // !! AI_DEBONE_THRESHOLD
+
+namespace Assimp {
+
+// ---------------------------------------------------------------------------
+/** ScaleProcess: Class to rescale the whole model.
+ * Now rescales animations, bones, and blend shapes properly.
+ * Please note this will not write to 'scale' transform it will rewrite mesh 
+ * and matrixes so that your scale values 
+ * from your model package are preserved, so this is completely intentional
+ * bugs should be reported as soon as they are found.
+*/
+class ASSIMP_API ArmaturePopulate : public BaseProcess {
+public:
+    /// The default class constructor.
+    ArmaturePopulate() : BaseProcess()
+    {}
+
+    /// The class destructor.
+    virtual ~ArmaturePopulate() 
+    {}
+
+    /// Overwritten, @see BaseProcess
+    virtual bool IsActive( unsigned int pFlags ) const;
+
+    /// Overwritten, @see BaseProcess
+    virtual void SetupProperties( const Importer* pImp );
+
+    /// Overwritten, @see BaseProcess
+    virtual void Execute( aiScene* pScene );
+
+    static aiNode *GetArmatureRoot(aiNode *bone_node,
+                                      std::vector<aiBone *> &bone_list);
+
+    static bool IsBoneNode(const aiString &bone_name,
+                              std::vector<aiBone *> &bones);
+
+    static aiNode *GetNodeFromStack(const aiString &node_name,
+                                       std::vector<aiNode *> &nodes);
+
+    static void BuildNodeList(const aiNode *current_node,
+                                 std::vector<aiNode *> &nodes);
+
+    static void BuildBoneList(aiNode *current_node, const aiNode *root_node,
+                                 const aiScene *scene,
+                                 std::vector<aiBone *> &bones);                        
+
+    static void BuildBoneStack(aiNode *current_node, const aiNode *root_node,
+                                  const aiScene *scene,
+                                  const std::vector<aiBone *> &bones,
+                                  std::map<aiBone *, aiNode *> &bone_stack,
+                                  std::vector<aiNode *> &node_stack);
+};
+
+} // Namespace Assimp
+
+
+#endif // SCALE_PROCESS_H_

+ 12 - 0
include/assimp/postprocess.h

@@ -537,6 +537,18 @@ enum aiPostProcessSteps
     */
     */
     aiProcess_Debone  = 0x4000000,
     aiProcess_Debone  = 0x4000000,
 
 
+
+    // -------------------------------------------------------------------------
+    /** 
+     * This step generically populates aiBone->mArmature and aiBone->mNode generically
+     * The point of these is it saves you later having to calculate these elements
+     * This is useful when handling rest information or skin information
+     * If you have multiple armatures on your models we strongly recommend enabling this 
+     * Instead of writing your own multi-root, multi-armature lookups we have done the 
+     * hard work for you :)
+   */
+    aiProcess_PopulateArmatureData = 0x5000000,
+
     // -------------------------------------------------------------------------
     // -------------------------------------------------------------------------
     /** <hr>This step will perform a global scale of the model.
     /** <hr>This step will perform a global scale of the model.
     *
     *