EditorClothComponent.cpp 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602
  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/Serialization/SerializeContext.h>
  9. #include <AzCore/Serialization/EditContext.h>
  10. #include <AzToolsFramework/API/ToolsApplicationAPI.h>
  11. #include <Editor/PropertyTypes.h>
  12. #include <Components/EditorClothComponent.h>
  13. #include <Components/ClothComponent.h>
  14. #include <Components/ClothComponentMesh/ClothComponentMesh.h>
  15. #include <Atom/RPI.Reflect/Model/ModelAsset.h>
  16. #include <Utils/AssetHelper.h>
  17. namespace NvCloth
  18. {
  19. namespace Internal
  20. {
  21. extern const char* const StatusMessageSelectNode = "Select a node";
  22. extern const char* const StatusMessageNoAsset = "<No asset>";
  23. extern const char* const StatusMessageNoClothNodes = "<No cloth modifiers>";
  24. const char* const AttributeSuffixMetersUnit = " m";
  25. }
  26. void EditorClothComponent::Reflect(AZ::ReflectContext* context)
  27. {
  28. if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
  29. {
  30. serializeContext->Class<EditorClothComponent, AzToolsFramework::Components::EditorComponentBase>()
  31. ->Field("Configuration", &EditorClothComponent::m_config)
  32. ->Version(0)
  33. ;
  34. if (auto editContext = serializeContext->GetEditContext())
  35. {
  36. editContext->Class<EditorClothComponent>(
  37. "Cloth", "The mesh node behaves like a piece of cloth.")
  38. ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
  39. ->Attribute(AZ::Edit::Attributes::Category, "PhysX")
  40. ->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/Cloth.svg")
  41. ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/Cloth.svg")
  42. ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("Game"))
  43. ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/physx/cloth/")
  44. ->Attribute(AZ::Edit::Attributes::AutoExpand, true)
  45. ->UIElement(AZ::Edit::UIHandlers::CheckBox, "Simulate in editor",
  46. "Enables cloth simulation in editor when set.")
  47. ->Attribute(AZ::Edit::Attributes::CheckboxDefaultValue, &EditorClothComponent::IsSimulatedInEditor)
  48. ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorClothComponent::OnSimulatedInEditorToggled)
  49. ->DataElement(AZ::Edit::UIHandlers::Default, &EditorClothComponent::m_config)
  50. ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorClothComponent::OnConfigurationChanged)
  51. ;
  52. editContext->Class<ClothConfiguration>("Cloth Configuration", "Configuration for cloth simulation.")
  53. ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
  54. ->Attribute(AZ::Edit::Attributes::Category, "PhysX")
  55. ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("Game"))
  56. ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
  57. ->Attribute(AZ::Edit::Attributes::AutoExpand, true)
  58. // Mesh Node
  59. ->DataElement(Editor::MeshNodeSelector, &ClothConfiguration::m_meshNode, "Mesh node",
  60. "List of mesh nodes with cloth simulation data. These are the nodes selected inside Cloth Modifiers in Scene Settings.")
  61. ->Attribute(AZ::Edit::UIHandlers::EntityId, &ClothConfiguration::m_entityId)
  62. ->Attribute(AZ::Edit::Attributes::StringList, &ClothConfiguration::m_meshNodeList)
  63. ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree)
  64. // Mass and Gravity
  65. ->DataElement(AZ::Edit::UIHandlers::Default, &ClothConfiguration::m_mass, "Mass",
  66. "Mass scale applied to all particles.")
  67. ->Attribute(AZ::Edit::Attributes::Min, 0.1f)
  68. ->DataElement(AZ::Edit::UIHandlers::Default, &ClothConfiguration::m_useCustomGravity, "Custom Gravity",
  69. "When enabled it allows to set a custom gravity value for this cloth.")
  70. ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree)
  71. ->DataElement(AZ::Edit::UIHandlers::Default, &ClothConfiguration::m_customGravity, "Gravity",
  72. "Gravity applied to particles.")
  73. ->Attribute(AZ::Edit::Attributes::ReadOnly, &ClothConfiguration::IsUsingWorldBusGravity)
  74. ->DataElement(AZ::Edit::UIHandlers::Default, &ClothConfiguration::m_gravityScale, "Gravity Scale",
  75. "Use this parameter to scale the gravity applied to particles.")
  76. // Global stiffness frequency
  77. ->DataElement(AZ::Edit::UIHandlers::Default, &ClothConfiguration::m_stiffnessFrequency, "Stiffness frequency",
  78. "Stiffness exponent per second applied to damping, damping dragging, wind dragging, wind lifting, self collision stiffness, fabric stiffness, fabric compression, fabric stretch and tether constraint stiffness.")
  79. ->Attribute(AZ::Edit::Attributes::Min, 0.01f)
  80. // Motion Constraints
  81. ->ClassElement(AZ::Edit::ClassElements::Group, "Motion constraints")
  82. ->DataElement(AZ::Edit::UIHandlers::Default, &ClothConfiguration::m_motionConstraintsMaxDistance, "Max Distance",
  83. "Maximum distance for motion constraints to limit particles movement during simulation.")
  84. ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
  85. ->Attribute(AZ::Edit::Attributes::Suffix, Internal::AttributeSuffixMetersUnit)
  86. ->DataElement(AZ::Edit::UIHandlers::Slider, &ClothConfiguration::m_motionConstraintsScale, "Scale",
  87. "Scale value applied to all motion constraints.")
  88. ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
  89. ->Attribute(AZ::Edit::Attributes::Max, 1.0f)
  90. ->Attribute(AZ::Edit::Attributes::Step, 0.0001f)
  91. ->Attribute(AZ::Edit::Attributes::Decimals, 6)
  92. ->DataElement(AZ::Edit::UIHandlers::Default, &ClothConfiguration::m_motionConstraintsBias, "Bias",
  93. "Bias value added to all motion constraints.")
  94. ->Attribute(AZ::Edit::Attributes::Suffix, Internal::AttributeSuffixMetersUnit)
  95. ->DataElement(AZ::Edit::UIHandlers::Slider, &ClothConfiguration::m_motionConstraintsStiffness, "Stiffness",
  96. "Stiffness for motion constraints.")
  97. ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
  98. ->Attribute(AZ::Edit::Attributes::Max, 1.0f)
  99. ->Attribute(AZ::Edit::Attributes::Step, 0.0001f)
  100. ->Attribute(AZ::Edit::Attributes::Decimals, 6)
  101. // Backstop
  102. ->ClassElement(AZ::Edit::ClassElements::Group, "Backstop")
  103. ->Attribute(AZ::Edit::Attributes::Visibility, &ClothConfiguration::m_hasBackstopData)
  104. ->DataElement(AZ::Edit::UIHandlers::Default, &ClothConfiguration::m_backstopRadius, "Radius",
  105. "Maximum radius that will prevent the associated cloth particle from moving into that area.")
  106. ->Attribute(AZ::Edit::Attributes::Min, 0.001f)
  107. ->Attribute(AZ::Edit::Attributes::Suffix, Internal::AttributeSuffixMetersUnit)
  108. ->Attribute(AZ::Edit::Attributes::Visibility, &ClothConfiguration::m_hasBackstopData)
  109. ->DataElement(AZ::Edit::UIHandlers::Default, &ClothConfiguration::m_backstopBackOffset, "Back offset",
  110. "Maximum offset for backstop spheres behind the cloth.")
  111. ->Attribute(AZ::Edit::Attributes::Suffix, Internal::AttributeSuffixMetersUnit)
  112. ->Attribute(AZ::Edit::Attributes::Visibility, &ClothConfiguration::m_hasBackstopData)
  113. ->DataElement(AZ::Edit::UIHandlers::Default, &ClothConfiguration::m_backstopFrontOffset, "Front offset",
  114. "Maximum offset for backstop spheres in front of the cloth.")
  115. ->Attribute(AZ::Edit::Attributes::Suffix, Internal::AttributeSuffixMetersUnit)
  116. ->Attribute(AZ::Edit::Attributes::Visibility, &ClothConfiguration::m_hasBackstopData)
  117. // Damping
  118. ->ClassElement(AZ::Edit::ClassElements::Group, "Damping")
  119. ->DataElement(AZ::Edit::UIHandlers::Default, &ClothConfiguration::m_damping, "Damping",
  120. "Damping of particle velocity.\n"
  121. "0: Velocity is unaffected\n"
  122. "1: Velocity is zeroed")
  123. ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
  124. ->Attribute(AZ::Edit::Attributes::Max, 1.0f)
  125. ->Attribute(AZ::Edit::Attributes::Step, 0.0001f)
  126. ->Attribute(AZ::Edit::Attributes::Decimals, 6)
  127. ->DataElement(AZ::Edit::UIHandlers::Default, &ClothConfiguration::m_linearDrag, "Linear drag",
  128. "Portion of velocity applied to particles.\n"
  129. "0: Particles is unaffected\n"
  130. "1: Damped global particle velocity")
  131. ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
  132. ->Attribute(AZ::Edit::Attributes::Max, 1.0f)
  133. ->Attribute(AZ::Edit::Attributes::Step, 0.0001f)
  134. ->Attribute(AZ::Edit::Attributes::Decimals, 6)
  135. ->DataElement(AZ::Edit::UIHandlers::Default, &ClothConfiguration::m_angularDrag, "Angular drag",
  136. "Portion of angular velocity applied to turning particles.\n"
  137. "0: Particles is unaffected\n"
  138. "1: Damped global particle angular velocity")
  139. ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
  140. ->Attribute(AZ::Edit::Attributes::Max, 1.0f)
  141. ->Attribute(AZ::Edit::Attributes::Step, 0.0001f)
  142. ->Attribute(AZ::Edit::Attributes::Decimals, 6)
  143. // Inertia
  144. ->ClassElement(AZ::Edit::ClassElements::Group, "Inertia")
  145. ->DataElement(AZ::Edit::UIHandlers::Default, &ClothConfiguration::m_linearInteria, "Linear",
  146. "Portion of acceleration applied to particles.\n"
  147. "0: Particles are unaffected\n"
  148. "1: Physically correct")
  149. ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
  150. ->Attribute(AZ::Edit::Attributes::Max, 1.0f)
  151. ->Attribute(AZ::Edit::Attributes::Step, 0.0001f)
  152. ->Attribute(AZ::Edit::Attributes::Decimals, 6)
  153. ->DataElement(AZ::Edit::UIHandlers::Default, &ClothConfiguration::m_angularInteria, "Angular",
  154. "Portion of angular acceleration applied to turning particles.\n"
  155. "0: Particles are unaffected\n"
  156. "1: Physically correct")
  157. ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
  158. ->Attribute(AZ::Edit::Attributes::Max, 1.0f)
  159. ->Attribute(AZ::Edit::Attributes::Step, 0.0001f)
  160. ->Attribute(AZ::Edit::Attributes::Decimals, 6)
  161. ->DataElement(AZ::Edit::UIHandlers::Default, &ClothConfiguration::m_centrifugalInertia, "Centrifugal",
  162. "Portion of angular velocity applied to turning particles.\n"
  163. "0: Particles are unaffected\n"
  164. "1: Physically correct")
  165. ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
  166. ->Attribute(AZ::Edit::Attributes::Max, 1.0f)
  167. ->Attribute(AZ::Edit::Attributes::Step, 0.0001f)
  168. ->Attribute(AZ::Edit::Attributes::Decimals, 6)
  169. // Wind
  170. ->ClassElement(AZ::Edit::ClassElements::Group, "Wind")
  171. ->DataElement(AZ::Edit::UIHandlers::Default, &ClothConfiguration::m_useCustomWindVelocity, "Enable local wind velocity",
  172. "When enabled it allows to set a custom wind velocity value for this cloth, otherwise using wind velocity from Physics::WindBus.\n"
  173. "Wind is disabled when both air coefficients are zero.")
  174. ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree)
  175. ->DataElement(AZ::Edit::UIHandlers::Default, &ClothConfiguration::m_windVelocity, "Local velocity",
  176. "Wind in global coordinates acting on cloth's triangles. Disabled when both air coefficients are zero.\n"
  177. "NOTE: A combination of high values in wind properties can cause unstable results.")
  178. ->Attribute(AZ::Edit::Attributes::Min, -50.0f)
  179. ->Attribute(AZ::Edit::Attributes::Max, 50.0f)
  180. ->Attribute(AZ::Edit::Attributes::ReadOnly, &ClothConfiguration::IsUsingWindBus )
  181. ->DataElement(AZ::Edit::UIHandlers::Slider, &ClothConfiguration::m_airDragCoefficient, "Air drag coefficient",
  182. "Amount of air dragging.\n"
  183. "NOTE: A combination of high values in wind properties can cause unstable results.")
  184. ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
  185. ->Attribute(AZ::Edit::Attributes::Max, 1.0f)
  186. ->Attribute(AZ::Edit::Attributes::Step, 0.0001f)
  187. ->Attribute(AZ::Edit::Attributes::Decimals, 6)
  188. ->DataElement(AZ::Edit::UIHandlers::Slider, &ClothConfiguration::m_airLiftCoefficient, "Air lift coefficient",
  189. "Amount of air lifting.\n"
  190. "NOTE: A combination of high values in wind properties can cause unstable results.")
  191. ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
  192. ->Attribute(AZ::Edit::Attributes::Max, 1.0f)
  193. ->Attribute(AZ::Edit::Attributes::Step, 0.0001f)
  194. ->Attribute(AZ::Edit::Attributes::Decimals, 6)
  195. ->DataElement(AZ::Edit::UIHandlers::Default, &ClothConfiguration::m_fluidDensity, "Air Density",
  196. "Density of air used for air drag and lift calculations.\n"
  197. "NOTE: A combination of high values in wind properties can cause unstable results.")
  198. ->Attribute(AZ::Edit::Attributes::Min, 0.01f)
  199. // Collision
  200. ->ClassElement(AZ::Edit::ClassElements::Group, "Collision")
  201. ->DataElement(AZ::Edit::UIHandlers::Default, &ClothConfiguration::m_collisionFriction, "Friction",
  202. "Amount of friction with colliders.\n"
  203. "0: No friction\n")
  204. ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
  205. ->DataElement(AZ::Edit::UIHandlers::Default, &ClothConfiguration::m_collisionMassScale, "Mass scale",
  206. "Controls how quickly mass is increased during collisions.\n"
  207. "0: No mass scaling\n")
  208. ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
  209. ->DataElement(AZ::Edit::UIHandlers::Default, &ClothConfiguration::m_continuousCollisionDetection, "Continuous detection",
  210. "Continuous collision detection improves collision by computing time of impact between cloth particles and colliders."
  211. "The increase in quality comes with a cost in performance, it's recommended to use only when required.")
  212. ->DataElement(AZ::Edit::UIHandlers::Default, &ClothConfiguration::m_collisionAffectsStaticParticles, "Affects static particles",
  213. "When enabled colliders will move static particles (inverse mass 0).")
  214. // Self collision
  215. ->ClassElement(AZ::Edit::ClassElements::Group, "Self collision")
  216. ->DataElement(AZ::Edit::UIHandlers::Default, &ClothConfiguration::m_selfCollisionDistance, "Distance",
  217. "Meters that particles need to be separated from each other.\n"
  218. "0: No self collision\n")
  219. ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
  220. ->DataElement(AZ::Edit::UIHandlers::Slider, &ClothConfiguration::m_selfCollisionStiffness, "Stiffness",
  221. "Stiffness for the self collision constraints.\n"
  222. "0: No self collision\n")
  223. ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
  224. ->Attribute(AZ::Edit::Attributes::Max, 1.0f)
  225. ->Attribute(AZ::Edit::Attributes::Step, 0.0001f)
  226. ->Attribute(AZ::Edit::Attributes::Decimals, 6)
  227. // Fabric stiffness
  228. ->ClassElement(AZ::Edit::ClassElements::Group, "Fabric stiffness")
  229. ->DataElement(AZ::Edit::UIHandlers::Slider, &ClothConfiguration::m_horizontalStiffness, "Horizontal",
  230. "Stiffness value for horizontal constraints.\n"
  231. "0: no horizontal constraints\n")
  232. ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
  233. ->Attribute(AZ::Edit::Attributes::Max, 1.0f)
  234. ->Attribute(AZ::Edit::Attributes::Step, 0.0001f)
  235. ->Attribute(AZ::Edit::Attributes::Decimals, 6)
  236. ->DataElement(AZ::Edit::UIHandlers::Slider, &ClothConfiguration::m_horizontalStiffnessMultiplier, "Horizontal multiplier",
  237. "Scale value for horizontal fabric compression and stretch limits.\n"
  238. "0: No horizontal compression and stretch limits applied\n"
  239. "1: Fully apply horizontal compression and stretch limits\n")
  240. ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
  241. ->Attribute(AZ::Edit::Attributes::Max, 1.0f)
  242. ->Attribute(AZ::Edit::Attributes::Step, 0.0001f)
  243. ->Attribute(AZ::Edit::Attributes::Decimals, 6)
  244. ->DataElement(AZ::Edit::UIHandlers::Slider, &ClothConfiguration::m_verticalStiffness, "Vertical",
  245. "Stiffness value for vertical constraints.\n"
  246. "0: no vertical constraints\n")
  247. ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
  248. ->Attribute(AZ::Edit::Attributes::Max, 1.0f)
  249. ->Attribute(AZ::Edit::Attributes::Step, 0.0001f)
  250. ->Attribute(AZ::Edit::Attributes::Decimals, 6)
  251. ->DataElement(AZ::Edit::UIHandlers::Slider, &ClothConfiguration::m_verticalStiffnessMultiplier, "Vertical multiplier",
  252. "Scale value for vertical fabric compression and stretch limits.\n"
  253. "0: No vertical compression and stretch limits applied\n"
  254. "1: Fully apply vertical compression and stretch limits\n")
  255. ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
  256. ->Attribute(AZ::Edit::Attributes::Max, 1.0f)
  257. ->Attribute(AZ::Edit::Attributes::Step, 0.0001f)
  258. ->Attribute(AZ::Edit::Attributes::Decimals, 6)
  259. ->DataElement(AZ::Edit::UIHandlers::Slider, &ClothConfiguration::m_bendingStiffness, "Bending",
  260. "Stiffness value for bending constraints.\n"
  261. "0: no bending constraints\n")
  262. ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
  263. ->Attribute(AZ::Edit::Attributes::Max, 1.0f)
  264. ->Attribute(AZ::Edit::Attributes::Step, 0.0001f)
  265. ->Attribute(AZ::Edit::Attributes::Decimals, 6)
  266. ->DataElement(AZ::Edit::UIHandlers::Slider, &ClothConfiguration::m_bendingStiffnessMultiplier, "Bending multiplier",
  267. "Scale value for bending fabric compression and stretch limits.\n"
  268. "0: No bending compression and stretch limits applied\n"
  269. "1: Fully apply bending compression and stretch limits\n")
  270. ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
  271. ->Attribute(AZ::Edit::Attributes::Max, 1.0f)
  272. ->Attribute(AZ::Edit::Attributes::Step, 0.0001f)
  273. ->Attribute(AZ::Edit::Attributes::Decimals, 6)
  274. ->DataElement(AZ::Edit::UIHandlers::Slider, &ClothConfiguration::m_shearingStiffness, "Shearing",
  275. "Stiffness value for shearing constraints.\n"
  276. "0: no shearing constraints\n")
  277. ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
  278. ->Attribute(AZ::Edit::Attributes::Max, 1.0f)
  279. ->Attribute(AZ::Edit::Attributes::Step, 0.0001f)
  280. ->Attribute(AZ::Edit::Attributes::Decimals, 6)
  281. ->DataElement(AZ::Edit::UIHandlers::Slider, &ClothConfiguration::m_shearingStiffnessMultiplier, "Shearing multiplier",
  282. "Scale value for shearing fabric compression and stretch limits.\n"
  283. "0: No shearing compression and stretch limits applied\n"
  284. "1: Fully apply shearing compression and stretch limits\n")
  285. ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
  286. ->Attribute(AZ::Edit::Attributes::Max, 1.0f)
  287. ->Attribute(AZ::Edit::Attributes::Step, 0.0001f)
  288. ->Attribute(AZ::Edit::Attributes::Decimals, 6)
  289. // Fabric compression
  290. ->ClassElement(AZ::Edit::ClassElements::Group, "Fabric compression")
  291. ->DataElement(AZ::Edit::UIHandlers::Default, &ClothConfiguration::m_horizontalCompressionLimit, "Horizontal limit",
  292. "Compression limit for horizontal constraints. It's affected by fabric horizontal stiffness multiplier.\n"
  293. "0: No compression\n")
  294. ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
  295. ->DataElement(AZ::Edit::UIHandlers::Default, &ClothConfiguration::m_verticalCompressionLimit, "Vertical limit",
  296. "Compression limit for vertical constraints. It's affected by fabric vertical stiffness multiplier.\n"
  297. "0: No compression\n")
  298. ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
  299. ->DataElement(AZ::Edit::UIHandlers::Default, &ClothConfiguration::m_bendingCompressionLimit, "Bending limit",
  300. "Compression limit for bending constraints. It's affected by fabric bending stiffness multiplier.\n"
  301. "0: No compression\n")
  302. ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
  303. ->DataElement(AZ::Edit::UIHandlers::Default, &ClothConfiguration::m_shearingCompressionLimit, "Shearing limit",
  304. "Compression limit for shearing constraints. It's affected by fabric shearing stiffness multiplier.\n"
  305. "0: No compression\n")
  306. ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
  307. // Fabric stretch
  308. ->ClassElement(AZ::Edit::ClassElements::Group, "Fabric stretch")
  309. ->DataElement(AZ::Edit::UIHandlers::Default, &ClothConfiguration::m_horizontalStretchLimit, "Horizontal limit",
  310. "Stretch limit for horizontal constraints. It's affected by fabric horizontal stiffness multiplier."
  311. "Reduce stiffness of tether constraints (or increase its scale) to allow cloth to stretch.\n"
  312. "0: No stretching\n")
  313. ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
  314. ->DataElement(AZ::Edit::UIHandlers::Default, &ClothConfiguration::m_verticalStretchLimit, "Vertical limit",
  315. "Stretch limit for vertical constraints. It's affected by fabric vertical stiffness multiplier."
  316. "Reduce stiffness of tether constraints (or increase its scale) to allow cloth to stretch.\n"
  317. "0: No stretching\n")
  318. ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
  319. ->DataElement(AZ::Edit::UIHandlers::Default, &ClothConfiguration::m_bendingStretchLimit, "Bending limit",
  320. "Stretch limit for bending constraints. It's affected by fabric bending stiffness multiplier."
  321. "Reduce stiffness of tether constraints (or increase its scale) to allow cloth to stretch.\n"
  322. "0: No stretching\n")
  323. ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
  324. ->DataElement(AZ::Edit::UIHandlers::Default, &ClothConfiguration::m_shearingStretchLimit, "Shearing limit",
  325. "Stretch limit for shearing constraints. It's affected by fabric shearing stiffness multiplier."
  326. "Reduce stiffness of tether constraints (or increase its scale) to allow cloth to stretch.\n"
  327. "0: No stretching\n")
  328. ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
  329. // Tether constraints
  330. ->ClassElement(AZ::Edit::ClassElements::Group, "Tether constraints")
  331. ->DataElement(AZ::Edit::UIHandlers::Slider, &ClothConfiguration::m_tetherConstraintStiffness, "Stiffness",
  332. "Stiffness for tether constraints. Tether constraints are generated when the inverse mass data of the cloth (selected in the cloth modifier) has static particles.\n"
  333. "0: No tether constraints applied\n"
  334. "1: Makes the constraints behave springy\n")
  335. ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
  336. ->Attribute(AZ::Edit::Attributes::Max, 1.0f)
  337. ->Attribute(AZ::Edit::Attributes::Step, 0.0001f)
  338. ->Attribute(AZ::Edit::Attributes::Decimals, 6)
  339. ->DataElement(AZ::Edit::UIHandlers::Default, &ClothConfiguration::m_tetherConstraintScale, "Scale",
  340. "Tether constraint scale")
  341. ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
  342. // Quality
  343. ->ClassElement(AZ::Edit::ClassElements::Group, "Quality")
  344. ->DataElement(AZ::Edit::UIHandlers::Default, &ClothConfiguration::m_solverFrequency, "Solver frequency",
  345. "Target solver iterations per second. At least 1 iteration per frame will be solved regardless of the value set.")
  346. ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
  347. ->DataElement(AZ::Edit::UIHandlers::Default, &ClothConfiguration::m_accelerationFilterIterations, "Acceleration filter iterations",
  348. "Number of iterations to average delta time factor used for gravity and external acceleration.")
  349. ->Attribute(AZ::Edit::Attributes::Min, 1)
  350. ->DataElement(AZ::Edit::UIHandlers::Default, &ClothConfiguration::m_removeStaticTriangles, "Remove static triangles",
  351. "Removing static triangles improves performance by not taking into account triangles whose particles are all static.\n"
  352. "The removed static particles will not be present for collision or self collision during simulation.")
  353. ->DataElement(AZ::Edit::UIHandlers::Default, &ClothConfiguration::m_updateNormalsOfStaticParticles, "Update normals of static particles",
  354. "When enabled the normals of static particles will be updated according with the movement of the simulated mesh.\n"
  355. "When disabled the static particles will keep the same normals as the original mesh.")
  356. ;
  357. }
  358. }
  359. }
  360. EditorClothComponent::EditorClothComponent()
  361. {
  362. m_meshNodeList = { {Internal::StatusMessageNoAsset} };
  363. m_config.m_meshNodeList = m_meshNodeList;
  364. }
  365. EditorClothComponent::~EditorClothComponent() = default;
  366. void EditorClothComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
  367. {
  368. provided.push_back(AZ_CRC_CE("ClothMeshService"));
  369. }
  370. void EditorClothComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
  371. {
  372. required.push_back(AZ_CRC_CE("MeshService"));
  373. }
  374. void EditorClothComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
  375. {
  376. incompatible.push_back(AZ_CRC_CE("NonUniformScaleService"));
  377. }
  378. const MeshNodeList& EditorClothComponent::GetMeshNodeList() const
  379. {
  380. return m_meshNodeList;
  381. }
  382. const AZStd::unordered_set<AZStd::string>& EditorClothComponent::GetMeshNodesWithBackstopData() const
  383. {
  384. return m_meshNodesWithBackstopData;
  385. }
  386. void EditorClothComponent::BuildGameEntity(AZ::Entity* gameEntity)
  387. {
  388. gameEntity->CreateComponent<ClothComponent>(m_config);
  389. }
  390. void EditorClothComponent::Activate()
  391. {
  392. AzToolsFramework::Components::EditorComponentBase::Activate();
  393. AZ::Render::MeshComponentNotificationBus::Handler::BusConnect(GetEntityId());
  394. m_config.m_entityId = GetEntityId();
  395. }
  396. void EditorClothComponent::Deactivate()
  397. {
  398. AZ::Render::MeshComponentNotificationBus::Handler::BusDisconnect();
  399. AzToolsFramework::Components::EditorComponentBase::Deactivate();
  400. OnModelPreDestroy();
  401. }
  402. void EditorClothComponent::OnModelReady(
  403. const AZ::Data::Asset<AZ::RPI::ModelAsset>& asset,
  404. [[maybe_unused]] const AZ::Data::Instance<AZ::RPI::Model>& model)
  405. {
  406. if (!asset.IsReady())
  407. {
  408. return;
  409. }
  410. m_meshNodeList.clear();
  411. m_meshNodesWithBackstopData.clear();
  412. AZStd::unique_ptr<AssetHelper> assetHelper = AssetHelper::CreateAssetHelper(GetEntityId());
  413. if (assetHelper)
  414. {
  415. // Gather cloth mesh node list
  416. assetHelper->GatherClothMeshNodes(m_meshNodeList);
  417. for (const auto& meshNode : m_meshNodeList)
  418. {
  419. if (ContainsBackstopData(assetHelper.get(), meshNode))
  420. {
  421. m_meshNodesWithBackstopData.insert(meshNode);
  422. }
  423. }
  424. }
  425. if (m_meshNodeList.empty())
  426. {
  427. m_meshNodeList.emplace_back(Internal::StatusMessageNoClothNodes);
  428. m_config.m_meshNode = Internal::StatusMessageNoClothNodes;
  429. }
  430. else
  431. {
  432. bool foundNode = AZStd::find(m_meshNodeList.cbegin(), m_meshNodeList.cend(), m_config.m_meshNode) != m_meshNodeList.cend();
  433. if (!foundNode && !m_lastKnownMeshNode.empty())
  434. {
  435. // Check the if the mesh node previously selected is still part of the mesh list
  436. // to keep using it and avoid the user to select it again in the combo box.
  437. foundNode = AZStd::find(m_meshNodeList.cbegin(), m_meshNodeList.cend(), m_lastKnownMeshNode) != m_meshNodeList.cend();
  438. if (foundNode)
  439. {
  440. m_config.m_meshNode = m_lastKnownMeshNode;
  441. }
  442. }
  443. // If the mesh node is not in the list then add and use an option
  444. // that tells the user to select the node.
  445. if (!foundNode)
  446. {
  447. m_meshNodeList.insert(m_meshNodeList.begin(), Internal::StatusMessageSelectNode);
  448. m_config.m_meshNode = Internal::StatusMessageSelectNode;
  449. }
  450. }
  451. m_lastKnownMeshNode = "";
  452. if (m_simulateInEditor)
  453. {
  454. m_clothComponentMesh = AZStd::make_unique<ClothComponentMesh>(GetEntityId(), m_config);
  455. }
  456. UpdateConfigMeshNodeData();
  457. // Refresh UI
  458. InvalidatePropertyDisplay(AzToolsFramework::Refresh_EntireTree);
  459. }
  460. void EditorClothComponent::OnModelPreDestroy()
  461. {
  462. if (m_config.m_meshNode != Internal::StatusMessageSelectNode &&
  463. m_config.m_meshNode != Internal::StatusMessageNoAsset &&
  464. m_config.m_meshNode != Internal::StatusMessageNoClothNodes)
  465. {
  466. m_lastKnownMeshNode = m_config.m_meshNode;
  467. }
  468. m_meshNodeList = { {Internal::StatusMessageNoAsset} };
  469. m_config.m_meshNode = Internal::StatusMessageNoAsset;
  470. m_clothComponentMesh.reset();
  471. m_meshNodesWithBackstopData.clear();
  472. UpdateConfigMeshNodeData();
  473. // Refresh UI
  474. InvalidatePropertyDisplay(AzToolsFramework::Refresh_EntireTree);
  475. }
  476. bool EditorClothComponent::IsSimulatedInEditor() const
  477. {
  478. return m_simulateInEditor;
  479. }
  480. AZ::u32 EditorClothComponent::OnSimulatedInEditorToggled()
  481. {
  482. m_simulateInEditor = !m_simulateInEditor;
  483. m_clothComponentMesh = AZStd::make_unique<ClothComponentMesh>(GetEntityId(), m_config);
  484. if (!m_simulateInEditor)
  485. {
  486. // Since the instance was just created this will restore the model
  487. // to its original position before cloth simulation.
  488. m_clothComponentMesh->CopyRenderDataToModel();
  489. m_clothComponentMesh.reset();
  490. }
  491. return AZ::Edit::PropertyRefreshLevels::None;
  492. }
  493. void EditorClothComponent::OnConfigurationChanged()
  494. {
  495. if (m_clothComponentMesh)
  496. {
  497. m_clothComponentMesh->UpdateConfiguration(GetEntityId(), m_config);
  498. }
  499. }
  500. bool EditorClothComponent::ContainsBackstopData(AssetHelper* assetHelper, const AZStd::string& meshNode) const
  501. {
  502. if (!assetHelper)
  503. {
  504. return false;
  505. }
  506. // Obtain cloth mesh info
  507. MeshNodeInfo meshNodeInfo;
  508. MeshClothInfo meshClothInfo;
  509. bool clothInfoObtained = assetHelper->ObtainClothMeshNodeInfo(meshNode,
  510. meshNodeInfo, meshClothInfo);
  511. if (!clothInfoObtained)
  512. {
  513. return false;
  514. }
  515. return AZStd::any_of(
  516. meshClothInfo.m_backstopData.cbegin(),
  517. meshClothInfo.m_backstopData.cend(),
  518. [](const AZ::Vector2& backstop)
  519. {
  520. const float backstopRadius = backstop.GetY();
  521. return backstopRadius > 0.0f;
  522. });
  523. }
  524. void EditorClothComponent::UpdateConfigMeshNodeData()
  525. {
  526. // Update our config mesh node data based on changes to the associated Mesh component
  527. // This gets called after updating our internal data on OnModelReady and OnModelPreDestroy
  528. m_config.m_meshNodeList = m_meshNodeList;
  529. auto meshNodeIt = m_meshNodesWithBackstopData.find(m_config.m_meshNode);
  530. m_config.m_hasBackstopData = (meshNodeIt != m_meshNodesWithBackstopData.end());
  531. }
  532. } // namespace NvCloth