SourceAssetsStorage.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513
  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 "SourceAssetsStorage.h"
  9. #include "RobotImporterUtils.h"
  10. #include <AzCore/IO/FileIO.h>
  11. #include <AzCore/Serialization/Json/JsonUtils.h>
  12. #include <AzCore/Utils/Utils.h>
  13. #include <AzCore/std/smart_ptr/make_shared.h>
  14. #include <AzCore/std/smart_ptr/shared_ptr.h>
  15. #include <AzToolsFramework/Asset/AssetUtils.h>
  16. #include <SceneAPI/SceneCore/Containers/Scene.h>
  17. #include <SceneAPI/SceneCore/Containers/Utilities/Filters.h>
  18. #include <SceneAPI/SceneCore/DataTypes/Groups/ISceneNodeGroup.h>
  19. #include <SceneAPI/SceneCore/Events/AssetImportRequest.h>
  20. #include <SceneAPI/SceneCore/Events/SceneSerializationBus.h>
  21. #include <SceneAPI/SceneCore/Utilities/SceneGraphSelector.h>
  22. #include <SceneAPI/SceneData/Groups/MeshGroup.h>
  23. #include <SceneAPI/SceneData/Rules/UVsRule.h>
  24. #include <Source/Pipeline/MeshGroup.h> // PhysX/Code/Source/Pipeline/MeshGroup.h
  25. namespace ROS2::Utils
  26. {
  27. //! A helper class that do no extend PhysX::Pipeline::MeshGroup functionality, but gives neccessary setters.
  28. class UrdfPhysxMeshGroupHelper : public PhysX::Pipeline::MeshGroup
  29. {
  30. public:
  31. void SetIsDecomposeMeshes(bool decompose)
  32. {
  33. m_decomposeMeshes = decompose;
  34. }
  35. void SetMeshExportMethod(PhysX::Pipeline::MeshExportMethod method)
  36. {
  37. m_exportMethod = method;
  38. }
  39. };
  40. //! Returns supported filenames by Asset Processor
  41. AZStd::vector<AZStd::string> GetSupportedExtensions()
  42. {
  43. struct Visitor : AZ::SettingsRegistryInterface::Visitor
  44. {
  45. using AZ::SettingsRegistryInterface::Visitor::Visit;
  46. void Visit(const AZ::SettingsRegistryInterface::VisitArgs&, AZStd::string_view value) override
  47. {
  48. m_supportedFileExtensions.emplace_back(value);
  49. }
  50. AZStd::vector<AZStd::string> m_supportedFileExtensions;
  51. };
  52. auto settingsRegistry = AZ::SettingsRegistry::Get();
  53. if (settingsRegistry == nullptr)
  54. {
  55. AZ_Warning("GetInterestingSourceAssetsCRC", false, "Global Settings Registry is not set.");
  56. return AZStd::vector<AZStd::string>();
  57. }
  58. using namespace AzToolsFramework::AssetUtils;
  59. Visitor assetImporterVisitor;
  60. settingsRegistry->Visit(
  61. assetImporterVisitor,
  62. AZ::SettingsRegistryInterface::FixedValueString("/O3DE/SceneAPI/AssetImporter/SupportedFileTypeExtensions"));
  63. return assetImporterVisitor.m_supportedFileExtensions;
  64. }
  65. /// Function computes CRC32 on first kilobyte of file.
  66. AZ::Crc32 GetFileCRC(const AZ::IO::Path& filename)
  67. {
  68. auto fileSize = AZ::IO::SystemFile::Length(filename.c_str());
  69. fileSize = AZStd::min(fileSize, 1024ull); // limit crc computation to first kilobyte
  70. if (fileSize == 0)
  71. {
  72. return AZ::Crc32();
  73. }
  74. AZStd::vector<char> buffer;
  75. buffer.resize_no_construct(fileSize + 1);
  76. buffer[fileSize] = '\0';
  77. if (!AZ::IO::SystemFile::Read(filename.c_str(), buffer.data(), fileSize))
  78. {
  79. return AZ::Crc32();
  80. }
  81. AZ::Crc32 r;
  82. r.Add(buffer.data(), fileSize);
  83. return r;
  84. }
  85. AZStd::string GetProductAsset(const AZ::Uuid& sourceAssetUUID, const AZ::TypeId typeId)
  86. {
  87. AZStd::vector<AZ::Data::AssetInfo> productsAssetInfo;
  88. using AssetSysReqBus = AzToolsFramework::AssetSystemRequestBus;
  89. bool ok{ false };
  90. AssetSysReqBus::BroadcastResult(ok, &AssetSysReqBus::Events::GetAssetsProducedBySourceUUID, sourceAssetUUID, productsAssetInfo);
  91. if (ok)
  92. {
  93. for (auto& product : productsAssetInfo)
  94. {
  95. if (product.m_assetType == typeId)
  96. {
  97. AZStd::string assetPath;
  98. AZ::Data::AssetCatalogRequestBus::BroadcastResult(
  99. assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, product.m_assetId);
  100. return assetPath;
  101. }
  102. }
  103. }
  104. return "";
  105. }
  106. AZStd::string GetModelProductAsset(const AZ::Uuid& sourceAssetUUID)
  107. {
  108. return GetProductAsset(sourceAssetUUID, AZ::TypeId("{2C7477B6-69C5-45BE-8163-BCD6A275B6D8}")); // AZ::RPI::ModelAsset;
  109. }
  110. AZStd::string GetPhysXMeshProductAsset(const AZ::Uuid& sourceAssetUUID)
  111. {
  112. return GetProductAsset(sourceAssetUUID, AZ::TypeId("{7A2871B9-5EAB-4DE0-A901-B0D2C6920DDB}")); // PhysX::Pipeline::MeshAsset
  113. }
  114. AZ::Data::AssetId GetProductAssetId(const AZ::Uuid& sourceAssetUUID, const AZ::TypeId typeId)
  115. {
  116. AZStd::vector<AZ::Data::AssetInfo> productsAssetInfo;
  117. using AssetSysReqBus = AzToolsFramework::AssetSystemRequestBus;
  118. bool ok{ false };
  119. AssetSysReqBus::BroadcastResult(ok, &AssetSysReqBus::Events::GetAssetsProducedBySourceUUID, sourceAssetUUID, productsAssetInfo);
  120. if (ok)
  121. {
  122. for (const auto& product : productsAssetInfo)
  123. {
  124. if (product.m_assetType == typeId)
  125. {
  126. return product.m_assetId;
  127. }
  128. }
  129. }
  130. return {};
  131. }
  132. AZ::Data::AssetId GetModelProductAssetId(const AZ::Uuid& sourceAssetUUID)
  133. {
  134. return GetProductAssetId(sourceAssetUUID, AZ::TypeId("{2C7477B6-69C5-45BE-8163-BCD6A275B6D8}")); // AZ::RPI::ModelAsset;
  135. }
  136. AZ::Data::AssetId GetPhysXMeshProductAssetId(const AZ::Uuid& sourceAssetUUID)
  137. {
  138. return GetProductAssetId(sourceAssetUUID, AZ::TypeId("{7A2871B9-5EAB-4DE0-A901-B0D2C6920DDB}")); // PhysX::Pipeline::MeshAsset
  139. }
  140. AvailableAsset GetAvailableAssetInfo(const AZStd::string& globalSourceAssetPath)
  141. {
  142. using AssetSysReqBus = AzToolsFramework::AssetSystemRequestBus;
  143. AvailableAsset foundAsset;
  144. // get source asset info
  145. bool sourceAssetFound{ false };
  146. AZ::Data::AssetInfo assetInfo;
  147. AZStd::string watchFolder;
  148. AssetSysReqBus::BroadcastResult(
  149. sourceAssetFound, &AssetSysReqBus::Events::GetSourceInfoBySourcePath, globalSourceAssetPath.c_str(), assetInfo, watchFolder);
  150. if (!sourceAssetFound)
  151. {
  152. AZ_Trace("GetAvailableAssetInfo", "Source asset info not found for: %s", globalSourceAssetPath.c_str());
  153. return foundAsset;
  154. }
  155. foundAsset.m_sourceGuid = assetInfo.m_assetId.m_guid;
  156. foundAsset.m_sourceAssetRelativePath = assetInfo.m_relativePath;
  157. foundAsset.m_sourceAssetGlobalPath = globalSourceAssetPath;
  158. AZ::Crc32 crc = Utils::GetFileCRC(foundAsset.m_sourceAssetGlobalPath);
  159. if (crc == AZ::Crc32(0))
  160. {
  161. AZ_Warning("GetInterestingSourceAssetsCRC", false, "Zero CRC for source asset %s", foundAsset.m_sourceAssetGlobalPath.c_str());
  162. return foundAsset;
  163. }
  164. // Todo Remove in review
  165. AZ_Printf("GetAvailableAssetInfo", "Found asset:");
  166. AZ_Printf("GetAvailableAssetInfo", "\tm_sourceAssetRelativePath : %s", foundAsset.m_sourceAssetRelativePath.c_str());
  167. AZ_Printf("GetAvailableAssetInfo", "\tm_sourceAssetGlobalPath : %s", foundAsset.m_sourceAssetGlobalPath.c_str());
  168. AZ_Printf("GetAvailableAssetInfo", "\tm_productAssetRelativePath : %s", foundAsset.m_productAssetRelativePath.c_str());
  169. AZ_Printf("GetAvailableAssetInfo", "\tm_sourceGuid : %s", foundAsset.m_sourceGuid.ToString<AZStd::string>().c_str());
  170. return foundAsset;
  171. }
  172. AZStd::unordered_map<AZ::Crc32, AvailableAsset> GetInterestingSourceAssetsCRC()
  173. {
  174. // connect to database API
  175. const AZStd::vector<AZStd::string> InterestingExtensions = GetSupportedExtensions();
  176. AZStd::unordered_map<AZ::Crc32, AvailableAsset> availableAssets;
  177. AzToolsFramework::AssetDatabase::AssetDatabaseConnection assetDatabaseConnection;
  178. if (!assetDatabaseConnection.OpenDatabase())
  179. {
  180. AZ_Warning("GetInterestingSourceAssetsCRC", false, "Cannot open database");
  181. return {};
  182. }
  183. auto callback = [&availableAssets](AzToolsFramework::AssetDatabase::SourceDatabaseEntry& entry)
  184. {
  185. using AssetSysReqBus = AzToolsFramework::AssetSystemRequestBus;
  186. AvailableAsset foundAsset;
  187. foundAsset.m_sourceGuid = entry.m_sourceGuid;
  188. using AssetSysReqBus = AzToolsFramework::AssetSystemRequestBus;
  189. // get source asset info
  190. bool sourceAssetFound{ false };
  191. AZ::Data::AssetInfo assetInfo;
  192. AZStd::string watchFolder;
  193. AssetSysReqBus::BroadcastResult(
  194. sourceAssetFound, &AssetSysReqBus::Events::GetSourceInfoBySourceUUID, entry.m_sourceGuid, assetInfo, watchFolder);
  195. if (!sourceAssetFound)
  196. {
  197. AZ_Warning("GetInterestingSourceAssetsCRC", false, "Cannot find source asset info for %s", entry.ToString().c_str());
  198. return true;
  199. }
  200. const auto fullSourcePath = AZ::IO::Path(watchFolder) / AZ::IO::Path(assetInfo.m_relativePath);
  201. foundAsset.m_sourceAssetRelativePath = assetInfo.m_relativePath;
  202. foundAsset.m_sourceAssetGlobalPath = fullSourcePath.String();
  203. AZ::Crc32 crc = Utils::GetFileCRC(foundAsset.m_sourceAssetGlobalPath);
  204. if (crc == AZ::Crc32(0))
  205. {
  206. AZ_Warning(
  207. "GetInterestingSourceAssetsCRC", false, "Zero CRC for source asset %s", foundAsset.m_sourceAssetGlobalPath.c_str());
  208. return true;
  209. }
  210. AZ_Printf("GetInterestingSourceAssetsCRC", "Found asset:");
  211. AZ_Printf("GetInterestingSourceAssetsCRC", "\tm_sourceAssetRelativePath : %s", foundAsset.m_sourceAssetRelativePath.c_str());
  212. AZ_Printf("GetInterestingSourceAssetsCRC", "\tm_sourceAssetGlobalPath : %s", foundAsset.m_sourceAssetGlobalPath.c_str());
  213. AZ_Printf("GetInterestingSourceAssetsCRC", "\tm_productAssetRelativePath : %s", foundAsset.m_productAssetRelativePath.c_str());
  214. AZ_Printf(
  215. "GetInterestingSourceAssetsCRC",
  216. "\tm_sourceGuid : %s",
  217. foundAsset.m_sourceGuid.ToString<AZStd::string>().c_str());
  218. AZ_Printf("GetInterestingSourceAssetsCRC", "\tcrc : %d", crc);
  219. auto availableAssetIt = availableAssets.find(crc);
  220. if (availableAssetIt != availableAssets.end())
  221. {
  222. AZ_Warning(
  223. "GetInterestingSourceAssetsCRC", false, "Asset already in database : %s ", foundAsset.m_sourceAssetGlobalPath.c_str());
  224. AZ_Warning(
  225. "GetInterestingSourceAssetsCRC", false, "Found asset : %s ", availableAssetIt->second.m_sourceAssetGlobalPath.c_str());
  226. }
  227. else
  228. {
  229. availableAssets.insert({ crc, foundAsset });
  230. }
  231. return true;
  232. };
  233. for (auto& extension : InterestingExtensions)
  234. {
  235. assetDatabaseConnection.QuerySourceLikeSourceName(
  236. extension.c_str(), AzToolsFramework::AssetDatabase::AssetDatabaseConnection::LikeType::EndsWith, callback);
  237. }
  238. return availableAssets;
  239. }
  240. UrdfAssetMap CopyAssetForURDFAndCreateAssetMap(
  241. const AZStd::unordered_set<AZStd::string>& meshesFilenames,
  242. const AZStd::string& urdfFilename,
  243. const AZStd::unordered_set<AZStd::string>& colliders,
  244. const AZStd::unordered_set<AZStd::string>& visuals,
  245. AZStd::string_view outputDirSuffix,
  246. AZ::IO::FileIOBase* fileIO)
  247. {
  248. auto enviromentalVariable = std::getenv("AMENT_PREFIX_PATH");
  249. AZ_Error("UrdfAssetMap", enviromentalVariable, "AMENT_PREFIX_PATH is not found.");
  250. UrdfAssetMap urdfAssetMap;
  251. if (meshesFilenames.empty())
  252. {
  253. return urdfAssetMap;
  254. }
  255. //! Maps the unresolved urdf path to global path
  256. AZStd::unordered_map<AZStd::string, AZ::IO::Path> copiedFiles;
  257. AZ_Assert(fileIO, "No FileIO instance");
  258. AZ::Crc32 urdfFileCrc;
  259. urdfFileCrc.Add(urdfFilename);
  260. const AZ::IO::Path urdfPath(urdfFilename);
  261. const auto directoryNameDst = AZ::IO::FixedMaxPathString::format(
  262. "%u_%.*s%.*s", AZ::u32(urdfFileCrc), AZ_PATH_ARG(urdfPath.Stem()), AZ_STRING_ARG(outputDirSuffix));
  263. const AZ::IO::Path importDirectoryDst = AZ::IO::Path(AZ::Utils::GetProjectPath()) / "Assets" / "UrdfImporter" / directoryNameDst;
  264. const auto outcomeCreateDstDir = fileIO->CreatePath(importDirectoryDst.c_str());
  265. AZ_Error("CopyAssetForURDF", outcomeCreateDstDir, "Cannot create destination directory : %s", importDirectoryDst.c_str());
  266. if (!outcomeCreateDstDir)
  267. {
  268. return urdfAssetMap;
  269. }
  270. AZStd::string amentPrefixPath{ enviromentalVariable };
  271. AZStd::set<AZStd::string> files;
  272. for (const auto& unresolvedUrfFileName : meshesFilenames)
  273. {
  274. auto resolved = Utils::ResolveURDFPath(unresolvedUrfFileName, AZ::IO::PathView(urdfFilename),
  275. AZ::IO::PathView(amentPrefixPath));
  276. if (resolved.empty())
  277. {
  278. AZ_Warning("CopyAssetForURDF", false, "There is not resolved path for %s", unresolvedUrfFileName.c_str());
  279. continue;
  280. }
  281. AZ::IO::Path resolvedPath(resolved);
  282. const bool needsCollider = colliders.contains(unresolvedUrfFileName);
  283. const AZStd::string pathSuffix = needsCollider ? "_collider" : "";
  284. const AZStd::string newFilename = resolvedPath.Stem().String() + pathSuffix + resolvedPath.Extension().String();
  285. AZ::IO::Path targetPathAssetDst(importDirectoryDst / newFilename);
  286. AZ::IO::Path targetPathAssetInfo(targetPathAssetDst.Native() + ".assetinfo");
  287. if (!fileIO->Exists(targetPathAssetDst.c_str()))
  288. {
  289. const auto outcomeMoveDst = fileIO->Copy(resolvedPath.c_str(), targetPathAssetDst.c_str());
  290. AZ_Printf(
  291. "CopyAssetForURDF",
  292. "Copy %s to %s, result: %d",
  293. resolvedPath.c_str(),
  294. targetPathAssetDst.c_str(),
  295. outcomeMoveDst.GetResultCode());
  296. if (outcomeMoveDst)
  297. {
  298. copiedFiles[unresolvedUrfFileName] = targetPathAssetDst.String();
  299. }
  300. }
  301. else
  302. {
  303. AZ_Printf("CopyAssetForURDF", "File %s already exists, omitting import", targetPathAssetDst.c_str());
  304. copiedFiles[unresolvedUrfFileName] = targetPathAssetDst.String();
  305. }
  306. Utils::UrdfAsset asset;
  307. asset.m_urdfPath = urdfFilename;
  308. asset.m_resolvedUrdfPath = Utils::ResolveURDFPath(unresolvedUrfFileName, AZ::IO::PathView(urdfFilename),
  309. AZ::IO::PathView(amentPrefixPath));
  310. asset.m_urdfFileCRC = AZ::Crc32();
  311. urdfAssetMap.emplace(unresolvedUrfFileName, AZStd::move(asset));
  312. }
  313. // Wait for assets to be scanned by asset processor
  314. Utils::WaitForAssetsToProcess(copiedFiles);
  315. // Add available asset info
  316. for (const auto& [unresolvedUrfFileName, sourceAssetGlobalPath] : copiedFiles)
  317. {
  318. AZ_Printf("CopyAssetForURDF", " %s is copied to %s", unresolvedUrfFileName.c_str(), sourceAssetGlobalPath.c_str());
  319. AZ_Assert(
  320. urdfAssetMap.contains(unresolvedUrfFileName), "urdfAssetMap should contain urdf path %s", unresolvedUrfFileName.c_str());
  321. urdfAssetMap[unresolvedUrfFileName].m_availableAssetInfo = Utils::GetAvailableAssetInfo(sourceAssetGlobalPath.String());
  322. }
  323. // Create assetinfo
  324. for (const auto& [unresolvedUrfFileName, sourceAssetGlobalPath] : copiedFiles)
  325. {
  326. AZ::IO::Path targetPathAssetInfo(sourceAssetGlobalPath.Native() + ".assetinfo");
  327. if (!fileIO->Exists(targetPathAssetInfo.c_str()))
  328. {
  329. const bool needsVisual = visuals.contains(unresolvedUrfFileName);
  330. const bool needsCollider = colliders.contains(unresolvedUrfFileName);
  331. CreateSceneManifest(sourceAssetGlobalPath.String(), targetPathAssetInfo.String(), needsCollider, needsVisual);
  332. }
  333. }
  334. return urdfAssetMap;
  335. }
  336. UrdfAssetMap FindAssetsForUrdf(const AZStd::unordered_set<AZStd::string>& meshesFilenames, const AZStd::string& urdfFilename)
  337. {
  338. // Support reading the AMENT_PREFIX_PATH environment variable on Unix/Windows platforms
  339. auto StoreAmentPrefixPath = [](char* buffer, size_t size) -> size_t
  340. {
  341. auto getEnvOutcome = AZ::Utils::GetEnv(AZStd::span(buffer, size), "AMENT_PREFIX_PATH");
  342. return getEnvOutcome ? getEnvOutcome.GetValue().size() : 0;
  343. };
  344. AZStd::fixed_string<4096> amentPrefixPath;
  345. amentPrefixPath.resize_and_overwrite(amentPrefixPath.capacity(), StoreAmentPrefixPath);
  346. AZ_Error("UrdfAssetMap", !amentPrefixPath.empty(), "AMENT_PREFIX_PATH is not found.");
  347. UrdfAssetMap urdfToAsset;
  348. for (const auto& t : meshesFilenames)
  349. {
  350. Utils::UrdfAsset asset;
  351. asset.m_urdfPath = t;
  352. asset.m_resolvedUrdfPath = Utils::ResolveURDFPath(asset.m_urdfPath, AZ::IO::PathView(urdfFilename),
  353. AZ::IO::PathView(amentPrefixPath));
  354. asset.m_urdfFileCRC = Utils::GetFileCRC(asset.m_resolvedUrdfPath);
  355. urdfToAsset.emplace(t, AZStd::move(asset));
  356. }
  357. if (!urdfToAsset.empty())
  358. {
  359. AZStd::unordered_map<AZ::Crc32, AvailableAsset> availableAssets = Utils::GetInterestingSourceAssetsCRC();
  360. // Search for suitable mappings by comparing checksum
  361. for (auto it = urdfToAsset.begin(); it != urdfToAsset.end(); it++)
  362. {
  363. Utils::UrdfAsset& asset = it->second;
  364. auto found_source_asset = availableAssets.find(asset.m_urdfFileCRC);
  365. if (found_source_asset != availableAssets.end())
  366. {
  367. asset.m_availableAssetInfo = found_source_asset->second;
  368. }
  369. }
  370. }
  371. return urdfToAsset;
  372. }
  373. bool CreateSceneManifest(const AZ::IO::Path& sourceAssetPath, const AZ::IO::Path& assetInfoFile, bool collider, bool visual)
  374. {
  375. const auto& azMeshPath = sourceAssetPath;
  376. AZ_Printf("CreateSceneManifest", "Creating manifest for asset %s at : %s ", sourceAssetPath.c_str(), assetInfoFile.c_str());
  377. AZStd::shared_ptr<AZ::SceneAPI::Containers::Scene> scene;
  378. AZ::SceneAPI::Events::SceneSerializationBus::BroadcastResult(
  379. scene, &AZ::SceneAPI::Events::SceneSerialization::LoadScene, azMeshPath.c_str(), AZ::Uuid::CreateNull(), "");
  380. if (!scene)
  381. {
  382. AZ_Error("CreateSceneManifest", false, "Error loading collider. Invalid scene: %s", azMeshPath.c_str());
  383. return false;
  384. }
  385. AZ::SceneAPI::Containers::SceneManifest& manifest = scene->GetManifest();
  386. auto valueStorage = manifest.GetValueStorage();
  387. if (valueStorage.empty())
  388. {
  389. AZ_Error("CreateSceneManifest", false, "Error loading collider. Invalid value storage: %s", azMeshPath.c_str());
  390. return false;
  391. }
  392. // remove default configuration to avoid procedural prefab creation
  393. AZStd::vector<AZStd::shared_ptr<AZ::SceneAPI::DataTypes::IManifestObject>> toDelete;
  394. for (size_t i = 0; i < manifest.GetEntryCount(); i++)
  395. {
  396. AZStd::shared_ptr<AZ::SceneAPI::DataTypes::IManifestObject> obj = manifest.GetValue(i);
  397. toDelete.push_back(obj);
  398. }
  399. for (auto obj : toDelete)
  400. {
  401. AZ_Printf("CreateSceneManifest", "Deleting %s", obj->RTTI_GetType().ToString<AZStd::string>().c_str());
  402. manifest.RemoveEntry(obj);
  403. }
  404. if (visual)
  405. {
  406. AZStd::shared_ptr<AZ::SceneAPI::SceneData::MeshGroup> sceneDataMeshGroup =
  407. AZStd::make_shared<AZ::SceneAPI::SceneData::MeshGroup>();
  408. // select all nodes to this mesh group
  409. AZ::SceneAPI::Utilities::SceneGraphSelector::SelectAll(scene->GetGraph(), sceneDataMeshGroup->GetSceneNodeSelectionList());
  410. // enable auto-generation of UVs
  411. sceneDataMeshGroup->GetRuleContainer().AddRule(AZStd::make_shared<AZ::SceneAPI::SceneData::UVsRule>());
  412. manifest.AddEntry(sceneDataMeshGroup);
  413. }
  414. if (collider)
  415. {
  416. AZStd::shared_ptr<UrdfPhysxMeshGroupHelper> physxDataMeshGroup = AZStd::make_shared<UrdfPhysxMeshGroupHelper>();
  417. physxDataMeshGroup->SetIsDecomposeMeshes(true);
  418. physxDataMeshGroup->SetMeshExportMethod(PhysX::Pipeline::MeshExportMethod::Convex);
  419. // select all nodes to this mesh group
  420. AZ::SceneAPI::Utilities::SceneGraphSelector::SelectAll(scene->GetGraph(), physxDataMeshGroup->GetSceneNodeSelectionList());
  421. manifest.AddEntry(physxDataMeshGroup);
  422. }
  423. // Update assetinfo
  424. AZ::SceneAPI::Events::ProcessingResultCombiner result;
  425. AZ::SceneAPI::Events::AssetImportRequestBus::BroadcastResult(
  426. result,
  427. &AZ::SceneAPI::Events::AssetImportRequest::UpdateManifest,
  428. *scene,
  429. AZ::SceneAPI::Events::AssetImportRequest::ManifestAction::Update,
  430. AZ::SceneAPI::Events::AssetImportRequest::RequestingApplication::Editor);
  431. if (result.GetResult() != AZ::SceneAPI::Events::ProcessingResult::Success)
  432. {
  433. AZ_Trace("CreateSceneManifest", "Scene updated\n");
  434. return false;
  435. }
  436. scene->GetManifest().SaveToFile(assetInfoFile.Native());
  437. AZ_Printf("CreateSceneManifest", "Saving scene manifest to %s\n", assetInfoFile.c_str());
  438. return true;
  439. }
  440. bool CreateSceneManifest(const AZ::IO::Path& sourceAssetPath, bool collider, bool visual)
  441. {
  442. auto assetInfoFilePath = AZ::IO::Path{ sourceAssetPath };
  443. assetInfoFilePath.Native() += ".assetinfo";
  444. return CreateSceneManifest(sourceAssetPath, sourceAssetPath.Native() + ".assetinfo", collider, visual);
  445. }
  446. } // namespace ROS2::Utils