3
0

ModelLodAssetCreator.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  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/std/containers/set.h>
  9. #include <Atom/RPI.Reflect/Buffer/BufferAssetCreator.h>
  10. #include <Atom/RPI.Reflect/Model/ModelLodAssetCreator.h>
  11. #include <AzCore/Asset/AssetManager.h>
  12. namespace AZ
  13. {
  14. namespace RPI
  15. {
  16. void ModelLodAssetCreator::Begin(const Data::AssetId& assetId)
  17. {
  18. BeginCommon(assetId);
  19. }
  20. void ModelLodAssetCreator::SetLodIndexBuffer(const Data::Asset<BufferAsset>& bufferAsset)
  21. {
  22. if (ValidateIsReady())
  23. {
  24. m_asset->m_indexBuffer = AZStd::move(bufferAsset);
  25. }
  26. }
  27. void ModelLodAssetCreator::AddLodStreamBuffer(const Data::Asset<BufferAsset>& bufferAsset)
  28. {
  29. if (ValidateIsReady())
  30. {
  31. m_asset->m_streamBuffers.push_back(AZStd::move(bufferAsset));
  32. }
  33. }
  34. void ModelLodAssetCreator::BeginMesh()
  35. {
  36. if (ValidateIsReady())
  37. {
  38. m_currentMesh = ModelLodAsset::Mesh();
  39. m_meshBegan = true;
  40. }
  41. }
  42. void ModelLodAssetCreator::SetMeshName(const AZ::Name& name)
  43. {
  44. if (ValidateIsMeshReady())
  45. {
  46. m_currentMesh.m_name = name;
  47. }
  48. }
  49. void ModelLodAssetCreator::SetMeshAabb(AZ::Aabb&& aabb)
  50. {
  51. if (ValidateIsMeshReady())
  52. {
  53. m_currentMesh.m_aabb = AZStd::move(aabb);
  54. }
  55. }
  56. void ModelLodAssetCreator::SetMeshMaterialSlot(ModelMaterialSlot::StableId id)
  57. {
  58. if (!ValidateIsMeshReady())
  59. {
  60. return;
  61. }
  62. m_currentMesh.m_materialSlotId = id;
  63. }
  64. void ModelLodAssetCreator::SetMeshIndexBuffer(const BufferAssetView& bufferAssetView)
  65. {
  66. if (!ValidateIsMeshReady())
  67. {
  68. return;
  69. }
  70. if (m_currentMesh.m_indexBufferAssetView.GetBufferAsset().Get() != nullptr)
  71. {
  72. ReportError("The current mesh has already had an index buffer set.");
  73. return;
  74. }
  75. m_currentMesh.m_indexBufferAssetView = AZStd::move(bufferAssetView);
  76. }
  77. bool ModelLodAssetCreator::AddMeshStreamBuffer(
  78. const RHI::ShaderSemantic& streamSemantic,
  79. const AZ::Name& customName,
  80. const BufferAssetView& bufferAssetView)
  81. {
  82. if (!ValidateIsMeshReady())
  83. {
  84. return false;
  85. }
  86. if (m_currentMesh.m_streamBufferInfo.size() >= RHI::Limits::Pipeline::StreamCountMax)
  87. {
  88. ReportError("Cannot add another stream buffer info. Maximum of %d already reached.", RHI::Limits::Pipeline::StreamCountMax);
  89. return false;
  90. }
  91. // If this streamId already exists throw an error
  92. for (const ModelLodAsset::Mesh::StreamBufferInfo& streamBufferInfo : m_currentMesh.m_streamBufferInfo)
  93. {
  94. if (streamBufferInfo.m_semantic == streamSemantic || (!streamBufferInfo.m_customName.IsEmpty() && streamBufferInfo.m_customName == customName))
  95. {
  96. ReportError("Failed to add Stream Buffer. Buffer with this streamId or name already exists.");
  97. return false;
  98. }
  99. }
  100. ModelLodAsset::Mesh::StreamBufferInfo streamBufferInfo;
  101. streamBufferInfo.m_semantic = streamSemantic;
  102. streamBufferInfo.m_customName = customName;
  103. streamBufferInfo.m_bufferAssetView = AZStd::move(bufferAssetView);
  104. m_currentMesh.m_streamBufferInfo.push_back(AZStd::move(streamBufferInfo));
  105. return true;
  106. }
  107. void ModelLodAssetCreator::AddMeshStreamBuffer(
  108. const ModelLodAsset::Mesh::StreamBufferInfo& streamBufferInfo)
  109. {
  110. if (!ValidateIsMeshReady())
  111. {
  112. return;
  113. }
  114. // If this semantic already exists throw an error
  115. for (const ModelLodAsset::Mesh::StreamBufferInfo& existingInfo : m_currentMesh.m_streamBufferInfo)
  116. {
  117. if (existingInfo.m_semantic == streamBufferInfo.m_semantic || (!existingInfo.m_customName.IsEmpty() && existingInfo.m_customName == streamBufferInfo.m_customName))
  118. {
  119. ReportError("Failed to add Stream Buffer. Buffer with this semantic or name already exists.");
  120. return;
  121. }
  122. }
  123. m_currentMesh.m_streamBufferInfo.push_back(AZStd::move(streamBufferInfo));
  124. }
  125. void ModelLodAssetCreator::EndMesh()
  126. {
  127. if (ValidateIsMeshReady() && ValidateMesh(m_currentMesh))
  128. {
  129. m_asset->AddMesh(AZStd::move(m_currentMesh));
  130. m_meshBegan = false;
  131. }
  132. }
  133. bool ModelLodAssetCreator::End(Data::Asset<ModelLodAsset>& result)
  134. {
  135. if (ValidateIsReady() && ValidateIsMeshEnded() && ValidateLod())
  136. {
  137. m_asset->SetReady();
  138. return EndCommon(result);
  139. }
  140. return false;
  141. }
  142. bool ModelLodAssetCreator::ValidateIsMeshReady()
  143. {
  144. if (!ValidateIsReady())
  145. {
  146. return false;
  147. }
  148. if (!m_meshBegan)
  149. {
  150. AZ_Assert(false, "BeginMesh() was not called");
  151. return false;
  152. }
  153. return true;
  154. }
  155. bool ModelLodAssetCreator::ValidateIsMeshEnded()
  156. {
  157. if (m_meshBegan)
  158. {
  159. AZ_Assert(false, "MeshEnd() was not called");
  160. return false;
  161. }
  162. return true;
  163. }
  164. bool ModelLodAssetCreator::ValidateLod()
  165. {
  166. if (m_asset->GetMeshes().empty())
  167. {
  168. ReportError("No meshes have been provided for this LOD");
  169. return false;
  170. }
  171. return true;
  172. }
  173. bool ModelLodAssetCreator::ValidateMesh(const ModelLodAsset::Mesh& mesh)
  174. {
  175. if (mesh.GetVertexCount() == 0)
  176. {
  177. ReportError("Mesh has a vertex count of 0");
  178. return false;
  179. }
  180. if (mesh.GetIndexCount() == 0)
  181. {
  182. ReportError("Mesh has an index count of 0");
  183. return false;
  184. }
  185. if (!mesh.GetAabb().IsValid())
  186. {
  187. ReportError("Mesh does not have a valid Aabb");
  188. return false;
  189. }
  190. if (mesh.m_indexBufferAssetView.GetBufferAsset().Get() == nullptr)
  191. {
  192. ReportError("Mesh does not have a valid index buffer");
  193. return false;
  194. }
  195. for (const ModelLodAsset::Mesh::StreamBufferInfo& streamBufferInfo : mesh.m_streamBufferInfo)
  196. {
  197. if (streamBufferInfo.m_bufferAssetView.GetBufferAsset().Get() == nullptr)
  198. {
  199. ReportError("Mesh has an invalid stream buffer");
  200. return false;
  201. }
  202. }
  203. return true;
  204. }
  205. bool ModelLodAssetCreator::Clone(const Data::Asset<ModelLodAsset>& sourceAsset, Data::Asset<ModelLodAsset>& clonedResult, Data::AssetId& inOutLastCreatedAssetId)
  206. {
  207. AZStd::span<const ModelLodAsset::Mesh> sourceMeshes = sourceAsset->GetMeshes();
  208. if (sourceMeshes.empty())
  209. {
  210. return true;
  211. }
  212. ModelLodAssetCreator creator;
  213. inOutLastCreatedAssetId.m_subId = inOutLastCreatedAssetId.m_subId + 1;
  214. creator.Begin(inOutLastCreatedAssetId);
  215. // Add the index buffer
  216. const Data::Asset<BufferAsset> sourceIndexBufferAsset = sourceMeshes[0].GetIndexBufferAssetView().GetBufferAsset();
  217. Data::Asset<BufferAsset> clonedIndexBufferAsset;
  218. BufferAssetCreator::Clone(sourceIndexBufferAsset, clonedIndexBufferAsset, inOutLastCreatedAssetId);
  219. creator.SetLodIndexBuffer(clonedIndexBufferAsset);
  220. // Add meshes
  221. AZStd::unordered_map<AZ::Data::AssetId, Data::Asset<BufferAsset>> oldToNewBufferAssets;
  222. for (const ModelLodAsset::Mesh& sourceMesh : sourceMeshes)
  223. {
  224. // Add stream buffers
  225. for (const AZ::RPI::ModelLodAsset::Mesh::StreamBufferInfo& streamBufferInfo : sourceMesh.GetStreamBufferInfoList())
  226. {
  227. const Data::Asset<BufferAsset>& sourceStreamBuffer = streamBufferInfo.m_bufferAssetView.GetBufferAsset();
  228. const AZ::Data::AssetId sourceBufferAssetId = sourceStreamBuffer.GetId();
  229. // In case the buffer asset id is not part of our old to new asset id mapping, we did not convert and add it yet.
  230. if (oldToNewBufferAssets.find(sourceBufferAssetId) == oldToNewBufferAssets.end())
  231. {
  232. Data::Asset<BufferAsset> streamBufferAsset;
  233. if (!BufferAssetCreator::Clone(sourceStreamBuffer, streamBufferAsset, inOutLastCreatedAssetId))
  234. {
  235. AZ_Error("ModelLodAssetCreator", false,
  236. "Cannot clone buffer asset for '%s'.", sourceBufferAssetId.ToString<AZStd::string>().c_str());
  237. return false;
  238. }
  239. oldToNewBufferAssets[sourceBufferAssetId] = streamBufferAsset;
  240. creator.AddLodStreamBuffer(streamBufferAsset);
  241. }
  242. }
  243. // Add mesh
  244. creator.BeginMesh();
  245. creator.SetMeshName(sourceMesh.GetName());
  246. AZ::Aabb aabb = sourceMesh.GetAabb();
  247. creator.SetMeshAabb(AZStd::move(aabb));
  248. creator.SetMeshMaterialSlot(sourceMesh.GetMaterialSlotId());
  249. // Mesh index buffer view
  250. const BufferAssetView& sourceIndexBufferView = sourceMesh.GetIndexBufferAssetView();
  251. BufferAssetView indexBufferAssetView(clonedIndexBufferAsset, sourceIndexBufferView.GetBufferViewDescriptor());
  252. creator.SetMeshIndexBuffer(indexBufferAssetView);
  253. // Mesh stream buffer views
  254. for (const AZ::RPI::ModelLodAsset::Mesh::StreamBufferInfo& streamBufferInfo : sourceMesh.GetStreamBufferInfoList())
  255. {
  256. // Get the corresponding new buffer asset id from the source buffer.
  257. const AZ::Data::AssetId sourceBufferAssetId = streamBufferInfo.m_bufferAssetView.GetBufferAsset().GetId();
  258. const auto assetIdIterator = oldToNewBufferAssets.find(sourceBufferAssetId);
  259. if (assetIdIterator != oldToNewBufferAssets.end())
  260. {
  261. const Data::Asset<BufferAsset>& clonedBufferAsset = assetIdIterator->second;
  262. BufferAssetView bufferAssetView(clonedBufferAsset, streamBufferInfo.m_bufferAssetView.GetBufferViewDescriptor());
  263. creator.AddMeshStreamBuffer(streamBufferInfo.m_semantic, streamBufferInfo.m_customName, bufferAssetView);
  264. }
  265. else
  266. {
  267. AZ_Error("ModelLodAssetCreator", false,
  268. "Cannot find cloned buffer asset for source buffer asset '%s'.",
  269. sourceBufferAssetId.ToString<AZStd::string>().c_str());
  270. return false;
  271. }
  272. }
  273. creator.EndMesh();
  274. }
  275. return creator.End(clonedResult);
  276. }
  277. } // namespace RPI
  278. } // namespace AZ