SceneImporter.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  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/Casting/numeric_cast.h>
  9. #include <AzCore/Debug/Trace.h>
  10. #include <AzCore/Math/Transform.h>
  11. #include <AzCore/Serialization/SerializeContext.h>
  12. #include <AzCore/Settings/SettingsRegistry.h>
  13. #include <AzCore/std/containers/queue.h>
  14. #include <AzCore/std/string/string.h>
  15. #include <AzCore/std/string/conversions.h>
  16. #include <AzCore/std/smart_ptr/make_shared.h>
  17. #include <AzToolsFramework/Debug/TraceContext.h>
  18. #include <SceneAPI/SceneBuilder/SceneImporter.h>
  19. #include <SceneAPI/SceneBuilder/ImportContexts/AssImpImportContexts.h>
  20. #include <SceneAPI/SceneBuilder/Importers/AssImpMaterialImporter.h>
  21. #include <SceneAPI/SceneBuilder/Importers/ImporterUtilities.h>
  22. #include <SceneAPI/SceneBuilder/Importers/Utilities/RenamedNodesMap.h>
  23. #include <SceneAPI/SceneCore/Containers/Scene.h>
  24. #include <SceneAPI/SceneCore/DataTypes/Groups/IImportGroup.h>
  25. #include <SceneAPI/SceneCore/Import/ManifestImportRequestHandler.h>
  26. #include <SceneAPI/SceneCore/Utilities/Reporting.h>
  27. #include <SceneAPI/SceneData/GraphData/TransformData.h>
  28. #include <SceneAPI/SDKWrapper/AssImpSceneWrapper.h>
  29. #include <SceneAPI/SDKWrapper/AssImpNodeWrapper.h>
  30. namespace AZ
  31. {
  32. namespace SceneAPI
  33. {
  34. namespace SceneBuilder
  35. {
  36. struct QueueNode
  37. {
  38. std::shared_ptr<SDKNode::NodeWrapper> m_node;
  39. Containers::SceneGraph::NodeIndex m_parent;
  40. QueueNode() = delete;
  41. QueueNode(std::shared_ptr<SDKNode::NodeWrapper>&& node, Containers::SceneGraph::NodeIndex parent)
  42. : m_node(std::move(node))
  43. , m_parent(parent)
  44. {
  45. }
  46. };
  47. SceneImporter::SceneImporter()
  48. : m_sceneSystem(new SceneSystem())
  49. {
  50. m_sceneWrapper = AZStd::make_unique<AssImpSDKWrapper::AssImpSceneWrapper>();
  51. BindToCall(&SceneImporter::ImportProcessing);
  52. }
  53. void SceneImporter::Reflect(ReflectContext* context)
  54. {
  55. SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
  56. if (serializeContext)
  57. {
  58. serializeContext->Class<SceneImporter, SceneCore::LoadingComponent>()->Version(2); // SPEC-5776
  59. }
  60. }
  61. SceneAPI::SceneImportSettings SceneImporter::GetSceneImportSettings(const AZStd::string& sourceAssetPath) const
  62. {
  63. // Start with a default set of import settings.
  64. SceneAPI::SceneImportSettings importSettings;
  65. // Try to read in any global settings from the settings registry.
  66. if (AZ::SettingsRegistryInterface* settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry)
  67. {
  68. settingsRegistry->GetObject(importSettings, AZ::SceneAPI::DataTypes::IImportGroup::SceneImportSettingsRegistryKey);
  69. }
  70. // Try reading in the scene manifest (.assetinfo file), which contains the import settings if they've been
  71. // changed from the defaults.
  72. Containers::Scene scene;
  73. Import::ManifestImportRequestHandler manifestHandler;
  74. manifestHandler.LoadAsset(
  75. scene, sourceAssetPath,
  76. Uuid::CreateNull(),
  77. Events::AssetImportRequest::RequestingApplication::AssetProcessor);
  78. // Search for the ImportGroup. If it's there, get the new import settings. If not, we'll just use the defaults.
  79. size_t count = scene.GetManifest().GetEntryCount();
  80. for (size_t index = 0; index < count; index++)
  81. {
  82. if (auto* importGroup = azrtti_cast<DataTypes::IImportGroup*>(scene.GetManifest().GetValue(index).get()); importGroup)
  83. {
  84. importSettings = importGroup->GetImportSettings();
  85. break;
  86. }
  87. }
  88. return importSettings;
  89. }
  90. Events::ProcessingResult SceneImporter::ImportProcessing(Events::ImportEventContext& context)
  91. {
  92. SceneAPI::SceneImportSettings importSettings = GetSceneImportSettings(context.GetInputDirectory());
  93. m_sceneWrapper->Clear();
  94. if (!m_sceneWrapper->LoadSceneFromFile(context.GetInputDirectory().c_str(), importSettings))
  95. {
  96. return Events::ProcessingResult::Failure;
  97. }
  98. m_sceneSystem->Set(m_sceneWrapper.get());
  99. if (!azrtti_istypeof<AssImpSDKWrapper::AssImpSceneWrapper>(m_sceneWrapper.get()))
  100. {
  101. return Events::ProcessingResult::Failure;
  102. }
  103. if (ConvertScene(context.GetScene()))
  104. {
  105. return Events::ProcessingResult::Success;
  106. }
  107. else
  108. {
  109. return Events::ProcessingResult::Failure;
  110. }
  111. }
  112. bool SceneImporter::ConvertScene(Containers::Scene& scene) const
  113. {
  114. std::shared_ptr<SDKNode::NodeWrapper> sceneRoot = m_sceneWrapper->GetRootNode();
  115. if (!sceneRoot)
  116. {
  117. return false;
  118. }
  119. const AssImpSDKWrapper::AssImpSceneWrapper* assImpSceneWrapper = azrtti_cast <AssImpSDKWrapper::AssImpSceneWrapper*>(m_sceneWrapper.get());
  120. AZStd::pair<AssImpSDKWrapper::AssImpSceneWrapper::AxisVector, int32_t> upAxisAndSign = assImpSceneWrapper->GetUpVectorAndSign();
  121. const aiAABB& aabb = assImpSceneWrapper->GetAABB();
  122. aiVector3t dimension = aabb.mMax - aabb.mMin;
  123. Vector3 t{ dimension.x, dimension.y, dimension.z };
  124. scene.SetSceneDimension(t);
  125. scene.SetSceneVertices(assImpSceneWrapper->GetVertices());
  126. if (upAxisAndSign.second <= 0)
  127. {
  128. AZ_TracePrintf(SceneAPI::Utilities::ErrorWindow, "Negative scene orientation is not a currently supported orientation.");
  129. return false;
  130. }
  131. switch (upAxisAndSign.first)
  132. {
  133. case AssImpSDKWrapper::AssImpSceneWrapper::AxisVector::X:
  134. scene.SetOriginalSceneOrientation(Containers::Scene::SceneOrientation::XUp);
  135. break;
  136. case AssImpSDKWrapper::AssImpSceneWrapper::AxisVector::Y:
  137. scene.SetOriginalSceneOrientation(Containers::Scene::SceneOrientation::YUp);
  138. break;
  139. case AssImpSDKWrapper::AssImpSceneWrapper::AxisVector::Z:
  140. scene.SetOriginalSceneOrientation(Containers::Scene::SceneOrientation::ZUp);
  141. break;
  142. default:
  143. AZ_TracePrintf(SceneAPI::Utilities::ErrorWindow, "Unknown scene orientation, %d.", upAxisAndSign.first);
  144. AZ_Assert(false, "Unknown scene orientation, %d.", upAxisAndSign.first);
  145. break;
  146. }
  147. AZStd::queue<SceneBuilder::QueueNode> nodes;
  148. nodes.emplace(AZStd::move(sceneRoot), scene.GetGraph().GetRoot());
  149. RenamedNodesMap nodeNameMap;
  150. while (!nodes.empty())
  151. {
  152. SceneBuilder::QueueNode& node = nodes.front();
  153. AZ_Assert(node.m_node, "Empty asset importer node queued");
  154. if (!nodeNameMap.RegisterNode(node.m_node, scene.GetGraph(), node.m_parent))
  155. {
  156. AZ_TracePrintf(Utilities::ErrorWindow, "Failed to register asset importer node in name table.");
  157. // Skip this node since it could not be registered
  158. nodes.pop();
  159. continue;
  160. }
  161. AZStd::string nodeName = nodeNameMap.GetNodeName(node.m_node);
  162. SanitizeNodeName(nodeName);
  163. AZ_TraceContext("SceneAPI Node Name", nodeName);
  164. Containers::SceneGraph::NodeIndex newNode = scene.GetGraph().AddChild(node.m_parent, nodeName.c_str());
  165. AZ_Error(Utilities::ErrorWindow, newNode.IsValid(), "Failed to add Asset Importer node to scene graph");
  166. if (!newNode.IsValid())
  167. {
  168. continue;
  169. }
  170. AssImpNodeEncounteredContext sourceNodeEncountered(scene, newNode, *assImpSceneWrapper, *m_sceneSystem, nodeNameMap, *azrtti_cast<AZ::AssImpSDKWrapper::AssImpNodeWrapper*>(node.m_node.get()));
  171. Events::ProcessingResultCombiner nodeResult;
  172. nodeResult += Events::Process(sourceNodeEncountered);
  173. // If no importer created data, we still create an empty node that may eventually contain a transform
  174. if (sourceNodeEncountered.m_createdData.empty())
  175. {
  176. AZ_Assert(nodeResult.GetResult() != Events::ProcessingResult::Success,
  177. "Importers returned success but no data was created");
  178. AZStd::shared_ptr<DataTypes::IGraphObject> nullData(nullptr);
  179. sourceNodeEncountered.m_createdData.emplace_back(nullData);
  180. nodeResult += Events::ProcessingResult::Success;
  181. }
  182. // Create single node since only one piece of graph data was created
  183. if (sourceNodeEncountered.m_createdData.size() == 1)
  184. {
  185. AZ_Assert(nodeResult.GetResult() != Events::ProcessingResult::Ignored,
  186. "An importer created data, but did not return success");
  187. if (nodeResult.GetResult() == Events::ProcessingResult::Failure)
  188. {
  189. AZ_TracePrintf(Utilities::ErrorWindow, "One or more importers failed to create data.");
  190. }
  191. AssImpSceneDataPopulatedContext dataProcessed(sourceNodeEncountered,
  192. sourceNodeEncountered.m_createdData[0], nodeName.c_str());
  193. Events::ProcessingResult result = AddDataNodeWithContexts(dataProcessed);
  194. if (result != Events::ProcessingResult::Failure)
  195. {
  196. newNode = dataProcessed.m_currentGraphPosition;
  197. }
  198. }
  199. // Create an empty parent node and place all data under it. The remaining
  200. // tree will be built off of this as the logical parent
  201. else
  202. {
  203. AZ_Assert(nodeResult.GetResult() != Events::ProcessingResult::Ignored,
  204. "%i importers created data, but did not return success",
  205. sourceNodeEncountered.m_createdData.size());
  206. if (nodeResult.GetResult() == Events::ProcessingResult::Failure)
  207. {
  208. AZ_TracePrintf(Utilities::ErrorWindow, "One or more importers failed to create data.");
  209. }
  210. size_t offset = nodeName.length();
  211. for (size_t i = 0; i < sourceNodeEncountered.m_createdData.size(); ++i)
  212. {
  213. nodeName += '_';
  214. nodeName += AZStd::to_string(aznumeric_cast<AZ::u64>(i + 1));
  215. Containers::SceneGraph::NodeIndex subNode =
  216. scene.GetGraph().AddChild(newNode, nodeName.c_str());
  217. AZ_Assert(subNode.IsValid(), "Failed to create new scene sub node");
  218. AssImpSceneDataPopulatedContext dataProcessed(sourceNodeEncountered,
  219. sourceNodeEncountered.m_createdData[i], nodeName);
  220. dataProcessed.m_currentGraphPosition = subNode;
  221. AddDataNodeWithContexts(dataProcessed);
  222. // Remove the temporary extension again.
  223. nodeName.erase(offset, nodeName.length() - offset);
  224. }
  225. }
  226. AZ_Assert(nodeResult.GetResult() == Events::ProcessingResult::Success,
  227. "No importers successfully added processed scene data.");
  228. AZ_Assert(newNode != node.m_parent,
  229. "Failed to update current graph position during data processing.");
  230. int childCount = node.m_node->GetChildCount();
  231. for (int i = 0; i < childCount; ++i)
  232. {
  233. const std::shared_ptr<SDKNode::NodeWrapper> nodeWrapper = node.m_node->GetChild(i);
  234. auto assImpNodeWrapper = azrtti_cast<AssImpSDKWrapper::AssImpNodeWrapper*>(nodeWrapper.get());
  235. AZ_Assert(assImpNodeWrapper, "Child node is not the expected AssImpNodeWrapper type");
  236. std::shared_ptr<AssImpSDKWrapper::AssImpNodeWrapper> child = std::make_shared<AssImpSDKWrapper::AssImpNodeWrapper>(assImpNodeWrapper->GetAssImpNode());
  237. if (child)
  238. {
  239. nodes.emplace(AZStd::move(child), newNode);
  240. }
  241. }
  242. nodes.pop();
  243. };
  244. Events::ProcessingResult result = Events::Process<AssImpFinalizeSceneContext>(scene, *assImpSceneWrapper, *m_sceneSystem, nodeNameMap);
  245. if (result == Events::ProcessingResult::Failure)
  246. {
  247. return false;
  248. }
  249. return true;
  250. }
  251. void SceneImporter::SanitizeNodeName(AZStd::string& nodeName) const
  252. {
  253. // Replace % with something else so it is safe for use in printfs.
  254. AZStd::replace(nodeName.begin(), nodeName.end(), '%', '_');
  255. }
  256. } // namespace SceneBuilder
  257. } // namespace SceneAPI
  258. } // namespace AZ