ModelAssetBuilderComponent.h 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  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. #pragma once
  9. #include <Atom/RPI.Reflect/Base.h>
  10. #include <Atom/RPI.Reflect/Model/MorphTargetMetaAssetCreator.h>
  11. #include <SceneAPI/SceneCore/Components/ExportingComponent.h>
  12. #include <SceneAPI/SceneCore/DataTypes/GraphData/IMaterialData.h>
  13. #include <SceneAPI/SceneCore/DataTypes/GraphData/IMeshData.h>
  14. #include <SceneAPI/SceneCore/DataTypes/GraphData/IMeshVertexColorData.h>
  15. #include <SceneAPI/SceneCore/DataTypes/GraphData/IMeshVertexUVData.h>
  16. #include <SceneAPI/SceneCore/DataTypes/GraphData/ITransform.h>
  17. #include <SceneAPI/SceneCore/DataTypes/GraphData/IMeshVertexTangentData.h>
  18. #include <SceneAPI/SceneCore/DataTypes/GraphData/IMeshVertexBitangentData.h>
  19. #include <SceneAPI/SceneCore/DataTypes/GraphData/ISkinWeightData.h>
  20. #include <SceneAPI/SceneCore/DataTypes/Rules/ISkinRule.h>
  21. #include <SceneAPI/SceneCore/Containers/SceneGraph.h>
  22. #include <SceneAPI/SceneCore/SceneBuilderDependencyBus.h>
  23. #include <Model/ModelExporterContexts.h>
  24. #include <AzCore/std/containers/map.h>
  25. namespace AZ
  26. {
  27. namespace RPI
  28. {
  29. using MeshData = AZ::SceneAPI::DataTypes::IMeshData;
  30. using TransformData = AZ::SceneAPI::DataTypes::ITransform;
  31. using UVData = AZ::SceneAPI::DataTypes::IMeshVertexUVData;
  32. using ColorData = AZ::SceneAPI::DataTypes::IMeshVertexColorData;
  33. using MaterialData = AZ::SceneAPI::DataTypes::IMaterialData;
  34. using TangentData = AZ::SceneAPI::DataTypes::IMeshVertexTangentData;
  35. using BitangentData = AZ::SceneAPI::DataTypes::IMeshVertexBitangentData;
  36. using SkinData = AZ::SceneAPI::DataTypes::ISkinWeightData;
  37. class Stream;
  38. class ModelAssetCreator;
  39. class ModelLodAssetCreator;
  40. class BufferAssetCreator;
  41. struct PackedCompressedMorphTargetDelta;
  42. //! Component responsible for building Atom's AzModel from SceneAPI input.
  43. //!
  44. //! The current strategy in this builder is to merge data as much as possible
  45. //! while keeping streams separate.
  46. //! This may change for different platforms in the future.
  47. //!
  48. //! Currently Meshes are merged as much as possible at the ModelLod level.
  49. //! An input SceneAPI Model with 3 meshes in an LOD are going to get merged
  50. //! into stream buffers owned by the ModelLod. The Meshes in the ModelLod
  51. //! are then just going to act as views into the ModelLod's buffers with
  52. //! an associated Material.
  53. class ModelAssetBuilderComponent
  54. : public AZ::SceneAPI::SceneCore::ExportingComponent
  55. {
  56. public:
  57. AZ_COMPONENT(
  58. ModelAssetBuilderComponent,
  59. "{FE21DEEB-F9E6-487E-B9F0-88478FC2F52F}",
  60. AZ::SceneAPI::SceneCore::ExportingComponent);
  61. static void Reflect(AZ::ReflectContext* context);
  62. ModelAssetBuilderComponent();
  63. ~ModelAssetBuilderComponent() override = default;
  64. AZ::SceneAPI::Events::ProcessingResult BuildModel(ModelAssetBuilderContext& context);
  65. using MaterialUid = uint64_t;
  66. //! Describes the source SceneAPI data that makes up a "Mesh" as understood by Atom.
  67. struct SourceMeshContent
  68. {
  69. AZ::Name m_name;
  70. AZStd::shared_ptr<const MeshData> m_meshData;
  71. SceneAPI::DataTypes::MatrixType m_worldTransform = SceneAPI::DataTypes::MatrixType::CreateIdentity();
  72. AZStd::shared_ptr<const TangentData> m_meshTangents;
  73. AZStd::shared_ptr<const BitangentData> m_meshBitangents;
  74. AZStd::vector<AZStd::shared_ptr<const UVData>> m_meshUVData;
  75. AZStd::vector<AZStd::shared_ptr<const ColorData>> m_meshColorData;
  76. AZStd::vector<AZStd::shared_ptr<const SkinData>> m_skinData;
  77. AZStd::vector<AZ::Color> m_meshClothData;
  78. AZStd::vector<MaterialUid> m_materials;
  79. bool m_isMorphed = false;
  80. MaterialUid GetMaterialUniqueId(uint32_t index) const;
  81. };
  82. using SourceMeshContentList = AZStd::vector<SourceMeshContent>;
  83. //! Describes the data needed to produce the buffers that make up a Mesh.
  84. struct ProductMeshContent
  85. {
  86. AZ::Name m_name;
  87. AZStd::vector<uint32_t> m_indices;
  88. AZStd::vector<float> m_positions;
  89. AZStd::vector<float> m_normals;
  90. AZStd::vector<float> m_tangents;
  91. AZStd::vector<float> m_bitangents;
  92. AZStd::vector<AZStd::vector<float>> m_uvSets;
  93. AZStd::vector<AZ::Name> m_uvCustomNames;
  94. AZStd::vector<AZStd::vector<float>> m_colorSets;
  95. AZStd::vector<AZ::Name> m_colorCustomNames;
  96. AZStd::vector<float> m_clothData;
  97. //! Joint index per vertex in range [0, numJoints].
  98. //! Note: The joint indices have to match the used skeleton when applying skinning.
  99. //! A mapping between the joint name and the used joint index is stored as a separate skin meta asset.
  100. AZStd::vector<uint16_t> m_skinJointIndices;
  101. AZStd::vector<float> m_skinWeights;
  102. // Morph targets
  103. AZStd::vector<RPI::PackedCompressedMorphTargetDelta> m_morphTargetVertexData;
  104. MaterialUid m_materialUid;
  105. uint32_t m_influencesPerVertex = 0;
  106. size_t m_vertexCount = 0;
  107. bool CanBeMerged() const
  108. {
  109. // Temporarily disable merging skinned meshes to avoid merging meshes that have different
  110. // per-vertex influence counts. This can be reverted when GHI-7588 is resolved
  111. return m_clothData.empty() && m_influencesPerVertex == 0;
  112. }
  113. };
  114. using ProductMeshContentList = AZStd::vector<ProductMeshContent>;
  115. static constexpr inline const char* s_builderName = "Atom Model Builder";
  116. static constexpr inline const char* s_defaultVertexBufferPoolSourcePath = "ResourcePools/DefaultVertexBufferPool.resourcepool";
  117. private:
  118. //! Used to accumulate info about how much space to allocate when creating a ProductMeshContent structure.
  119. //!
  120. //! This is needed to batch memory allocations together. Otherwise
  121. //! hundreds of thousands of small allocations when building a ProductMeshContent
  122. //! structure can cause the allocators to fragment heavily and waste large
  123. //! amounts of memory. 2GB of model memory can become 30+GB of fragmented memory in
  124. //! the allocator.
  125. struct ProductMeshContentAllocInfo
  126. {
  127. size_t m_indexCount = 0;
  128. size_t m_positionsFloatCount = 0;
  129. size_t m_normalsFloatCount = 0;
  130. size_t m_tangentsFloatCount = 0;
  131. size_t m_bitangentsFloatCount = 0;
  132. size_t m_clothDataFloatCount = 0;
  133. AZStd::vector<size_t> m_uvSetFloatCounts;
  134. AZStd::vector<size_t> m_colorSetFloatCounts;
  135. size_t m_jointIdsCount = 0;
  136. size_t m_jointWeightsCount = 0;
  137. size_t m_morphTargetVertexDeltaCount = 0;
  138. };
  139. //! Describes a view into data described in a ProductMeshContent structure.
  140. //!
  141. //! As described by the strategy in the class comment, Meshes are going to
  142. //! just be views into the ModelLod-wide buffers.
  143. //! If a ProductMeshContent structure describes all the buffers in a ModelLod,
  144. //! a ProductMeshView describes each Mesh's view into those ModelLod buffers.
  145. struct ProductMeshView
  146. {
  147. AZ::Name m_name;
  148. RHI::BufferViewDescriptor m_indexView;
  149. RHI::BufferViewDescriptor m_positionView;
  150. RHI::BufferViewDescriptor m_normalView;
  151. AZStd::vector<RHI::BufferViewDescriptor> m_uvSetViews;
  152. AZStd::vector<AZ::Name> m_uvCustomNames;
  153. AZStd::vector<RHI::BufferViewDescriptor> m_colorSetViews;
  154. AZStd::vector<AZ::Name> m_colorCustomNames;
  155. RHI::BufferViewDescriptor m_tangentView;
  156. RHI::BufferViewDescriptor m_bitangentView;
  157. RHI::BufferViewDescriptor m_skinJointIndicesView;
  158. RHI::BufferViewDescriptor m_skinWeightsView;
  159. RHI::BufferViewDescriptor m_morphTargetVertexDataView;
  160. RHI::BufferViewDescriptor m_clothDataView;
  161. MaterialUid m_materialUid;
  162. };
  163. using ProductMeshViewList = AZStd::vector<ProductMeshView>;
  164. //! Takes an abstract graph object and tries to add it to the given SourceMeshContent object.
  165. void AddToMeshContent(
  166. const AZStd::shared_ptr<const AZ::SceneAPI::DataTypes::IGraphObject>& data,
  167. SourceMeshContent& content);
  168. //! Takes in a list of SourceMeshContent and outputs list of ProductMeshContent.
  169. //! This product list is not 1:1 but it is as close as we can get with minimal processing.
  170. //! Since a SouceMeshContent object may have faces that have multiple materials we have to break
  171. //! that into a ProductMeshContent object for each material. No further processing is done
  172. AZ::Outcome<ProductMeshContentList> SourceMeshListToProductMeshList(
  173. const ModelAssetBuilderContext& context,
  174. const SourceMeshContentList& sourceMeshContentList,
  175. AZStd::unordered_map<AZStd::string, uint16_t>& jointNameToIndexMap,
  176. MorphTargetMetaAssetCreator& morphTargetMetaCreator);
  177. //! Checks if this is a skinned mesh and if soe,
  178. //! adds some extra padding to make vertex streams align for skinning
  179. //! Skinning is applied on an entire lod at once, so it presumes that
  180. //! Each vertex stream that is modified by skinning is the same length
  181. void PadVerticesForSkinning(ProductMeshContentList& productMeshList);
  182. //! Takes in a ProductMeshContentList and merges all elements that share the same MaterialUid.
  183. AZ::Outcome<ModelAssetBuilderComponent::ProductMeshContentList> MergeMeshesByMaterialUid(
  184. const ProductMeshContentList& productMeshList);
  185. //! Simple helper to create a MeshView that views an entire given ProductMeshContent object as one mesh.
  186. ProductMeshView CreateViewToEntireMesh(const ProductMeshContent& mesh);
  187. //! Takes a ProductMeshContentList and merges all elements into a single ProductMeshContent object.
  188. //! This also produces a ProductMeshViewList that contains views to all
  189. //! the original meshes described in the lodMeshList collection.
  190. void MergeMeshesToCommonBuffers(
  191. ProductMeshContentList& lodMeshList,
  192. ProductMeshContent& lodMeshContent,
  193. ProductMeshViewList& meshViewsPerLodBuffer);
  194. enum IndicesOperation
  195. {
  196. PreserveIndices,
  197. RemapIndices
  198. };
  199. //! Helper method for MergeMeshesByMaterialUid and MergeAllMeshes.
  200. //! Takes a given ProductMeshContentList and outputs a single
  201. //! ProductMeshContent object.
  202. //!
  203. //! If preserveIndices is true the values of the indices will not be rescaled
  204. //! to treat the merged mesh as one continuous mesh. Instead each mesh will retain
  205. //! its indices as they were.
  206. ProductMeshContent MergeMeshList(
  207. const ProductMeshContentList& productMeshList,
  208. IndicesOperation indicesOp);
  209. //! Create stream buffer asset with a structured view descriptor from the given data and add it to the out stream buffers
  210. template<typename T>
  211. bool BuildStructuredStreamBuffer(
  212. AZStd::vector<ModelLodAsset::Mesh::StreamBufferInfo>& outStreamBuffers,
  213. const AZStd::vector<T>& bufferData,
  214. const RHI::ShaderSemantic& semantic,
  215. const AZ::Name& uvCustomName = AZ::Name());
  216. //! Create stream buffer asset with a raw view descriptor from the given data and add it to the out stream buffers.
  217. template<typename T>
  218. bool BuildRawStreamBuffer(
  219. AZStd::vector<ModelLodAsset::Mesh::StreamBufferInfo>& outStreamBuffers,
  220. const AZStd::vector<T>& bufferData,
  221. const RHI::ShaderSemantic& semantic,
  222. const AZ::Name& uvCustomName = AZ::Name());
  223. //! Create stream buffer asset with a typed view descriptor from the given data and add it to the out stream buffers.
  224. template<typename T>
  225. bool BuildTypedStreamBuffer(
  226. AZStd::vector<ModelLodAsset::Mesh::StreamBufferInfo>& outStreamBuffers,
  227. const AZStd::vector<T>& bufferData,
  228. AZ::RHI::Format format,
  229. const RHI::ShaderSemantic& semantic,
  230. const AZ::Name& uvCustomName = AZ::Name());
  231. //! Create stream buffer asset with a typed view descriptor from the given data and add it to the out stream buffers.
  232. template<typename T>
  233. bool BuildStreamBuffer(
  234. size_t vertexCount,
  235. AZStd::vector<ModelLodAsset::Mesh::StreamBufferInfo>& outStreamBuffers,
  236. const AZStd::vector<T>& bufferData,
  237. AZ::RHI::Format format,
  238. const RHI::ShaderSemantic& semantic,
  239. const AZ::Name& uvCustomName = AZ::Name());
  240. //! Returns true if the two meshes have the same type and count of vertex streams
  241. bool VertexStreamLayoutMatches(const ProductMeshContent& lhs, const ProductMeshContent& rhs) const;
  242. //! Checks to see if a data buffer is the expected size
  243. template<typename T>
  244. bool ValidateStreamSize(
  245. size_t expectedVertexCount,
  246. const AZStd::vector<T>& bufferData,
  247. AZ::RHI::Format format,
  248. const char* streamName,
  249. bool isAligned = false) const;
  250. //! Checks to see if the vertex count for each stream within a mesh is the same
  251. bool ValidateStreamAlignment(const ProductMeshContent& mesh) const;
  252. //! Takes a ProductMeshContent object, produces BufferAsset objects for each
  253. //! stream and then applies those to the given ModelLodAssetCreator as the
  254. //! lod-wide buffers. It also returns the index and stream buffer data so that it
  255. //! can be referenced later.
  256. //!
  257. //! Returns false if an error occurs
  258. bool CreateModelLodBuffers(
  259. const ProductMeshContent& lodBufferContent,
  260. BufferAssetView& outIndexBuffer,
  261. AZStd::vector<ModelLodAsset::Mesh::StreamBufferInfo>& outStreamBuffers,
  262. ModelLodAssetCreator& lodAssetCreator);
  263. //! Takes a ProductMeshView and the buffers that it is supposed to be a view
  264. //! into and adds that data as a Mesh onto the given ModelLodAssetCreator.
  265. //!
  266. //! Returns false if an error occurs
  267. bool CreateMesh(
  268. const ProductMeshView& meshView,
  269. const BufferAssetView& lodIndexBuffer,
  270. const AZStd::vector<ModelLodAsset::Mesh::StreamBufferInfo>& lodStreamBuffers,
  271. ModelAssetCreator& modelAssetCreator,
  272. ModelLodAssetCreator& lodAssetCreator,
  273. const MaterialAssetsByUid& materialAssetsByUid);
  274. //! Takes in a pointer to data with a given element count and format and creates a BufferAsset.
  275. Outcome<Data::Asset<BufferAsset>> CreateTypedBufferAsset(
  276. const void* data, const size_t elementCount, RHI::Format format, const AZStd::string& bufferName);
  277. //! Takes in a pointer to data and a size in bytes and creates a BufferAsset.
  278. Outcome<Data::Asset<BufferAsset>> CreateStructuredBufferAsset(
  279. const void* data, const size_t elementCount, const size_t elementSize, const AZStd::string& bufferName);
  280. //! Takes in a pointer to data and a size in bytes and creates a BufferAsset.
  281. Outcome<Data::Asset<BufferAsset>> CreateRawBufferAsset(
  282. const void* data, const size_t totalSizeInBytes, const AZStd::string& bufferName);
  283. //! Takes in a pointer to data with a view descriptor count and format and creates a BufferAsset.
  284. Outcome<Data::Asset<BufferAsset>> CreateBufferAsset(
  285. const void* data, const RHI::BufferViewDescriptor& bufferViewDescriptor, const AZStd::string& bufferName);
  286. //! Helper method for CreateMesh.
  287. //! Searches lodStreamBuffers for the given semantic and if found takes
  288. //! the BufferAsset in that StreamBufferInfo and pairs it with the given
  289. //! bufferViewDescriptor to add a Mesh stream buffer to the given lodAssetCreator.
  290. bool SetMeshStreamBufferById(
  291. const RHI::ShaderSemantic& semantic,
  292. const AZ::Name& customName,
  293. const RHI::BufferViewDescriptor& bufferViewDescriptor,
  294. const AZStd::vector<ModelLodAsset::Mesh::StreamBufferInfo>& lodStreamBuffers,
  295. ModelLodAssetCreator& lodAssetCreator);
  296. // Create stable asset id from an unique name
  297. Data::AssetId CreateAssetId(const AZStd::string& assetName);
  298. // Get asset full name for different product assets based on their type
  299. // For buffer asset, it needs to provide a buffer name
  300. AZStd::string GetAssetFullName(const TypeId& assetType, const AZStd::string& bufferName = {});
  301. //! Calculates the AABB of the SubMesh.
  302. //! This should be called when a position stream is added
  303. //!
  304. //! @param[in] bufferViewDesc The buffer view descriptor used to examine the given bufferAsset
  305. //! and determine the range of the buffer to use to calculate the AABB from.
  306. //! @param[in] bufferAsset The BufferAsset to calculate the AABB from. Expected to
  307. //! be a Position stream
  308. //! @param[out] aabb The AABB that encompasses the given stream
  309. //! @return True if the AABB was successfully calculated
  310. static bool CalculateAABB(const RHI::BufferViewDescriptor& bufferViewDesc, const BufferAsset& bufferAsset, AZ::Aabb& aabb);
  311. //! Helper method for CreateMesh.
  312. //! Finds a buffer in the given streamBufferInfoList that matches the given stream id
  313. //! and returns it as part of outStreamBufferInfo.
  314. //! Returns false if no StreamBufferInfo is found.
  315. bool FindStreamBufferById(
  316. const AZStd::vector<ModelLodAsset::Mesh::StreamBufferInfo>& streamBufferInfoList,
  317. const RHI::ShaderSemantic& streamSemantic,
  318. ModelLodAsset::Mesh::StreamBufferInfo& outStreamBufferInfo);
  319. // Check if a given node contains any morph target data.
  320. bool GetIsMorphed(const AZ::SceneAPI::Containers::SceneGraph& graph, const AZ::SceneAPI::Containers::SceneGraph::NodeIndex& nodeIndex) const;
  321. Uuid m_sourceUuid;
  322. // cached names for asset id generation
  323. AZStd::string m_modelName;
  324. AZStd::string m_lodName;
  325. AZStd::string m_meshName;
  326. SceneAPI::DataTypes::SkinRuleSettings m_skinRuleSettings;
  327. AZStd::set<uint32_t> m_createdSubId;
  328. // NOTE: This is explicitly fetched from a filename. In the future, this should be fetched from the RPI system
  329. // configuration data.
  330. Data::AssetId m_systemInputAssemblyBufferPoolId;
  331. //! Calculates the world transform of the node given all of its parent nodes
  332. SceneAPI::DataTypes::MatrixType GetWorldTransform(const SceneAPI::Containers::SceneGraph& sceneGraph, SceneAPI::Containers::SceneGraph::NodeIndex node);
  333. private:
  334. //! Collects skinning influences of a vertex from the SceneAPI source mesh and fills them in the resulting mesh
  335. uint32_t CalculateMaxUsedSkinInfluencesPerVertex(
  336. const SourceMeshContent& sourceMesh,
  337. const AZStd::map<uint32_t, uint32_t>& oldToNewIndicesMap,
  338. bool& warnedExcessOfSkinInfluences) const;
  339. //! Collects skinning influences of a vertex from the SceneAPI source mesh and fills them in the resulting mesh
  340. void GatherVertexSkinningInfluences(
  341. const SourceMeshContent& sourceMesh,
  342. ProductMeshContent& productMesh,
  343. AZStd::unordered_map<AZStd::string, uint16_t>& jointNameToIndexMap,
  344. size_t vertexIndex) const;
  345. };
  346. //! Report dependencies for the ModelAssetBuilderComponent.
  347. //! Specifically, this reports the dependency on DefaultVertexBufferPool.resourcepool.
  348. class ModelAssetDependenciesComponent
  349. : public Component
  350. , public SceneAPI::SceneBuilderDependencyBus::Handler
  351. {
  352. public:
  353. AZ_COMPONENT(ModelAssetDependenciesComponent, "{CE1E8C2B-A05F-4AED-8771-88E58377A82B}");
  354. static void Reflect(ReflectContext* context);
  355. ModelAssetDependenciesComponent() = default;
  356. ~ModelAssetDependenciesComponent() override = default;
  357. static void GetProvidedServices(ComponentDescriptor::DependencyArrayType& provided);
  358. static void GetIncompatibleServices(ComponentDescriptor::DependencyArrayType& incompatible);
  359. // AZ::Component overrides...
  360. void Activate() override;
  361. void Deactivate() override;
  362. // SceneAPI::SceneBuilderDependencyBus::Handler overrides...
  363. void ReportJobDependencies(SceneAPI::JobDependencyList& jobDependencyList, const char* platformIdentifier) override;
  364. };
  365. } // namespace RPI
  366. } // namespace AZ