SceneSystem.cpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  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/Math/Vector3.h>
  9. #include <AzCore/Settings/SettingsRegistry.h>
  10. #include <SceneAPI/SceneBuilder/SceneSystem.h>
  11. #include <SceneAPI/SceneCore/Utilities/Reporting.h>
  12. #include <SceneAPI/SDKWrapper/AssImpSceneWrapper.h>
  13. #include <SceneAPI/SDKWrapper/AssImpTypeConverter.h>
  14. #include <assimp/scene.h>
  15. namespace AZ
  16. {
  17. namespace SceneAPI
  18. {
  19. SceneSystem::SceneSystem() :
  20. m_unitSizeInMeters(1.0f),
  21. m_originalUnitSizeInMeters(1.0f),
  22. m_adjustTransform(nullptr),
  23. m_adjustTransformInverse(nullptr)
  24. {
  25. }
  26. void SceneSystem::Set(const SDKScene::SceneWrapperBase* scene)
  27. {
  28. static constexpr const char* s_UseNewAssimpBehaviorKey = "/O3DE/Preferences/SceneAPI/AssImpReadRootTransform";
  29. bool useNewAssimpBehavior{ false };
  30. if (AZ::SettingsRegistryInterface* settingsRegistry = AZ::SettingsRegistry::Get())
  31. {
  32. settingsRegistry->Get(useNewAssimpBehavior, s_UseNewAssimpBehaviorKey);
  33. }
  34. // Get unit conversion factor to meter.
  35. if (!azrtti_istypeof<AssImpSDKWrapper::AssImpSceneWrapper>(scene))
  36. {
  37. return;
  38. }
  39. const AssImpSDKWrapper::AssImpSceneWrapper* assImpScene = azrtti_cast<const AssImpSDKWrapper::AssImpSceneWrapper*>(scene);
  40. DataTypes::MatrixType rootTransform = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(assImpScene->GetAssImpScene()->mRootNode->mTransformation);
  41. /* Check if metadata has information about "UnitScaleFactor" or "OriginalUnitScaleFactor".
  42. * This particular metadata is FBX format only. */
  43. if (assImpScene->GetAssImpScene()->mMetaData->HasKey("UnitScaleFactor") ||
  44. assImpScene->GetAssImpScene()->mMetaData->HasKey("OriginalUnitScaleFactor"))
  45. {
  46. // If either metadata piece is not available, the default of 1 will be used.
  47. assImpScene->GetAssImpScene()->mMetaData->Get("UnitScaleFactor", m_unitSizeInMeters);
  48. assImpScene->GetAssImpScene()->mMetaData->Get("OriginalUnitScaleFactor", m_originalUnitSizeInMeters);
  49. /* Conversion factor for converting from centimeters to meters.
  50. * This applies to an FBX format in which the default unit is a centimeter. */
  51. m_unitSizeInMeters = m_unitSizeInMeters * .01f;
  52. }
  53. else
  54. {
  55. // Some file formats (like DAE) embed the scale in the root transformation, so extract that scale from here.
  56. m_unitSizeInMeters = rootTransform.ExtractScale().GetMaxElement();
  57. rootTransform /= m_unitSizeInMeters;
  58. }
  59. if (useNewAssimpBehavior)
  60. {
  61. // AssImp SDK internally uses a Y-up coordinate system, so we need to adjust the coordinate system to match the O3DE coordinate system (Z-up).
  62. AZ::Matrix3x4 adjustmatrix = AZ::Matrix3x4::CreateFromRows(
  63. AZ::Vector4(1, 0, 0, 0),
  64. AZ::Vector4(0, 0, -1, 0),
  65. AZ::Vector4(0, 1, 0, 0)
  66. );
  67. m_adjustTransform.reset(new DataTypes::MatrixType(adjustmatrix * rootTransform));
  68. m_adjustTransformInverse.reset(new DataTypes::MatrixType(m_adjustTransform->GetInverseFull()));
  69. return;
  70. }
  71. AZStd::pair<AssImpSDKWrapper::AssImpSceneWrapper::AxisVector, int32_t> upAxisAndSign = assImpScene->GetUpVectorAndSign();
  72. if (upAxisAndSign.second <= 0)
  73. {
  74. AZ_TracePrintf(SceneAPI::Utilities::ErrorWindow, "Negative scene orientation is not a currently supported orientation.");
  75. return;
  76. }
  77. AZStd::pair<AssImpSDKWrapper::AssImpSceneWrapper::AxisVector, int32_t> frontAxisAndSign = assImpScene->GetFrontVectorAndSign();
  78. if (upAxisAndSign.first != AssImpSDKWrapper::AssImpSceneWrapper::AxisVector::Z &&
  79. upAxisAndSign.first != AssImpSDKWrapper::AssImpSceneWrapper::AxisVector::Unknown)
  80. {
  81. AZ::Matrix4x4 currentCoordMatrix = AZ::Matrix4x4::CreateIdentity();
  82. //(UpVector = +Z, FrontVector = +Y, CoordSystem = -X(RightHanded))
  83. AZ::Matrix4x4 targetCoordMatrix = AZ::Matrix4x4::CreateFromColumns(
  84. AZ::Vector4(-1, 0, 0, 0),
  85. AZ::Vector4(0, 0, 1, 0),
  86. AZ::Vector4(0, 1, 0, 0),
  87. AZ::Vector4(0, 0, 0, 1));
  88. switch (upAxisAndSign.first)
  89. {
  90. case AssImpSDKWrapper::AssImpSceneWrapper::AxisVector::X: {
  91. if (frontAxisAndSign.second == 1)
  92. {
  93. currentCoordMatrix = AZ::Matrix4x4::CreateFromColumns(
  94. AZ::Vector4(0, -1, 0, 0),
  95. AZ::Vector4(1, 0, 0, 0),
  96. AZ::Vector4(0, 0, 1, 0),
  97. AZ::Vector4(0, 0, 0, 1));
  98. }
  99. else
  100. {
  101. currentCoordMatrix = AZ::Matrix4x4::CreateFromColumns(
  102. AZ::Vector4(0, 1, 0, 0),
  103. AZ::Vector4(1, 0, 0, 0),
  104. AZ::Vector4(0, 0, -1, 0),
  105. AZ::Vector4(0, 0, 0, 1));
  106. }
  107. }
  108. break;
  109. case AssImpSDKWrapper::AssImpSceneWrapper::AxisVector::Y: {
  110. if (frontAxisAndSign.second == 1)
  111. {
  112. currentCoordMatrix = AZ::Matrix4x4::CreateFromColumns(
  113. AZ::Vector4(1, 0, 0, 0),
  114. AZ::Vector4(0, 1, 0, 0),
  115. AZ::Vector4(0, 0, 1, 0),
  116. AZ::Vector4(0, 0, 0, 1));
  117. }
  118. else
  119. {
  120. currentCoordMatrix = AZ::Matrix4x4::CreateFromColumns(
  121. AZ::Vector4(-1, 0, 0, 0),
  122. AZ::Vector4(0, 1, 0, 0),
  123. AZ::Vector4(0, 0, -1, 0),
  124. AZ::Vector4(0, 0, 0, 1));
  125. }
  126. }
  127. break;
  128. }
  129. AZ::Matrix4x4 adjustmatrix = targetCoordMatrix * currentCoordMatrix.GetInverseTransform();
  130. m_adjustTransform.reset(new DataTypes::MatrixType(AssImpSDKWrapper::AssImpTypeConverter::ToTransform(adjustmatrix)));
  131. m_adjustTransformInverse.reset(new DataTypes::MatrixType(m_adjustTransform->GetInverseFull()));
  132. }
  133. }
  134. void SceneSystem::SwapVec3ForUpAxis(Vector3& swapVector) const
  135. {
  136. if (m_adjustTransform)
  137. {
  138. swapVector = *m_adjustTransform * swapVector;
  139. }
  140. }
  141. void SceneSystem::SwapTransformForUpAxis(DataTypes::MatrixType& inOutTransform) const
  142. {
  143. if (m_adjustTransform)
  144. {
  145. inOutTransform = (*m_adjustTransform * inOutTransform) * *m_adjustTransformInverse;
  146. }
  147. }
  148. void SceneSystem::ConvertUnit(Vector3& scaleVector) const
  149. {
  150. scaleVector *= m_unitSizeInMeters;
  151. }
  152. void SceneSystem::ConvertUnit(DataTypes::MatrixType& inOutTransform) const
  153. {
  154. Vector3 translation = inOutTransform.GetTranslation();
  155. translation *= m_unitSizeInMeters;
  156. inOutTransform.SetTranslation(translation);
  157. }
  158. void SceneSystem::ConvertBoneUnit(DataTypes::MatrixType& inOutTransform) const
  159. {
  160. // Need to scale translation explicitly as MultiplyByScale won't change the translation component
  161. // and we need to convert to meter unit
  162. Vector3 translation = inOutTransform.GetTranslation();
  163. translation *= m_unitSizeInMeters;
  164. inOutTransform.SetTranslation(translation);
  165. }
  166. }
  167. }