瀏覽代碼

Update assimp importing

assimp importer now works for the most part for fbx and gltf
animations for gltf still need to be sorted out
marauder2k7 9 月之前
父節點
當前提交
ca6e26520b

+ 7 - 7
Engine/lib/assimp/CMakeLists.txt

@@ -70,7 +70,7 @@ if (NOT ASSIMP_BUILD_M3D_EXPORTER)
 endif () # if (not ASSIMP_BUILD_M3D_EXPORTER)
 
 # Toggles the use of the hunter package manager
-option(ASSIMP_HUNTER_ENABLED "Enable Hunter package manager support" ON)
+option(ASSIMP_HUNTER_ENABLED "Enable Hunter package manager support" OFF)
 
 IF(ASSIMP_HUNTER_ENABLED)
   include("cmake-modules/HunterGate.cmake")
@@ -127,7 +127,7 @@ OPTION ( ASSIMP_COVERALLS
 )
 OPTION( ASSIMP_INSTALL
   "Disable this if you want to use assimp as a submodule."
-  OFF
+  ON
 )
 OPTION ( ASSIMP_WARNINGS_AS_ERRORS
   "Treat all warnings as errors."
@@ -511,12 +511,12 @@ IF(ASSIMP_HUNTER_ENABLED)
   find_package(ZLIB CONFIG REQUIRED)
 
   add_definitions(-DASSIMP_BUILD_NO_OWN_ZLIB)
-  set( TRUE)
+  set(ZLIB_FOUND TRUE)
   set(ZLIB_LIBRARIES ZLIB::zlib)
   set(ASSIMP_BUILD_MINIZIP TRUE)
 ELSE()
   # If the zlib is already found outside, add an export in case assimpTargets can't find it.
-  IF(  AND ASSIMP_INSTALL)
+  IF( ZLIB_FOUND AND ASSIMP_INSTALL)
     INSTALL( TARGETS zlib zlibstatic
         EXPORT "${TARGETS_EXPORT_NAME}")
   ENDIF()
@@ -525,11 +525,11 @@ ELSE()
     FIND_PACKAGE(ZLIB)
   ENDIF()
 
-  IF ( NOT  AND NOT ASSIMP_BUILD_ZLIB )
+  IF ( NOT ZLIB_FOUND AND NOT ASSIMP_BUILD_ZLIB )
     message( FATAL_ERROR
       "Build configured with -DASSIMP_BUILD_ZLIB=OFF but unable to find zlib"
     )
-  ELSEIF( NOT  )
+  ELSEIF( NOT ZLIB_FOUND )
     MESSAGE(STATUS "compiling zlib from sources")
     INCLUDE(CheckIncludeFile)
     INCLUDE(CheckTypeSize)
@@ -545,7 +545,7 @@ ELSE()
 
     # compile from sources
     ADD_SUBDIRECTORY(contrib/zlib)
-    SET( 1)
+    SET(ZLIB_FOUND 1)
     SET(ZLIB_LIBRARIES zlibstatic)
     SET(ZLIB_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/contrib/zlib ${CMAKE_CURRENT_BINARY_DIR}/contrib/zlib)
     # need to ensure we don't link with system zlib or minizip as well.

+ 23 - 9
Engine/source/ts/assimp/assimpAppNode.cpp

@@ -35,14 +35,17 @@ aiAnimation* AssimpAppNode::sActiveSequence = NULL;
 F32 AssimpAppNode::sTimeMultiplier = 1.0f;
 
 AssimpAppNode::AssimpAppNode(const struct aiScene* scene, const struct aiNode* node, AssimpAppNode* parent)
-:  mInvertMeshes(false),
-   mLastTransformTime(TSShapeLoader::DefaultTime - 1),
-   mDefaultTransformValid(false)
+   :  mScene(scene),
+      mNode(node ? node : scene->mRootNode),
+      appParent(parent),
+      mInvertMeshes(false),
+      mLastTransformTime(TSShapeLoader::DefaultTime - 1),
+      mDefaultTransformValid(false)
 {
-   mScene = scene;
-   mNode = node;
-   appParent = parent;
 
+   mScene = scene;
+   mNode = node ? node : scene->mRootNode; 
+   // Initialize node and parent names.
    mName = dStrdup(mNode->mName.C_Str());
    if ( dStrlen(mName) == 0 )
    {
@@ -51,6 +54,8 @@ AssimpAppNode::AssimpAppNode(const struct aiScene* scene, const struct aiNode* n
    }
 
    mParentName = dStrdup(parent ? parent->getName() : "ROOT");
+
+   // Convert transformation matrix
    assimpToTorqueMat(node->mTransformation, mNodeTransform);
    Con::printf("[ASSIMP] Node Created: %s, Parent: %s", mName, mParentName);
 }
@@ -58,12 +63,21 @@ AssimpAppNode::AssimpAppNode(const struct aiScene* scene, const struct aiNode* n
 // Get all child nodes
 void AssimpAppNode::buildChildList()
 {
-   if (!mNode)
-   {
-      mNode = mScene->mRootNode;
+   // Ensure mNode is valid
+   if (!mNode) {
+      Con::errorf("[ASSIMP] Error: mNode is null in buildChildList");
+      return;
    }
 
+   if (!mNode->mChildren)
+      return;
+    
    for (U32 n = 0; n < mNode->mNumChildren; ++n) {
+      if (!mNode->mChildren[n]) {
+         Con::errorf("[ASSIMP] Warning: Null child node at index %d", n);
+         continue;
+      }
+
       mChildNodes.push_back(new AssimpAppNode(mScene, mNode->mChildren[n], this));
    }
 }

+ 2 - 2
Engine/source/ts/assimp/assimpAppNode.h

@@ -50,8 +50,8 @@ class AssimpAppNode : public AppNode
 
 protected:
 
-   const struct aiScene*   mScene;
-   const struct aiNode*    mNode;                  ///< Pointer to the assimp scene node
+   const aiScene*   mScene;
+   const aiNode*    mNode;                  ///< Pointer to the assimp scene node
    AssimpAppNode*          appParent;              ///< Parent node
    MatrixF                 mNodeTransform;         ///< Scene node transform converted to TorqueSpace (filled for ALL nodes)
 

+ 180 - 92
Engine/source/ts/assimp/assimpShapeLoader.cpp

@@ -59,8 +59,6 @@
 #include <assimp/config.h>
 #include <exception>
 
-#include <assimp/Importer.hpp>
-
 MODULE_BEGIN( AssimpShapeLoader )
    MODULE_INIT_AFTER( ShapeLoader )
    MODULE_INIT
@@ -124,7 +122,80 @@ AssimpShapeLoader::~AssimpShapeLoader()
 
 void AssimpShapeLoader::releaseImport()
 {
-   aiReleaseImport(mScene);
+}
+
+void debugSceneMetaData(const aiScene* scene) {
+   if (!scene->mMetaData) {
+      Con::printf("[ASSIMP] No metadata available.");
+      return;
+   }
+
+   for (unsigned int i = 0; i < scene->mMetaData->mNumProperties; ++i) {
+      const char* key = scene->mMetaData->mKeys[i].C_Str();
+      aiMetadataType type = scene->mMetaData->mValues[i].mType;
+      Con::printf("[ASSIMP] Metadata key: %s", key);
+
+      switch (type) {
+      case AI_BOOL:
+         Con::printf("  Value: %d (bool)", *(bool*)scene->mMetaData->mValues[i].mData);
+         break;
+      case AI_INT32:
+         Con::printf("  Value: %d (int)", *(int*)scene->mMetaData->mValues[i].mData);
+         break;
+      case AI_UINT64:
+         Con::printf("  Value: %llu (uint64)", *(uint64_t*)scene->mMetaData->mValues[i].mData);
+         break;
+      case AI_FLOAT:
+         Con::printf("  Value: %f (float)", *(float*)scene->mMetaData->mValues[i].mData);
+         break;
+      case AI_DOUBLE:
+         Con::printf("  Value: %f (double)", *(double*)scene->mMetaData->mValues[i].mData);
+         break;
+      case AI_AISTRING:
+         Con::printf("  Value: %s (string)", ((aiString*)scene->mMetaData->mValues[i].mData)->C_Str());
+         break;
+      case AI_AIVECTOR3D:
+      {
+         aiVector3D* vec = (aiVector3D*)scene->mMetaData->mValues[i].mData;
+         Con::printf("  Value: (%f, %f, %f) (vector3d)", vec->x, vec->y, vec->z);
+      }
+      break;
+      default:
+         Con::printf("  Unknown metadata type.");
+      }
+   }
+}
+
+void applyTransformation(aiNode* node, const aiMatrix4x4& transform) {
+   node->mTransformation = transform * node->mTransformation; // Apply transformation to the node
+}
+
+void reorientGLTFScene(const aiScene* scene) {
+   aiMatrix4x4 rotationMatrix;
+   rotationMatrix = aiMatrix4x4::RotationX(AI_MATH_PI / 2, rotationMatrix); // Rotate -90 degrees around X-axis
+
+   applyTransformation(scene->mRootNode, rotationMatrix);
+
+   rotationMatrix = aiMatrix4x4::RotationZ(AI_MATH_PI, rotationMatrix); // Rotate -90 degrees around X-axis
+   applyTransformation(scene->mRootNode, rotationMatrix);
+}
+
+float getUnitScaleFactor(const aiScene* scene) {
+   float scale = 1.0f;
+
+   if (scene->mMetaData) {
+      double unitScaleFactor;
+      if (scene->mMetaData->Get("UnitScaleFactor", unitScaleFactor)) {
+         scale = static_cast<float>(unitScaleFactor);
+      }
+   }
+
+   return scale;
+}
+
+void scaleScene(const aiScene* scene, float scaleFactor) {
+   aiMatrix4x4 scaleMatrix = aiMatrix4x4::Scaling(aiVector3D(scaleFactor, scaleFactor, scaleFactor), aiMatrix4x4());
+   applyTransformation(scene->mRootNode, scaleMatrix);
 }
 
 void AssimpShapeLoader::enumerateScene()
@@ -132,31 +203,28 @@ void AssimpShapeLoader::enumerateScene()
    TSShapeLoader::updateProgress(TSShapeLoader::Load_ReadFile, "Reading File");
    Con::printf("[ASSIMP] Attempting to load file: %s", shapePath.getFullPath().c_str());
 
-   // Post-Processing
-   unsigned int ppsteps = 
-      (ColladaUtils::getOptions().convertLeftHanded ? aiProcess_MakeLeftHanded : 0) |
-      (ColladaUtils::getOptions().reverseWindingOrder ? aiProcess_FlipWindingOrder : 0) |
-      (ColladaUtils::getOptions().calcTangentSpace ? aiProcess_CalcTangentSpace : 0) |
-      (ColladaUtils::getOptions().joinIdenticalVerts ? aiProcess_JoinIdenticalVertices : 0) |
-      (ColladaUtils::getOptions().removeRedundantMats ? aiProcess_RemoveRedundantMaterials : 0) |
-      (ColladaUtils::getOptions().genUVCoords ? aiProcess_GenUVCoords : 0) |
-      (ColladaUtils::getOptions().transformUVCoords ? aiProcess_TransformUVCoords : 0) |
-      (ColladaUtils::getOptions().flipUVCoords ? aiProcess_FlipUVs : 0) |
-      (ColladaUtils::getOptions().findInstances ? aiProcess_FindInstances : 0) |
-      (ColladaUtils::getOptions().limitBoneWeights ? aiProcess_LimitBoneWeights : 0);
-
-   if (Con::getBoolVariable("$Assimp::OptimizeMeshes", false))
+   // Define post-processing steps
+   unsigned int ppsteps = aiProcess_Triangulate | aiProcess_ValidateDataStructure | aiProcess_MakeLeftHanded | aiProcess_FlipUVs;
+
+   const auto& options = ColladaUtils::getOptions();
+   if (options.convertLeftHanded) ppsteps |= aiProcess_MakeLeftHanded;
+   if (options.reverseWindingOrder) ppsteps |= aiProcess_FlipWindingOrder;
+   if (options.calcTangentSpace) ppsteps |= aiProcess_CalcTangentSpace;
+   if (options.joinIdenticalVerts) ppsteps |= aiProcess_JoinIdenticalVertices;
+   if (options.removeRedundantMats) ppsteps |= aiProcess_RemoveRedundantMaterials;
+   if (options.genUVCoords) ppsteps |= aiProcess_GenUVCoords;
+   if (options.transformUVCoords) ppsteps |= aiProcess_TransformUVCoords;
+   if (options.findInstances) ppsteps |= aiProcess_FindInstances;
+   if (options.limitBoneWeights) ppsteps |= aiProcess_LimitBoneWeights;
+
+   if (Con::getBoolVariable("$Assimp::OptimizeMeshes", false)) {
       ppsteps |= aiProcess_OptimizeMeshes | aiProcess_OptimizeGraph;
-
-   if (Con::getBoolVariable("$Assimp::SplitLargeMeshes", false))
+   }
+   if (Con::getBoolVariable("$Assimp::SplitLargeMeshes", false)) {
       ppsteps |= aiProcess_SplitLargeMeshes;
+   }
 
-   // Mandatory options
-   //ppsteps |= aiProcess_ValidateDataStructure | aiProcess_Triangulate | aiProcess_ImproveCacheLocality;
-   ppsteps |= aiProcess_Triangulate;
-   //aiProcess_SortByPType              | // make 'clean' meshes which consist of a single typ of primitives
-
-   aiPropertyStore* props = aiCreatePropertyStore();
+   ppsteps |= aiProcess_ValidateDataStructure;
 
    struct aiLogStream shapeLog = aiGetPredefinedLogStream(aiDefaultLogStream_STDOUT, NULL);
    shapeLog.callback = assimpLogCallback;
@@ -165,94 +233,113 @@ void AssimpShapeLoader::enumerateScene()
 #ifdef TORQUE_DEBUG
    aiEnableVerboseLogging(true);
 #endif
+   
+   // Read the file
+   mScene = mImporter.ReadFile(shapePath.getFullPath().c_str(), ppsteps);
 
-   mScene = (aiScene*)aiImportFileExWithProperties(shapePath.getFullPath().c_str(), ppsteps, NULL, props);
+   if (!mScene || (mScene->mFlags & AI_SCENE_FLAGS_INCOMPLETE) || !mScene->mRootNode) {
+      Con::errorf("[ASSIMP] ERROR: Could not load file: %s", shapePath.getFullPath().c_str());
+      Con::errorf("[ASSIMP] Importer error: %s", mImporter.GetErrorString());
+      TSShapeLoader::updateProgress(TSShapeLoader::Load_Complete, "Import failed");
+      return;
+   }
 
-   aiReleasePropertyStore(props);
+   //debugSceneMetaData(mScene);
 
-   if ( mScene )
-   {
-      Con::printf("[ASSIMP] Mesh Count: %d", mScene->mNumMeshes);
-      Con::printf("[ASSIMP] Material Count: %d", mScene->mNumMaterials);
+   Con::printf("[ASSIMP] Mesh Count: %d", mScene->mNumMeshes);
+   Con::printf("[ASSIMP] Material Count: %d", mScene->mNumMaterials);
 
-      // Setup default units for shape format
-      String importFormat;
+   // Format-specific adjustments
+   String fileExt = String::ToLower(shapePath.getExtension());
+   const aiImporterDesc* importerDescription = aiGetImporterDesc(fileExt.c_str());
+   if (fileExt == String::ToString("gltf") || fileExt == String::ToString("glb")) {
+      Con::printf("[ASSIMP] Detected GLTF format, applying reorientation...");
+      reorientGLTFScene(mScene); // Reorient GLTF
+   }
 
-      String fileExt = String::ToLower(shapePath.getExtension());
-      const aiImporterDesc* importerDescription = aiGetImporterDesc(fileExt.c_str());
-      if (importerDescription && StringTable->insert(importerDescription->mName) == StringTable->insert("Autodesk FBX Importer"))
-      {
-         ColladaUtils::getOptions().formatScaleFactor = 0.01f;
+   if (importerDescription && dStrcmp(importerDescription->mName, "Autodesk FBX Importer") == 0) {
+      Con::printf("[ASSIMP] Detected FBX format, checking unit scale...");
+      F32 scaleFactor = getUnitScaleFactor(mScene);
+      if (scaleFactor != 1.0f) {
+         Con::printf("[ASSIMP] Applying FBX scale factor: %f", scaleFactor);
+         scaleScene(mScene, scaleFactor);
       }
-
-      // Set import options (if they are not set to override)
-      if (ColladaUtils::getOptions().unit <= 0.0f)
+      else
       {
-         F64 unit;
-         if (!getMetaDouble("UnitScaleFactor", unit))
-         {
-            F32 floatVal;
-            S32 intVal;
-            if (getMetaFloat("UnitScaleFactor", floatVal))
-               unit = (F64)floatVal;
-            else if (getMetaInt("UnitScaleFactor", intVal))
-               unit = (F64)intVal;
-            else
-               unit = 1.0;
-         }
-         ColladaUtils::getOptions().unit = (F32)unit;
+         scaleScene(mScene, 0.01f);
       }
+   }
 
-      if (ColladaUtils::getOptions().upAxis == UPAXISTYPE_COUNT)
-      {
-         S32 upAxis;
-         if (!getMetaInt("UpAxis", upAxis))
-            upAxis = UPAXISTYPE_Z_UP;
-         ColladaUtils::getOptions().upAxis = (domUpAxisType) upAxis;
-      }
+   // Handle scaling and up-axis conversions if necessary
+   configureImportUnitsAndAxis();
 
-      // Extract embedded textures
-      for (U32 i = 0; i < mScene->mNumTextures; ++i)
-         extractTexture(i, mScene->mTextures[i]);
+   // Extract embedded textures
+   for (unsigned int i = 0; i < mScene->mNumTextures; ++i) {
+      extractTexture(i, mScene->mTextures[i]);
+   }
 
-      // Load all the materials.
-      AssimpAppMaterial::sDefaultMatNumber = 0;
-      for ( U32 i = 0; i < mScene->mNumMaterials; i++ )
-         AppMesh::appMaterials.push_back(new AssimpAppMaterial(mScene->mMaterials[i]));
+   // Load all materials
+   AssimpAppMaterial::sDefaultMatNumber = 0;
+   for (unsigned int i = 0; i < mScene->mNumMaterials; ++i) {
+      AppMesh::appMaterials.push_back(new AssimpAppMaterial(mScene->mMaterials[i]));
+   }
 
-      // Setup LOD checks
-      detectDetails();
+   // Setup LOD checks
+   detectDetails();
 
-      // Define the root node, and process down the chain.
-      AssimpAppNode* node = new AssimpAppNode(mScene, mScene->mRootNode, 0);
-      
-      if (!processNode(node))
-         delete node;
+   // Process the scene graph
+   AssimpAppNode* rootNode = new AssimpAppNode(mScene, mScene->mRootNode, 0);
+   if (!processNode(rootNode)) {
+      delete rootNode;
+   }
 
-      // add bounds node.
-      if (!boundsNode)
-      {
-         aiNode* req[1];
-         req[0] = new aiNode("bounds");
-         mScene->mRootNode->addChildren(1, req);
+   // Add a bounds node if none exists
+   if (!boundsNode) {
+      aiNode* req[1];
+      req[0] = new aiNode("bounds");
+      mScene->mRootNode->addChildren(1, req);
 
-         AssimpAppNode* appBounds = new AssimpAppNode(mScene, req[0]);
-         if (!processNode(appBounds))
-            delete appBounds;
+      auto* appBoundsNode = new AssimpAppNode(mScene, req[0]);
+      if (!processNode(appBoundsNode)) {
+         delete appBoundsNode;
       }
-
-      // Check for animations and process those.
-      processAnimations();
-   } 
-   else 
-   {
-      TSShapeLoader::updateProgress(TSShapeLoader::Load_Complete, "Import failed");
-      Con::printf("[ASSIMP] Import Error: %s", aiGetErrorString());
    }
 
+   // Process animations if available
+   processAnimations();
+
+   // Clean up log stream
    aiDetachLogStream(&shapeLog);
 }
 
+void AssimpShapeLoader::configureImportUnitsAndAxis() {
+   auto& options = ColladaUtils::getOptions();
+
+   // Configure unit scaling
+   if (options.unit <= 0.0f) {
+      F64 unitScaleFactor = 1.0;
+      if (!getMetaDouble("UnitScaleFactor", unitScaleFactor)) {
+         float floatVal;
+         int intVal;
+         if (getMetaFloat("UnitScaleFactor", floatVal)) {
+            unitScaleFactor = static_cast<F64>(floatVal);
+         }
+         else if (getMetaInt("UnitScaleFactor", intVal)) {
+            unitScaleFactor = static_cast<F64>(intVal);
+         }
+      }
+      options.unit = static_cast<float>(unitScaleFactor);
+   }
+
+   // Configure up-axis
+   if (options.upAxis == UPAXISTYPE_COUNT) {
+      int upAxis = UPAXISTYPE_Z_UP;
+      if (getMetaInt("UpAxis", upAxis)) {
+         options.upAxis = static_cast<domUpAxisType>(upAxis);
+      }
+   }
+}
+
 void AssimpShapeLoader::processAnimations()
 {
    // add all animations into 1 ambient animation.
@@ -266,6 +353,7 @@ void AssimpShapeLoader::processAnimations()
       for (U32 i = 0; i < mScene->mNumAnimations; ++i)
       {
          aiAnimation* anim = mScene->mAnimations[i];
+         duration = anim->mDuration;
          for (U32 j = 0; j < anim->mNumChannels; j++)
          {
             aiNodeAnim* nodeAnim = anim->mChannels[j];

+ 4 - 1
Engine/source/ts/assimp/assimpShapeLoader.h

@@ -26,6 +26,7 @@
 #ifndef _TSSHAPELOADER_H_
 #include "ts/loader/tsShapeLoader.h"
 #endif
+#include <assimp/Importer.hpp>
 #include <assimp/texture.h>
 
 class GuiTreeViewCtrl;
@@ -37,7 +38,8 @@ class AssimpShapeLoader : public TSShapeLoader
    friend TSShape* assimpLoadShape(const Torque::Path &path);
 
 protected:
-   const struct aiScene* mScene;
+   Assimp::Importer mImporter;
+   const aiScene* mScene;
 
    bool ignoreNode(const String& name) override;
    bool ignoreMesh(const String& name) override;
@@ -59,6 +61,7 @@ public:
 
    void releaseImport();
    void enumerateScene() override;
+   void configureImportUnitsAndAxis();
    void updateMaterialsScript(const Torque::Path &path);
    void processAnimations();