3
0

ClothRule.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  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/Memory/SystemAllocator.h>
  9. #include <AzCore/RTTI/ReflectContext.h>
  10. #include <AzCore/Serialization/EditContext.h>
  11. #include <SceneAPI/SceneCore/DataTypes/GraphData/IMeshData.h>
  12. #include <SceneAPI/SceneCore/DataTypes/GraphData/IMeshVertexColorData.h>
  13. #include <Pipeline/SceneAPIExt/ClothRule.h>
  14. namespace NvCloth
  15. {
  16. namespace Pipeline
  17. {
  18. // It's necessary for the rule to specify the system allocator, otherwise
  19. // the editor crashes when deleting the cloth modifier from Scene Settings.
  20. AZ_CLASS_ALLOCATOR_IMPL(ClothRule, AZ::SystemAllocator)
  21. const char* const ClothRule::DefaultChooseNodeName = "Choose a node";
  22. const char* const ClothRule::DefaultInverseMassesString = "Default: 1.0";
  23. const char* const ClothRule::DefaultMotionConstraintsString = "Default: 1.0";
  24. const char* const ClothRule::DefaultBackstopString = "None";
  25. const AZStd::string& ClothRule::GetMeshNodeName() const
  26. {
  27. return m_meshNodeName;
  28. }
  29. AZStd::vector<AZ::Color> ClothRule::ExtractClothData(
  30. const AZ::SceneAPI::Containers::SceneGraph& graph,
  31. const size_t numVertices) const
  32. {
  33. const AZ::SceneAPI::Containers::SceneGraph::NodeIndex meshNodeIndex = [this, &graph]()
  34. {
  35. const auto originalMeshIndex = graph.Find(GetMeshNodeName());
  36. return AZ::SceneAPI::Utilities::SceneGraphSelector::RemapToOptimizedMesh(
  37. graph, originalMeshIndex);
  38. }();
  39. if (!meshNodeIndex.IsValid())
  40. {
  41. return {};
  42. }
  43. const float defaultInverseMass = 1.0f;
  44. const float defaultMotionConstraint = 1.0f;
  45. const float defaultBackstopOffset = 0.5f; // 0.5 means offset 0 once the range is converted from [0,1] -> [-1,1]
  46. const float defaultBackstopRadius = 0.0f;
  47. using GetterFunction = AZStd::function<float(size_t index)>;
  48. GetterFunction getInverseMass = [defaultInverseMass]([[maybe_unused]] size_t index) { return defaultInverseMass; };
  49. GetterFunction getMotionConstraint = [defaultMotionConstraint]([[maybe_unused]] size_t index) { return defaultMotionConstraint; };
  50. GetterFunction getBackstopOffset = [defaultBackstopOffset]([[maybe_unused]] size_t index) { return defaultBackstopOffset; };
  51. GetterFunction getBackstopRadius = [defaultBackstopRadius]([[maybe_unused]] size_t index) { return defaultBackstopRadius; };
  52. auto getColorChannelSafe = [](
  53. const AZ::SceneAPI::DataTypes::IMeshVertexColorData* data,
  54. size_t index,
  55. AZ::SceneAPI::DataTypes::ColorChannel channel)
  56. {
  57. const float colorChannel = data->GetColor(index).GetChannel(channel);
  58. return AZ::GetClamp(colorChannel, 0.0f, 1.0f);
  59. };
  60. if (!IsInverseMassesStreamDisabled())
  61. {
  62. if (auto data = FindVertexColorData(graph, meshNodeIndex, m_inverseMassesStreamName, numVertices))
  63. {
  64. getInverseMass =
  65. [&getColorChannelSafe, data, channel = m_inverseMassesChannel](size_t index)
  66. {
  67. return getColorChannelSafe(data.get(), index, channel);
  68. };
  69. }
  70. }
  71. if (!IsMotionConstraintsStreamDisabled())
  72. {
  73. if (auto data = FindVertexColorData(graph, meshNodeIndex, m_motionConstraintsStreamName, numVertices))
  74. {
  75. getMotionConstraint =
  76. [&getColorChannelSafe, data, channel = m_motionConstraintsChannel](size_t index)
  77. {
  78. return getColorChannelSafe(data.get(), index, channel);
  79. };
  80. }
  81. }
  82. if (!IsBackstopStreamDisabled())
  83. {
  84. if (auto data = FindVertexColorData(graph, meshNodeIndex, m_backstopStreamName, numVertices))
  85. {
  86. getBackstopOffset =
  87. [&getColorChannelSafe, data, channel = m_backstopOffsetChannel](size_t index)
  88. {
  89. return getColorChannelSafe(data.get(), index, channel);
  90. };
  91. getBackstopRadius =
  92. [&getColorChannelSafe, data, channel = m_backstopRadiusChannel](size_t index)
  93. {
  94. return getColorChannelSafe(data.get(), index, channel);
  95. };
  96. }
  97. }
  98. AZStd::vector<AZ::Color> clothData;
  99. clothData.resize_no_construct(numVertices);
  100. // Compile all the data to the vertex color stream of the mesh.
  101. for (size_t i = 0; i < numVertices; ++i)
  102. {
  103. clothData[i].Set(
  104. getInverseMass(i), // Store inverse masses in red channel
  105. getMotionConstraint(i), // Store motion constraints in green channel
  106. getBackstopOffset(i), // Store backstop offsets in blue channel
  107. getBackstopRadius(i)); // Store backstop radius in alpha channel
  108. }
  109. return clothData;
  110. }
  111. const AZStd::string& ClothRule::GetInverseMassesStreamName() const
  112. {
  113. return m_inverseMassesStreamName;
  114. }
  115. const AZStd::string& ClothRule::GetMotionConstraintsStreamName() const
  116. {
  117. return m_motionConstraintsStreamName;
  118. }
  119. const AZStd::string& ClothRule::GetBackstopStreamName() const
  120. {
  121. return m_backstopStreamName;
  122. }
  123. void ClothRule::SetMeshNodeName(const AZStd::string& name)
  124. {
  125. m_meshNodeName = name;
  126. }
  127. void ClothRule::SetInverseMassesStreamName(const AZStd::string& name)
  128. {
  129. m_inverseMassesStreamName = name;
  130. }
  131. void ClothRule::SetMotionConstraintsStreamName(const AZStd::string& name)
  132. {
  133. m_motionConstraintsStreamName = name;
  134. }
  135. void ClothRule::SetBackstopStreamName(const AZStd::string& name)
  136. {
  137. m_backstopStreamName = name;
  138. }
  139. bool ClothRule::IsInverseMassesStreamDisabled() const
  140. {
  141. return m_inverseMassesStreamName == DefaultInverseMassesString;
  142. }
  143. bool ClothRule::IsMotionConstraintsStreamDisabled() const
  144. {
  145. return m_motionConstraintsStreamName == DefaultMotionConstraintsString;
  146. }
  147. bool ClothRule::IsBackstopStreamDisabled() const
  148. {
  149. return m_backstopStreamName == DefaultBackstopString;
  150. }
  151. AZ::SceneAPI::DataTypes::ColorChannel ClothRule::GetInverseMassesStreamChannel() const
  152. {
  153. return m_inverseMassesChannel;
  154. }
  155. AZ::SceneAPI::DataTypes::ColorChannel ClothRule::GetMotionConstraintsStreamChannel() const
  156. {
  157. return m_motionConstraintsChannel;
  158. }
  159. AZ::SceneAPI::DataTypes::ColorChannel ClothRule::GetBackstopOffsetStreamChannel() const
  160. {
  161. return m_backstopOffsetChannel;
  162. }
  163. AZ::SceneAPI::DataTypes::ColorChannel ClothRule::GetBackstopRadiusStreamChannel() const
  164. {
  165. return m_backstopRadiusChannel;
  166. }
  167. void ClothRule::SetInverseMassesStreamChannel(AZ::SceneAPI::DataTypes::ColorChannel channel)
  168. {
  169. m_inverseMassesChannel = channel;
  170. }
  171. void ClothRule::SetMotionConstraintsStreamChannel(AZ::SceneAPI::DataTypes::ColorChannel channel)
  172. {
  173. m_motionConstraintsChannel = channel;
  174. }
  175. void ClothRule::SetBackstopOffsetStreamChannel(AZ::SceneAPI::DataTypes::ColorChannel channel)
  176. {
  177. m_backstopOffsetChannel = channel;
  178. }
  179. void ClothRule::SetBackstopRadiusStreamChannel(AZ::SceneAPI::DataTypes::ColorChannel channel)
  180. {
  181. m_backstopRadiusChannel = channel;
  182. }
  183. AZStd::shared_ptr<const AZ::SceneAPI::DataTypes::IMeshVertexColorData> ClothRule::FindVertexColorData(
  184. const AZ::SceneAPI::Containers::SceneGraph& graph,
  185. const AZ::SceneAPI::Containers::SceneGraph::NodeIndex& meshNodeIndex,
  186. const AZStd::string& vertexColorName,
  187. const size_t numVertices) const
  188. {
  189. if (vertexColorName.empty())
  190. {
  191. return nullptr;
  192. }
  193. const auto vertexColorNodeIndex = graph.Find(meshNodeIndex, vertexColorName);
  194. auto vertexColorData = azrtti_cast<const AZ::SceneAPI::DataTypes::IMeshVertexColorData*>(graph.GetNodeContent(vertexColorNodeIndex));
  195. if (vertexColorData)
  196. {
  197. if (numVertices != vertexColorData->GetCount())
  198. {
  199. AZ_TracePrintf(AZ::SceneAPI::Utilities::WarningWindow,
  200. "Number of vertices in the mesh node '%s' (%zu) doesn't match with the number of stored vertex color stream '%s' (%zu).",
  201. GetMeshNodeName().c_str(), numVertices, vertexColorName.c_str(), vertexColorData->GetCount());
  202. vertexColorData.reset();
  203. }
  204. }
  205. else
  206. {
  207. AZ_TracePrintf(AZ::SceneAPI::Utilities::WarningWindow,
  208. "Vertex color stream '%s' not found for mesh node '%s'.",
  209. vertexColorName.c_str(),
  210. GetMeshNodeName().c_str());
  211. }
  212. return vertexColorData;
  213. }
  214. void ClothRule::Reflect(AZ::ReflectContext* context)
  215. {
  216. AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
  217. if (!serializeContext)
  218. {
  219. return;
  220. }
  221. serializeContext->Class<AZ::SceneAPI::DataTypes::IClothRule, AZ::SceneAPI::DataTypes::IRule>()->Version(1);
  222. serializeContext->Class<ClothRule, AZ::SceneAPI::DataTypes::IClothRule>()
  223. ->Version(2, &VersionConverter)
  224. ->Field("meshNodeName", &ClothRule::m_meshNodeName)
  225. ->Field("inverseMassesStreamName", &ClothRule::m_inverseMassesStreamName)
  226. ->Field("inverseMassesChannel", &ClothRule::m_inverseMassesChannel)
  227. ->Field("motionConstraintsStreamName", &ClothRule::m_motionConstraintsStreamName)
  228. ->Field("motionConstraintsChannel", &ClothRule::m_motionConstraintsChannel)
  229. ->Field("backstopStreamName", &ClothRule::m_backstopStreamName)
  230. ->Field("backstopOffsetChannel", &ClothRule::m_backstopOffsetChannel)
  231. ->Field("backstopRadiusChannel", &ClothRule::m_backstopRadiusChannel);
  232. AZ::EditContext* editContext = serializeContext->GetEditContext();
  233. if (editContext)
  234. {
  235. editContext->Class<ClothRule>("Cloth", "Adds cloth data to the exported CGF asset. The cloth data will be used to determine what meshes to use for cloth simulation.")
  236. ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
  237. ->Attribute(AZ::Edit::Attributes::AutoExpand, true)
  238. ->Attribute(AZ::Edit::Attributes::NameLabelOverride, "")
  239. ->DataElement("NodeListSelection", &ClothRule::m_meshNodeName, "Select Cloth Mesh", "Mesh used for cloth simulation.")
  240. ->Attribute("ClassTypeIdFilter", AZ::SceneAPI::DataTypes::IMeshData::TYPEINFO_Uuid())
  241. ->Attribute("DisabledOption", DefaultChooseNodeName)
  242. ->DataElement("NodeListSelection", &ClothRule::m_inverseMassesStreamName, "Inverse Masses",
  243. "Select the 'vertex color' stream that contains cloth inverse masses or 'Default: 1.0' to use mass 1.0 for all vertices.")
  244. ->Attribute("ClassTypeIdFilter", AZ::SceneAPI::DataTypes::IMeshVertexColorData::TYPEINFO_Uuid())
  245. ->Attribute("DisabledOption", DefaultInverseMassesString)
  246. ->Attribute("UseShortNames", true)
  247. ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree)
  248. ->DataElement(AZ::Edit::UIHandlers::ComboBox, &ClothRule::m_inverseMassesChannel, "Inverse Masses Channel",
  249. "Select which color channel to obtain the inverse mass information from.")
  250. ->EnumAttribute(AZ::SceneAPI::DataTypes::ColorChannel::Red, "Red")
  251. ->EnumAttribute(AZ::SceneAPI::DataTypes::ColorChannel::Green, "Green")
  252. ->EnumAttribute(AZ::SceneAPI::DataTypes::ColorChannel::Blue, "Blue")
  253. ->EnumAttribute(AZ::SceneAPI::DataTypes::ColorChannel::Alpha, "Alpha")
  254. ->Attribute(AZ::Edit::Attributes::ReadOnly, &ClothRule::IsInverseMassesStreamDisabled)
  255. ->DataElement("NodeListSelection", &ClothRule::m_motionConstraintsStreamName, "Motion Constraints",
  256. "Select the 'vertex color' stream that contains cloth motion constraints or 'Default: 1.0' to use 1.0 for all vertices.")
  257. ->Attribute("ClassTypeIdFilter", AZ::SceneAPI::DataTypes::IMeshVertexColorData::TYPEINFO_Uuid())
  258. ->Attribute("DisabledOption", DefaultMotionConstraintsString)
  259. ->Attribute("UseShortNames", true)
  260. ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree)
  261. ->DataElement(AZ::Edit::UIHandlers::ComboBox, &ClothRule::m_motionConstraintsChannel, "Motion Constraints Channel",
  262. "Select which color channel to obtain the motion constraints information from.")
  263. ->EnumAttribute(AZ::SceneAPI::DataTypes::ColorChannel::Red, "Red")
  264. ->EnumAttribute(AZ::SceneAPI::DataTypes::ColorChannel::Green, "Green")
  265. ->EnumAttribute(AZ::SceneAPI::DataTypes::ColorChannel::Blue, "Blue")
  266. ->EnumAttribute(AZ::SceneAPI::DataTypes::ColorChannel::Alpha, "Alpha")
  267. ->Attribute(AZ::Edit::Attributes::ReadOnly, &ClothRule::IsMotionConstraintsStreamDisabled)
  268. ->DataElement("NodeListSelection", &ClothRule::m_backstopStreamName, "Backstop",
  269. "Select the 'vertex color' stream that contains cloth backstop data.")
  270. ->Attribute("ClassTypeIdFilter", AZ::SceneAPI::DataTypes::IMeshVertexColorData::TYPEINFO_Uuid())
  271. ->Attribute("DisabledOption", DefaultBackstopString)
  272. ->Attribute("UseShortNames", true)
  273. ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree)
  274. ->DataElement(AZ::Edit::UIHandlers::ComboBox, &ClothRule::m_backstopOffsetChannel, "Backstop Offset Channel",
  275. "Select which color channel to obtain the backstop offset from.")
  276. ->EnumAttribute(AZ::SceneAPI::DataTypes::ColorChannel::Red, "Red")
  277. ->EnumAttribute(AZ::SceneAPI::DataTypes::ColorChannel::Green, "Green")
  278. ->EnumAttribute(AZ::SceneAPI::DataTypes::ColorChannel::Blue, "Blue")
  279. ->EnumAttribute(AZ::SceneAPI::DataTypes::ColorChannel::Alpha, "Alpha")
  280. ->Attribute(AZ::Edit::Attributes::ReadOnly, &ClothRule::IsBackstopStreamDisabled)
  281. ->DataElement(AZ::Edit::UIHandlers::ComboBox, &ClothRule::m_backstopRadiusChannel, "Backstop Radius Channel",
  282. "Select which color channel to obtain the backstop radius from.")
  283. ->EnumAttribute(AZ::SceneAPI::DataTypes::ColorChannel::Red, "Red")
  284. ->EnumAttribute(AZ::SceneAPI::DataTypes::ColorChannel::Green, "Green")
  285. ->EnumAttribute(AZ::SceneAPI::DataTypes::ColorChannel::Blue, "Blue")
  286. ->EnumAttribute(AZ::SceneAPI::DataTypes::ColorChannel::Alpha, "Alpha")
  287. ->Attribute(AZ::Edit::Attributes::ReadOnly, &ClothRule::IsBackstopStreamDisabled);
  288. }
  289. }
  290. bool ClothRule::VersionConverter(
  291. AZ::SerializeContext& context,
  292. AZ::SerializeContext::DataElementNode& classElement)
  293. {
  294. if (classElement.GetVersion() <= 1)
  295. {
  296. AZStd::string vertexColorStreamName;
  297. classElement.FindSubElementAndGetData(AZ_CRC_CE("vertexColorStreamName"), vertexColorStreamName);
  298. classElement.RemoveElementByName(AZ_CRC_CE("vertexColorStreamName"));
  299. classElement.AddElementWithData(context, "inverseMassesStreamName", vertexColorStreamName.empty() ? AZStd::string(DefaultInverseMassesString) : vertexColorStreamName);
  300. classElement.AddElementWithData(context, "motionConstraintsStreamName", AZStd::string(DefaultMotionConstraintsString));
  301. classElement.AddElementWithData(context, "backstopStreamName", AZStd::string(DefaultBackstopString));
  302. }
  303. return true;
  304. }
  305. } // namespace Pipeline
  306. } // namespace NvCloth