PhysXMaterialConfiguration.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  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 <AzCore/Asset/AssetManager.h>
  11. #include <AzFramework/Physics/NameConstants.h>
  12. #include <PhysX/Material/PhysXMaterialConfiguration.h>
  13. namespace PhysX
  14. {
  15. void CompliantContactModeConfiguration::Reflect(AZ::ReflectContext* context)
  16. {
  17. if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
  18. {
  19. serializeContext->Class<PhysX::CompliantContactModeConfiguration>()
  20. ->Version(1)
  21. ->Field("Enabled", &CompliantContactModeConfiguration::m_enabled)
  22. ->Field("Damping", &CompliantContactModeConfiguration::m_damping)
  23. ->Field("Stiffness", &CompliantContactModeConfiguration::m_stiffness);
  24. if (auto* editContext = serializeContext->GetEditContext())
  25. {
  26. editContext->Class<PhysX::CompliantContactModeConfiguration>("", "")
  27. ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
  28. ->DataElement(
  29. AZ::Edit::UIHandlers::Default,
  30. &CompliantContactModeConfiguration::m_enabled,
  31. "Enable",
  32. "When enabled the normal force of the contact is computed using an implicit spring. Restitution properties are not used when enabled.")
  33. ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::AttributesAndValues)
  34. ->DataElement(
  35. AZ::Edit::UIHandlers::Default,
  36. &CompliantContactModeConfiguration::m_damping,
  37. "Damping",
  38. "Higher damping values produce spongy contacts.")
  39. ->Attribute(AZ::Edit::Attributes::Min, 0.f)
  40. ->Attribute(AZ::Edit::Attributes::ReadOnly, &CompliantContactModeConfiguration::ReadOnlyProperties)
  41. ->DataElement(
  42. AZ::Edit::UIHandlers::Default,
  43. &CompliantContactModeConfiguration::m_stiffness,
  44. "Stiffness",
  45. "Higher stiffness values produce stiffer springs that behave more like a rigid contact. The higher the mass of the object, the higher the stiffness needs to be to reduce penetration.")
  46. ->Attribute(AZ::Edit::Attributes::Min, 0.f)
  47. ->Attribute(AZ::Edit::Attributes::ReadOnly, &CompliantContactModeConfiguration::ReadOnlyProperties);
  48. }
  49. }
  50. }
  51. bool CompliantContactModeConfiguration::ReadOnlyProperties() const
  52. {
  53. return !m_enabled;
  54. }
  55. void MaterialConfiguration::Reflect(AZ::ReflectContext* context)
  56. {
  57. CompliantContactModeConfiguration::Reflect(context);
  58. if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
  59. {
  60. serializeContext->Class<PhysX::MaterialConfiguration>()
  61. ->Version(1)
  62. ->Field("DynamicFriction", &MaterialConfiguration::m_dynamicFriction)
  63. ->Field("StaticFriction", &MaterialConfiguration::m_staticFriction)
  64. ->Field("Restitution", &MaterialConfiguration::m_restitution)
  65. ->Field("FrictionCombine", &MaterialConfiguration::m_frictionCombine)
  66. ->Field("RestitutionCombine", &MaterialConfiguration::m_restitutionCombine)
  67. ->Field("Density", &MaterialConfiguration::m_density)
  68. ->Field("CompliantContactMode", &MaterialConfiguration::m_compliantContactMode)
  69. ->Field("DebugColor", &MaterialConfiguration::m_debugColor)
  70. ;
  71. if (auto* editContext = serializeContext->GetEditContext())
  72. {
  73. editContext->Class<PhysX::MaterialConfiguration>("", "")
  74. ->ClassElement(AZ::Edit::ClassElements::EditorData, "PhysX Material")
  75. ->Attribute(AZ::Edit::Attributes::AutoExpand, true)
  76. ->DataElement(AZ::Edit::UIHandlers::Default, &MaterialConfiguration::m_staticFriction, "Static friction", "Friction coefficient when object is still")
  77. ->Attribute(AZ::Edit::Attributes::Min, 0.f)
  78. ->DataElement(AZ::Edit::UIHandlers::Default, &MaterialConfiguration::m_dynamicFriction, "Dynamic friction", "Friction coefficient when object is moving")
  79. ->Attribute(AZ::Edit::Attributes::Min, 0.f)
  80. ->DataElement(AZ::Edit::UIHandlers::Default, &MaterialConfiguration::m_restitution, "Restitution", "Restitution coefficient")
  81. ->Attribute(AZ::Edit::Attributes::Min, 0.f)
  82. ->Attribute(AZ::Edit::Attributes::Max, 1.f)
  83. ->Attribute(AZ::Edit::Attributes::ReadOnly, &MaterialConfiguration::IsRestitutionReadOnly)
  84. ->DataElement(AZ::Edit::UIHandlers::ComboBox, &MaterialConfiguration::m_frictionCombine, "Friction combine", "How the friction is combined between colliding objects")
  85. ->EnumAttribute(CombineMode::Average, "Average")
  86. ->EnumAttribute(CombineMode::Minimum, "Minimum")
  87. ->EnumAttribute(CombineMode::Maximum, "Maximum")
  88. ->EnumAttribute(CombineMode::Multiply, "Multiply")
  89. ->DataElement(AZ::Edit::UIHandlers::ComboBox, &MaterialConfiguration::m_restitutionCombine, "Restitution combine", "How the restitution is combined between colliding objects")
  90. ->EnumAttribute(CombineMode::Average, "Average")
  91. ->EnumAttribute(CombineMode::Minimum, "Minimum")
  92. ->EnumAttribute(CombineMode::Maximum, "Maximum")
  93. ->EnumAttribute(CombineMode::Multiply, "Multiply")
  94. ->Attribute(AZ::Edit::Attributes::ReadOnly, &MaterialConfiguration::IsRestitutionReadOnly)
  95. ->DataElement(AZ::Edit::UIHandlers::Default, &MaterialConfiguration::m_density, "Density", "Material density")
  96. ->Attribute(AZ::Edit::Attributes::Min, &MaterialConfiguration::GetMinDensityLimit)
  97. ->Attribute(AZ::Edit::Attributes::Max, &MaterialConfiguration::GetMaxDensityLimit)
  98. ->Attribute(AZ::Edit::Attributes::Suffix, " " + Physics::NameConstants::GetDensityUnit())
  99. ->DataElement(AZ::Edit::UIHandlers::Default, &MaterialConfiguration::m_compliantContactMode, "Compliant Contact Mode",
  100. "When enabled the normal force of the contact is computed using an implicit spring. Restitution properties are not used when enabled.")
  101. ->Attribute(AZ::Edit::Attributes::Visibility, &MaterialConfiguration::GetCompliantConstantModeVisibility)
  102. ->DataElement(AZ::Edit::UIHandlers::Color, &MaterialConfiguration::m_debugColor, "Debug Color", "Debug color to use for this material")
  103. ;
  104. }
  105. }
  106. }
  107. AZ::Data::Asset<Physics::MaterialAsset> MaterialConfiguration::CreateMaterialAsset() const
  108. {
  109. AZ::Data::Asset<Physics::MaterialAsset> materialAsset =
  110. AZ::Data::AssetManager::Instance().CreateAsset<Physics::MaterialAsset>(
  111. AZ::Data::AssetId(AZ::Uuid::CreateRandom()));
  112. const Physics::MaterialAsset::MaterialProperties materialProperties =
  113. {
  114. {MaterialConstants::DynamicFrictionName, m_dynamicFriction},
  115. {MaterialConstants::StaticFrictionName, m_staticFriction},
  116. {MaterialConstants::RestitutionName, m_restitution},
  117. {MaterialConstants::DensityName, m_density},
  118. {MaterialConstants::RestitutionCombineModeName, static_cast<AZ::u32>(m_restitutionCombine)},
  119. {MaterialConstants::FrictionCombineModeName, static_cast<AZ::u32>(m_frictionCombine)},
  120. {MaterialConstants::CompliantContactModeEnabledName, m_compliantContactMode.m_enabled},
  121. {MaterialConstants::CompliantContactModeDampingName, m_compliantContactMode.m_damping},
  122. {MaterialConstants::CompliantContactModeStiffnessName, m_compliantContactMode.m_stiffness},
  123. {MaterialConstants::DebugColorName, m_debugColor}
  124. };
  125. materialAsset->SetData(
  126. MaterialConstants::MaterialAssetType,
  127. MaterialConstants::MaterialAssetVersion,
  128. materialProperties);
  129. return materialAsset;
  130. }
  131. void MaterialConfiguration::ValidateMaterialAsset(
  132. [[maybe_unused]] AZ::Data::Asset<Physics::MaterialAsset> materialAsset)
  133. {
  134. #if !defined(AZ_RELEASE_BUILD)
  135. if (!materialAsset)
  136. {
  137. AZ_Error("MaterialConfiguration", false, "Invalid material asset");
  138. return;
  139. }
  140. AZ_Error("MaterialConfiguration", materialAsset->GetMaterialType() == MaterialConstants::MaterialAssetType,
  141. "Material asset '%s' has unexpected material type ('%s'). Expected type is '%.*s'.",
  142. materialAsset.GetHint().c_str(), materialAsset->GetMaterialType().c_str(), AZ_STRING_ARG(MaterialConstants::MaterialAssetType));
  143. AZ_Error("MaterialConfiguration", materialAsset->GetVersion() <= MaterialConstants::MaterialAssetVersion,
  144. "Material asset '%s' has unexpected material version (%u). Expected version is <='%u'.",
  145. materialAsset.GetHint().c_str(), materialAsset->GetVersion(), MaterialConstants::MaterialAssetVersion);
  146. auto checkProperties = [materialAsset](AZStd::span<const AZStd::string_view> materialPropertyNames)
  147. {
  148. const auto& materialProperties = materialAsset->GetMaterialProperties();
  149. for (const auto& materialPropertyName : materialPropertyNames)
  150. {
  151. AZ_Error(
  152. "MaterialConfiguration",
  153. materialProperties.find(materialPropertyName) != materialProperties.end(),
  154. "Material asset '%s' does not have property '%.*s'.",
  155. materialAsset.GetHint().c_str(),
  156. AZ_STRING_ARG(materialPropertyName));
  157. }
  158. };
  159. // Check properties from version 1
  160. {
  161. const AZStd::fixed_vector materialPropertyNames =
  162. {
  163. MaterialConstants::DynamicFrictionName,
  164. MaterialConstants::StaticFrictionName,
  165. MaterialConstants::RestitutionName,
  166. MaterialConstants::DensityName,
  167. MaterialConstants::RestitutionCombineModeName,
  168. MaterialConstants::FrictionCombineModeName,
  169. MaterialConstants::DebugColorName
  170. };
  171. checkProperties(materialPropertyNames);
  172. }
  173. // Check properties from version 2: Added Compliant Contact Mode properties.
  174. if (materialAsset->GetVersion() == 2)
  175. {
  176. const AZStd::fixed_vector materialPropertyNames =
  177. {
  178. MaterialConstants::CompliantContactModeEnabledName,
  179. MaterialConstants::CompliantContactModeDampingName,
  180. MaterialConstants::CompliantContactModeStiffnessName
  181. };
  182. checkProperties(materialPropertyNames);
  183. }
  184. #endif
  185. }
  186. float MaterialConfiguration::GetMinDensityLimit()
  187. {
  188. return MaterialConstants::MinDensityLimit;
  189. }
  190. float MaterialConfiguration::GetMaxDensityLimit()
  191. {
  192. return MaterialConstants::MaxDensityLimit;
  193. }
  194. bool MaterialConfiguration::IsRestitutionReadOnly() const
  195. {
  196. #if (PX_PHYSICS_VERSION_MAJOR >= 5)
  197. return m_compliantContactMode.m_enabled;
  198. #else
  199. return false;
  200. #endif
  201. }
  202. AZ::Crc32 MaterialConfiguration::GetCompliantConstantModeVisibility() const
  203. {
  204. #if (PX_PHYSICS_VERSION_MAJOR >= 5)
  205. return AZ::Edit::PropertyVisibility::Show;
  206. #else
  207. return AZ::Edit::PropertyVisibility::Hide;
  208. #endif
  209. }
  210. } // namespace PhysX