ModelAssetHelpers.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  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 <Atom/RPI.Reflect/Buffer/BufferAssetCreator.h>
  9. #include <Atom/RPI.Reflect/Model/ModelAssetHelpers.h>
  10. #include <Atom/RPI.Reflect/Model/ModelLodAssetCreator.h>
  11. #include <Atom/RPI.Reflect/ResourcePoolAssetCreator.h>
  12. namespace AZ
  13. {
  14. namespace RPI
  15. {
  16. AZ::Data::Asset<AZ::RPI::BufferAsset> ModelAssetHelpers::CreateBufferAsset(
  17. const void* data, const uint32_t elementCount, const uint32_t elementSize)
  18. {
  19. // Create a buffer pool asset for use with the buffer asset
  20. AZ::Data::Asset<AZ::RPI::ResourcePoolAsset> bufferPoolAsset;
  21. {
  22. AZ::Data::AssetId bufferPoolId = AZ::Uuid::CreateRandom();
  23. bufferPoolAsset = AZ::Data::AssetManager::Instance().CreateAsset(
  24. bufferPoolId, azrtti_typeid<AZ::RPI::ResourcePoolAsset>(), Data::AssetLoadBehavior::PreLoad);
  25. auto bufferPoolDesc = AZStd::make_unique<AZ::RHI::BufferPoolDescriptor>();
  26. bufferPoolDesc->m_bindFlags = AZ::RHI::BufferBindFlags::InputAssembly;
  27. bufferPoolDesc->m_heapMemoryLevel = AZ::RHI::HeapMemoryLevel::Host;
  28. AZ::RPI::ResourcePoolAssetCreator creator;
  29. creator.Begin(bufferPoolId);
  30. creator.SetPoolDescriptor(AZStd::move(bufferPoolDesc));
  31. creator.SetPoolName("ModelAssetHelperBufferPool");
  32. creator.End(bufferPoolAsset);
  33. }
  34. // Create a buffer asset that contains a copy of the input data.
  35. AZ::Data::Asset<AZ::RPI::BufferAsset> asset;
  36. {
  37. AZ::Data::AssetId bufferId = AZ::Uuid::CreateRandom();
  38. asset = AZ::Data::AssetManager::Instance().CreateAsset(
  39. bufferId, azrtti_typeid<AZ::RPI::BufferAsset>(), Data::AssetLoadBehavior::PreLoad);
  40. AZ::RHI::BufferDescriptor bufferDescriptor;
  41. bufferDescriptor.m_bindFlags = AZ::RHI::BufferBindFlags::InputAssembly;
  42. bufferDescriptor.m_byteCount = elementCount * elementSize;
  43. AZ::RPI::BufferAssetCreator creator;
  44. creator.Begin(bufferId);
  45. creator.SetPoolAsset(bufferPoolAsset);
  46. creator.SetBuffer(data, bufferDescriptor.m_byteCount, bufferDescriptor);
  47. creator.SetBufferViewDescriptor(AZ::RHI::BufferViewDescriptor::CreateStructured(0, elementCount, elementSize));
  48. creator.End(asset);
  49. }
  50. return asset;
  51. }
  52. void ModelAssetHelpers::CreateModel(
  53. ModelAsset* modelAsset,
  54. const AZ::Name& name,
  55. AZStd::span<const uint32_t> indices,
  56. AZStd::span<const float_t> positions,
  57. AZStd::span<const float> normals,
  58. AZStd::span<const float> tangents,
  59. AZStd::span<const float> bitangents,
  60. AZStd::span<const float> uvs)
  61. {
  62. // First build a model LOD asset that contains a mesh for the given data.
  63. AZ::Data::Asset<AZ::RPI::ModelLodAsset> lodAsset;
  64. AZ::Data::AssetId lodAssetId = AZ::Uuid::CreateRandom();
  65. lodAsset = AZ::Data::AssetManager::Instance().CreateAsset(
  66. lodAssetId, azrtti_typeid<AZ::RPI::ModelLodAsset>(), Data::AssetLoadBehavior::PreLoad);
  67. AZ::RPI::ModelLodAssetCreator creator;
  68. creator.Begin(lodAssetId);
  69. const uint32_t positionElementCount = aznumeric_cast<uint32_t>(positions.size() / 3);
  70. const uint32_t indexElementCount = aznumeric_cast<uint32_t>(indices.size());
  71. const uint32_t uvElementCount = aznumeric_cast<uint32_t>(uvs.size() / 2);
  72. const uint32_t normalElementCount = aznumeric_cast<uint32_t>(normals.size() / 3);
  73. const uint32_t tangentElementCount = aznumeric_cast<uint32_t>(tangents.size() / 4);
  74. const uint32_t bitangentElementCount = aznumeric_cast<uint32_t>(bitangents.size() / 3);
  75. constexpr uint32_t PositionElementSize = aznumeric_cast<uint32_t>(sizeof(float) * 3);
  76. constexpr uint32_t IndexElementSize = aznumeric_cast<uint32_t>(sizeof(uint32_t));
  77. constexpr uint32_t UvElementSize = aznumeric_cast<uint32_t>(sizeof(float) * 2);
  78. constexpr uint32_t NormalElementSize = aznumeric_cast<uint32_t>(sizeof(float) * 3);
  79. constexpr uint32_t TangentElementSize = aznumeric_cast<uint32_t>(sizeof(float) * 4);
  80. constexpr uint32_t BitangentElementSize = aznumeric_cast<uint32_t>(sizeof(float) * 3);
  81. // Calculate the Aabb for the given positions.
  82. AZ::Aabb aabb = AZ::Aabb::CreateNull();
  83. for (uint32_t i = 0; i < positions.size(); i += 3)
  84. {
  85. aabb.AddPoint(AZ::Vector3(positions[i], positions[i + 1], positions[i + 2]));
  86. }
  87. // Set up a single-mesh asset with only position data.
  88. creator.BeginMesh();
  89. creator.SetMeshAabb(AZStd::move(aabb));
  90. creator.SetMeshMaterialSlot(0);
  91. creator.SetMeshIndexBuffer({ CreateBufferAsset(indices.data(), indexElementCount, IndexElementSize),
  92. AZ::RHI::BufferViewDescriptor::CreateTyped(0, indexElementCount, AZ::RHI::Format::R32_UINT) });
  93. creator.AddMeshStreamBuffer(
  94. AZ::RHI::ShaderSemantic(AZ::Name("POSITION")),
  95. AZ::Name(),
  96. { CreateBufferAsset(positions.data(), positionElementCount, PositionElementSize),
  97. AZ::RHI::BufferViewDescriptor::CreateTyped(0, positionElementCount, AZ::RHI::Format::R32G32B32_FLOAT) });
  98. creator.AddMeshStreamBuffer(
  99. AZ::RHI::ShaderSemantic(AZ::Name("NORMAL")),
  100. AZ::Name(),
  101. { CreateBufferAsset(normals.data(), normalElementCount, NormalElementSize),
  102. AZ::RHI::BufferViewDescriptor::CreateTyped(0, normalElementCount, AZ::RHI::Format::R32G32B32_FLOAT) });
  103. creator.AddMeshStreamBuffer(
  104. AZ::RHI::ShaderSemantic(AZ::Name("TANGENT")),
  105. AZ::Name(),
  106. { CreateBufferAsset(tangents.data(), tangentElementCount, TangentElementSize),
  107. AZ::RHI::BufferViewDescriptor::CreateTyped(0, tangentElementCount, AZ::RHI::Format::R32G32B32A32_FLOAT) });
  108. creator.AddMeshStreamBuffer(
  109. AZ::RHI::ShaderSemantic(AZ::Name("BITANGENT")),
  110. AZ::Name(),
  111. { CreateBufferAsset(bitangents.data(), bitangentElementCount, BitangentElementSize),
  112. AZ::RHI::BufferViewDescriptor::CreateTyped(0, bitangentElementCount, AZ::RHI::Format::R32G32B32_FLOAT) });
  113. creator.AddMeshStreamBuffer(
  114. AZ::RHI::ShaderSemantic(AZ::Name("UV")),
  115. AZ::Name(),
  116. { CreateBufferAsset(uvs.data(), uvElementCount, UvElementSize),
  117. AZ::RHI::BufferViewDescriptor::CreateTyped(0, uvElementCount, AZ::RHI::Format::R32G32_FLOAT) });
  118. creator.EndMesh();
  119. creator.End(lodAsset);
  120. // Create a model asset that contains the single LOD built above.
  121. modelAsset->InitData(
  122. name,
  123. AZStd::span<AZ::Data::Asset<AZ::RPI::ModelLodAsset>>(&lodAsset, 1),
  124. {}, // no material slots
  125. {}, // no fallback material
  126. {} // no tags
  127. );
  128. }
  129. void ModelAssetHelpers::CreateUnitCube(ModelAsset* modelAsset)
  130. {
  131. // Build a mesh containing a unit cube.
  132. // The vertices are duplicated for each face so that we can have correct per-face normals and UVs.
  133. constexpr int ValuesPerPositionEntry = 3;
  134. constexpr int ValuesPerUvEntry = 2;
  135. constexpr int ValuesPerNormalEntry = 3;
  136. constexpr int ValuesPerTangentEntry = 4;
  137. constexpr int ValuesPerBitangentEntry = 3;
  138. constexpr int VerticesPerFace = 6;
  139. constexpr int MeshFaces = 6;
  140. constexpr int ValuesPerFace = 4;
  141. // 6 vertices per face, 6 faces.
  142. constexpr AZStd::array<uint32_t, VerticesPerFace * MeshFaces> indices = {
  143. 0, 1, 2, 0, 2, 3, // front face
  144. 4, 5, 6, 4, 6, 7, // right face
  145. 8, 9, 10, 8, 10, 11, // back face
  146. 12, 13, 14, 12, 14, 15, // left face
  147. 16, 17, 18, 16, 18, 19, // top face
  148. 20, 21, 22, 20, 22, 23 // bottom face
  149. };
  150. // 3 values per position, 4 positions per face, 6 faces
  151. constexpr AZStd::array<float, ValuesPerPositionEntry * ValuesPerFace * MeshFaces> positions = {
  152. -0.5f, -0.5f, -0.5f, +0.5f, -0.5f, -0.5f, +0.5f, -0.5f, +0.5f, -0.5f, -0.5f, +0.5f, // front
  153. +0.5f, -0.5f, -0.5f, +0.5f, +0.5f, -0.5f, +0.5f, +0.5f, +0.5f, +0.5f, -0.5f, +0.5f, // right
  154. +0.5f, +0.5f, -0.5f, -0.5f, +0.5f, -0.5f, -0.5f, +0.5f, +0.5f, +0.5f, +0.5f, +0.5f, // back
  155. -0.5f, +0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f, +0.5f, -0.5f, +0.5f, +0.5f, // left
  156. -0.5f, -0.5f, +0.5f, +0.5f, -0.5f, +0.5f, +0.5f, +0.5f, +0.5f, -0.5f, +0.5f, +0.5f, // top
  157. -0.5f, +0.5f, -0.5f, +0.5f, +0.5f, -0.5f, +0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f, // bottom
  158. };
  159. // 2 values per position, 4 positions per face, 6 faces
  160. // This aribtrarily maps the UVs to use the full texture on each face.
  161. // This choice can be changed if a different mapping would be more usable.
  162. constexpr AZStd::array<float, ValuesPerUvEntry * ValuesPerFace * MeshFaces> uvs = {
  163. 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, // front
  164. 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, // right
  165. 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, // back
  166. 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, // left
  167. 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, // top
  168. 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, // bottom
  169. };
  170. // 3 values per position, 4 positions per face, 6 faces
  171. constexpr AZStd::array<float, ValuesPerNormalEntry * ValuesPerFace * MeshFaces> normals = {
  172. +0.0f, -1.0f, +0.0f, +0.0f, -1.0f, +0.0f, +0.0f, -1.0f, +0.0f, +0.0f, -1.0f, +0.0f, // front (-Y)
  173. +1.0f, +0.0f, +0.0f, +1.0f, +0.0f, +0.0f, +1.0f, +0.0f, +0.0f, +1.0f, +0.0f, +0.0f, // right (+X)
  174. +0.0f, +1.0f, +0.0f, +0.0f, +1.0f, +0.0f, +0.0f, +1.0f, +0.0f, +0.0f, +1.0f, +0.0f, // back (+Y)
  175. -1.0f, +0.0f, +0.0f, -1.0f, +0.0f, +0.0f, -1.0f, +0.0f, +0.0f, -1.0f, +0.0f, +0.0f, // left (-X)
  176. +0.0f, +0.0f, +1.0f, +0.0f, +0.0f, +1.0f, +0.0f, +0.0f, +1.0f, +0.0f, +0.0f, +1.0f, // top (+Z)
  177. +0.0f, +0.0f, -1.0f, +0.0f, +0.0f, -1.0f, +0.0f, +0.0f, -1.0f, +0.0f, +0.0f, -1.0f, // bottom (-Z)
  178. };
  179. // 4 values per position, 4 positions per face, 6 faces
  180. constexpr AZStd::array<float, ValuesPerTangentEntry * ValuesPerFace * MeshFaces> tangents = {
  181. 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // front (+Z)
  182. 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // right (+Z)
  183. 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // back (+Z)
  184. 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // left (+Z)
  185. 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, // top (+Y)
  186. 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, // bottom (-Y)
  187. };
  188. // 3 values per position, 4 positions per face, 6 faces
  189. constexpr AZStd::array<float, ValuesPerBitangentEntry * ValuesPerFace * MeshFaces> bitangents = {
  190. +1.0f, +0.0f, +0.0f, +1.0f, +0.0f, +0.0f, +1.0f, +0.0f, +0.0f, +1.0f, +0.0f, +0.0f, // front (+X)
  191. +0.0f, +1.0f, +0.0f, +0.0f, +1.0f, +0.0f, +0.0f, +1.0f, +0.0f, +0.0f, +1.0f, +0.0f, // right (+Y)
  192. -1.0f, +0.0f, +0.0f, -1.0f, +0.0f, +0.0f, -1.0f, +0.0f, +0.0f, -1.0f, +0.0f, +0.0f, // back (-X)
  193. +0.0f, -1.0f, +0.0f, +0.0f, -1.0f, +0.0f, +0.0f, -1.0f, +0.0f, +0.0f, -1.0f, +0.0f, // left (-Y)
  194. +1.0f, +0.0f, +0.0f, +1.0f, +0.0f, +0.0f, +1.0f, +0.0f, +0.0f, +1.0f, +0.0f, +0.0f, // top (+X)
  195. +1.0f, +0.0f, +0.0f, +1.0f, +0.0f, +0.0f, +1.0f, +0.0f, +0.0f, +1.0f, +0.0f, +0.0f, // bottom (+X)
  196. };
  197. CreateModel(modelAsset, AZ::Name("UnitCube"), indices, positions, normals, tangents, bitangents, uvs);
  198. }
  199. void ModelAssetHelpers::CreateUnitX(ModelAsset* modelAsset)
  200. {
  201. // Build a mesh containing a unit X model.
  202. // To make the X double-sided regardless of material, we'll create two faces for each branch of the X.
  203. constexpr int ValuesPerPositionEntry = 3;
  204. constexpr int ValuesPerUvEntry = 2;
  205. constexpr int ValuesPerNormalEntry = 3;
  206. constexpr int ValuesPerTangentEntry = 4;
  207. constexpr int ValuesPerBitangentEntry = 3;
  208. constexpr int VerticesPerFace = 6;
  209. constexpr int MeshFaces = 4;
  210. constexpr int ValuesPerFace = 4;
  211. // 6 vertices per face, 4 faces.
  212. constexpr AZStd::array<uint32_t, VerticesPerFace * MeshFaces> indices = {
  213. 0, 1, 2, 0, 2, 3, // / face of X
  214. 4, 5, 6, 4, 6, 7, // \ face of X
  215. 8, 9, 10, 8, 10, 11, // / face of X (back)
  216. 12, 13, 14, 12, 14, 15, // \ face of X (back)
  217. };
  218. // 3 values per position, 4 positions per face, 2 faces
  219. constexpr AZStd::array<float, ValuesPerPositionEntry * ValuesPerFace * MeshFaces> positions = {
  220. -0.5f, -0.5f, -0.5f, +0.5f, +0.5f, -0.5f, +0.5f, +0.5f, +0.5f, -0.5f, -0.5f, +0.5f, // / face of X
  221. -0.5f, +0.5f, -0.5f, +0.5f, -0.5f, -0.5f, +0.5f, -0.5f, +0.5f, -0.5f, +0.5f, +0.5f, // \ face of X
  222. +0.5f, +0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f, +0.5f, +0.5f, +0.5f, +0.5f, // / face of X (back)
  223. +0.5f, -0.5f, -0.5f, -0.5f, +0.5f, -0.5f, -0.5f, +0.5f, +0.5f, +0.5f, -0.5f, +0.5f, // \ face of X (back)
  224. };
  225. // 2 values per position, 4 positions per face, 2 faces
  226. // This aribtrarily maps the UVs to use the full texture on each face.
  227. // This choice can be changed if a different mapping would be more usable.
  228. constexpr AZStd::array<float, ValuesPerUvEntry * ValuesPerFace * MeshFaces> uvs = {
  229. 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, // / face of X
  230. 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, // \ face of X
  231. 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, // / face of X (back)
  232. 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, // \ face of X (back
  233. };
  234. // 3 values per position, 4 positions per face, 2 faces
  235. constexpr AZStd::array<float, ValuesPerNormalEntry * ValuesPerFace * MeshFaces> normals = {
  236. +0.5f, -0.5f, +0.0f, +0.5f, -0.5f, +0.0f, +0.5f, -0.5f, +0.0f, +0.5f, -0.5f, +0.0f, // / face of X
  237. -0.5f, -0.5f, +0.0f, -0.5f, -0.5f, +0.0f, -0.5f, -0.5f, +0.0f, -0.5f, -0.5f, +0.0f, // \ face of X
  238. -0.5f, +0.5f, +0.0f, -0.5f, +0.5f, +0.0f, -0.5f, +0.5f, +0.0f, -0.5f, +0.5f, +0.0f, // / face of X (back)
  239. +0.5f, +0.5f, +0.0f, +0.5f, +0.5f, +0.0f, +0.5f, +0.5f, +0.0f, +0.5f, +0.5f, +0.0f, // \ face of X (back)
  240. };
  241. // 4 values per position, 4 positions per face, 2 faces
  242. constexpr AZStd::array<float, ValuesPerTangentEntry * ValuesPerFace * MeshFaces> tangents = {
  243. 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // / face of X
  244. 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // \ face of X
  245. 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // / face of X (back)
  246. 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // \ face of X (back)
  247. };
  248. // 3 values per position, 4 positions per face, 2 faces
  249. constexpr AZStd::array<float, ValuesPerBitangentEntry * ValuesPerFace * MeshFaces> bitangents = {
  250. +0.5f, +0.5f, +0.0f, +0.5f, +0.5f, +0.0f, +0.5f, +0.5f, +0.0f, +0.5f, +0.5f, +0.0f, // / face of X
  251. -0.5f, +0.5f, +0.0f, -0.5f, +0.5f, +0.0f, -0.5f, +0.5f, +0.0f, -0.5f, +0.5f, +0.0f, // \ face of X
  252. -0.5f, -0.5f, +0.0f, -0.5f, -0.5f, +0.0f, -0.5f, -0.5f, +0.0f, -0.5f, -0.5f, +0.0f, // / face of X (back)
  253. +0.5f, -0.5f, +0.0f, +0.5f, -0.5f, +0.0f, +0.5f, -0.5f, +0.0f, +0.5f, -0.5f, +0.0f, // \ face of X (back)
  254. };
  255. CreateModel(modelAsset, AZ::Name("UnitX"), indices, positions, normals, tangents, bitangents, uvs);
  256. }
  257. } // namespace RPI
  258. } // namespace AZ