AssImpSceneWrapper.cpp 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <AzCore/Debug/Trace.h>
  9. #include <AzCore/Settings/SettingsRegistry.h>
  10. #include <AzToolsFramework/Debug/TraceContext.h>
  11. #include <SceneAPI/SceneCore/Utilities/Reporting.h>
  12. #include <SceneAPI/SDKWrapper/AssImpSceneWrapper.h>
  13. #include <SceneAPI/SDKWrapper/AssImpNodeWrapper.h>
  14. #include <assimp/postprocess.h>
  15. #if AZ_TRAIT_COMPILER_SUPPORT_CSIGNAL
  16. #include <csignal>
  17. #include <cstdlib>
  18. #include <iostream>
  19. #include <stdlib.h>
  20. #endif // AZ_TRAIT_COMPILER_SUPPORT_CSIGNAL
  21. namespace AZ
  22. {
  23. namespace AssImpSDKWrapper
  24. {
  25. static constexpr const char s_UseSkeletonBoneContainerKey[] = "/O3DE/Preferences/SceneAPI/UseSkeletonBoneContainer";
  26. AssImpSceneWrapper::AssImpSceneWrapper()
  27. : m_assImpScene(nullptr)
  28. , m_importer(AZStd::make_unique<Assimp::Importer>())
  29. {
  30. }
  31. AssImpSceneWrapper::AssImpSceneWrapper(aiScene* aiScene)
  32. : m_assImpScene(aiScene)
  33. , m_importer(AZStd::make_unique<Assimp::Importer>())
  34. {
  35. }
  36. #if AZ_TRAIT_COMPILER_SUPPORT_CSIGNAL
  37. void signal_handler([[maybe_unused]] int signal)
  38. {
  39. AZ_TracePrintf(
  40. SceneAPI::Utilities::ErrorWindow,
  41. "Failed to import scene with Asset Importer library. An %s has occurred in the library, this scene file cannot be parsed by the library.",
  42. signal == SIGABRT ? "assert" : "unknown error");
  43. }
  44. #endif // AZ_TRAIT_COMPILER_SUPPORT_CSIGNAL
  45. bool AssImpSceneWrapper::LoadSceneFromFile(const char* fileName, const AZ::SceneAPI::SceneImportSettings& importSettings)
  46. {
  47. AZ_TracePrintf(SceneAPI::Utilities::LogWindow, "AssImpSceneWrapper::LoadSceneFromFile %s", fileName);
  48. AZ_TraceContext("Filename", fileName);
  49. #if AZ_TRAIT_COMPILER_SUPPORT_CSIGNAL
  50. // Turn off the abort popup because it can disrupt automation.
  51. // AssImp calls abort when asserts are enabled, and an assert is encountered.
  52. #ifdef _WRITE_ABORT_MSG
  53. _set_abort_behavior(0, _WRITE_ABORT_MSG);
  54. #endif // #ifdef _WRITE_ABORT_MSG
  55. // Instead, capture any calls to abort with a signal handler, and report them.
  56. auto previous_handler = std::signal(SIGABRT, signal_handler);
  57. #endif // AZ_TRAIT_COMPILER_SUPPORT_CSIGNAL
  58. bool useSkeletonBoneContainer = false;
  59. if (AZ::SettingsRegistryInterface* settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry)
  60. {
  61. settingsRegistry->Get(useSkeletonBoneContainer, s_UseSkeletonBoneContainerKey);
  62. }
  63. // aiProcess_JoinIdenticalVertices is not enabled because O3DE has a mesh optimizer that also does this,
  64. // this flag is disabled to keep AssImp output similar to FBX SDK to reduce downstream bugs for the initial AssImp release.
  65. // There's currently a minimum of properties and flags set to maximize compatibility with the existing node graph.
  66. unsigned int importFlags =
  67. aiProcess_Triangulate // Triangulates all faces of all meshes
  68. | static_cast<unsigned long>(aiProcess_GenBoundingBoxes) // Generate bounding boxes
  69. | aiProcess_GenNormals // Generate normals for meshes
  70. | (importSettings.m_optimizeScene ? aiProcess_OptimizeGraph : 0) // Merge excess scene nodes together
  71. | (importSettings.m_optimizeMeshes ? aiProcess_OptimizeMeshes : 0) // Combines meshes in the scene together
  72. ;
  73. // aiProcess_LimitBoneWeights is not enabled because it will remove bones which are not associated with a mesh.
  74. // This results in the loss of the offset matrix data for nodes without a mesh which is required for the Transform Importer.
  75. m_importer->SetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, false);
  76. m_importer->SetPropertyBool(AI_CONFIG_IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES, false);
  77. m_importer->SetPropertyBool(AI_CONFIG_FBX_USE_SKELETON_BONE_CONTAINER, useSkeletonBoneContainer);
  78. // The remove empty bones flag is on by default, but doesn't do anything internal to AssImp right now.
  79. // This is here as a bread crumb to save others times investigating issues with empty bones.
  80. // m_importer.SetPropertyBool(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, false);
  81. m_sceneFileName = fileName;
  82. m_assImpScene = m_importer->ReadFile(fileName, importFlags);
  83. #if AZ_TRAIT_COMPILER_SUPPORT_CSIGNAL
  84. // Reset abort behavior for anything else that may call abort.
  85. std::signal(SIGABRT, previous_handler);
  86. #ifdef _WRITE_ABORT_MSG
  87. _set_abort_behavior(1, _WRITE_ABORT_MSG);
  88. #endif // #ifdef _WRITE_ABORT_MSG
  89. #endif // AZ_TRAIT_COMPILER_SUPPORT_CSIGNAL
  90. if (!m_assImpScene)
  91. {
  92. AZ_TracePrintf(SceneAPI::Utilities::ErrorWindow, "Failed to import Asset Importer Scene. Error returned: %s", m_importer->GetErrorString());
  93. return false;
  94. }
  95. CalculateAABBandVertices(m_assImpScene, m_aabb, m_vertices);
  96. return true;
  97. }
  98. bool AssImpSceneWrapper::LoadSceneFromFile(const AZStd::string& fileName, const AZ::SceneAPI::SceneImportSettings& importSettings)
  99. {
  100. return LoadSceneFromFile(fileName.c_str(), importSettings);
  101. }
  102. const std::shared_ptr<SDKNode::NodeWrapper> AssImpSceneWrapper::GetRootNode() const
  103. {
  104. return std::shared_ptr<SDKNode::NodeWrapper>(new AssImpNodeWrapper(m_assImpScene->mRootNode));
  105. }
  106. std::shared_ptr<SDKNode::NodeWrapper> AssImpSceneWrapper::GetRootNode()
  107. {
  108. return std::shared_ptr<SDKNode::NodeWrapper>(new AssImpNodeWrapper(m_assImpScene->mRootNode));
  109. }
  110. void AssImpSceneWrapper::CalculateAABBandVertices(const aiScene* scene, aiAABB& aabb, uint32_t& vertices)
  111. {
  112. if (scene->HasMeshes())
  113. {
  114. aabb = scene->mMeshes[0]->mAABB;
  115. vertices = scene->mMeshes[0]->mNumVertices;
  116. for (unsigned int i = 1; i < scene->mNumMeshes; ++i)
  117. {
  118. const aiAABB& thisAabb = scene->mMeshes[i]->mAABB;
  119. if (thisAabb.mMin.x < aabb.mMin.x)
  120. aabb.mMin.x = thisAabb.mMin.x;
  121. if (thisAabb.mMin.y < aabb.mMin.y)
  122. aabb.mMin.y = thisAabb.mMin.y;
  123. if (thisAabb.mMin.z < aabb.mMin.z)
  124. aabb.mMin.z = thisAabb.mMin.z;
  125. if (thisAabb.mMax.x > aabb.mMax.x)
  126. aabb.mMax.x = thisAabb.mMax.x;
  127. if (thisAabb.mMax.y > aabb.mMax.y)
  128. aabb.mMax.y = thisAabb.mMax.y;
  129. if (thisAabb.mMax.z > aabb.mMax.z)
  130. aabb.mMax.z = thisAabb.mMax.z;
  131. vertices += scene->mMeshes[i]->mNumVertices;
  132. }
  133. }
  134. }
  135. void AssImpSceneWrapper::Clear()
  136. {
  137. if(m_importer)
  138. {
  139. m_importer->FreeScene();
  140. m_importer = AZStd::make_unique<Assimp::Importer>();
  141. }
  142. }
  143. const aiScene* AssImpSceneWrapper::GetAssImpScene() const
  144. {
  145. return m_assImpScene;
  146. }
  147. AZStd::pair<AssImpSceneWrapper::AxisVector, int32_t> AssImpSceneWrapper::GetUpVectorAndSign() const
  148. {
  149. AZStd::pair<AssImpSceneWrapper::AxisVector, int32_t> result(AxisVector::Z, 1);
  150. int32_t upVectorRead(static_cast<int32_t>(result.first));
  151. m_assImpScene->mMetaData->Get("UpAxis", upVectorRead);
  152. m_assImpScene->mMetaData->Get("UpAxisSign", result.second);
  153. result.first = static_cast<AssImpSceneWrapper::AxisVector>(upVectorRead);
  154. return result;
  155. }
  156. AZStd::pair<AssImpSceneWrapper::AxisVector, int32_t> AssImpSceneWrapper::GetFrontVectorAndSign() const
  157. {
  158. AZStd::pair<AssImpSceneWrapper::AxisVector, int32_t> result(AxisVector::Y, 1);
  159. int32_t frontVectorRead(static_cast<int32_t>(result.first));
  160. m_assImpScene->mMetaData->Get("FrontAxis", frontVectorRead);
  161. m_assImpScene->mMetaData->Get("FrontAxisSign", result.second);
  162. result.first = static_cast<AssImpSceneWrapper::AxisVector>(frontVectorRead);
  163. return result;
  164. }
  165. }//namespace AssImpSDKWrapper
  166. } // namespace AZ