AssImpSceneWrapper.cpp 9.4 KB

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