SceneSystem.cpp 8.5 KB

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