SceneSystem.cpp 9.2 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/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_ReadRootTransformKey = "/O3DE/Preferences/SceneAPI/AssImpReadRootTransform";
  29. bool readRootTransform = false;
  30. if (AZ::SettingsRegistryInterface* settingsRegistry = AZ::SettingsRegistry::Get())
  31. {
  32. settingsRegistry->Get(readRootTransform, s_ReadRootTransformKey);
  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 (readRootTransform)
  60. {
  61. AZ::Matrix3x4 adjustmatrix = AZ::Matrix3x4::CreateZero();
  62. // for FBX, root transform is not converted where there are no meshes in the scene.
  63. if ((assImpScene->GetAssImpScene()->mFlags & AI_SCENE_FLAGS_INCOMPLETE)
  64. && assImpScene->GetAssImpScene()->mMetaData->HasKey("UpAxis"))
  65. {
  66. auto upAxisAndSign = assImpScene->GetUpVectorAndSign();
  67. auto frontAxisAndSign = assImpScene->GetFrontVectorAndSign();
  68. auto rightAxisAndSign = assImpScene->GetRightVectorAndSign();
  69. // Set transform matrix with basis vector (-right, front, up)
  70. adjustmatrix.SetElement(0, (int)rightAxisAndSign.first, -(float)rightAxisAndSign.second);
  71. adjustmatrix.SetElement(1, (int)frontAxisAndSign.first, (float)frontAxisAndSign.second);
  72. adjustmatrix.SetElement(2, (int)upAxisAndSign.first, (float)upAxisAndSign.second);
  73. }
  74. else
  75. {
  76. // 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).
  77. adjustmatrix = AZ::Matrix3x4::CreateFromRows(
  78. AZ::Vector4(-1, 0, 0, 0),
  79. AZ::Vector4(0, 0, 1, 0),
  80. AZ::Vector4(0, 1, 0, 0)
  81. );
  82. }
  83. m_adjustTransform.reset(new DataTypes::MatrixType(adjustmatrix * rootTransform));
  84. m_adjustTransformInverse.reset(new DataTypes::MatrixType(m_adjustTransform->GetInverseFull()));
  85. return;
  86. }
  87. AZStd::pair<AssImpSDKWrapper::AssImpSceneWrapper::AxisVector, int32_t> upAxisAndSign = assImpScene->GetUpVectorAndSign();
  88. if (upAxisAndSign.second <= 0)
  89. {
  90. AZ_TracePrintf(SceneAPI::Utilities::ErrorWindow, "Negative scene orientation is not a currently supported orientation.");
  91. return;
  92. }
  93. AZStd::pair<AssImpSDKWrapper::AssImpSceneWrapper::AxisVector, int32_t> frontAxisAndSign = assImpScene->GetFrontVectorAndSign();
  94. if (upAxisAndSign.first != AssImpSDKWrapper::AssImpSceneWrapper::AxisVector::Z &&
  95. upAxisAndSign.first != AssImpSDKWrapper::AssImpSceneWrapper::AxisVector::Unknown)
  96. {
  97. AZ::Matrix4x4 currentCoordMatrix = AZ::Matrix4x4::CreateIdentity();
  98. //(UpVector = +Z, FrontVector = +Y, CoordSystem = -X(RightHanded))
  99. AZ::Matrix4x4 targetCoordMatrix = AZ::Matrix4x4::CreateFromColumns(
  100. AZ::Vector4(-1, 0, 0, 0),
  101. AZ::Vector4(0, 0, 1, 0),
  102. AZ::Vector4(0, 1, 0, 0),
  103. AZ::Vector4(0, 0, 0, 1));
  104. switch (upAxisAndSign.first)
  105. {
  106. case AssImpSDKWrapper::AssImpSceneWrapper::AxisVector::X: {
  107. if (frontAxisAndSign.second == 1)
  108. {
  109. currentCoordMatrix = AZ::Matrix4x4::CreateFromColumns(
  110. AZ::Vector4(0, -1, 0, 0),
  111. AZ::Vector4(1, 0, 0, 0),
  112. AZ::Vector4(0, 0, 1, 0),
  113. AZ::Vector4(0, 0, 0, 1));
  114. }
  115. else
  116. {
  117. currentCoordMatrix = AZ::Matrix4x4::CreateFromColumns(
  118. AZ::Vector4(0, 1, 0, 0),
  119. AZ::Vector4(1, 0, 0, 0),
  120. AZ::Vector4(0, 0, -1, 0),
  121. AZ::Vector4(0, 0, 0, 1));
  122. }
  123. }
  124. break;
  125. case AssImpSDKWrapper::AssImpSceneWrapper::AxisVector::Y: {
  126. if (frontAxisAndSign.second == 1)
  127. {
  128. currentCoordMatrix = AZ::Matrix4x4::CreateFromColumns(
  129. AZ::Vector4(1, 0, 0, 0),
  130. AZ::Vector4(0, 1, 0, 0),
  131. AZ::Vector4(0, 0, 1, 0),
  132. AZ::Vector4(0, 0, 0, 1));
  133. }
  134. else
  135. {
  136. currentCoordMatrix = AZ::Matrix4x4::CreateFromColumns(
  137. AZ::Vector4(-1, 0, 0, 0),
  138. AZ::Vector4(0, 1, 0, 0),
  139. AZ::Vector4(0, 0, -1, 0),
  140. AZ::Vector4(0, 0, 0, 1));
  141. }
  142. }
  143. break;
  144. }
  145. AZ::Matrix4x4 adjustmatrix = targetCoordMatrix * currentCoordMatrix.GetInverseTransform();
  146. m_adjustTransform.reset(new DataTypes::MatrixType(AssImpSDKWrapper::AssImpTypeConverter::ToTransform(adjustmatrix)));
  147. m_adjustTransformInverse.reset(new DataTypes::MatrixType(m_adjustTransform->GetInverseFull()));
  148. }
  149. }
  150. void SceneSystem::SwapVec3ForUpAxis(Vector3& swapVector) const
  151. {
  152. if (m_adjustTransform)
  153. {
  154. swapVector = *m_adjustTransform * swapVector;
  155. }
  156. }
  157. void SceneSystem::SwapTransformForUpAxis(DataTypes::MatrixType& inOutTransform) const
  158. {
  159. if (m_adjustTransform)
  160. {
  161. inOutTransform = (*m_adjustTransform * inOutTransform) * *m_adjustTransformInverse;
  162. }
  163. }
  164. void SceneSystem::ConvertUnit(Vector3& scaleVector) const
  165. {
  166. scaleVector *= m_unitSizeInMeters;
  167. }
  168. void SceneSystem::ConvertUnit(DataTypes::MatrixType& inOutTransform) const
  169. {
  170. Vector3 translation = inOutTransform.GetTranslation();
  171. translation *= m_unitSizeInMeters;
  172. inOutTransform.SetTranslation(translation);
  173. }
  174. void SceneSystem::ConvertBoneUnit(DataTypes::MatrixType& inOutTransform) const
  175. {
  176. // Need to scale translation explicitly as MultiplyByScale won't change the translation component
  177. // and we need to convert to meter unit
  178. Vector3 translation = inOutTransform.GetTranslation();
  179. translation *= m_unitSizeInMeters;
  180. inOutTransform.SetTranslation(translation);
  181. }
  182. }
  183. }