MeshAssetHelper.cpp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  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 <AtomLyIntegration/CommonFeatures/Mesh/MeshComponentBus.h>
  9. #include <Atom/RPI.Reflect/Model/ModelAsset.h>
  10. #include <NvCloth/ITangentSpaceHelper.h>
  11. #include <Utils/MeshAssetHelper.h>
  12. namespace NvCloth
  13. {
  14. MeshAssetHelper::MeshAssetHelper(AZ::EntityId entityId)
  15. : AssetHelper(entityId)
  16. {
  17. }
  18. void MeshAssetHelper::GatherClothMeshNodes(MeshNodeList& meshNodes)
  19. {
  20. AZ::Data::Asset<AZ::RPI::ModelAsset> modelDataAsset;
  21. AZ::Render::MeshComponentRequestBus::EventResult(
  22. modelDataAsset, m_entityId, &AZ::Render::MeshComponentRequestBus::Events::GetModelAsset);
  23. if (!modelDataAsset.IsReady())
  24. {
  25. return;
  26. }
  27. const AZ::RPI::ModelAsset* modelAsset = modelDataAsset.Get();
  28. if (!modelAsset)
  29. {
  30. return;
  31. }
  32. const auto lodAssets = modelAsset->GetLodAssets();
  33. AZStd::set<AZStd::string> meshNodeNames;
  34. if (!lodAssets.empty())
  35. {
  36. const int lodLevel = 0;
  37. if (const AZ::RPI::ModelLodAsset* lodAsset = lodAssets[lodLevel].Get())
  38. {
  39. const auto meshes = lodAsset->GetMeshes();
  40. for (const auto& mesh : meshes)
  41. {
  42. const bool hasClothData = (mesh.GetSemanticBufferAssetView(AZ::Name("CLOTH_DATA")) != nullptr);
  43. if (hasClothData)
  44. {
  45. meshNodeNames.insert(mesh.GetName().GetStringView());
  46. }
  47. }
  48. }
  49. }
  50. meshNodes.assign(meshNodeNames.begin(), meshNodeNames.end());
  51. }
  52. bool MeshAssetHelper::ObtainClothMeshNodeInfo(
  53. const AZStd::string& meshNode,
  54. MeshNodeInfo& meshNodeInfo,
  55. MeshClothInfo& meshClothInfo)
  56. {
  57. AZ_PROFILE_FUNCTION(Cloth);
  58. AZ::Data::Asset<AZ::RPI::ModelAsset> modelDataAsset;
  59. AZ::Render::MeshComponentRequestBus::EventResult(
  60. modelDataAsset, m_entityId, &AZ::Render::MeshComponentRequestBus::Events::GetModelAsset);
  61. if (!modelDataAsset.IsReady())
  62. {
  63. return false;
  64. }
  65. const AZ::RPI::ModelAsset* modelAsset = modelDataAsset.Get();
  66. if (!modelAsset)
  67. {
  68. return false;
  69. }
  70. const auto lodAssets = modelAsset->GetLodAssets();
  71. AZStd::vector<const AZ::RPI::ModelLodAsset::Mesh*> meshNodes;
  72. AZStd::vector<size_t> meshPrimitiveIndices;
  73. if(!lodAssets.empty())
  74. {
  75. const int lodLevel = 0;
  76. if (const AZ::RPI::ModelLodAsset* lodAsset = lodAssets[lodLevel].Get())
  77. {
  78. const auto meshes = lodAsset->GetMeshes();
  79. for (size_t meshIndex = 0; meshIndex < meshes.size(); ++meshIndex)
  80. {
  81. if (meshNode == meshes[meshIndex].GetName().GetStringView())
  82. {
  83. meshNodes.push_back(&meshes[meshIndex]);
  84. meshPrimitiveIndices.push_back(meshIndex);
  85. meshNodeInfo.m_lodLevel = lodLevel;
  86. }
  87. }
  88. }
  89. }
  90. bool infoObtained = false;
  91. if (!meshNodes.empty())
  92. {
  93. bool dataCopied = CopyDataFromMeshes(meshNodes, meshClothInfo);
  94. if (dataCopied)
  95. {
  96. const size_t numSubMeshes = meshNodes.size();
  97. meshNodeInfo.m_subMeshes.reserve(meshNodes.size());
  98. int firstVertex = 0;
  99. int firstIndex = 0;
  100. for (size_t subMeshIndex = 0; subMeshIndex < numSubMeshes; ++subMeshIndex)
  101. {
  102. MeshNodeInfo::SubMesh subMesh;
  103. subMesh.m_primitiveIndex = static_cast<int>(meshPrimitiveIndices[subMeshIndex]);
  104. subMesh.m_verticesFirstIndex = firstVertex;
  105. subMesh.m_numVertices = static_cast<int>(meshNodes[subMeshIndex]->GetVertexCount());
  106. subMesh.m_indicesFirstIndex = firstIndex;
  107. subMesh.m_numIndices = static_cast<int>(meshNodes[subMeshIndex]->GetIndexCount());
  108. firstVertex += subMesh.m_numVertices;
  109. firstIndex += subMesh.m_numIndices;
  110. meshNodeInfo.m_subMeshes.push_back(AZStd::move(subMesh));
  111. }
  112. infoObtained = true;
  113. }
  114. else
  115. {
  116. AZ_Error("MeshAssetHelper", false, "Failed to extract data from node %s in model %s",
  117. meshNode.c_str(), modelDataAsset.GetHint().c_str());
  118. }
  119. }
  120. return infoObtained;
  121. }
  122. bool MeshAssetHelper::CopyDataFromMeshes(
  123. const AZStd::vector<const AZ::RPI::ModelLodAsset::Mesh*>& meshes,
  124. MeshClothInfo& meshClothInfo)
  125. {
  126. uint32_t numTotalVertices = 0;
  127. uint32_t numTotalIndices = 0;
  128. for (const auto* mesh : meshes)
  129. {
  130. numTotalVertices += mesh->GetVertexCount();
  131. numTotalIndices += mesh->GetIndexCount();
  132. }
  133. if (numTotalVertices == 0 || numTotalIndices == 0)
  134. {
  135. return false;
  136. }
  137. meshClothInfo.m_particles.reserve(numTotalVertices);
  138. meshClothInfo.m_uvs.reserve(numTotalVertices);
  139. meshClothInfo.m_motionConstraints.reserve(numTotalVertices);
  140. meshClothInfo.m_backstopData.reserve(numTotalVertices);
  141. meshClothInfo.m_normals.reserve(numTotalVertices);
  142. meshClothInfo.m_indices.reserve(numTotalIndices);
  143. struct Vec2
  144. {
  145. float x, y;
  146. };
  147. struct Vec3
  148. {
  149. float x, y, z;
  150. };
  151. struct Vec4
  152. {
  153. float x, y, z, w;
  154. };
  155. const SimUVType uvZero(0.0f, 0.0f);
  156. for (const auto* mesh : meshes)
  157. {
  158. const auto sourceIndices = mesh->GetIndexBufferTyped<uint32_t>();
  159. const auto sourcePositions = mesh->GetSemanticBufferTyped<Vec3>(AZ::Name("POSITION"));
  160. const auto sourceNormals = mesh->GetSemanticBufferTyped<Vec3>(AZ::Name("NORMAL"));
  161. const auto sourceClothData = mesh->GetSemanticBufferTyped<Vec4>(AZ::Name("CLOTH_DATA"));
  162. const auto sourceUVs = mesh->GetSemanticBufferTyped<Vec2>(AZ::Name("UV"));
  163. if (sourceIndices.empty() ||
  164. sourcePositions.empty() ||
  165. sourceNormals.empty() ||
  166. sourceClothData.empty() ||
  167. sourceUVs.empty())
  168. {
  169. return false;
  170. }
  171. const uint32_t numVertices = mesh->GetVertexCount();
  172. for (uint32_t index = 0; index < numVertices; ++index)
  173. {
  174. const float inverseMass = sourceClothData[index].x;
  175. const float motionConstraint = sourceClothData[index].y;
  176. const float backstopOffset = ConvertBackstopOffset(sourceClothData[index].z);
  177. const float backstopRadius = sourceClothData[index].w;
  178. meshClothInfo.m_particles.emplace_back(
  179. sourcePositions[index].x,
  180. sourcePositions[index].y,
  181. sourcePositions[index].z,
  182. inverseMass);
  183. meshClothInfo.m_normals.emplace_back(
  184. sourceNormals[index].x,
  185. sourceNormals[index].y,
  186. sourceNormals[index].z);
  187. meshClothInfo.m_motionConstraints.emplace_back(motionConstraint);
  188. meshClothInfo.m_backstopData.emplace_back(backstopOffset, backstopRadius);
  189. meshClothInfo.m_uvs.emplace_back(
  190. sourceUVs.empty()
  191. ? uvZero
  192. : SimUVType(sourceUVs[index].x, sourceUVs[index].y));
  193. }
  194. meshClothInfo.m_indices.insert(meshClothInfo.m_indices.end(), sourceIndices.begin(), sourceIndices.end());
  195. }
  196. // Calculate tangents and bitangents for the whole mesh
  197. [[maybe_unused]] bool tangentsAndBitangentsCalculated =
  198. AZ::Interface<ITangentSpaceHelper>::Get()->CalculateTangentsAndBitagents(
  199. meshClothInfo.m_particles, meshClothInfo.m_indices, meshClothInfo.m_uvs, meshClothInfo.m_normals,
  200. meshClothInfo.m_tangents, meshClothInfo.m_bitangents);
  201. AZ_Assert(tangentsAndBitangentsCalculated, "Failed to calculate tangents and bitangents.");
  202. return true;
  203. }
  204. } // namespace NvCloth