3
0

ActorClothSkinning.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561
  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 <Integration/ActorComponentBus.h>
  10. // Needed to access the Mesh information inside Actor.
  11. #include <EMotionFX/Source/TransformData.h>
  12. #include <EMotionFX/Source/ActorInstance.h>
  13. #include <MCore/Source/DualQuaternion.h>
  14. #include <Components/ClothComponentMesh/ActorClothSkinning.h>
  15. #include <Utils/AssetHelper.h>
  16. #include <AzCore/Math/PackedVector3.h>
  17. namespace NvCloth
  18. {
  19. namespace Internal
  20. {
  21. bool ObtainSkinningInfluences(
  22. AZ::EntityId entityId,
  23. const MeshNodeInfo& meshNodeInfo,
  24. AZStd::vector<SkinningInfluence>& skinningInfluences,
  25. AZStd::vector<AZ::u32>& numInfluencesPerSubmesh)
  26. {
  27. AZ::Data::Asset<AZ::RPI::ModelAsset> modelAsset;
  28. AZ::Render::MeshComponentRequestBus::EventResult(
  29. modelAsset, entityId, &AZ::Render::MeshComponentRequestBus::Events::GetModelAsset);
  30. if (!modelAsset.IsReady())
  31. {
  32. return false;
  33. }
  34. if (modelAsset->GetLodCount() < meshNodeInfo.m_lodLevel)
  35. {
  36. return false;
  37. }
  38. const auto modelLodAssets = modelAsset->GetLodAssets();
  39. const AZ::Data::Asset<AZ::RPI::ModelLodAsset> modelLodAsset = modelLodAssets[meshNodeInfo.m_lodLevel];
  40. if (!modelLodAsset.GetId().IsValid())
  41. {
  42. return false;
  43. }
  44. EMotionFX::ActorInstance* actorInstance = nullptr;
  45. EMotionFX::Integration::ActorComponentRequestBus::EventResult(actorInstance, entityId, &EMotionFX::Integration::ActorComponentRequestBus::Events::GetActorInstance);
  46. if (!actorInstance)
  47. {
  48. return false;
  49. }
  50. const EMotionFX::Actor* actor = actorInstance->GetActor();
  51. if (!actor)
  52. {
  53. return false;
  54. }
  55. const auto& skinToSkeletonIndexMap = actor->GetSkinToSkeletonIndexMap();
  56. // Pre-calculate the total number of vertices and the number of influences per-vertex
  57. size_t totalInfluenceCount = 0;
  58. numInfluencesPerSubmesh.clear();
  59. numInfluencesPerSubmesh.reserve(meshNodeInfo.m_subMeshes.size());
  60. for (const auto& subMeshInfo : meshNodeInfo.m_subMeshes)
  61. {
  62. if (modelLodAsset->GetMeshes().size() < subMeshInfo.m_primitiveIndex)
  63. {
  64. AZ_Error("ActorClothSkinning", false,
  65. "Unable to access submesh %d from lod asset '%s' as it only has %d submeshes.",
  66. subMeshInfo.m_primitiveIndex,
  67. modelAsset.GetHint().c_str(),
  68. modelLodAsset->GetMeshes().size());
  69. return false;
  70. }
  71. const auto subMeshes = modelLodAsset->GetMeshes();
  72. const AZ::RPI::ModelLodAsset::Mesh& subMesh = subMeshes[subMeshInfo.m_primitiveIndex];
  73. const auto sourcePositions = subMesh.GetSemanticBufferTyped<AZ::PackedVector3f>(AZ::Name("POSITION"));
  74. if (sourcePositions.size() != subMeshInfo.m_numVertices)
  75. {
  76. AZ_Error("ActorClothSkinning", false,
  77. "Number of vertices (%zu) in submesh %d doesn't match the cloth's submesh (%d)",
  78. sourcePositions.size(), subMeshInfo.m_primitiveIndex, subMeshInfo.m_numVertices);
  79. return false;
  80. }
  81. const auto sourceSkinJointIndices = subMesh.GetSemanticBufferTyped<uint16_t>(AZ::Name("SKIN_JOINTINDICES"));
  82. const auto sourceSkinWeights = subMesh.GetSemanticBufferTyped<float>(AZ::Name("SKIN_WEIGHTS"));
  83. if (sourceSkinJointIndices.empty() || sourceSkinWeights.empty())
  84. {
  85. // Ignoring skinning when there is no skin data.
  86. // All submeshes will either have or not have skin data, since they come from the same mesh.
  87. return false;
  88. }
  89. AZ_Assert(sourceSkinJointIndices.size() == sourceSkinWeights.size(),
  90. "Size of skin joint indices buffer (%zu) different from skin weights buffer (%zu)",
  91. sourceSkinJointIndices.size(), sourceSkinWeights.size());
  92. const AZ::u32 subMeshInfluenceCount = aznumeric_caster(sourceSkinWeights.size() / sourcePositions.size());
  93. AZ_Assert(subMeshInfluenceCount > 0,
  94. "Submesh %d skinning data has zero joint influences per vertex.",
  95. subMeshInfo.m_primitiveIndex);
  96. numInfluencesPerSubmesh.push_back(subMeshInfluenceCount);
  97. totalInfluenceCount += sourceSkinWeights.size();
  98. }
  99. skinningInfluences.resize(totalInfluenceCount);
  100. // For each submesh...
  101. size_t currentInfluenceIndex = 0;
  102. for (size_t meshIndex = 0; meshIndex < meshNodeInfo.m_subMeshes.size(); ++meshIndex)
  103. {
  104. const auto& subMeshInfo = meshNodeInfo.m_subMeshes[meshIndex];
  105. const auto subMeshes = modelLodAsset->GetMeshes();
  106. const AZ::RPI::ModelLodAsset::Mesh& subMesh = subMeshes[subMeshInfo.m_primitiveIndex];
  107. const auto sourceSkinJointIndices = subMesh.GetSemanticBufferTyped<uint16_t>(AZ::Name("SKIN_JOINTINDICES"));
  108. const auto sourceSkinWeights = subMesh.GetSemanticBufferTyped<float>(AZ::Name("SKIN_WEIGHTS"));
  109. size_t numberOfInfluencesPerSubmesh = aznumeric_caster(numInfluencesPerSubmesh[meshIndex]);
  110. for (int subMeshVertexIndex = 0; subMeshVertexIndex < subMeshInfo.m_numVertices; ++subMeshVertexIndex)
  111. {
  112. // sourceSkinJointIndices and sourceSkinWeights buffers are views into the influences for the current mesh.
  113. // Get the offset to the start of the influences for the current vertex
  114. const size_t influenceStart = subMeshVertexIndex * numberOfInfluencesPerSubmesh;
  115. for (size_t influenceIndex = 0; influenceIndex < numberOfInfluencesPerSubmesh; ++influenceIndex)
  116. {
  117. const AZ::u16 jointIndex = sourceSkinJointIndices[influenceStart + influenceIndex];
  118. const float weight = sourceSkinWeights[influenceStart + influenceIndex];
  119. auto skeletonIndexIt = skinToSkeletonIndexMap.find(jointIndex);
  120. if (skeletonIndexIt == skinToSkeletonIndexMap.end())
  121. {
  122. AZ_Error("ActorClothSkinning", false,
  123. "Joint index %d from model asset not found in map to skeleton indices",
  124. jointIndex);
  125. return false;
  126. }
  127. // currentInfluenceIndex is the offset into the unified buffer of skin influences
  128. // that combines all sub-meshes
  129. skinningInfluences[currentInfluenceIndex].m_jointIndex = skeletonIndexIt->second;
  130. skinningInfluences[currentInfluenceIndex].m_jointWeight = weight;
  131. ++currentInfluenceIndex;
  132. }
  133. }
  134. }
  135. return true;
  136. }
  137. EMotionFX::Integration::SkinningMethod ObtainSkinningMethod(AZ::EntityId entityId)
  138. {
  139. EMotionFX::Integration::SkinningMethod skinningMethod =
  140. EMotionFX::Integration::SkinningMethod::DualQuat;
  141. EMotionFX::Integration::ActorComponentRequestBus::EventResult(skinningMethod, entityId,
  142. &EMotionFX::Integration::ActorComponentRequestBus::Events::GetSkinningMethod);
  143. return skinningMethod;
  144. }
  145. const AZ::Matrix3x4* ObtainSkinningMatrices(AZ::EntityId entityId)
  146. {
  147. EMotionFX::ActorInstance* actorInstance = nullptr;
  148. EMotionFX::Integration::ActorComponentRequestBus::EventResult(actorInstance, entityId,
  149. &EMotionFX::Integration::ActorComponentRequestBus::Events::GetActorInstance);
  150. if (!actorInstance)
  151. {
  152. return nullptr;
  153. }
  154. const EMotionFX::TransformData* transformData = actorInstance->GetTransformData();
  155. if (!transformData)
  156. {
  157. return nullptr;
  158. }
  159. return transformData->GetSkinningMatrices();
  160. }
  161. AZStd::unordered_map<AZ::u16, MCore::DualQuaternion> ObtainSkinningDualQuaternions(
  162. AZ::EntityId entityId,
  163. const AZStd::vector<AZ::u16>& jointIndices)
  164. {
  165. const AZ::Matrix3x4* skinningMatrices = ObtainSkinningMatrices(entityId);
  166. if (!skinningMatrices)
  167. {
  168. return {};
  169. }
  170. AZStd::unordered_map<AZ::u16, MCore::DualQuaternion> skinningDualQuaternions;
  171. for (AZ::u16 jointIndex : jointIndices)
  172. {
  173. skinningDualQuaternions.emplace(jointIndex, MCore::DualQuaternion(AZ::Transform::CreateFromMatrix3x4(skinningMatrices[jointIndex])));
  174. }
  175. return skinningDualQuaternions;
  176. }
  177. }
  178. // Specialized class that applies linear blending skinning
  179. class ActorClothSkinningLinear
  180. : public ActorClothSkinning
  181. {
  182. public:
  183. explicit ActorClothSkinningLinear(AZ::EntityId entityId)
  184. : ActorClothSkinning(entityId)
  185. {
  186. }
  187. // ActorClothSkinning overrides ...
  188. void UpdateSkinning() override;
  189. void ApplySkinning(
  190. const AZStd::vector<AZ::Vector4>& originalPositions,
  191. AZStd::vector<AZ::Vector4>& positions) override;
  192. void ApplySkinningOnNonSimulatedVertices(
  193. const MeshClothInfo& originalData,
  194. ClothComponentMesh::RenderData& renderData) override;
  195. private:
  196. AZ::Matrix3x4 ComputeVertexSkinningTransform(
  197. AZ::u32 influenceOffset, AZ::u32 numberOfInfluencesPerVertex);
  198. const AZ::Matrix3x4* m_skinningMatrices = nullptr;
  199. inline static const AZ::Matrix3x4 s_zeroMatrix3x4 = AZ::Matrix3x4::CreateZero();
  200. };
  201. void ActorClothSkinningLinear::UpdateSkinning()
  202. {
  203. AZ_PROFILE_FUNCTION(Cloth);
  204. m_skinningMatrices = Internal::ObtainSkinningMatrices(m_entityId);
  205. }
  206. void ActorClothSkinningLinear::ApplySkinning(
  207. const AZStd::vector<AZ::Vector4>& originalPositions,
  208. AZStd::vector<AZ::Vector4>& positions)
  209. {
  210. if (!m_skinningMatrices ||
  211. originalPositions.empty() ||
  212. originalPositions.size() != positions.size() ||
  213. originalPositions.size() != m_simulatedVertices.size())
  214. {
  215. return;
  216. }
  217. AZ_PROFILE_FUNCTION(Cloth);
  218. const size_t vertexCount = m_simulatedVertices.size();
  219. for (size_t index = 0; index < vertexCount; ++index)
  220. {
  221. const SimulatedVertex& vertex = m_simulatedVertices[index];
  222. const AZ::Matrix3x4 vertexSkinningTransform = ComputeVertexSkinningTransform(vertex.m_influenceOffset, vertex.m_influenceCount);
  223. const AZ::Vector3 skinnedPosition = vertexSkinningTransform * originalPositions[index].GetAsVector3();
  224. positions[index].Set(skinnedPosition, positions[index].GetW()); // Avoid overwriting the w component
  225. }
  226. }
  227. void ActorClothSkinningLinear::ApplySkinningOnNonSimulatedVertices(
  228. const MeshClothInfo& originalData,
  229. ClothComponentMesh::RenderData& renderData)
  230. {
  231. if (!m_skinningMatrices ||
  232. originalData.m_particles.empty() ||
  233. originalData.m_particles.size() != renderData.m_particles.size())
  234. {
  235. return;
  236. }
  237. AZ_PROFILE_FUNCTION(Cloth);
  238. for (const NonSimulatedVertex& vertex : m_nonSimulatedVertices)
  239. {
  240. const AZ::u32 index = vertex.m_originalVertexIndex;
  241. const AZ::Matrix3x4 vertexSkinningTransform =
  242. ComputeVertexSkinningTransform(vertex.m_influenceOffset, vertex.m_influenceCount);
  243. const AZ::Vector3 skinnedPosition = vertexSkinningTransform * originalData.m_particles[index].GetAsVector3();
  244. renderData.m_particles[index].Set(skinnedPosition, renderData.m_particles[index].GetW()); // Avoid overwriting the w component
  245. // Calculate the reciprocal scale version of the matrix to transform the normals.
  246. // Note: This operation is not strictly equivalent to the full inverse transpose when the matrix's
  247. // basis vectors are not perpendicular, which is the case blending linearly the matrices.
  248. // This is a fast approximation, which is also done by the GPU skinning shader.
  249. const AZ::Matrix3x4 vertexSkinningTransformReciprocalScale = vertexSkinningTransform.GetReciprocalScaled();
  250. renderData.m_normals[index] = vertexSkinningTransformReciprocalScale.TransformVector(originalData.m_normals[index]).GetNormalized();
  251. // Tangents and Bitangents are recalculated immediately after this call
  252. // by cloth mesh component, so there is no need to transform them here.
  253. }
  254. }
  255. AZ::Matrix3x4 ActorClothSkinningLinear::ComputeVertexSkinningTransform(
  256. AZ::u32 influenceOffset, AZ::u32 numberOfInfluencesPerVertex)
  257. {
  258. AZ::Matrix3x4 vertexSkinningTransform = s_zeroMatrix3x4;
  259. for (size_t influenceIndex = 0; influenceIndex < numberOfInfluencesPerVertex; ++influenceIndex)
  260. {
  261. const size_t vertexInfluenceIndex = influenceOffset + influenceIndex;
  262. const AZ::u16 jointIndex = m_skinningInfluences[vertexInfluenceIndex].m_jointIndex;
  263. const float jointWeight = m_skinningInfluences[vertexInfluenceIndex].m_jointWeight;
  264. // Blending matrices the same way done in GPU shaders, by adding each weighted matrix element by element.
  265. // This operation results in a non orthogonal matrix, but it's done this way because it's fast to perform.
  266. vertexSkinningTransform += m_skinningMatrices[jointIndex] * jointWeight;
  267. }
  268. return vertexSkinningTransform;
  269. }
  270. // Specialized class that applies dual quaternion blending skinning
  271. class ActorClothSkinningDualQuaternion
  272. : public ActorClothSkinning
  273. {
  274. public:
  275. explicit ActorClothSkinningDualQuaternion(AZ::EntityId entityId)
  276. : ActorClothSkinning(entityId)
  277. {
  278. }
  279. // ActorClothSkinning overrides ...
  280. void UpdateSkinning() override;
  281. void ApplySkinning(
  282. const AZStd::vector<AZ::Vector4>& originalPositions,
  283. AZStd::vector<AZ::Vector4>& positions) override;
  284. void ApplySkinningOnNonSimulatedVertices(
  285. const MeshClothInfo& originalData,
  286. ClothComponentMesh::RenderData& renderData) override;
  287. private:
  288. MCore::DualQuaternion ComputeVertexSkinningTransform(
  289. AZ::u32 influenceOffset, AZ::u32 numberOfInfluencesPerVertex);
  290. AZStd::unordered_map<AZ::u16, MCore::DualQuaternion> m_skinningDualQuaternions;
  291. inline static const MCore::DualQuaternion s_zeroDualQuaternion = MCore::DualQuaternion(AZ::Quaternion::CreateZero(), AZ::Quaternion::CreateZero());
  292. };
  293. void ActorClothSkinningDualQuaternion::UpdateSkinning()
  294. {
  295. AZ_PROFILE_FUNCTION(Cloth);
  296. m_skinningDualQuaternions = Internal::ObtainSkinningDualQuaternions(m_entityId, m_jointIndices);
  297. }
  298. void ActorClothSkinningDualQuaternion::ApplySkinning(
  299. const AZStd::vector<AZ::Vector4>& originalPositions,
  300. AZStd::vector<AZ::Vector4>& positions)
  301. {
  302. if (m_skinningDualQuaternions.empty() ||
  303. originalPositions.empty() ||
  304. originalPositions.size() != positions.size() ||
  305. originalPositions.size() != m_simulatedVertices.size())
  306. {
  307. return;
  308. }
  309. AZ_PROFILE_FUNCTION(Cloth);
  310. const size_t vertexCount = m_simulatedVertices.size();
  311. for (size_t index = 0; index < vertexCount; ++index)
  312. {
  313. const SimulatedVertex& vertex = m_simulatedVertices[index];
  314. const MCore::DualQuaternion vertexSkinningTransform =
  315. ComputeVertexSkinningTransform(vertex.m_influenceOffset, vertex.m_influenceCount);
  316. const AZ::Vector3 skinnedPosition = vertexSkinningTransform.TransformPoint(originalPositions[index].GetAsVector3());
  317. positions[index].Set(skinnedPosition, positions[index].GetW()); // Avoid overwriting the w component
  318. }
  319. }
  320. void ActorClothSkinningDualQuaternion::ApplySkinningOnNonSimulatedVertices(
  321. const MeshClothInfo& originalData,
  322. ClothComponentMesh::RenderData& renderData)
  323. {
  324. if (m_skinningDualQuaternions.empty() ||
  325. originalData.m_particles.empty() ||
  326. originalData.m_particles.size() != renderData.m_particles.size())
  327. {
  328. return;
  329. }
  330. AZ_PROFILE_FUNCTION(Cloth);
  331. for (const NonSimulatedVertex& vertex : m_nonSimulatedVertices)
  332. {
  333. const AZ::u32 index = vertex.m_originalVertexIndex;
  334. const MCore::DualQuaternion vertexSkinningTransform =
  335. ComputeVertexSkinningTransform(vertex.m_influenceOffset, vertex.m_influenceCount);
  336. const AZ::Vector3 skinnedPosition = vertexSkinningTransform.TransformPoint(originalData.m_particles[index].GetAsVector3());
  337. renderData.m_particles[index].Set(skinnedPosition, renderData.m_particles[index].GetW()); // Avoid overwriting the w component
  338. // ComputeVertexSkinningTransform is normalizing the blended dual quaternion. This means the dual
  339. // quaternion will not have any scale and there is no need to compute the reciprocal scale version
  340. // for transforming normals.
  341. // Note: The GPU skinning shader does the same operation.
  342. renderData.m_normals[index] = vertexSkinningTransform.TransformVector(originalData.m_normals[index]).GetNormalized();
  343. // Tangents and Bitangents are recalculated immediately after this call
  344. // by cloth mesh component, so there is no need to transform them here.
  345. }
  346. }
  347. MCore::DualQuaternion ActorClothSkinningDualQuaternion::ComputeVertexSkinningTransform(AZ::u32 influenceOffset, AZ::u32 numberOfInfluencesPerVertex)
  348. {
  349. MCore::DualQuaternion vertexSkinningTransform = s_zeroDualQuaternion;
  350. for (size_t influenceIndex = 0; influenceIndex < numberOfInfluencesPerVertex; ++influenceIndex)
  351. {
  352. const size_t vertexInfluenceIndex = influenceOffset + influenceIndex;
  353. const AZ::u16 jointIndex = m_skinningInfluences[vertexInfluenceIndex].m_jointIndex;
  354. const float jointWeight = m_skinningInfluences[vertexInfluenceIndex].m_jointWeight;
  355. const MCore::DualQuaternion& skinningDualQuaternion = m_skinningDualQuaternions.at(jointIndex);
  356. float flip = AZ::GetSign(vertexSkinningTransform.m_real.Dot(skinningDualQuaternion.m_real));
  357. vertexSkinningTransform += skinningDualQuaternion * jointWeight * flip;
  358. }
  359. // Normalizing the dual quaternion as the GPU shaders do. This will remove the scale from the transform.
  360. vertexSkinningTransform.Normalize();
  361. return vertexSkinningTransform;
  362. }
  363. AZStd::unique_ptr<ActorClothSkinning> ActorClothSkinning::Create(
  364. AZ::EntityId entityId,
  365. const MeshNodeInfo& meshNodeInfo,
  366. const AZStd::vector<SimParticleFormat>& originalMeshParticles,
  367. const size_t numSimulatedVertices,
  368. const AZStd::vector<int>& meshRemappedVertices)
  369. {
  370. const size_t numVertices = originalMeshParticles.size();
  371. AZStd::vector<SkinningInfluence> skinningInfluences;
  372. AZStd::vector<AZ::u32> numInfluencesPerSubmesh;
  373. if (!Internal::ObtainSkinningInfluences(entityId, meshNodeInfo, skinningInfluences, numInfluencesPerSubmesh))
  374. {
  375. return nullptr;
  376. }
  377. AZStd::unique_ptr<ActorClothSkinning> actorClothSkinning;
  378. const auto skinningMethod = Internal::ObtainSkinningMethod(entityId);
  379. switch (skinningMethod)
  380. {
  381. case EMotionFX::Integration::SkinningMethod::DualQuat:
  382. actorClothSkinning = AZStd::make_unique<ActorClothSkinningDualQuaternion>(entityId);
  383. break;
  384. case EMotionFX::Integration::SkinningMethod::Linear:
  385. actorClothSkinning = AZStd::make_unique<ActorClothSkinningLinear>(entityId);
  386. break;
  387. default:
  388. AZ_Error("ActorClothSkinning", false,
  389. "Unknown skinning method (%u).", static_cast<AZ::u32>(skinningMethod));
  390. return nullptr;
  391. }
  392. // Collect all indices of the joints that influence the vertices
  393. AZStd::set<AZ::u16> jointIndices;
  394. for (const auto& skinningInfluence : skinningInfluences)
  395. {
  396. jointIndices.insert(skinningInfluence.m_jointIndex);
  397. }
  398. actorClothSkinning->m_jointIndices.assign(jointIndices.begin(), jointIndices.end());
  399. // Collect the indices for simulated and non-simulated vertices
  400. actorClothSkinning->m_simulatedVertices.resize(numSimulatedVertices);
  401. actorClothSkinning->m_nonSimulatedVertices.reserve(numVertices);
  402. // For each submesh...
  403. int meshIndexOffset = 0;
  404. AZ::u32 meshInfluenceOffset = 0;
  405. for (size_t subMeshIndex = 0; subMeshIndex < meshNodeInfo.m_subMeshes.size(); ++subMeshIndex)
  406. {
  407. const auto& subMeshInfo = meshNodeInfo.m_subMeshes[subMeshIndex];
  408. for (int vertexIndex = meshIndexOffset; vertexIndex < meshIndexOffset + subMeshInfo.m_numVertices; ++vertexIndex)
  409. {
  410. const AZ::u32 influenceOffset = meshInfluenceOffset + (vertexIndex - meshIndexOffset) * numInfluencesPerSubmesh[subMeshIndex];
  411. // The cloth cooker has previously simplified the original mesh and re-mapped the vertices
  412. const int remappedIndex = meshRemappedVertices[vertexIndex];
  413. // If the vertex has been remapped, it's part of the simulation
  414. if (remappedIndex >= 0)
  415. {
  416. SimulatedVertex vertex;
  417. vertex.m_influenceOffset = influenceOffset;
  418. vertex.m_influenceCount = numInfluencesPerSubmesh[subMeshIndex];
  419. actorClothSkinning->m_simulatedVertices[remappedIndex] = vertex;
  420. }
  421. if (remappedIndex < 0 || originalMeshParticles[vertexIndex].GetW() == 0.0f)
  422. {
  423. NonSimulatedVertex vertex;
  424. vertex.m_originalVertexIndex = static_cast<AZ::u32>(vertexIndex);
  425. vertex.m_influenceOffset = influenceOffset;
  426. vertex.m_influenceCount = numInfluencesPerSubmesh[subMeshIndex];
  427. actorClothSkinning->m_nonSimulatedVertices.emplace_back(vertex);
  428. }
  429. }
  430. meshIndexOffset += subMeshInfo.m_numVertices;
  431. meshInfluenceOffset += subMeshInfo.m_numVertices * numInfluencesPerSubmesh[subMeshIndex];
  432. }
  433. actorClothSkinning->m_nonSimulatedVertices.shrink_to_fit();
  434. actorClothSkinning->m_skinningInfluences = AZStd::move(skinningInfluences);
  435. return actorClothSkinning;
  436. }
  437. ActorClothSkinning::ActorClothSkinning(AZ::EntityId entityId)
  438. : m_entityId(entityId)
  439. {
  440. }
  441. void ActorClothSkinning::UpdateActorVisibility()
  442. {
  443. bool isVisible = true;
  444. EMotionFX::ActorInstance* actorInstance = nullptr;
  445. EMotionFX::Integration::ActorComponentRequestBus::EventResult(actorInstance, m_entityId,
  446. &EMotionFX::Integration::ActorComponentRequestBus::Events::GetActorInstance);
  447. if (actorInstance)
  448. {
  449. isVisible = actorInstance->GetIsVisible();
  450. }
  451. m_wasActorVisible = m_isActorVisible;
  452. m_isActorVisible = isVisible;
  453. }
  454. bool ActorClothSkinning::IsActorVisible() const
  455. {
  456. return m_isActorVisible;
  457. }
  458. bool ActorClothSkinning::WasActorVisible() const
  459. {
  460. return m_wasActorVisible;
  461. }
  462. } // namespace NvCloth