diff --git a/AutomatedTesting/Gem/PythonTests/physics/TestSuite_Main.py b/AutomatedTesting/Gem/PythonTests/physics/TestSuite_Main.py index 8f1f2f7481..2cf55c7a58 100644 --- a/AutomatedTesting/Gem/PythonTests/physics/TestSuite_Main.py +++ b/AutomatedTesting/Gem/PythonTests/physics/TestSuite_Main.py @@ -42,6 +42,7 @@ class TestAutomation(TestAutomationBase): self._run_test(request, workspace, editor, test_module) @revert_physics_config + @fm.file_override('physxsystemconfiguration.setreg','C4044459_Material_DynamicFriction.setreg_override', 'AutomatedTesting/Registry') def test_C4044459_Material_DynamicFriction(self, request, workspace, editor, launcher_platform): from . import C4044459_Material_DynamicFriction as test_module self._run_test(request, workspace, editor, test_module) diff --git a/AutomatedTesting/Registry/C3510644_Collider_CollisionGroups.setreg_override b/AutomatedTesting/Registry/C3510644_Collider_CollisionGroups.setreg_override index 9fa5e26768..696a0a74da 100644 --- a/AutomatedTesting/Registry/C3510644_Collider_CollisionGroups.setreg_override +++ b/AutomatedTesting/Registry/C3510644_Collider_CollisionGroups.setreg_override @@ -119,6 +119,9 @@ ] } }, + "DefaultMaterial": { + "SurfaceType": "Default_1" + }, "MaterialLibrary": { "assetId": { "guid": "{3A055A3F-8CB7-5FEE-B437-EB365FACD0D4}" diff --git a/AutomatedTesting/Registry/C4044459_Material_DynamicFriction.setreg_override b/AutomatedTesting/Registry/C4044459_Material_DynamicFriction.setreg_override new file mode 100644 index 0000000000..c53b04e5c2 --- /dev/null +++ b/AutomatedTesting/Registry/C4044459_Material_DynamicFriction.setreg_override @@ -0,0 +1,118 @@ +{ + "Amazon": { + "Gems": { + "PhysX": { + "PhysXSystemConfiguration": { + "CollisionConfig": { + "Layers": { + "LayerNames": [ + "Default", + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + "TouchBend" + ] + }, + "Groups": { + "GroupPresets": [ + { + "Name": "All", + "ReadOnly": true + }, + { + "Id": { + "GroupId": "{CDB6B8D8-5CD0-40A8-874D-839B00A92EBB}" + }, + "Name": "None", + "Group": { + "Mask": 0 + }, + "ReadOnly": true + }, + { + "Id": { + "GroupId": "{22769429-5D46-429B-829A-0115239D9AAA}" + }, + "Name": "All_NoTouchBend", + "Group": { + "Mask": 9223372036854775807 + }, + "ReadOnly": true + } + ] + } + }, + "DefaultMaterial": { + "SurfaceType": "Default_1" + }, + "MaterialLibrary": { + "assetId": { + "guid": "{6AA79EE4-7EC3-5717-87AE-EDD7D886FD7F}" + }, + "loadBehavior": "QueueLoad", + "assetHint": "levels/physics/c4044459_material_dynamicfriction/dynamic_friction.physmaterial" + } + } + } + } + } +} \ No newline at end of file diff --git a/AutomatedTesting/Registry/C4976227_Collider_NewGroup.setreg_override b/AutomatedTesting/Registry/C4976227_Collider_NewGroup.setreg_override index afbe6a9d38..5e98e08ede 100644 --- a/AutomatedTesting/Registry/C4976227_Collider_NewGroup.setreg_override +++ b/AutomatedTesting/Registry/C4976227_Collider_NewGroup.setreg_override @@ -107,6 +107,9 @@ ] } }, + "DefaultMaterial": { + "SurfaceType": "Default_1" + }, "MaterialLibrary": { "assetId": { "guid": "{3A055A3F-8CB7-5FEE-B437-EB365FACD0D4}" diff --git a/AutomatedTesting/Registry/C4976244_Collider_SameGroupSameLayerCollision.setreg_override b/AutomatedTesting/Registry/C4976244_Collider_SameGroupSameLayerCollision.setreg_override index 9fa5e26768..696a0a74da 100644 --- a/AutomatedTesting/Registry/C4976244_Collider_SameGroupSameLayerCollision.setreg_override +++ b/AutomatedTesting/Registry/C4976244_Collider_SameGroupSameLayerCollision.setreg_override @@ -119,6 +119,9 @@ ] } }, + "DefaultMaterial": { + "SurfaceType": "Default_1" + }, "MaterialLibrary": { "assetId": { "guid": "{3A055A3F-8CB7-5FEE-B437-EB365FACD0D4}" diff --git a/AutomatedTesting/Registry/C4976245_PhysXCollider_CollisionLayerTest.setreg_override b/AutomatedTesting/Registry/C4976245_PhysXCollider_CollisionLayerTest.setreg_override index 9fa5e26768..696a0a74da 100644 --- a/AutomatedTesting/Registry/C4976245_PhysXCollider_CollisionLayerTest.setreg_override +++ b/AutomatedTesting/Registry/C4976245_PhysXCollider_CollisionLayerTest.setreg_override @@ -119,6 +119,9 @@ ] } }, + "DefaultMaterial": { + "SurfaceType": "Default_1" + }, "MaterialLibrary": { "assetId": { "guid": "{3A055A3F-8CB7-5FEE-B437-EB365FACD0D4}" diff --git a/AutomatedTesting/Registry/C4982593_PhysXCollider_CollisionLayer.setreg_override b/AutomatedTesting/Registry/C4982593_PhysXCollider_CollisionLayer.setreg_override index 9fa5e26768..696a0a74da 100644 --- a/AutomatedTesting/Registry/C4982593_PhysXCollider_CollisionLayer.setreg_override +++ b/AutomatedTesting/Registry/C4982593_PhysXCollider_CollisionLayer.setreg_override @@ -119,6 +119,9 @@ ] } }, + "DefaultMaterial": { + "SurfaceType": "Default_1" + }, "MaterialLibrary": { "assetId": { "guid": "{3A055A3F-8CB7-5FEE-B437-EB365FACD0D4}" diff --git a/AutomatedTesting/Registry/physxsystemconfiguration.setreg b/AutomatedTesting/Registry/physxsystemconfiguration.setreg index 02f65b685b..30e9dced44 100644 --- a/AutomatedTesting/Registry/physxsystemconfiguration.setreg +++ b/AutomatedTesting/Registry/physxsystemconfiguration.setreg @@ -101,6 +101,9 @@ ] } }, + "DefaultMaterial": { + "SurfaceType": "Default_1" + }, "MaterialLibrary": { "assetId": { "guid": "{3A055A3F-8CB7-5FEE-B437-EB365FACD0D4}" diff --git a/AutomatedTesting/surfacetypemateriallibrary.physmaterial b/AutomatedTesting/surfacetypemateriallibrary.physmaterial index 3c39d5521e..434d673998 100644 --- a/AutomatedTesting/surfacetypemateriallibrary.physmaterial +++ b/AutomatedTesting/surfacetypemateriallibrary.physmaterial @@ -1,18 +1,19 @@ - + - - - + + + + - + diff --git a/Code/Framework/AzFramework/AzFramework/Physics/ClassConverters.cpp b/Code/Framework/AzFramework/AzFramework/Physics/ClassConverters.cpp index e43bda4c88..4f206858af 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/ClassConverters.cpp +++ b/Code/Framework/AzFramework/AzFramework/Physics/ClassConverters.cpp @@ -259,11 +259,18 @@ namespace Physics if (success) { - success = success && dataElement.RemoveElementByName(AZ_CRC("MaterialId", 0x9360e002)); + dataElement.RemoveElementByName(AZ_CRC("MaterialId", 0x9360e002)); + success = success && (dataElement.FindElement(AZ_CRC("MaterialId", 0x9360e002)) < 0); success = success && dataElement.AddElementWithData(context, "MaterialIds", AZStd::vector { materialId }); } } + if (success && dataElement.GetVersion() <= 2) + { + dataElement.RemoveElementByName(AZ_CRC_CE("Material")); + success = success && (dataElement.FindElement(AZ_CRC_CE("Material")) < 0); + } + return success; } } // namespace ClassConverters diff --git a/Code/Framework/AzFramework/AzFramework/Physics/Common/PhysicsEvents.h b/Code/Framework/AzFramework/AzFramework/Physics/Common/PhysicsEvents.h index d5a82c0367..a3a34dc1df 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/Common/PhysicsEvents.h +++ b/Code/Framework/AzFramework/AzFramework/Physics/Common/PhysicsEvents.h @@ -58,9 +58,18 @@ namespace AzPhysics //! When triggered will send the handle to the old Scene (after this call, the Handle will be invalid). using OnSceneRemovedEvent = AZ::Event; - //! Event that triggers when the default material library changes. + //! Event that triggers when the material library changes. //! When triggered the event will send the Asset Id of the new material library. - using OnDefaultMaterialLibraryChangedEvent = AZ::Event; + using OnMaterialLibraryChangedEvent = AZ::Event; + + enum class MaterialLibraryLoadErrorType : uint8_t + { + InvalidId, + ErrorLoading + }; + + //! Event that triggers when the default material library has loaded with errors. + using OnMaterialLibraryLoadErrorEvent = AZ::Event; //! Event that triggers when the default scene configuration changes. //! When triggered the event will send the new default scene configuration. diff --git a/Code/Framework/AzFramework/AzFramework/Physics/Configuration/SystemConfiguration.cpp b/Code/Framework/AzFramework/AzFramework/Physics/Configuration/SystemConfiguration.cpp index cd250b71a9..d7532cbfea 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/Configuration/SystemConfiguration.cpp +++ b/Code/Framework/AzFramework/AzFramework/Physics/Configuration/SystemConfiguration.cpp @@ -39,6 +39,8 @@ namespace AzPhysics ->Field("ShapecastBufferSize", &SystemConfiguration::m_shapecastBufferSize) ->Field("OverlapBufferSize", &SystemConfiguration::m_overlapBufferSize) ->Field("CollisionConfig", &SystemConfiguration::m_collisionConfig) + ->Field("DefaultMaterial", &SystemConfiguration::m_defaultMaterialConfiguration) + ->Field("MaterialLibrary", &SystemConfiguration::m_materialLibraryAsset) ; if (AZ::EditContext* editContext = serializeContext->GetEditContext()) @@ -79,7 +81,9 @@ namespace AzPhysics m_overlapBufferSize == other.m_overlapBufferSize && AZ::IsClose(m_maxTimestep, other.m_maxTimestep) && AZ::IsClose(m_fixedTimestep, other.m_fixedTimestep) && - m_collisionConfig == other.m_collisionConfig + m_collisionConfig == other.m_collisionConfig && + m_defaultMaterialConfiguration == other.m_defaultMaterialConfiguration && + m_materialLibraryAsset == other.m_materialLibraryAsset ; } diff --git a/Code/Framework/AzFramework/AzFramework/Physics/Configuration/SystemConfiguration.h b/Code/Framework/AzFramework/AzFramework/Physics/Configuration/SystemConfiguration.h index 0a00d627a7..56fe9a68c4 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/Configuration/SystemConfiguration.h +++ b/Code/Framework/AzFramework/AzFramework/Physics/Configuration/SystemConfiguration.h @@ -13,6 +13,7 @@ #include #include +#include namespace AZ { @@ -45,6 +46,9 @@ namespace AzPhysics //! Each Physics Scene uses this as a base and will override as needed. CollisionConfiguration m_collisionConfig; + Physics::MaterialConfiguration m_defaultMaterialConfiguration; //!< Default material parameters for the project. + AZ::Data::Asset m_materialLibraryAsset = AZ::Data::AssetLoadBehavior::NoLoad; //!< Material Library exposed by the system component SystemBus API. + //! Controls whether the Physics System will self register to the TickBus and call StartSimulation / FinishSimulation on each Scene. //! Disable this to manually control Physics Scene simulation logic. bool m_autoManageSimulationUpdate = true; diff --git a/Code/Framework/AzFramework/AzFramework/Physics/Material.cpp b/Code/Framework/AzFramework/AzFramework/Physics/Material.cpp index 5552cef448..78e0431753 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/Material.cpp +++ b/Code/Framework/AzFramework/AzFramework/Physics/Material.cpp @@ -49,10 +49,7 @@ namespace Physics { materialSelection->SetMaterialSlots(Physics::MaterialSelection::SlotsArray()); } - if (materialSelection->IsDefaultMaterialLibraryAsset()) - { - materialSelection->SyncSelectionToMaterialLibrary(); - } + materialSelection->SyncSelectionToMaterialLibrary(); } }; @@ -122,6 +119,24 @@ namespace Physics } } + bool MaterialConfiguration::operator==(const MaterialConfiguration& other) const + { + return m_surfaceType == other.m_surfaceType && + AZ::IsClose(m_dynamicFriction, other.m_dynamicFriction) && + AZ::IsClose(m_staticFriction, other.m_staticFriction) && + AZ::IsClose(m_restitution, other.m_restitution) && + AZ::IsClose(m_density, other.m_density) && + m_restitutionCombine == other.m_restitutionCombine && + m_frictionCombine == other.m_frictionCombine && + m_debugColor == other.m_debugColor + ; + } + + bool MaterialConfiguration::operator!=(const MaterialConfiguration& other) const + { + return !(*this == other); + } + AZ::Color MaterialConfiguration::GenerateDebugColor(const char* materialName) { static const AZ::Color colors[] = @@ -191,51 +206,25 @@ namespace Physics ////////////////////////////////////////////////////////////////////////// - void MaterialLibraryAssetReflectionWrapper::Reflect(AZ::ReflectContext* context) - { - AZ::SerializeContext* serializeContext = azrtti_cast(context); - if (serializeContext) - { - serializeContext->Class() - ->Version(1) - ->Field("Asset", &MaterialLibraryAssetReflectionWrapper::m_asset) - ; - - AZ::EditContext* editContext = serializeContext->GetEditContext(); - if (editContext) - { - editContext->Class("", "") - ->ClassElement(AZ::Edit::ClassElements::EditorData, "") - ->Attribute(AZ::Edit::Attributes::AutoExpand, "") - ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) - ->DataElement(AZ::Edit::UIHandlers::Default, &MaterialLibraryAssetReflectionWrapper::m_asset, "Physics Material Library", "Physics Material Library") - ->Attribute("EditButton", "") - ; - } - } - } - - ////////////////////////////////////////////////////////////////////////// - - - void DefaultMaterialLibraryAssetReflectionWrapper::Reflect(AZ::ReflectContext* context) + void MaterialInfoReflectionWrapper::Reflect(AZ::ReflectContext* context) { AZ::SerializeContext* serializeContext = azrtti_cast(context); if (serializeContext) { - serializeContext->Class() + serializeContext->Class() ->Version(1) - ->Field("Asset", &DefaultMaterialLibraryAssetReflectionWrapper::m_asset) + ->Field("DefaultMaterial", &MaterialInfoReflectionWrapper::m_defaultMaterialConfiguration) + ->Field("Asset", &MaterialInfoReflectionWrapper::m_materialLibraryAsset) ; AZ::EditContext* editContext = serializeContext->GetEditContext(); if (editContext) { - editContext->Class("", "") + editContext->Class("Physics Materials", "") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") - ->Attribute(AZ::Edit::Attributes::AutoExpand, "") - ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) - ->DataElement(AZ::Edit::UIHandlers::Default, &DefaultMaterialLibraryAssetReflectionWrapper::m_asset, "Default Physics Material Library", "Library to use by default") + ->Attribute(AZ::Edit::Attributes::AutoExpand, true) + ->DataElement(AZ::Edit::UIHandlers::Default, &MaterialInfoReflectionWrapper::m_defaultMaterialConfiguration, "Default Physics Material", "Material used by default") + ->DataElement(AZ::Edit::UIHandlers::Default, &MaterialInfoReflectionWrapper::m_materialLibraryAsset, "Physics Material Library", "Library to use for the project") ->Attribute(AZ::Edit::Attributes::AllowClearAsset, false) ->Attribute("EditButton", "") ; @@ -269,6 +258,17 @@ namespace Physics } } + bool MaterialFromAssetConfiguration::operator==(const MaterialFromAssetConfiguration& other) const + { + return m_configuration == other.m_configuration && + m_id == other.m_id; + } + + bool MaterialFromAssetConfiguration::operator!=(const MaterialFromAssetConfiguration& other) const + { + return !(*this == other); + } + ////////////////////////////////////////////////////////////////////////// bool MaterialLibraryAsset::GetDataForMaterialId(const MaterialId& materialId, MaterialFromAssetConfiguration& configuration) const @@ -370,9 +370,8 @@ namespace Physics if (auto serializeContext = azrtti_cast(context)) { serializeContext->Class() - ->Version(2, &ClassConverters::MaterialSelectionConverter) + ->Version(3, &ClassConverters::MaterialSelectionConverter) ->EventHandler() - ->Field("Material", &MaterialSelection::m_materialLibrary) ->Field("MaterialIds", &MaterialSelection::m_materialIdsAssignedToSlots) ; @@ -381,14 +380,8 @@ namespace Physics editContext->Class("Physics Material", "Select physics material library and which materials to use for the object") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->DataElement(AZ::Edit::UIHandlers::Default, &MaterialSelection::m_materialLibrary, "Library", "Physics material library to use for this object") - ->Attribute(AZ::Edit::Attributes::ContainerCanBeModified, true) - ->Attribute("EditButton", "") - ->Attribute("EditDescription", "Open in Asset Editor") - ->Attribute(AZ::Edit::Attributes::DefaultAsset, &MaterialSelection::GetDefaultMaterialLibraryId) - ->Attribute(AZ::Edit::Attributes::ChangeNotify, &MaterialSelection::OnMaterialLibraryChanged) ->DataElement(AZ::Edit::UIHandlers::Default, &MaterialSelection::m_materialIdsAssignedToSlots, "Mesh Surfaces", "Specify which Physics Material to use for each element of this object") - ->ElementAttribute(Attributes::MaterialLibraryAssetId, &MaterialSelection::GetMaterialLibraryAssetId) + ->ElementAttribute(Attributes::MaterialLibraryAssetId, &MaterialSelection::GetMaterialLibraryId) ->Attribute(AZ::Edit::Attributes::IndexedChildNameLabelOverride, &MaterialSelection::GetMaterialSlotLabel) ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->ElementAttribute(AZ::Edit::Attributes::ReadOnly, &MaterialSelection::AreMaterialSlotsReadOnly) @@ -398,12 +391,6 @@ namespace Physics } } - AZ::u32 MaterialSelection::OnMaterialLibraryChanged() - { - SyncSelectionToMaterialLibrary(); - return AZ::Edit::PropertyRefreshLevels::EntireTree; - } - AZStd::string MaterialSelection::GetMaterialSlotLabel(int index) { if (index < m_materialSlots.size()) @@ -425,28 +412,9 @@ namespace Physics } } - AZ::Data::AssetId MaterialSelection::GetMaterialLibraryAssetId() const + void MaterialSelection::OnMaterialLibraryChanged([[maybe_unused]] const AZ::Data::AssetId& defaultMaterialLibraryId) { - return GetMaterialLibraryAsset().GetId(); - } - - const Physics::MaterialLibraryAsset* MaterialSelection::GetMaterialLibraryAssetData() const - { - return GetMaterialLibraryAsset().Get(); - } - - const AZStd::string& MaterialSelection::GetMaterialLibraryAssetHint() const - { - return m_materialLibrary.GetHint(); - } - - void MaterialSelection::OnDefaultMaterialLibraryChanged(const AZ::Data::AssetId& defaultMaterialLibraryId) - { - AZ_UNUSED(defaultMaterialLibraryId); - if (IsDefaultMaterialLibraryAsset()) - { - OnMaterialLibraryChanged(); - } + SyncSelectionToMaterialLibrary(); } void MaterialSelection::SetSlotsReadOnly(bool readOnly) @@ -454,45 +422,6 @@ namespace Physics m_slotsReadOnly = readOnly; } - bool MaterialSelection::IsMaterialLibraryValid() const - { - if (GetMaterialLibraryAssetId().IsValid()) - { - auto materialAsset = LoadAsset(); - const auto& materialsData = materialAsset.Get()->GetMaterialsData(); - - if (materialsData.size() != 0) - { - return true; - } - } - return false; - } - - bool MaterialSelection::GetMaterialConfiguration(Physics::MaterialFromAssetConfiguration& configuration, const Physics::MaterialId& materialId) const - { - if (IsMaterialLibraryValid()) - { - auto materialAsset = LoadAsset(); - if (materialAsset.Get()) - { - return materialAsset.Get()->GetDataForMaterialId(materialId, configuration); - } - } - return false; - } - - void MaterialSelection::SetMaterialLibrary(const AZ::Data::AssetId& assetId) - { - m_materialLibrary = AZ::Data::AssetManager::Instance().GetAsset(assetId, m_materialLibrary.GetAutoLoadBehavior()); - m_materialLibrary.BlockUntilLoadComplete(); - } - - void MaterialSelection::ResetToDefaultMaterialLibrary() - { - m_materialLibrary = {}; - } - void MaterialSelection::SetMaterialSlots(const SlotsArray& slots) { if (slots.empty()) @@ -533,74 +462,45 @@ namespace Physics m_materialIdsAssignedToSlots[slotIndex] = materialId; } - AZ::Data::Asset MaterialSelection::LoadAsset() const - { - AZ::Data::Asset asset = AZ::Data::AssetManager::Instance() - .GetAsset(GetMaterialLibraryAssetId(), AZ::Data::AssetLoadBehavior::Default); - - asset.BlockUntilLoadComplete(); - - return asset; - } - void MaterialSelection::SyncSelectionToMaterialLibrary() { - if (GetMaterialLibraryAssetId().IsValid()) + auto* materialLibrary = GetMaterialLibrary().Get(); + if (!materialLibrary) { - auto materialLibraryAsset = AZ::Data::AssetManager::Instance().GetAsset(GetMaterialLibraryAssetId(), AZ::Data::AssetLoadBehavior::Default); + return; + } - materialLibraryAsset.BlockUntilLoadComplete(); - - // We try to check whether existing selection matches any materials in the newly assigned library and do one of the following: - // 1. If previous MaterialId is invalid for this material library, and it is not the Default material, we set it to the Default material from the library. - // 2. If it's valid, or it is the Default material, we don't change it (useful when user accidentally re-assigns the same library: previous selection won't go away). - - if (materialLibraryAsset.Get()) + for (Physics::MaterialId& materialId : m_materialIdsAssignedToSlots) + { + // Leave nulls (default) unchanged. + if (materialId.IsNull()) { - for (Physics::MaterialId& materialId : m_materialIdsAssignedToSlots) - { - if (!materialLibraryAsset.Get()->HasDataForMaterialId(materialId) - && !materialId.IsNull()) // Null materialId is the Default material. - { - materialId = MaterialId(); - } - } + continue; } - else + + // If the material id is not present in the library anymore, set it to default + if (!materialLibrary->HasDataForMaterialId(materialId)) { - AZ_Warning("PhysX", false, "MaterialSelection: invalid material library"); + materialId = MaterialId(); } } } - const AZ::Data::Asset& MaterialSelection::GetMaterialLibraryAsset() const - { - if (IsDefaultMaterialLibraryAsset()) - { - const AZ::Data::Asset& defaultMaterialLibrary = GetDefaultMaterialLibrary(); - return defaultMaterialLibrary; - } - - return m_materialLibrary; - } - - bool MaterialSelection::IsDefaultMaterialLibraryAsset() const - { - return !m_materialLibrary.GetId().IsValid(); - } - - const AZ::Data::Asset& MaterialSelection::GetDefaultMaterialLibrary() + const AZ::Data::Asset& MaterialSelection::GetMaterialLibrary() { if (auto* physicsSystem = AZ::Interface::Get()) { - return physicsSystem->GetDefaultMaterialLibrary(); + if (const auto* physicsConfiguration = physicsSystem->GetConfiguration()) + { + return physicsConfiguration->m_materialLibraryAsset; + } } return s_invalidMaterialLibrary; } - const AZ::Data::AssetId& MaterialSelection::GetDefaultMaterialLibraryId() + const AZ::Data::AssetId& MaterialSelection::GetMaterialLibraryId() { - return GetDefaultMaterialLibrary().GetId(); + return GetMaterialLibrary().GetId(); } bool MaterialSelection::AreMaterialSlotsReadOnly() const diff --git a/Code/Framework/AzFramework/AzFramework/Physics/Material.h b/Code/Framework/AzFramework/AzFramework/Physics/Material.h index e9eaae929f..69edf3ed25 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/Material.h +++ b/Code/Framework/AzFramework/AzFramework/Physics/Material.h @@ -29,7 +29,6 @@ namespace Physics /// ========================= /// This is the interface to the wrapper around native material type (such as PxMaterial in PhysX gem) /// that stores extra metadata, like Surface Type name. - /// To see more details about PhysX implementation please refer to PhysX::Material class /// /// Usage example /// ------------------------- @@ -37,14 +36,7 @@ namespace Physics /// /// Physics::MaterialConfiguration materialProperties; /// AZStd::shared_ptr newMaterial = AZ::Interface::Get()->CreateMaterial(materialProperties); - /// - /// To get PxMaterial use GetNativePointer function - /// - /// physx::PxMaterial* material = static_cast(newMaterial->GetNativePointer()); - /// - /// You can use retrieved PxMaterial pointer on its own, provided you increment its reference count. - /// If this class goes out of scope, the PxMaterial pointer will be valid, but its userData - /// will be cleaned up to point to nullptr. + /// class Material { public: @@ -63,9 +55,9 @@ namespace Physics /// Returns AZ::Crc32 of the surface name. virtual AZ::Crc32 GetSurfaceType() const = 0; - virtual void SetSurfaceType(AZ::Crc32 surfaceType) = 0; virtual const AZStd::string& GetSurfaceTypeName() const = 0; + virtual void SetSurfaceTypeName(const AZStd::string& surfaceTypeName) = 0; virtual float GetDynamicFriction() const = 0; virtual void SetDynamicFriction(float dynamicFriction) = 0; @@ -85,6 +77,9 @@ namespace Physics virtual float GetDensity() const = 0; virtual void SetDensity(float density) = 0; + virtual AZ::Color GetDebugColor() const = 0; + virtual void SetDebugColor(const AZ::Color& debugColor) = 0; + /// If the name of this material matches the name of one of the CrySurface types, it will return its CrySurface Id.\n /// If there's no match it will return default CrySurface Id.\n /// CrySurface types are defined in libs/materialeffects/surfacetypes.xml @@ -122,6 +117,10 @@ namespace Physics Material::CombineMode m_frictionCombine = Material::CombineMode::Average; AZ::Color m_debugColor = AZ::Colors::White; + + bool operator==(const MaterialConfiguration& other) const; + bool operator!=(const MaterialConfiguration& other) const; + private: static bool VersionConverter(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement); static AZ::Color GenerateDebugColor(const char* materialName); @@ -147,6 +146,7 @@ namespace Physics static MaterialId FromUUID(const AZ::Uuid& uuid); bool IsNull() const { return m_id.IsNull(); } bool operator==(const MaterialId& other) const { return m_id == other.m_id; } + bool operator!=(const MaterialId& other) const { return !(*this == other); } const AZ::Uuid& GetUuid() const { return m_id; } private: @@ -166,6 +166,9 @@ namespace Physics MaterialConfiguration m_configuration; MaterialId m_id; + + bool operator==(const MaterialFromAssetConfiguration& other) const; + bool operator!=(const MaterialFromAssetConfiguration& other) const; }; /// An asset that holds a list of materials to be edited and assigned in Open 3D Engine Editor @@ -222,40 +225,27 @@ namespace Physics AZStd::vector m_materialLibrary; }; - /// The class is used to expose a MaterialLibraryAsset to Edit Context + /// The class is used to expose a default material and material library asset to Edit Context /// ======================================================================= /// /// Since AZ::Data::Asset doesn't reflect the data to EditContext /// we have to have a wrapper doing it. - class MaterialLibraryAssetReflectionWrapper + class MaterialInfoReflectionWrapper { public: - AZ_CLASS_ALLOCATOR(MaterialLibraryAssetReflectionWrapper, AZ::SystemAllocator, 0); - AZ_TYPE_INFO(Physics::MaterialLibraryAssetReflectionWrapper, "{3D2EF5DF-EFD0-47EB-B88F-3E6FE1FEE5B0}"); + AZ_CLASS_ALLOCATOR(MaterialInfoReflectionWrapper, AZ::SystemAllocator, 0); + AZ_TYPE_INFO(Physics::MaterialInfoReflectionWrapper, "{02AB8CBC-D35B-4E0F-89BA-A96D94DAD4F9}"); static void Reflect(AZ::ReflectContext* context); - AZ::Data::Asset m_asset = + Physics::MaterialConfiguration m_defaultMaterialConfiguration; + AZ::Data::Asset m_materialLibraryAsset = AZ::Data::AssetLoadBehavior::NoLoad; }; - /// Customized material library for use as default material library - class DefaultMaterialLibraryAssetReflectionWrapper : public Physics::MaterialLibraryAssetReflectionWrapper - { - public: - AZ_CLASS_ALLOCATOR(MaterialLibraryAssetReflectionWrapper, AZ::SystemAllocator, 0); - AZ_TYPE_INFO(Physics::DefaultMaterialLibraryAssetReflectionWrapper, "{02AB8CBC-D35B-4E0F-89BA-A96D94DAD4F9}"); - static void Reflect(AZ::ReflectContext* context); - - AZ::Data::Asset m_asset = - AZ::Data::AssetLoadBehavior::NoLoad; - }; - - /// The class is used to store a MaterialLibraryAsset and a vector of MaterialIds selected from the library + /// The class is used to store a vector of MaterialIds selected from the library /// ======================================================================= /// - /// This class is used to store a reference to the library asset and user's - /// selection of the materials from this library.\n - /// It also reflects UI controls for assigning MaterialLibraryAsset and selecting a material from it. + /// This class is used to store the user's selection of the materials from this library. /// You can reflect this class in EditorContext to provide UI for selecting materials /// on any custom component or QWidget. class MaterialSelection @@ -269,27 +259,6 @@ namespace Physics static void Reflect(AZ::ReflectContext* context); - /// Returns whether MaterialLibraryAsset assigned to this selection exists and valid. Attempts to load - /// the library if it's not loaded yet. - /// @return true if MaterialLibraryAsset has a valid AssetId, loaded and isn't empty - bool IsMaterialLibraryValid() const; - - /// Looks up MaterialLibraryAsset for MaterialFromAssetConfiguration with MaterialId that is stored intrenally. - /// @param configuration contains material data if there is a material selected by user - /// and if it exists in the MaterialLibraryAsset - /// @param materialId MaterialId to retrieve MaterialFromAssetConfiguration for - /// @return true if lookup was successful. - bool GetMaterialConfiguration(Physics::MaterialFromAssetConfiguration& configuration, const Physics::MaterialId& materialId) const; - - /// Sets and loads MaterialLibraryAsset with specified AssetId. - /// It is used to construct MaterialSelection at runtime. - /// It is not a typical use case and mostly needed to convert legacy entities and auto-generate material libraries - /// @param assetId AssetId to create MaterialLibraryAsset with - void SetMaterialLibrary(const AZ::Data::AssetId& assetId); - - /// Sets the material library to none, this will cause to use the project-wide default material library - void ResetToDefaultMaterialLibrary(); - /// Sets an array of material slots to pick MaterialIds for. Having multiple slots is required for assigning multiple materials on a mesh /// or heightfield object. SlotsArray can be empty and in this case Default slot will be created. /// @param slots Array of names for slots. Can be empty, in this case Default slot will be created @@ -298,48 +267,34 @@ namespace Physics /// Returns a list of MaterialId that were assigned for each corresponding slot. const AZStd::vector& GetMaterialIdsAssignedToSlots() const; - /// Sets the MaterialId from MaterialLibraryAsset as the selected material at a specific slotIndex. - /// @param materialId MaterialId that user selected from the MaterialLibraryAsset - /// @param slotIndex index of the slot to set MaterialId for + /// Sets the MaterialId as the selected material at a specific slotIndex. + /// @param materialId MaterialId that user selected + /// @param slotIndex Index of the slot to set the MaterialId void SetMaterialId(const Physics::MaterialId& materialId, int slotIndex = 0); - /// Returns the material library asset id. - AZ::Data::AssetId GetMaterialLibraryAssetId() const; - /// Returns the material id assigned to this selection at a specific slotIndex. - /// @param slotIndex index of the slot to retrieve MaterialId for + /// @param slotIndex Index of the slot to retrieve the MaterialId Physics::MaterialId GetMaterialId(int slotIndex = 0) const; - /// Returns the material library asset. - const Physics::MaterialLibraryAsset* GetMaterialLibraryAssetData() const; - - /// Returns the material library asset hint(UI display string) - const AZStd::string& GetMaterialLibraryAssetHint() const; - /// Called when the material library has changed - void OnDefaultMaterialLibraryChanged(const AZ::Data::AssetId& defaultMaterialLibraryId); + void OnMaterialLibraryChanged(const AZ::Data::AssetId& defaultMaterialLibraryId); /// Set if the material slots are editable in the edit context void SetSlotsReadOnly(bool readOnly); private: - AZ::Data::Asset m_materialLibrary { AZ::Data::AssetLoadBehavior::NoLoad }; AZStd::vector m_materialIdsAssignedToSlots; SlotsArray m_materialSlots; bool m_slotsReadOnly = false; - const AZ::Data::Asset& GetMaterialLibraryAsset() const; - AZ::Data::Asset LoadAsset() const; - bool IsDefaultMaterialLibraryAsset() const; void SyncSelectionToMaterialLibrary(); - static const AZ::Data::Asset& GetDefaultMaterialLibrary(); - static const AZ::Data::AssetId& GetDefaultMaterialLibraryId(); + static const AZ::Data::Asset& GetMaterialLibrary(); + static const AZ::Data::AssetId& GetMaterialLibraryId(); bool AreMaterialSlotsReadOnly() const; // EditorContext callbacks - AZ::u32 OnMaterialLibraryChanged(); AZStd::string GetMaterialSlotLabel(int index); }; diff --git a/Code/Framework/AzFramework/AzFramework/Physics/MaterialBus.h b/Code/Framework/AzFramework/AzFramework/Physics/MaterialBus.h index edfa3096d3..a7e4869df1 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/MaterialBus.h +++ b/Code/Framework/AzFramework/AzFramework/Physics/MaterialBus.h @@ -25,21 +25,26 @@ namespace Physics static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; // Implemented by sole owner of materials, e.g. class MaterialManager in PhysX gem. - /// Get default material + /// Get default material. virtual AZStd::shared_ptr GetGenericDefaultMaterial() = 0; /// Returns weak pointers to physics materials. /// Connect to PhysicsMaterialNotifications::MaterialsReleased to be informed when material pointers are deleted by owner. virtual void GetMaterials(const MaterialSelection& materialSelection - , AZStd::vector>& outMaterials) = 0; + , AZStd::vector>& outMaterials) = 0; + + /// Returns a weak pointer to physics material with the given id. + virtual AZStd::shared_ptr GetMaterialById(Physics::MaterialId id) = 0; /// Returns a weak pointer to physics material with the given name. - virtual AZStd::weak_ptr GetMaterialByName(const AZStd::string& name) = 0; + virtual AZStd::shared_ptr GetMaterialByName(const AZStd::string& name) = 0; - /// Returns index of the first selected material in MaterialSelection's material library. - /// A MaterialSelection can contain multiple material selections. - /// Returned index is 0-based where 0 is the Default material, and materials from the material library are 1 and onwards. - virtual AZ::u32 GetFirstSelectedMaterialIndex(const MaterialSelection& materialSelection) = 0; + /// Updates the material selection from the physics asset or sets it to default if there's no asset provided. + /// @param shapeConfiguration The shape information that contains the physics asset. + /// @param materialSelection The material selection to update. + virtual void UpdateMaterialSelectionFromPhysicsAsset( + const ShapeConfiguration& shapeConfiguration, + MaterialSelection& materialSelection) = 0; }; using PhysicsMaterialRequestBus = AZ::EBus; diff --git a/Code/Framework/AzFramework/AzFramework/Physics/PhysicsSystem.h b/Code/Framework/AzFramework/AzFramework/Physics/PhysicsSystem.h index e3ed449046..36ae4dbecb 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/PhysicsSystem.h +++ b/Code/Framework/AzFramework/AzFramework/Physics/PhysicsSystem.h @@ -130,13 +130,6 @@ namespace AzPhysics //! @param forceReinitialization Flag to force a reinitialization of the physics system. Default false. virtual void UpdateConfiguration(const SystemConfiguration* newConfig, bool forceReinitialization = false) = 0; - //! Update the default material library. - //! @param materialLibrary The new material library asset to use. - virtual void UpdateDefaultMaterialLibrary(const AZ::Data::Asset& materialLibrary) = 0; - - //! Accessor to get the current Material Library. This is also available in the PhysXSystemConfiguration. - virtual const AZ::Data::Asset& GetDefaultMaterialLibrary() const = 0; - //! Update the current default scene configuration. //! This is the configuration used to to create scenes without a custom configuration. //! @param sceneConfiguration The new configuration to apply. @@ -169,9 +162,12 @@ namespace AzPhysics //! Register to receive notifications when the SystemConfiguration changes. //! @param handler The handler to receive the event. void RegisterSystemConfigurationChangedEvent(SystemEvents::OnConfigurationChangedEvent::Handler& handler) { handler.Connect(m_configChangeEvent); } - //! Register a handler to receive an event when the default material library changes. + //! Register a handler to receive an event when the material library changes. //! @param handler The handler to receive the event. - void RegisterOnDefaultMaterialLibraryChangedEventHandler(SystemEvents::OnDefaultMaterialLibraryChangedEvent::Handler& handler) { handler.Connect(m_onDefaultMaterialLibraryChangedEvent); } + void RegisterOnMaterialLibraryChangedEventHandler(SystemEvents::OnMaterialLibraryChangedEvent::Handler& handler) { handler.Connect(m_onMaterialLibraryChangedEvent); } + //! Register a handler to receive an event when the material library fails to load on startup. + //! @param handler The handler to receive the event. + void RegisterOnMaterialLibraryLoadErrorEventHandler(SystemEvents::OnMaterialLibraryLoadErrorEvent::Handler& handler) { handler.Connect(m_onMaterialLibraryLoadErrorEvent); } //! Register a handler to receive an event when the default SceneConfiguration changes. //! @param handler The handler to receive the event. void RegisterOnDefaultSceneConfigurationChangedEventHandler(SystemEvents::OnDefaultSceneConfigurationChangedEvent::Handler& handler) { handler.Connect(m_onDefaultSceneConfigurationChangedEvent); } @@ -185,7 +181,8 @@ namespace AzPhysics SystemEvents::OnSceneAddedEvent m_sceneAddedEvent; SystemEvents::OnSceneRemovedEvent m_sceneRemovedEvent; SystemEvents::OnConfigurationChangedEvent m_configChangeEvent; - SystemEvents::OnDefaultMaterialLibraryChangedEvent m_onDefaultMaterialLibraryChangedEvent; + SystemEvents::OnMaterialLibraryChangedEvent m_onMaterialLibraryChangedEvent; + SystemEvents::OnMaterialLibraryLoadErrorEvent m_onMaterialLibraryLoadErrorEvent; SystemEvents::OnDefaultSceneConfigurationChangedEvent m_onDefaultSceneConfigurationChangedEvent; }; } // namespace AzPhysics diff --git a/Code/Framework/AzFramework/AzFramework/Physics/ShapeConfiguration.cpp b/Code/Framework/AzFramework/AzFramework/Physics/ShapeConfiguration.cpp index a535f5f65d..275103bc28 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/ShapeConfiguration.cpp +++ b/Code/Framework/AzFramework/AzFramework/Physics/ShapeConfiguration.cpp @@ -17,6 +17,21 @@ namespace Physics { + namespace Internal + { + bool ShapeConfigurationVersionConverter( + [[maybe_unused]] AZ::SerializeContext& context, + AZ::SerializeContext::DataElementNode& classElement) + { + if (classElement.GetVersion() <= 1) + { + classElement.RemoveElementByName(AZ_CRC_CE("UseMaterialsFromAsset")); + } + + return true; + } + } + void ShapeConfiguration::Reflect(AZ::ReflectContext* context) { if (auto serializeContext = azrtti_cast(context)) @@ -166,10 +181,9 @@ namespace Physics ->RegisterGenericType>(); serializeContext->Class() - ->Version(1) + ->Version(2, &Internal::ShapeConfigurationVersionConverter) ->Field("PhysicsAsset", &PhysicsAssetShapeConfiguration::m_asset) ->Field("AssetScale", &PhysicsAssetShapeConfiguration::m_assetScale) - ->Field("UseMaterialsFromAsset", &PhysicsAssetShapeConfiguration::m_useMaterialsFromAsset) ->Field("SubdivisionLevel", &PhysicsAssetShapeConfiguration::m_subdivisionLevel) ; @@ -182,7 +196,6 @@ namespace Physics ->DataElement(AZ::Edit::UIHandlers::Default, &PhysicsAssetShapeConfiguration::m_assetScale, "Asset Scale", "The scale of the asset shape") ->Attribute(AZ::Edit::Attributes::Min, 0.0f) ->Attribute(AZ::Edit::Attributes::Step, 0.01f) - ->DataElement(AZ::Edit::UIHandlers::Default, &PhysicsAssetShapeConfiguration::m_useMaterialsFromAsset, "Physics Materials from Mesh", "Auto-set physics materials using Mesh's material surfaces names") ; } } diff --git a/Code/Framework/AzFramework/AzFramework/Physics/ShapeConfiguration.h b/Code/Framework/AzFramework/AzFramework/Physics/ShapeConfiguration.h index b3d04a10c9..8234ef9173 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/ShapeConfiguration.h +++ b/Code/Framework/AzFramework/AzFramework/Physics/ShapeConfiguration.h @@ -140,7 +140,7 @@ namespace Physics AZ::Data::Asset m_asset{ AZ::Data::AssetLoadBehavior::PreLoad }; AZ::Vector3 m_assetScale = AZ::Vector3::CreateOne(); - bool m_useMaterialsFromAsset = true; + bool m_useMaterialsFromAsset = false; // Not reflected or exposed to the user until there is a way to auto-match mesh's materials with physics materials AZ::u8 m_subdivisionLevel = 4; ///< The level of subdivision if a primitive shape is replaced with a convex mesh due to scaling. }; diff --git a/Code/Framework/AzFramework/AzFramework/Physics/SystemBus.h b/Code/Framework/AzFramework/AzFramework/Physics/SystemBus.h index f198551148..8cdd0e0cf0 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/SystemBus.h +++ b/Code/Framework/AzFramework/AzFramework/Physics/SystemBus.h @@ -142,24 +142,12 @@ namespace Physics virtual AZStd::shared_ptr CreateShape(const ColliderConfiguration& colliderConfiguration, const ShapeConfiguration& configuration) = 0; + virtual AZStd::shared_ptr CreateMaterial(const Physics::MaterialConfiguration& materialConfiguration) = 0; + /// Releases the mesh object created by the physics backend. /// @param nativeMeshObject Pointer to the mesh object. virtual void ReleaseNativeMeshObject(void* nativeMeshObject) = 0; - ////////////////////////////////////////////////////////////////////////// - //// Physics Materials - - virtual AZStd::shared_ptr CreateMaterial(const Physics::MaterialConfiguration& materialConfiguration) = 0; - virtual AZStd::shared_ptr GetDefaultMaterial() = 0; - virtual AZStd::vector> CreateMaterialsFromLibrary(const Physics::MaterialSelection& materialSelection) = 0; - - - /// Updates the collider material selection from the physics asset or sets it to default if there's no asset provided. - /// @param shapeConfiguration The shape information - /// @param colliderConfiguration The collider information - virtual bool UpdateMaterialSelection(const Physics::ShapeConfiguration& shapeConfiguration, - Physics::ColliderConfiguration& colliderConfiguration) = 0; - ////////////////////////////////////////////////////////////////////////// //// Joints diff --git a/Code/Framework/AzFramework/AzFramework/Physics/Utils.cpp b/Code/Framework/AzFramework/AzFramework/Physics/Utils.cpp index b5f113582b..2c3b62bb88 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/Utils.cpp +++ b/Code/Framework/AzFramework/AzFramework/Physics/Utils.cpp @@ -119,8 +119,7 @@ namespace Physics AzPhysics::SceneConfiguration::Reflect(context); MaterialConfiguration::Reflect(context); MaterialLibraryAsset::Reflect(context); - MaterialLibraryAssetReflectionWrapper::Reflect(context); - DefaultMaterialLibraryAssetReflectionWrapper::Reflect(context); + MaterialInfoReflectionWrapper::Reflect(context); JointLimitConfiguration::Reflect(context); AzPhysics::SimulatedBodyConfiguration::Reflect(context); AzPhysics::RigidBodyConfiguration::Reflect(context); diff --git a/Gems/Blast/Code/Source/Actor/BlastActorImpl.cpp b/Gems/Blast/Code/Source/Actor/BlastActorImpl.cpp index 6c4c78c412..8f82f3366f 100644 --- a/Gems/Blast/Code/Source/Actor/BlastActorImpl.cpp +++ b/Gems/Blast/Code/Source/Actor/BlastActorImpl.cpp @@ -151,8 +151,6 @@ namespace Blast colliderConfiguration.m_position = transform.GetTranslation(); colliderConfiguration.m_rotation = transform.GetRotation(); colliderConfiguration.m_isExclusive = true; - colliderConfiguration.m_materialSelection.SetMaterialLibrary( - AZ::Interface::Get()->GetDefaultMaterialLibrary()->GetId()); colliderConfiguration.m_materialSelection.SetMaterialId(material); colliderConfiguration.m_collisionGroupId = actorConfiguration.m_collisionGroupId; colliderConfiguration.m_collisionLayer = actorConfiguration.m_collisionLayer; diff --git a/Gems/Blast/Code/Source/Components/BlastFamilyComponent.cpp b/Gems/Blast/Code/Source/Components/BlastFamilyComponent.cpp index 0f2668442c..d5cb16596a 100644 --- a/Gems/Blast/Code/Source/Components/BlastFamilyComponent.cpp +++ b/Gems/Blast/Code/Source/Components/BlastFamilyComponent.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -265,10 +266,23 @@ namespace Blast auto solverPtr = Nv::Blast::ExtStressSolver::create( const_cast(*m_family->GetTkFamily()->getFamilyLL()), stressSolverSettings); m_solver = physx::unique_ptr(solverPtr); - Physics::MaterialFromAssetConfiguration material; - AZ::Interface::Get()->GetDefaultMaterialLibrary()->GetDataForMaterialId( - m_physicsMaterialId, material); - m_solver->setAllNodesInfoFromLL(material.m_configuration.m_density); + + AZStd::shared_ptr physicsMaterial; + Physics::PhysicsMaterialRequestBus::BroadcastResult( + physicsMaterial, + &Physics::PhysicsMaterialRequestBus::Events::GetMaterialById, + m_physicsMaterialId); + if (!physicsMaterial) + { + AZ_Warning("BlastFamilyComponent", false, "Material Id %s was not found, using default material instead.", + m_physicsMaterialId.GetUuid().ToString().c_str()); + + Physics::PhysicsMaterialRequestBus::BroadcastResult( + physicsMaterial, + &Physics::PhysicsMaterialRequestBus::Events::GetGenericDefaultMaterial); + AZ_Assert(physicsMaterial, "BlastFamilyComponent: Invalid default physics material"); + } + m_solver->setAllNodesInfoFromLL(physicsMaterial->GetDensity()); // Create damage and actor render managers m_damageManager = AZStd::make_unique(blastMaterial, m_family->GetActorTracker()); diff --git a/Gems/Blast/Code/Source/Editor/EditorBlastFamilyComponent.cpp b/Gems/Blast/Code/Source/Editor/EditorBlastFamilyComponent.cpp index 9241449483..873ef7248d 100644 --- a/Gems/Blast/Code/Source/Editor/EditorBlastFamilyComponent.cpp +++ b/Gems/Blast/Code/Source/Editor/EditorBlastFamilyComponent.cpp @@ -131,6 +131,6 @@ namespace Blast AZ::Data::AssetId EditorBlastFamilyComponent::GetPhysicsMaterialLibraryAssetId() const { - return AZ::Interface::Get()->GetDefaultMaterialLibrary()->GetId(); + return AZ::Interface::Get()->GetConfiguration()->m_materialLibraryAsset.GetId(); } } // namespace Blast diff --git a/Gems/EMotionFX/Code/Tests/Mocks/PhysicsSystem.h b/Gems/EMotionFX/Code/Tests/Mocks/PhysicsSystem.h index 22102fd38a..3aafdb4e2b 100644 --- a/Gems/EMotionFX/Code/Tests/Mocks/PhysicsSystem.h +++ b/Gems/EMotionFX/Code/Tests/Mocks/PhysicsSystem.h @@ -35,9 +35,6 @@ namespace Physics MOCK_METHOD2(CreateShape, AZStd::shared_ptr(const Physics::ColliderConfiguration& colliderConfiguration, const Physics::ShapeConfiguration& configuration)); MOCK_METHOD1(ReleaseNativeMeshObject, void(void* nativeMeshObject)); MOCK_METHOD1(CreateMaterial, AZStd::shared_ptr(const Physics::MaterialConfiguration& materialConfiguration)); - MOCK_METHOD0(GetDefaultMaterial, AZStd::shared_ptr()); - MOCK_METHOD1(CreateMaterialsFromLibrary, AZStd::vector>(const Physics::MaterialSelection& materialSelection)); - MOCK_METHOD2(UpdateMaterialSelection, bool(const Physics::ShapeConfiguration& shapeConfiguration, Physics::ColliderConfiguration& colliderConfiguration)); MOCK_METHOD0(GetSupportedJointTypes, AZStd::vector()); MOCK_METHOD1(CreateJointLimitConfiguration, AZStd::shared_ptr(AZ::TypeId jointType)); MOCK_METHOD3(CreateJoint, AZStd::shared_ptr(const AZStd::shared_ptr& configuration, AzPhysics::SimulatedBody* parentBody, AzPhysics::SimulatedBody* childBody)); @@ -59,7 +56,6 @@ namespace Physics void Shutdown() override {} void Simulate([[maybe_unused]] float deltaTime) override {} void UpdateConfiguration([[maybe_unused]] const AzPhysics::SystemConfiguration* newConfig, [[maybe_unused]] bool forceReinitialization = false) override {} - void UpdateDefaultMaterialLibrary([[maybe_unused]] const AZ::Data::Asset& materialLibrary) override {} void UpdateDefaultSceneConfiguration([[maybe_unused]] const AzPhysics::SceneConfiguration& sceneConfiguration) override {} void RemoveScene([[maybe_unused]] AzPhysics::SceneHandle handle) override {} void RemoveScenes([[maybe_unused]] const AzPhysics::SceneHandleList& handles) override {} @@ -73,7 +69,6 @@ namespace Physics MOCK_METHOD0(GetAllScenes, AzPhysics::SceneList& ()); MOCK_METHOD1(FindAttachedBodyHandleFromEntityId, AZStd::pair(AZ::EntityId entityId)); MOCK_CONST_METHOD0(GetConfiguration, const AzPhysics::SystemConfiguration* ()); - MOCK_CONST_METHOD0(GetDefaultMaterialLibrary, const AZ::Data::Asset& ()); MOCK_CONST_METHOD0(GetDefaultSceneConfiguration, const AzPhysics::SceneConfiguration& ()); }; diff --git a/Gems/EMotionFX/Code/Tests/ProvidesUI/Ragdoll/CanCopyPasteColliders.cpp b/Gems/EMotionFX/Code/Tests/ProvidesUI/Ragdoll/CanCopyPasteColliders.cpp index 858980fbe8..eaef6f31ee 100644 --- a/Gems/EMotionFX/Code/Tests/ProvidesUI/Ragdoll/CanCopyPasteColliders.cpp +++ b/Gems/EMotionFX/Code/Tests/ProvidesUI/Ragdoll/CanCopyPasteColliders.cpp @@ -54,14 +54,11 @@ namespace EMotionFX [[maybe_unused]] const AZ::Vector3& axis, [[maybe_unused]] const AZStd::vector& exampleLocalRotations) { return AZStd::make_unique(); }); - EXPECT_CALL(m_physicsInterface, GetDefaultMaterialLibrary) - .WillRepeatedly(testing::ReturnRef(m_materialLibraryAsset)); } private: Physics::MockPhysicsSystem m_physicsSystem; Physics::MockPhysicsInterface m_physicsInterface; - AZ::Data::Asset m_materialLibraryAsset; }; #if AZ_TRAIT_DISABLE_FAILED_EMOTION_FX_EDITOR_TESTS diff --git a/Gems/EMotionFX/Code/Tests/ProvidesUI/Ragdoll/CanCopyPasteJointLimits.cpp b/Gems/EMotionFX/Code/Tests/ProvidesUI/Ragdoll/CanCopyPasteJointLimits.cpp index b4b4d14d58..6223af3599 100644 --- a/Gems/EMotionFX/Code/Tests/ProvidesUI/Ragdoll/CanCopyPasteJointLimits.cpp +++ b/Gems/EMotionFX/Code/Tests/ProvidesUI/Ragdoll/CanCopyPasteJointLimits.cpp @@ -59,9 +59,6 @@ namespace EMotionFX .WillRepeatedly(testing::Return(AZStd::vector{azrtti_typeid()})); EXPECT_CALL(physicsSystem, ComputeInitialJointLimitConfiguration(azrtti_typeid(), _, _, _, _)) .WillRepeatedly([]([[maybe_unused]] const AZ::TypeId& jointLimitTypeId, [[maybe_unused]] const AZ::Quaternion& parentWorldRotation, [[maybe_unused]] const AZ::Quaternion& childWorldRotation, [[maybe_unused]] const AZ::Vector3& axis, [[maybe_unused]] const AZStd::vector& exampleLocalRotations) { return AZStd::make_unique(); }); - AZ::Data::Asset materialLibraryAsset; - EXPECT_CALL(physicsInterface, GetDefaultMaterialLibrary) - .WillRepeatedly(testing::ReturnRef(materialLibraryAsset)); AutoRegisteredActor actor {ActorFactory::CreateAndInit(4)}; diff --git a/Gems/PhysX/Code/Editor/DebugDraw.cpp b/Gems/PhysX/Code/Editor/DebugDraw.cpp index 23a9a3cb44..829b776e28 100644 --- a/Gems/PhysX/Code/Editor/DebugDraw.cpp +++ b/Gems/PhysX/Code/Editor/DebugDraw.cpp @@ -17,13 +17,13 @@ #include #include #include +#include #include #include #include #include -#include -#include +#include namespace PhysX { @@ -415,11 +415,16 @@ namespace PhysX { case GlobalCollisionDebugColorMode::MaterialColor: { - Physics::MaterialFromAssetConfiguration materialConfiguration; const Physics::MaterialId materialId = colliderConfig.m_materialSelection.GetMaterialId(elementDebugInfo.m_materialSlotIndex); - if (colliderConfig.m_materialSelection.GetMaterialConfiguration(materialConfiguration, materialId)) + + AZStd::shared_ptr physicsMaterial; + Physics::PhysicsMaterialRequestBus::BroadcastResult( + physicsMaterial, + &Physics::PhysicsMaterialRequestBus::Events::GetMaterialById, + materialId); + if (physicsMaterial) { - debugColor = materialConfiguration.m_configuration.m_debugColor; + debugColor = physicsMaterial->GetDebugColor(); } break; } diff --git a/Gems/PhysX/Code/Editor/SettingsWidget.cpp b/Gems/PhysX/Code/Editor/SettingsWidget.cpp index 38022e8c92..20a67a778d 100644 --- a/Gems/PhysX/Code/Editor/SettingsWidget.cpp +++ b/Gems/PhysX/Code/Editor/SettingsWidget.cpp @@ -37,14 +37,15 @@ namespace PhysX const Debug::DebugDisplayData& debugDisplayData) { m_physxSystemConfiguration = physxSystemConfiguration; - m_defaultPhysicsMaterialLibrary.m_asset = m_physxSystemConfiguration.m_defaultMaterialLibrary; + m_physicsMaterialInfo.m_defaultMaterialConfiguration = m_physxSystemConfiguration.m_defaultMaterialConfiguration; + m_physicsMaterialInfo.m_materialLibraryAsset = m_physxSystemConfiguration.m_materialLibraryAsset; m_defaultSceneConfiguration = defaultSceneConfiguration; m_debugDisplayData = debugDisplayData; blockSignals(true); m_propertyEditor->ClearInstances(); m_propertyEditor->AddInstance(&m_physxSystemConfiguration); - m_propertyEditor->AddInstance(&m_defaultPhysicsMaterialLibrary); + m_propertyEditor->AddInstance(&m_physicsMaterialInfo); m_propertyEditor->AddInstance(&m_defaultSceneConfiguration); m_propertyEditor->AddInstance(&m_debugDisplayData); m_propertyEditor->AddInstance(&m_physxSystemConfiguration.m_windConfiguration); @@ -88,7 +89,8 @@ namespace PhysX void SettingsWidget::SetPropertyEditingComplete(AzToolsFramework::InstanceDataNode* /*node*/) { - m_physxSystemConfiguration.m_defaultMaterialLibrary = m_defaultPhysicsMaterialLibrary.m_asset; + m_physxSystemConfiguration.m_defaultMaterialConfiguration = m_physicsMaterialInfo.m_defaultMaterialConfiguration; + m_physxSystemConfiguration.m_materialLibraryAsset = m_physicsMaterialInfo.m_materialLibraryAsset; emit onValueChanged(m_physxSystemConfiguration, m_defaultSceneConfiguration, m_debugDisplayData diff --git a/Gems/PhysX/Code/Editor/SettingsWidget.h b/Gems/PhysX/Code/Editor/SettingsWidget.h index 78df72b6d3..a4001e13b7 100644 --- a/Gems/PhysX/Code/Editor/SettingsWidget.h +++ b/Gems/PhysX/Code/Editor/SettingsWidget.h @@ -56,7 +56,7 @@ namespace PhysX AzToolsFramework::ReflectedPropertyEditor* m_propertyEditor; DocumentationLinkWidget* m_documentationLinkWidget; - Physics::DefaultMaterialLibraryAssetReflectionWrapper m_defaultPhysicsMaterialLibrary; + Physics::MaterialInfoReflectionWrapper m_physicsMaterialInfo; PhysX::PhysXSystemConfiguration m_physxSystemConfiguration; AzPhysics::SceneConfiguration m_defaultSceneConfiguration; Debug::DebugDisplayData m_debugDisplayData; diff --git a/Gems/PhysX/Code/Editor/Source/Components/EditorSystemComponent.cpp b/Gems/PhysX/Code/Editor/Source/Components/EditorSystemComponent.cpp index e510aa505e..c3f0411d58 100644 --- a/Gems/PhysX/Code/Editor/Source/Components/EditorSystemComponent.cpp +++ b/Gems/PhysX/Code/Editor/Source/Components/EditorSystemComponent.cpp @@ -30,40 +30,45 @@ namespace PhysX { - static bool CreateSurfaceTypeMaterialLibrary(const AZStd::string & targetFilePath) + constexpr const char* DefaultAssetFilename = "SurfaceTypeMaterialLibrary"; + + static AZStd::optional> CreateMaterialLibrary(const AZStd::string& fullTargetFilePath, const AZStd::string& relativePath) { - auto assetType = AZ::AzTypeInfo::Uuid(); - - // Create File - AZ::Data::Asset newAsset = AZ::Data::AssetManager::Instance().CreateAsset(AZ::Uuid::CreateRandom(), assetType, AZ::Data::AssetLoadBehavior::Default); - - AZ::IO::FileIOStream fileStream(targetFilePath.c_str(), AZ::IO::OpenMode::ModeWrite); + AZ::IO::FileIOStream fileStream(fullTargetFilePath.c_str(), AZ::IO::OpenMode::ModeWrite); if (fileStream.IsOpen()) { - Physics::MaterialLibraryAsset* materialLibraryAsset = azrtti_cast(newAsset.GetData()); - if (materialLibraryAsset) + const auto& assetType = AZ::AzTypeInfo::Uuid(); + AZ::Data::AssetId assetId; + + AZ::Data::AssetCatalogRequestBus::BroadcastResult( + assetId, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetIdByPath, relativePath.c_str(), assetType, true); + + AZ::Data::Asset newAsset = + AZ::Data::AssetManager::Instance().GetAsset(assetId, assetType, AZ::Data::AssetLoadBehavior::Default); + + if (Physics::MaterialLibraryAsset* materialLibraryAsset = azrtti_cast(newAsset.GetData())) { // check it out in the source control system AzToolsFramework::SourceControlCommandBus::Broadcast( - &AzToolsFramework::SourceControlCommandBus::Events::RequestEdit, targetFilePath.c_str(), true, + &AzToolsFramework::SourceControlCommandBus::Events::RequestEdit, fullTargetFilePath.c_str(), true, [](bool /*success*/, const AzToolsFramework::SourceControlFileInfo& /*info*/) {}); // Save the material library asset into a file - auto assetHandler = const_cast(AZ::Data::AssetManager::Instance().GetHandler(assetType)); + auto assetHandler = AZ::Data::AssetManager::Instance().GetHandler(assetType); if (assetHandler->SaveAssetData(newAsset, &fileStream)) { - return true; + return newAsset; } else { AZ_Error("PhysX", false, "CreateSurfaceTypeMaterialLibrary: Unable to save Surface Types Material Library Asset to %s", - targetFilePath.c_str()); + fullTargetFilePath.c_str()); } } } - return false; + return AZStd::nullopt; } void EditorSystemComponent::Reflect(AZ::ReflectContext* context) @@ -84,11 +89,26 @@ namespace PhysX { Physics::EditorWorldBus::Handler::BusConnect(); + m_onMaterialLibraryLoadErrorEventHandler = AzPhysics::SystemEvents::OnMaterialLibraryLoadErrorEvent::Handler( + [this]([[maybe_unused]] AzPhysics::SystemEvents::MaterialLibraryLoadErrorType error) + { + // Attempt to set/create the default material library if there was an error + if (auto* physxSystem = GetPhysXSystem()) + { + if (auto retrievedMaterialLibrary = RetrieveDefaultMaterialLibrary()) + { + physxSystem->UpdateMaterialLibrary(retrievedMaterialLibrary.value()); + } + } + } + ); + if (auto* physicsSystem = AZ::Interface::Get()) { AzPhysics::SceneConfiguration editorWorldConfiguration = physicsSystem->GetDefaultSceneConfiguration(); editorWorldConfiguration.m_sceneName = AzPhysics::EditorPhysicsSceneName; m_editorWorldSceneHandle = physicsSystem->AddScene(editorWorldConfiguration); + physicsSystem->RegisterOnMaterialLibraryLoadErrorEventHandler(m_onMaterialLibraryLoadErrorEventHandler); } PhysX::RegisterConfigStringLineEditHandler(); // Register custom unique string line edit control @@ -109,6 +129,8 @@ namespace PhysX physicsSystem->RemoveScene(m_editorWorldSceneHandle); } m_editorWorldSceneHandle = AzPhysics::InvalidSceneHandle; + + m_onMaterialLibraryLoadErrorEventHandler.Disconnect(); } AzPhysics::SceneHandle EditorSystemComponent::GetEditorSceneHandle() const @@ -148,7 +170,7 @@ namespace PhysX PhysX::Editor::EditorWindow::RegisterViewClass(); } - AZ::Data::AssetId EditorSystemComponent::GenerateSurfaceTypesLibrary() + AZStd::optional> EditorSystemComponent::RetrieveDefaultMaterialLibrary() { AZ::Data::AssetId resultAssetId; @@ -159,8 +181,6 @@ namespace PhysX if (assetTypeExtensions.size() == 1) { - const char* DefaultAssetFilename = "SurfaceTypeMaterialLibrary"; - // Constructing the path to the library asset const AZStd::string& assetExtension = assetTypeExtensions[0]; @@ -173,36 +193,39 @@ namespace PhysX if (!resultAssetId.IsValid()) { + // No file for the default material library, create it const char* assetRoot = AZ::IO::FileIOBase::GetInstance()->GetAlias("@devassets@"); - AZStd::string fullPath; AzFramework::StringFunc::Path::ConstructFull(assetRoot, DefaultAssetFilename, assetExtension.c_str(), fullPath); - if (CreateSurfaceTypeMaterialLibrary(fullPath)) + if (auto materialLibraryOpt = CreateMaterialLibrary(fullPath, relativePath)) { - // Find out the asset ID for the material library we've just created - AZ::Data::AssetCatalogRequestBus::BroadcastResult( - resultAssetId, &AZ::Data::AssetCatalogRequests::GetAssetIdByPath, - relativePath.c_str(), - azrtti_typeid(), true); + return materialLibraryOpt; } else { AZ_Warning("PhysX", false, - "GenerateSurfaceTypesLibrary: Failed to create material library at %s. " + "CreateMaterialLibrary: Failed to create material library at %s. " "Please check if the file is writable", fullPath.c_str()); } } + else + { + AZ::Data::Asset existingMaterialLibrary = + AZ::Data::AssetManager::Instance().GetAsset(resultAssetId, AZ::Data::AssetLoadBehavior::NoLoad); + + return existingMaterialLibrary; + } } else { AZ_Warning("PhysX", false, - "GenerateSurfaceTypesLibrary: Number of extensions for the physics material library asset is %u" + "RetrieveDefaultMaterialLibrary: Number of extensions for the physics material library asset is %u" " but should be 1. Please check if the asset registered itself with the asset system correctly", assetTypeExtensions.size()) } - return resultAssetId; + return AZStd::nullopt; } } diff --git a/Gems/PhysX/Code/Editor/Source/Components/EditorSystemComponent.h b/Gems/PhysX/Code/Editor/Source/Components/EditorSystemComponent.h index 9ebca05ccd..4bd11a951f 100644 --- a/Gems/PhysX/Code/Editor/Source/Components/EditorSystemComponent.h +++ b/Gems/PhysX/Code/Editor/Source/Components/EditorSystemComponent.h @@ -14,6 +14,7 @@ #include #include +#include #include namespace AzPhysics @@ -65,8 +66,9 @@ namespace PhysX void PopulateEditorGlobalContextMenu(QMenu* menu, const AZ::Vector2& point, int flags) override; void NotifyRegisterViews() override; - AZ::Data::AssetId GenerateSurfaceTypesLibrary(); + AZStd::optional> RetrieveDefaultMaterialLibrary(); + AzPhysics::SystemEvents::OnMaterialLibraryLoadErrorEvent::Handler m_onMaterialLibraryLoadErrorEventHandler; AzPhysics::SceneHandle m_editorWorldSceneHandle = AzPhysics::InvalidSceneHandle; }; } diff --git a/Gems/PhysX/Code/Include/PhysX/Configuration/PhysXConfiguration.h b/Gems/PhysX/Code/Include/PhysX/Configuration/PhysXConfiguration.h index 936eadad18..598cdc1b4c 100644 --- a/Gems/PhysX/Code/Include/PhysX/Configuration/PhysXConfiguration.h +++ b/Gems/PhysX/Code/Include/PhysX/Configuration/PhysXConfiguration.h @@ -13,7 +13,6 @@ #pragma once #include #include -#include #include #include @@ -55,7 +54,6 @@ namespace PhysX static PhysXSystemConfiguration CreateDefault(); WindConfiguration m_windConfiguration; //!< Wind configuration for PhysX. - AZ::Data::Asset m_defaultMaterialLibrary = AZ::Data::AssetLoadBehavior::NoLoad; //!< Material Library exposed by the system component SystemBus API. bool operator==(const PhysXSystemConfiguration& other) const; bool operator!=(const PhysXSystemConfiguration& other) const; diff --git a/Gems/PhysX/Code/Include/PhysX/MeshColliderComponentBus.h b/Gems/PhysX/Code/Include/PhysX/MeshColliderComponentBus.h index 33305be145..ac36ebbc7f 100644 --- a/Gems/PhysX/Code/Include/PhysX/MeshColliderComponentBus.h +++ b/Gems/PhysX/Code/Include/PhysX/MeshColliderComponentBus.h @@ -38,10 +38,6 @@ namespace PhysX /// @param id The asset ID to set it to. virtual void SetMeshAsset(const AZ::Data::AssetId& id) = 0; - /// Sets the material library asset to the collider. - /// @param id The asset ID to set it to. - virtual void SetMaterialAsset(const AZ::Data::AssetId& id) = 0; - /// Sets the material id from the material library. /// @param id The asset ID to set it to. virtual void SetMaterialId(const Physics::MaterialId& id) = 0; diff --git a/Gems/PhysX/Code/Source/Configuration/PhysXConfiguration.cpp b/Gems/PhysX/Code/Source/Configuration/PhysXConfiguration.cpp index 3ba520513f..a0db4d5d30 100644 --- a/Gems/PhysX/Code/Source/Configuration/PhysXConfiguration.cpp +++ b/Gems/PhysX/Code/Source/Configuration/PhysXConfiguration.cpp @@ -36,6 +36,18 @@ namespace PhysX return configuration; } + + bool PhysXSystemConfigurationConverter([[maybe_unused]] AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& dataElement) + { + if (dataElement.GetVersion() <= 1) + { + dataElement.RemoveElementByName(AZ_CRC_CE("DefaultMaterialLibrary")); + AZ_Warning("PhysXSystemConfigurationConverter", false, + "Old version of PhysX Configuration data found. Physics material library will be reset to default."); + } + + return true; + } } AZ_CLASS_ALLOCATOR_IMPL(WindConfiguration, AZ::SystemAllocator, 0); @@ -89,9 +101,8 @@ namespace PhysX if (auto* serializeContext = azdynamic_cast(context)) { serializeContext->Class() - ->Version(1) + ->Version(2, &PhysXInternal::PhysXSystemConfigurationConverter) ->Field("WindConfiguration", &PhysXSystemConfiguration::m_windConfiguration) - ->Field("MaterialLibrary", &PhysXSystemConfiguration::m_defaultMaterialLibrary) ; if (AZ::EditContext* editContext = serializeContext->GetEditContext()) @@ -115,7 +126,6 @@ namespace PhysX bool PhysXSystemConfiguration::operator==(const PhysXSystemConfiguration& other) const { return AzPhysics::SystemConfiguration::operator==(other) && - m_defaultMaterialLibrary == other.m_defaultMaterialLibrary && m_windConfiguration == other.m_windConfiguration ; } diff --git a/Gems/PhysX/Code/Source/EditorColliderComponent.cpp b/Gems/PhysX/Code/Source/EditorColliderComponent.cpp index 87bb702184..4454429092 100644 --- a/Gems/PhysX/Code/Source/EditorColliderComponent.cpp +++ b/Gems/PhysX/Code/Source/EditorColliderComponent.cpp @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include @@ -352,10 +352,13 @@ namespace PhysX AzToolsFramework::PropertyModificationRefreshLevel::Refresh_AttributesAndValues); }); - m_onDefaultMaterialLibraryChangedEventHandler = AzPhysics::SystemEvents::OnDefaultMaterialLibraryChangedEvent::Handler( + m_onMaterialLibraryChangedEventHandler = AzPhysics::SystemEvents::OnMaterialLibraryChangedEvent::Handler( [this](const AZ::Data::AssetId& defaultMaterialLibrary) { - m_configuration.m_materialSelection.OnDefaultMaterialLibraryChanged(defaultMaterialLibrary); + m_configuration.m_materialSelection.OnMaterialLibraryChanged(defaultMaterialLibrary); + + AzToolsFramework::PropertyEditorGUIMessages::Bus::Broadcast(&AzToolsFramework::PropertyEditorGUIMessages::RequestRefresh, + AzToolsFramework::PropertyModificationRefreshLevel::Refresh_AttributesAndValues); }); AzToolsFramework::Components::EditorComponentBase::Activate(); @@ -463,13 +466,13 @@ namespace PhysX if (auto* physXSystem = GetPhysXSystem()) { physXSystem->RegisterSystemConfigurationChangedEvent(m_physXConfigChangedHandler); - physXSystem->RegisterOnDefaultMaterialLibraryChangedEventHandler(m_onDefaultMaterialLibraryChangedEventHandler); + physXSystem->RegisterOnMaterialLibraryChangedEventHandler(m_onMaterialLibraryChangedEventHandler); } } void EditorColliderComponent::OnDeselected() { - m_onDefaultMaterialLibraryChangedEventHandler.Disconnect(); + m_onMaterialLibraryChangedEventHandler.Disconnect(); m_physXConfigChangedHandler.Disconnect(); } @@ -681,11 +684,6 @@ namespace PhysX } } - void EditorColliderComponent::SetMaterialAsset(const AZ::Data::AssetId& id) - { - m_configuration.m_materialSelection.SetMaterialLibrary(id); - } - void EditorColliderComponent::SetMaterialId(const Physics::MaterialId& id) { m_configuration.m_materialSelection.SetMaterialId(id); @@ -693,8 +691,10 @@ namespace PhysX void EditorColliderComponent::UpdateMaterialSlotsFromMeshAsset() { - Physics::SystemRequestBus::Broadcast(&Physics::SystemRequests::UpdateMaterialSelection, - m_shapeConfiguration.GetCurrent(), m_configuration); + Physics::PhysicsMaterialRequestBus::Broadcast( + &Physics::PhysicsMaterialRequestBus::Events::UpdateMaterialSelectionFromPhysicsAsset, + m_shapeConfiguration.GetCurrent(), + m_configuration.m_materialSelection); AzToolsFramework::ToolsApplicationEvents::Bus::Broadcast(&AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay, AzToolsFramework::Refresh_EntireTree); diff --git a/Gems/PhysX/Code/Source/EditorColliderComponent.h b/Gems/PhysX/Code/Source/EditorColliderComponent.h index 818de62a04..07e1131ea9 100644 --- a/Gems/PhysX/Code/Source/EditorColliderComponent.h +++ b/Gems/PhysX/Code/Source/EditorColliderComponent.h @@ -158,7 +158,6 @@ namespace PhysX AZ::Data::Asset GetMeshAsset() const override; Physics::MaterialId GetMaterialId() const override; void SetMeshAsset(const AZ::Data::AssetId& id) override; - void SetMaterialAsset(const AZ::Data::AssetId& id) override; void SetMaterialId(const Physics::MaterialId& id) override; void UpdateMaterialSlotsFromMeshAsset(); @@ -251,7 +250,7 @@ namespace PhysX DebugDraw::Collider m_colliderDebugDraw; AzPhysics::SystemEvents::OnConfigurationChangedEvent::Handler m_physXConfigChangedHandler; - AzPhysics::SystemEvents::OnDefaultMaterialLibraryChangedEvent::Handler m_onDefaultMaterialLibraryChangedEventHandler; + AzPhysics::SystemEvents::OnMaterialLibraryChangedEvent::Handler m_onMaterialLibraryChangedEventHandler; AZ::Transform m_cachedWorldTransform; AZ::NonUniformScaleChangedEvent::Handler m_nonUniformScaleChangedHandler; //!< Responds to changes in non-uniform scale. diff --git a/Gems/PhysX/Code/Source/EditorShapeColliderComponent.cpp b/Gems/PhysX/Code/Source/EditorShapeColliderComponent.cpp index 692fbf96f3..0cdba94a34 100644 --- a/Gems/PhysX/Code/Source/EditorShapeColliderComponent.cpp +++ b/Gems/PhysX/Code/Source/EditorShapeColliderComponent.cpp @@ -44,11 +44,14 @@ namespace PhysX AzToolsFramework::PropertyEditorGUIMessages::Bus::Broadcast(&AzToolsFramework::PropertyEditorGUIMessages::RequestRefresh, AzToolsFramework::PropertyModificationRefreshLevel::Refresh_AttributesAndValues); }) - , m_onDefaultMaterialLibraryChangedEventHandler( + , m_onMaterialLibraryChangedEventHandler( [this](const AZ::Data::AssetId& defaultMaterialLibrary) { - m_colliderConfig.m_materialSelection.OnDefaultMaterialLibraryChanged(defaultMaterialLibrary); + m_colliderConfig.m_materialSelection.OnMaterialLibraryChanged(defaultMaterialLibrary); Physics::ColliderComponentEventBus::Event(GetEntityId(), &Physics::ColliderComponentEvents::OnColliderChanged); + + AzToolsFramework::PropertyEditorGUIMessages::Bus::Broadcast(&AzToolsFramework::PropertyEditorGUIMessages::RequestRefresh, + AzToolsFramework::PropertyModificationRefreshLevel::Refresh_AttributesAndValues); }) , m_nonUniformScaleChangedHandler([this](const AZ::Vector3& scale) {OnNonUniformScaleChanged(scale);}) { @@ -694,16 +697,16 @@ namespace PhysX { physXSystem->RegisterSystemConfigurationChangedEvent(m_physXConfigChangedHandler); } - if (!m_onDefaultMaterialLibraryChangedEventHandler.IsConnected()) + if (!m_onMaterialLibraryChangedEventHandler.IsConnected()) { - physXSystem->RegisterOnDefaultMaterialLibraryChangedEventHandler(m_onDefaultMaterialLibraryChangedEventHandler); + physXSystem->RegisterOnMaterialLibraryChangedEventHandler(m_onMaterialLibraryChangedEventHandler); } } } void EditorShapeColliderComponent::OnDeselected() { - m_onDefaultMaterialLibraryChangedEventHandler.Disconnect(); + m_onMaterialLibraryChangedEventHandler.Disconnect(); m_physXConfigChangedHandler.Disconnect(); } diff --git a/Gems/PhysX/Code/Source/EditorShapeColliderComponent.h b/Gems/PhysX/Code/Source/EditorShapeColliderComponent.h index 7b7fab789a..1ee87c9564 100644 --- a/Gems/PhysX/Code/Source/EditorShapeColliderComponent.h +++ b/Gems/PhysX/Code/Source/EditorShapeColliderComponent.h @@ -155,7 +155,7 @@ namespace PhysX mutable GeometryCache m_geometryCache; //!< Cached data for generating sample points inside the attached shape. AzPhysics::SystemEvents::OnConfigurationChangedEvent::Handler m_physXConfigChangedHandler; - AzPhysics::SystemEvents::OnDefaultMaterialLibraryChangedEvent::Handler m_onDefaultMaterialLibraryChangedEventHandler; + AzPhysics::SystemEvents::OnMaterialLibraryChangedEvent::Handler m_onMaterialLibraryChangedEventHandler; AZ::Transform m_cachedWorldTransform; AZ::NonUniformScaleChangedEvent::Handler m_nonUniformScaleChangedHandler; //!< Responds to changes in non-uniform scale. AZ::Vector3 m_currentNonUniformScale = AZ::Vector3::CreateOne(); //!< Caches the current non-uniform scale. diff --git a/Gems/PhysX/Code/Source/Material.cpp b/Gems/PhysX/Code/Source/Material.cpp index e8e5cab76e..5e8e3bf759 100644 --- a/Gems/PhysX/Code/Source/Material.cpp +++ b/Gems/PhysX/Code/Source/Material.cpp @@ -15,6 +15,8 @@ #include "Material.h" #include #include +#include +#include namespace PhysX { @@ -22,6 +24,9 @@ namespace PhysX : m_pxMaterial(AZStd::move(material.m_pxMaterial)) , m_surfaceType(material.m_surfaceType) , m_surfaceString(AZStd::move(material.m_surfaceString)) + , m_cryEngineSurfaceId(material.m_cryEngineSurfaceId) + , m_density(material.m_density) + , m_debugColor(AZStd::move(material.m_debugColor)) { m_pxMaterial->userData = this; } @@ -31,6 +36,11 @@ namespace PhysX m_pxMaterial = AZStd::move(material.m_pxMaterial); m_surfaceType = material.m_surfaceType; m_surfaceString = AZStd::move(material.m_surfaceString); + m_cryEngineSurfaceId = material.m_cryEngineSurfaceId; + m_density = material.m_density; + m_debugColor = AZStd::move(material.m_debugColor); + + m_pxMaterial->userData = this; return *this; } @@ -93,8 +103,10 @@ namespace PhysX pxMaterial->userData = this; m_pxMaterial = PxMaterialUniquePtr(pxMaterial, materialDestructor); - m_surfaceType = AZ::Crc32(materialConfiguration.m_surfaceType.c_str()); - m_surfaceString = materialConfiguration.m_surfaceType; + + SetSurfaceTypeName(materialConfiguration.m_surfaceType); + + SetDebugColor(materialConfiguration.m_debugColor); Physics::LegacySurfaceTypeRequestsBus::BroadcastResult( m_cryEngineSurfaceId, @@ -115,8 +127,9 @@ namespace PhysX SetDensity(configuration.m_density); - m_surfaceType = AZ::Crc32(configuration.m_surfaceType.c_str()); - m_surfaceString = configuration.m_surfaceType; + SetSurfaceTypeName(configuration.m_surfaceType); + + SetDebugColor(configuration.m_debugColor); Physics::LegacySurfaceTypeRequestsBus::BroadcastResult( m_cryEngineSurfaceId, @@ -134,9 +147,15 @@ namespace PhysX return m_surfaceType; } - void Material::SetSurfaceType(AZ::Crc32 surfaceType) + const AZStd::string& Material::GetSurfaceTypeName() const { - m_surfaceType = surfaceType; + return m_surfaceString; + } + + void Material::SetSurfaceTypeName(const AZStd::string& surfaceTypeName) + { + m_surfaceString = surfaceTypeName; + m_surfaceType = AZ::Crc32(m_surfaceString.c_str()); } float Material::GetDynamicFriction() const @@ -232,6 +251,16 @@ namespace PhysX MaterialConfiguration::MinDensityLimit, MaterialConfiguration::MaxDensityLimit); } + AZ::Color Material::GetDebugColor() const + { + return m_debugColor; + } + + void Material::SetDebugColor(const AZ::Color& debugColor) + { + m_debugColor = debugColor; + } + AZ::u32 Material::GetCryEngineSurfaceId() const { return m_cryEngineSurfaceId; @@ -243,6 +272,16 @@ namespace PhysX } MaterialsManager::MaterialsManager() + : m_physicsConfigChangedHandler( + [this](const AzPhysics::SystemConfiguration* config) + { + OnPhysicsConfigurationChanged(config); + }) + , m_materialLibraryChangedHandler( + [this](const AZ::Data::AssetId& materialLibraryAssetId) + { + OnMaterialLibraryChanged(materialLibraryAssetId); + }) { } @@ -254,133 +293,152 @@ namespace PhysX { Physics::PhysicsMaterialRequestBus::Handler::BusConnect(); MaterialManagerRequestsBus::Handler::BusConnect(); + + if (auto* physicsSystem = AZ::Interface::Get()) + { + physicsSystem->RegisterSystemConfigurationChangedEvent(m_physicsConfigChangedHandler); + physicsSystem->RegisterOnMaterialLibraryChangedEventHandler(m_materialLibraryChangedHandler); + } } void MaterialsManager::Disconnect() { + m_materialLibraryChangedHandler.Disconnect(); + m_physicsConfigChangedHandler.Disconnect(); MaterialManagerRequestsBus::Handler::BusDisconnect(); Physics::PhysicsMaterialRequestBus::Handler::BusDisconnect(); } void MaterialsManager::GetMaterials(const Physics::MaterialSelection& materialSelection - , AZStd::vector>& outMaterials) + , AZStd::vector>& outMaterials) { outMaterials.clear(); - outMaterials.reserve(materialSelection.GetMaterialIdsAssignedToSlots().size()); - // Ensure PxMaterial instances are initialized if possible. - InitializeMaterials(materialSelection); - - for (const auto& id : materialSelection.GetMaterialIdsAssignedToSlots()) + const auto& materialIdsAssignedToSlots = materialSelection.GetMaterialIdsAssignedToSlots(); + if (materialIdsAssignedToSlots.empty()) { - Physics::MaterialFromAssetConfiguration configuration; - if (materialSelection.GetMaterialConfiguration(configuration, id)) + // The material selection doesn't have any slots, return empty list. + return; + } + + // It is important to return exactly the amount of materials specified in materialSelection + // If a number of materials different to what was cooked is assigned on a physx mesh it will lead to undefined + // behavior and subtle bugs. Unfortunately, there's no warning or assertion on physx side at the shape creation time, + // nor mention of this in the documentation + outMaterials.resize(materialIdsAssignedToSlots.size(), GetDefaultMaterial()); + + for (size_t slotIndex = 0; slotIndex < materialIdsAssignedToSlots.size(); ++slotIndex) + { + const auto& materialId = materialIdsAssignedToSlots[slotIndex]; + + if (auto iterator = FindOrCreateMaterial(materialId); + iterator != m_materials.end()) { - auto iterator = m_materialsFromAssets.find(id.GetUuid()); - if (iterator != m_materialsFromAssets.end()) - { - outMaterials.push_back(iterator->second); - } - else - { - outMaterials.push_back(GetDefaultMaterial()); - } - } - else - { - // It is important to return exactly the amount of materials specified in materialSelection - // If a number of materials different to what was cooked is assigned on a physx mesh it will lead to undefined - // behavior and subtle bugs. Unfortunately, there's no warning or assertion on physx side at the shape creation time, - // nor mention of this in the documentation - outMaterials.push_back(GetDefaultMaterial()); + outMaterials[slotIndex] = iterator->second; } } } - AZStd::weak_ptr MaterialsManager::GetMaterialByName(const AZStd::string& name) + AZStd::shared_ptr MaterialsManager::GetMaterialById(Physics::MaterialId id) { - auto it = AZStd::find_if(m_materialsFromAssets.begin(), m_materialsFromAssets.end(), - [&name](const AZStd::pair>& elem) - { - return elem.second.get()->GetSurfaceTypeName() == name; - }); - - if (it != m_materialsFromAssets.end()) + if (auto it = FindOrCreateMaterial(id); + it != m_materials.end()) { return it->second; } - return {}; + return nullptr; } - AZ::u32 MaterialsManager::GetFirstSelectedMaterialIndex(const Physics::MaterialSelection& materialSelection) + AZStd::shared_ptr MaterialsManager::GetMaterialByName(const AZStd::string& name) { - const AZ::u32 defaultMaterialIndex = 0; - - if (!materialSelection.IsMaterialLibraryValid()) + if (auto it = FindOrCreateMaterial(name); + it != m_materials.end()) { - return defaultMaterialIndex; + return it->second; } - - auto materialAsset = AZ::Data::AssetManager::Instance().GetAsset(materialSelection.GetMaterialLibraryAssetId(), AZ::Data::AssetLoadBehavior::Default); - - materialAsset.BlockUntilLoadComplete(); - - AZStd::vector materialList = materialAsset.Get()->GetMaterialsData(); - - const AZStd::vector& selectedMaterials = materialSelection.GetMaterialIdsAssignedToSlots(); - if (selectedMaterials.size() == 0) - { - return defaultMaterialIndex; - } - for (AZ::u32 i=0; i < materialList.size(); ++i) - { - if (materialList[i].m_id == selectedMaterials[0]) - { - return i + 1; // Index 0 is reserved for Default material. - } - } - - return defaultMaterialIndex; + return nullptr; } void MaterialsManager::GetPxMaterials(const Physics::MaterialSelection& materialSelection , AZStd::vector& outMaterials) { - outMaterials.clear(); - if (materialSelection.GetMaterialIdsAssignedToSlots().empty()) + AZStd::vector> materials; + GetMaterials(materialSelection, materials); + + outMaterials.reserve(materials.size()); + for (const auto& material : materials) + { + PhysX::Material* physxMaterial = azrtti_cast(material.get()); + AZ_Assert(physxMaterial, "Invalid physx material"); + + outMaterials.emplace_back(physxMaterial->GetPxMaterial()); + } + } + + void MaterialsManager::UpdateMaterialSelectionFromPhysicsAsset( + const Physics::ShapeConfiguration& shapeConfiguration, + Physics::MaterialSelection& materialSelection) + { + if (shapeConfiguration.GetShapeType() != Physics::ShapeType::PhysicsAsset) { - // if the materialSelection is invalid we still - // return a default material as a fallback behavior - outMaterials.push_back(GetDefaultMaterial()->GetPxMaterial()); return; } - outMaterials.reserve(materialSelection.GetMaterialIdsAssignedToSlots().size()); - // Ensure PxMaterial instances are initialized if possible. - InitializeMaterials(materialSelection); + const Physics::PhysicsAssetShapeConfiguration& assetConfiguration = + static_cast(shapeConfiguration); - for (const auto& id : materialSelection.GetMaterialIdsAssignedToSlots()) + if (!assetConfiguration.m_asset.GetId().IsValid()) { - Physics::MaterialFromAssetConfiguration configuration; - if (materialSelection.GetMaterialConfiguration(configuration, id)) + // Set the default selection if there's no physics asset. + materialSelection.SetMaterialSlots(Physics::MaterialSelection::SlotsArray()); + return; + } + + if (!assetConfiguration.m_asset.IsReady()) + { + // The asset is valid but is still loading, + // Do not set the empty slots in this case to avoid the entity being in invalid state + return; + } + + Pipeline::MeshAsset* meshAsset = assetConfiguration.m_asset.GetAs(); + if (!meshAsset) + { + materialSelection.SetMaterialSlots(Physics::MaterialSelection::SlotsArray()); + AZ_Warning("PhysX", false, "UpdateMaterialSelectionFromPhysicsAsset: MeshAsset is invalid"); + return; + } + + // Set the slots from the mesh asset + materialSelection.SetMaterialSlots(meshAsset->m_assetData.m_surfaceNames); + + if (!assetConfiguration.m_useMaterialsFromAsset) + { + // Not using the materials from the asset. Nothing else to do. + return; + } + + // Update material IDs in the selection for each slot + const AZStd::vector& meshMaterialNames = meshAsset->m_assetData.m_materialNames; + for (size_t slotIndex = 0; slotIndex < meshMaterialNames.size(); ++slotIndex) + { + const AZStd::string& physicsMaterialNameFromPhysicsAsset = meshMaterialNames[slotIndex]; + if (physicsMaterialNameFromPhysicsAsset == DefaultPhysicsMaterialNameFromPhysicsAsset) { - auto iterator = m_materialsFromAssets.find(id.GetUuid()); - if (iterator != m_materialsFromAssets.end()) - { - outMaterials.push_back(iterator->second->GetPxMaterial()); - } - else - { - outMaterials.push_back(GetDefaultMaterial()->GetPxMaterial()); - } + continue; + } + + if (auto it = FindOrCreateMaterial(physicsMaterialNameFromPhysicsAsset); + it != m_materials.end()) + { + materialSelection.SetMaterialId(Physics::MaterialId::FromUUID(it->first), slotIndex); } else { - // It is important to return exactly the amount of materials specified in materialSelection - // If a number of materials different to what was cooked is assigned on a physx mesh it will lead to undefined - // behavior and subtle bugs. Unfortunately, there's no warning or assertion on physx side at the shape creation time, - // nor mention of this in the documentation - outMaterials.push_back(GetDefaultMaterial()->GetPxMaterial()); + AZ_Warning("PhysX", false, + "UpdateMaterialSelectionFromPhysicsAsset: Physics material '%s' not found in the material library. Mesh surface '%s' will use the default material.", + physicsMaterialNameFromPhysicsAsset.c_str(), + meshAsset->m_assetData.m_surfaceNames[slotIndex].c_str()); } } } @@ -390,11 +448,21 @@ namespace PhysX return GetDefaultMaterial(); } - const AZStd::shared_ptr& MaterialsManager::GetDefaultMaterial() + AZStd::shared_ptr MaterialsManager::GetDefaultMaterial() { if (!m_defaultMaterial) { - m_defaultMaterial = AZStd::make_shared(Physics::MaterialConfiguration()); + // Get default material from physics configuration + if (auto* physicsSystem = AZ::Interface::Get()) + { + m_defaultMaterialConfiguration = physicsSystem->GetConfiguration()->m_defaultMaterialConfiguration; + } + else + { + AZ_Warning("MaterialsManager", false, "Unable to get Physics System, default material will not be in sync with PhysX Configuration"); + } + + m_defaultMaterial = AZStd::make_shared(m_defaultMaterialConfiguration); } return m_defaultMaterial; @@ -403,38 +471,138 @@ namespace PhysX void MaterialsManager::ReleaseAllMaterials() { m_defaultMaterial = nullptr; - m_materialsFromAssets.clear(); + m_materials.clear(); Physics::PhysicsMaterialNotificationsBus::Broadcast(&Physics::PhysicsMaterialNotificationsBus::Events::MaterialsReleased); } - void MaterialsManager::InitializeMaterials(const Physics::MaterialSelection& materialSelection) + MaterialsManager::Materials::iterator MaterialsManager::FindOrCreateMaterial(Physics::MaterialId materialId) { - const AZStd::vector& materialIds = materialSelection.GetMaterialIdsAssignedToSlots(); - for (const auto& id : materialIds) + if (materialId.IsNull()) { - Physics::MaterialFromAssetConfiguration configuration; - if (!materialSelection.GetMaterialConfiguration(configuration, id)) - { - continue; // Default material skips code below. - } - - auto materialId = configuration.m_id; + return m_materials.end(); + } + if (auto it = m_materials.find(materialId.GetUuid()); + it != m_materials.end()) + { + return it; + } + else + { + auto* materialLibrary = GetMaterialLibrary(); + if (!materialLibrary) + { + return m_materials.end(); + } + + Physics::MaterialFromAssetConfiguration configuration; + if (!materialLibrary->GetDataForMaterialId(materialId, configuration)) + { + return m_materials.end(); + } + + auto newMaterial = AZStd::make_shared(configuration.m_configuration); + auto insertedPair = m_materials.emplace(materialId.GetUuid(), AZStd::move(newMaterial)); + return insertedPair.first; + } + } + + MaterialsManager::Materials::iterator MaterialsManager::FindOrCreateMaterial(const AZStd::string& materialName) + { + if (materialName.empty()) + { + return m_materials.end(); + } + + auto it = AZStd::find_if(m_materials.begin(), m_materials.end(), [&materialName](const auto& data) + { + return data.second->GetSurfaceTypeName() == materialName; + }); + if (it != m_materials.end()) + { + return it; + } + else + { + auto* materialLibrary = GetMaterialLibrary(); + if (!materialLibrary) + { + return m_materials.end(); + } + + Physics::MaterialFromAssetConfiguration configuration; + if (!materialLibrary->GetDataForMaterialName(materialName, configuration)) + { + return m_materials.end(); + } + + auto newMaterial = AZStd::make_shared(configuration.m_configuration); + auto insertedPair = m_materials.emplace(configuration.m_id.GetUuid(), AZStd::move(newMaterial)); + return insertedPair.first; + } + } + + Physics::MaterialLibraryAsset* MaterialsManager::GetMaterialLibrary() + { + if (auto* physicsSystem = AZ::Interface::Get()) + { + if (const auto* physicsConfiguration = physicsSystem->GetConfiguration()) + { + return physicsConfiguration->m_materialLibraryAsset.Get(); + } + } + return nullptr; + } + + void MaterialsManager::OnPhysicsConfigurationChanged(const AzPhysics::SystemConfiguration* config) + { + if (m_defaultMaterial && + m_defaultMaterialConfiguration != config->m_defaultMaterialConfiguration) + { + m_defaultMaterialConfiguration = config->m_defaultMaterialConfiguration; + + m_defaultMaterial->UpdateWithConfiguration(m_defaultMaterialConfiguration); + } + } + + void MaterialsManager::OnMaterialLibraryChanged([[maybe_unused]] const AZ::Data::AssetId& materialLibraryAssetId) + { + auto* materialLibrary = GetMaterialLibrary(); + if (!materialLibrary) + { + AZ_Warning("PhysX", false, "MaterialsManager: invalid material library"); + return; + } + + AZStd::vector materialsToRemove; + + for (auto& idMaterialPair : m_materials) + { + const Physics::MaterialId materialId = Physics::MaterialId::FromUUID(idMaterialPair.first); + + // Remove null materials if (materialId.IsNull()) { - materialId = Physics::MaterialId::Create(); + materialsToRemove.push_back(materialId.GetUuid()); + continue; } - auto iterator = m_materialsFromAssets.find(materialId.GetUuid()); - if (iterator != m_materialsFromAssets.end()) + Physics::MaterialFromAssetConfiguration configuration; + if (materialLibrary->GetDataForMaterialId(materialId, configuration)) { - iterator->second->UpdateWithConfiguration(configuration.m_configuration); + // Update materials found in the library. + idMaterialPair.second->UpdateWithConfiguration(configuration.m_configuration); } else { - auto newMaterial = AZStd::make_shared(configuration.m_configuration); - m_materialsFromAssets.emplace(materialId.GetUuid(), newMaterial); + // Add for removal the materials not present in the library anymore. + materialsToRemove.push_back(materialId.GetUuid()); } } + + for (const auto& id : materialsToRemove) + { + m_materials.erase(id); + } } } diff --git a/Gems/PhysX/Code/Source/Material.h b/Gems/PhysX/Code/Source/Material.h index a44c9766fc..1541d156d8 100644 --- a/Gems/PhysX/Code/Source/Material.h +++ b/Gems/PhysX/Code/Source/Material.h @@ -15,11 +15,18 @@ #include #include #include -#include +#include +#include #include namespace PhysX { + /// Name used by physx asset exporter to indicate that the default + /// physics material should be used for a mesh surface. The exporter + /// will use it as the fallback option when it's not possible to obtain + /// the surface information from the mesh material. + static const char* const DefaultPhysicsMaterialNameFromPhysicsAsset = ""; + /// PhysX implementation of Physics::Material interface /// =================================================== /// @@ -58,9 +65,9 @@ namespace PhysX // Physics::Material AZ::Crc32 GetSurfaceType() const override; - void SetSurfaceType(AZ::Crc32 surfaceType) override; - const AZStd::string& GetSurfaceTypeName() const override { return m_surfaceString; } + const AZStd::string& GetSurfaceTypeName() const override; + void SetSurfaceTypeName(const AZStd::string& surfaceTypeName) override; float GetDynamicFriction() const override; void SetDynamicFriction(float dynamicFriction) override; @@ -80,6 +87,9 @@ namespace PhysX float GetDensity() const override; void SetDensity(float density) override; + AZ::Color GetDebugColor() const override; + void SetDebugColor(const AZ::Color& debugColor) override; + AZ::u32 GetCryEngineSurfaceId() const override; void* GetNativePointer() override; @@ -92,6 +102,7 @@ namespace PhysX AZ::u32 m_cryEngineSurfaceId = -1; AZStd::string m_surfaceString; float m_density = 1000.0f; + AZ::Color m_debugColor = AZ::Colors::White; }; /// Bus with requests to MaterialsManager @@ -108,9 +119,17 @@ namespace PhysX static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; + /// Returns weak pointers to physx::PxMaterial. + /// Equivalent to PhysicsMaterialRequests::GetMaterials but it returns physx::PxMaterial pointers instead. + /// @param materialSelection MaterialSelection instance to create or get materials for + /// @param outMaterials vector of pointers to physx::PxMaterial to fill with. The vector will be cleared inside the function. virtual void GetPxMaterials(const Physics::MaterialSelection& materialSelection, AZStd::vector& outMaterials) = 0; - virtual const AZStd::shared_ptr& GetDefaultMaterial() = 0; + /// Returns default material + /// @return default PhysX::Material instance + virtual AZStd::shared_ptr GetDefaultMaterial() = 0; + + /// Releases ownership of all materials created before. virtual void ReleaseAllMaterials() = 0; }; using MaterialManagerRequestsBus = AZ::EBus; @@ -120,6 +139,9 @@ namespace PhysX /// /// Material managers creates PhysX::Material instances from MaterialLibraryAsset and assumes their ownership. /// Also keeps a reference to the default material. + /// + /// Note: Materials will be created on the fly while doing queries and + /// they will be updated when the material library changes. class MaterialsManager : public MaterialManagerRequestsBus::Handler , public Physics::PhysicsMaterialRequestBus::Handler @@ -131,35 +153,19 @@ namespace PhysX MaterialsManager(); ~MaterialsManager() override; - /// Returns a vector of weak pointers to materials selected. - /// To be notified if the pointers are deleted, connect to PhysicsMaterialNotifications::MaterialsReleased(). - /// @param materialSelection MaterialSelection instance to create or get materials for. - /// @param outMaterials Collection of material weak pointers corresponding to the material selection to be returned. + // PhysicsMaterialRequestBus::Handler overrides... void GetMaterials(const Physics::MaterialSelection& materialSelection - , AZStd::vector>& outMaterials) override; - - /// Returns a weak pointer to physics material with the given name. - AZStd::weak_ptr GetMaterialByName(const AZStd::string& name) override; - - /// Returns index of selected material in its material library. 0 is the Default material. - /// @param materialSelection Selection of materials. - AZ::u32 GetFirstSelectedMaterialIndex(const Physics::MaterialSelection& materialSelection) override; - - /// Slightly faster version of GetMaterials that returns physx::PxMaterial pointers instead. \n - /// The rest is equivalent to GetMaterials function. - /// @param materialSelection MaterialSelection instance to create or get materials for - /// @param outMaterials vector of pointers to physx::PxMaterial to fill with. The vector will be cleared inside the function. - void GetPxMaterials(const Physics::MaterialSelection& materialSelection, AZStd::vector& outMaterials) override; - - /// Returns default material - /// @return default PhysX::Material instance - const AZStd::shared_ptr& GetDefaultMaterial() override; - - /// Return default material - /// @return default Physics::Material instance + , AZStd::vector>& outMaterials) override; + AZStd::shared_ptr GetMaterialById(Physics::MaterialId id) override; + AZStd::shared_ptr GetMaterialByName(const AZStd::string& name) override; + void UpdateMaterialSelectionFromPhysicsAsset( + const Physics::ShapeConfiguration& shapeConfiguration, + Physics::MaterialSelection& materialSelection) override; AZStd::shared_ptr GetGenericDefaultMaterial() override; - /// Releases ownership of all materials created before. + // MaterialManagerRequestsBus::Handler overrides... + void GetPxMaterials(const Physics::MaterialSelection& materialSelection, AZStd::vector& outMaterials) override; + AZStd::shared_ptr GetDefaultMaterial() override; void ReleaseAllMaterials() override; /// Connect to any necessary buses @@ -169,9 +175,31 @@ namespace PhysX void Disconnect(); private: - void InitializeMaterials(const Physics::MaterialSelection& materialSelection); + using Materials = AZStd::unordered_map>; - AZStd::unordered_map> m_materialsFromAssets; + /// Search a material by id, if it exists already it returns its iterator, + /// if it doesn't exist it tries to create it and add it to the list. + /// If the material id is null or not part of the material library then the + /// iterator returned is end of material list. + Materials::iterator FindOrCreateMaterial(Physics::MaterialId materialId); + + /// Search a material by name, if it exists already it returns its iterator, + /// if it doesn't exist it tries to create it and add it to the list. + /// If the material id is null or not part of the material library then the + /// iterator returned is end of material list. + Materials::iterator FindOrCreateMaterial(const AZStd::string& materialName); + + /// Returns the material library of the project. + Physics::MaterialLibraryAsset* GetMaterialLibrary(); + + void OnPhysicsConfigurationChanged(const AzPhysics::SystemConfiguration* config); + void OnMaterialLibraryChanged(const AZ::Data::AssetId& materialLibraryAssetId); + + Materials m_materials; AZStd::shared_ptr m_defaultMaterial; + Physics::MaterialConfiguration m_defaultMaterialConfiguration; + + AzPhysics::SystemEvents::OnConfigurationChangedEvent::Handler m_physicsConfigChangedHandler; + AzPhysics::SystemEvents::OnMaterialLibraryChangedEvent::Handler m_materialLibraryChangedHandler; }; } diff --git a/Gems/PhysX/Code/Source/MeshColliderComponent.cpp b/Gems/PhysX/Code/Source/MeshColliderComponent.cpp index d383ba97de..1c6fdca640 100644 --- a/Gems/PhysX/Code/Source/MeshColliderComponent.cpp +++ b/Gems/PhysX/Code/Source/MeshColliderComponent.cpp @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include @@ -85,11 +85,6 @@ namespace PhysX UpdateMeshAsset(); } - void MeshColliderComponent::SetMaterialAsset(const AZ::Data::AssetId& id) - { - m_colliderConfiguration->m_materialSelection.SetMaterialLibrary(id); - } - void MeshColliderComponent::SetMaterialId(const Physics::MaterialId& id) { m_colliderConfiguration->m_materialSelection.SetMaterialId(id); @@ -111,8 +106,10 @@ namespace PhysX { m_shapeConfiguration->m_asset = asset; - Physics::SystemRequestBus::Broadcast(&Physics::SystemRequests::UpdateMaterialSelection, - *m_shapeConfiguration, *m_colliderConfiguration); + Physics::PhysicsMaterialRequestBus::Broadcast( + &Physics::PhysicsMaterialRequestBus::Events::UpdateMaterialSelectionFromPhysicsAsset, + *m_shapeConfiguration, + m_colliderConfiguration->m_materialSelection); } } @@ -122,8 +119,10 @@ namespace PhysX { m_shapeConfiguration->m_asset = asset; - Physics::SystemRequestBus::Broadcast(&Physics::SystemRequests::UpdateMaterialSelection, - *m_shapeConfiguration, *m_colliderConfiguration); + Physics::PhysicsMaterialRequestBus::Broadcast( + &Physics::PhysicsMaterialRequestBus::Events::UpdateMaterialSelectionFromPhysicsAsset, + *m_shapeConfiguration, + m_colliderConfiguration->m_materialSelection); } } diff --git a/Gems/PhysX/Code/Source/MeshColliderComponent.h b/Gems/PhysX/Code/Source/MeshColliderComponent.h index 4014f7ab5a..9d781fd6eb 100644 --- a/Gems/PhysX/Code/Source/MeshColliderComponent.h +++ b/Gems/PhysX/Code/Source/MeshColliderComponent.h @@ -40,7 +40,6 @@ namespace PhysX AZ::Data::Asset GetMeshAsset() const override; Physics::MaterialId GetMaterialId() const override; void SetMeshAsset(const AZ::Data::AssetId& id) override; - void SetMaterialAsset(const AZ::Data::AssetId& id) override; void SetMaterialId(const Physics::MaterialId& id) override; // BaseColliderComponent diff --git a/Gems/PhysX/Code/Source/PhysXCharacters/API/CharacterUtils.cpp b/Gems/PhysX/Code/Source/PhysXCharacters/API/CharacterUtils.cpp index d1502a0c65..87e3304a90 100644 --- a/Gems/PhysX/Code/Source/PhysXCharacters/API/CharacterUtils.cpp +++ b/Gems/PhysX/Code/Source/PhysXCharacters/API/CharacterUtils.cpp @@ -15,9 +15,7 @@ #include #include #include -#include -#include -#include +#include #include #include #include @@ -51,18 +49,32 @@ namespace PhysX static void AppendShapeIndependentProperties(physx::PxControllerDesc& controllerDesc, const Physics::CharacterConfiguration& characterConfig, CharacterControllerCallbackManager* callbackManager) { - AZStd::vector > materials; + AZStd::vector> materials; - Physics::SystemRequestBus::BroadcastResult( - materials, - &Physics::SystemRequests::CreateMaterialsFromLibrary, - characterConfig.m_materialSelection - ); - - if (materials.empty()) + if (characterConfig.m_materialSelection.GetMaterialIdsAssignedToSlots().empty()) { - AZ_Error("PhysX Character Controller", false, "Could not create character controller, material was invalid."); - return; + // If material selection has no slots, falling back to default material. + AZStd::shared_ptr defaultMaterial; + Physics::PhysicsMaterialRequestBus::BroadcastResult(defaultMaterial, + &Physics::PhysicsMaterialRequestBus::Events::GetGenericDefaultMaterial); + if (!defaultMaterial) + { + AZ_Error("PhysX Character Controller", false, "Invalid default material."); + return; + } + materials.push_back(AZStd::move(defaultMaterial)); + } + else + { + Physics::PhysicsMaterialRequestBus::Broadcast( + &Physics::PhysicsMaterialRequestBus::Events::GetMaterials, + characterConfig.m_materialSelection, + materials); + if (materials.empty()) + { + AZ_Error("PhysX Character Controller", false, "Could not create character controller, material list was empty."); + return; + } } physx::PxMaterial* pxMaterial = static_cast(materials.front()->GetNativePointer()); diff --git a/Gems/PhysX/Code/Source/Pipeline/MeshExporter.cpp b/Gems/PhysX/Code/Source/Pipeline/MeshExporter.cpp index 56042fbc91..24e532e2d1 100644 --- a/Gems/PhysX/Code/Source/Pipeline/MeshExporter.cpp +++ b/Gems/PhysX/Code/Source/Pipeline/MeshExporter.cpp @@ -25,7 +25,7 @@ #include #include -#include +#include #include #include #include @@ -153,7 +153,7 @@ namespace PhysX AZ::SerializeContext* serializeContext = azrtti_cast(context); if (serializeContext) { - serializeContext->Class()->Version(3); + serializeContext->Class()->Version(4); } } @@ -215,7 +215,7 @@ namespace PhysX if (nameAttribute) { AZStd::string materialName = nameAttribute->value(); - AZStd::string surfaceTypeName = DefaultMaterialName; + AZStd::string surfaceTypeName = DefaultPhysicsMaterialNameFromPhysicsAsset; AZ::rapidxml::xml_attribute* surfaceTypeNode = materialNode->first_attribute("SurfaceType"); if (surfaceTypeNode && surfaceTypeNode->value_size() != 0) @@ -268,7 +268,7 @@ namespace PhysX } else { - materialName = DefaultMaterialName; + materialName = DefaultPhysicsMaterialNameFromPhysicsAsset; } materialNames.emplace_back(AZStd::move(materialName)); diff --git a/Gems/PhysX/Code/Source/System/PhysXSystem.cpp b/Gems/PhysX/Code/Source/System/PhysXSystem.cpp index 8df9e9a86f..92f68ea13b 100644 --- a/Gems/PhysX/Code/Source/System/PhysXSystem.cpp +++ b/Gems/PhysX/Code/Source/System/PhysXSystem.cpp @@ -40,8 +40,8 @@ namespace PhysX } #endif - PhysXSystem::MaterialLibraryAssetHelper::MaterialLibraryAssetHelper(PhysXSystem* physXSystem) - : m_physXSystem(physXSystem) + PhysXSystem::MaterialLibraryAssetHelper::MaterialLibraryAssetHelper(OnMaterialLibraryReloadedCallback callback) + : m_onMaterialLibraryReloadedCallback(callback) { } @@ -62,16 +62,16 @@ namespace PhysX void PhysXSystem::MaterialLibraryAssetHelper::OnAssetReloaded(AZ::Data::Asset asset) { - if (m_physXSystem == nullptr || m_physXSystem->GetDefaultMaterialLibrary() != asset) - { - return; - } - m_physXSystem->UpdateDefaultMaterialLibrary(asset); + m_onMaterialLibraryReloadedCallback(asset); } PhysXSystem::PhysXSystem(PhysXSettingsRegistryManager* registryManager, const physx::PxCookingParams& cookingParams) : m_registryManager(*registryManager) - , m_materialLibraryAssetHelper(this) + , m_materialLibraryAssetHelper( + [this](const AZ::Data::Asset& materialLibrary) + { + UpdateMaterialLibrary(materialLibrary); + }) , m_sceneInterface(this) { // Start PhysX allocator @@ -127,7 +127,7 @@ namespace PhysX m_materialLibraryAssetHelper.Disconnect(); // Clear the asset reference in deactivate. The asset system is shut down before destructors are called // for system components, causing any hanging asset references to become crashes on shutdown in release builds. - m_systemConfig.m_defaultMaterialLibrary.Reset(); + m_systemConfig.m_materialLibraryAsset.Reset(); m_accumulatedTime = 0.0f; m_state = State::Shutdown; @@ -369,8 +369,18 @@ namespace PhysX void PhysXSystem::OnCatalogLoaded([[maybe_unused]]const char* catalogFile) { - //now that assets can be resolved, lets load the default material library. - LoadDefaultMaterialLibrary(); + // now that assets can be resolved, lets load the default material library. + + if (!m_systemConfig.m_materialLibraryAsset.GetId().IsValid()) + { + m_onMaterialLibraryLoadErrorEvent.Signal(AzPhysics::SystemEvents::MaterialLibraryLoadErrorType::InvalidId); + } + + bool success = LoadMaterialLibrary(); + if (!success) + { + m_onMaterialLibraryLoadErrorEvent.Signal(AzPhysics::SystemEvents::MaterialLibraryLoadErrorType::ErrorLoading); + } } void PhysXSystem::UpdateConfiguration(const AzPhysics::SystemConfiguration* newConfig, [[maybe_unused]] bool forceReinitialization /*= false*/) @@ -378,7 +388,7 @@ namespace PhysX if (const auto* physXConfig = azdynamic_cast(newConfig); m_systemConfig != (*physXConfig)) { - const bool newMaterialLibrary = m_systemConfig.m_defaultMaterialLibrary != physXConfig->m_defaultMaterialLibrary; + const bool newMaterialLibrary = m_systemConfig.m_materialLibraryAsset != physXConfig->m_materialLibraryAsset; m_systemConfig = (*physXConfig); m_configChangeEvent.Signal(physXConfig); @@ -386,9 +396,11 @@ namespace PhysX if (newMaterialLibrary) { - LoadDefaultMaterialLibrary(); - m_onDefaultMaterialLibraryChangedEvent.Signal(m_systemConfig.m_defaultMaterialLibrary.GetId()); + LoadMaterialLibrary(); + m_onMaterialLibraryChangedEvent.Signal(m_systemConfig.m_materialLibraryAsset.GetId()); } + // This function is not called from reloading the material library asset, + // which means we don't need to check if the materials inside the library have been modified. } } @@ -445,23 +457,6 @@ namespace PhysX return m_systemConfig; } - void PhysXSystem::UpdateDefaultMaterialLibrary(const AZ::Data::Asset& materialLibrary) - { - if (m_systemConfig.m_defaultMaterialLibrary == materialLibrary) - { - return; - } - m_systemConfig.m_defaultMaterialLibrary = materialLibrary; - - LoadDefaultMaterialLibrary(); - m_onDefaultMaterialLibraryChangedEvent.Signal(materialLibrary.GetId()); - } - - const AZ::Data::Asset& PhysXSystem::GetDefaultMaterialLibrary() const - { - return m_systemConfig.m_defaultMaterialLibrary; - } - void PhysXSystem::UpdateDefaultSceneConfiguration(const AzPhysics::SceneConfiguration& sceneConfiguration) { if (m_defaultSceneConfiguration != sceneConfiguration) @@ -482,9 +477,30 @@ namespace PhysX return m_registryManager; } - bool PhysXSystem::LoadDefaultMaterialLibrary() + void PhysXSystem::UpdateMaterialLibrary(const AZ::Data::Asset& materialLibrary) { - AZ::Data::Asset& materialLibrary = m_systemConfig.m_defaultMaterialLibrary; + if (m_systemConfig.m_materialLibraryAsset == materialLibrary) + { + // Same library asset, check if its data has changed. + if (m_systemConfig.m_materialLibraryAsset->GetMaterialsData() != materialLibrary->GetMaterialsData()) + { + m_systemConfig.m_materialLibraryAsset = materialLibrary; + m_onMaterialLibraryChangedEvent.Signal(materialLibrary.GetId()); + } + } + else + { + // New material library asset + m_systemConfig.m_materialLibraryAsset = materialLibrary; + + LoadMaterialLibrary(); + m_onMaterialLibraryChangedEvent.Signal(materialLibrary.GetId()); + } + } + + bool PhysXSystem::LoadMaterialLibrary() + { + AZ::Data::Asset& materialLibrary = m_systemConfig.m_materialLibraryAsset; const AZ::Data::AssetId& materialLibraryId = materialLibrary.GetId(); if (!materialLibraryId.IsValid()) { @@ -503,7 +519,7 @@ namespace PhysX AZ_Warning("PhysX", (materialLibrary.GetData() != nullptr), "LoadDefaultMaterialLibrary: Default Material Library asset data is invalid."); - return materialLibrary.GetData() != nullptr; + return materialLibrary.GetData() != nullptr && !materialLibrary.IsError(); } //TEMP -- until these are fully moved over here diff --git a/Gems/PhysX/Code/Source/System/PhysXSystem.h b/Gems/PhysX/Code/Source/System/PhysXSystem.h index 04d23ad47d..533685bbd1 100644 --- a/Gems/PhysX/Code/Source/System/PhysXSystem.h +++ b/Gems/PhysX/Code/Source/System/PhysXSystem.h @@ -64,8 +64,6 @@ namespace PhysX AZStd::pair FindAttachedBodyHandleFromEntityId(AZ::EntityId entityId) override; const AzPhysics::SystemConfiguration* GetConfiguration() const override; void UpdateConfiguration(const AzPhysics::SystemConfiguration* newConfig, bool forceReinitialization = false) override; - void UpdateDefaultMaterialLibrary(const AZ::Data::Asset& materialLibrary) override; - const AZ::Data::Asset& GetDefaultMaterialLibrary() const override; void UpdateDefaultSceneConfiguration(const AzPhysics::SceneConfiguration& sceneConfiguration) override; const AzPhysics::SceneConfiguration& GetDefaultSceneConfiguration() const override; @@ -75,6 +73,8 @@ namespace PhysX //! Accessor to get the Settings Registry Manager. const PhysXSettingsRegistryManager& GetSettingsRegistryManager() const; + void UpdateMaterialLibrary(const AZ::Data::Asset& materialLibrary); + //TEMP -- until these are fully moved over here physx::PxPhysics* GetPxPhysics() { return m_physXSdk.m_physics; } physx::PxCooking* GetPxCooking() { return m_physXSdk.m_cooking; } @@ -92,7 +92,7 @@ namespace PhysX //! @param cookingParams The cooking params to use when setting up PhysX cooking interface. void InitializePhysXSdk(const physx::PxCookingParams& cookingParams); void ShutdownPhysXSdk(); - bool LoadDefaultMaterialLibrary(); + bool LoadMaterialLibrary(); // AzFramework::AssetCatalogEventBus::Handler ... void OnCatalogLoaded(const char* catalogFile) override; @@ -133,7 +133,9 @@ namespace PhysX : private AZ::Data::AssetBus::Handler { public: - MaterialLibraryAssetHelper(PhysXSystem* physXSystem); + using OnMaterialLibraryReloadedCallback = AZStd::function& materialLibrary)>; + + MaterialLibraryAssetHelper(OnMaterialLibraryReloadedCallback callback); void Connect(const AZ::Data::AssetId& materialLibraryId); void Disconnect(); @@ -142,7 +144,7 @@ namespace PhysX // AZ::Data::AssetBus::Handler void OnAssetReloaded(AZ::Data::Asset asset) override; - PhysXSystem* m_physXSystem; + OnMaterialLibraryReloadedCallback m_onMaterialLibraryReloadedCallback; }; MaterialLibraryAssetHelper m_materialLibraryAssetHelper; }; diff --git a/Gems/PhysX/Code/Source/SystemComponent.cpp b/Gems/PhysX/Code/Source/SystemComponent.cpp index 9ef4dc5099..b4c17f672d 100644 --- a/Gems/PhysX/Code/Source/SystemComponent.cpp +++ b/Gems/PhysX/Code/Source/SystemComponent.cpp @@ -347,27 +347,6 @@ namespace PhysX return AZStd::make_shared(materialConfiguration); } - AZStd::vector> SystemComponent::CreateMaterialsFromLibrary(const Physics::MaterialSelection& materialSelection) - { - AZStd::vector pxMaterials; - m_materialManager.GetPxMaterials(materialSelection, pxMaterials); - - AZStd::vector> genericMaterials; - genericMaterials.reserve(pxMaterials.size()); - - for (physx::PxMaterial* pxMaterial : pxMaterials) - { - genericMaterials.push_back(static_cast(pxMaterial->userData)->shared_from_this()); - } - - return genericMaterials; - } - - AZStd::shared_ptr SystemComponent::GetDefaultMaterial() - { - return m_materialManager.GetDefaultMaterial(); - } - AZStd::vector SystemComponent::GetSupportedJointTypes() { return JointUtils::GetSupportedJointTypes(); @@ -484,58 +463,6 @@ namespace PhysX return m_physXSystem->GetPxCooking(); } - bool SystemComponent::UpdateMaterialSelection(const Physics::ShapeConfiguration& shapeConfiguration, - Physics::ColliderConfiguration& colliderConfiguration) - { - Physics::MaterialSelection& materialSelection = colliderConfiguration.m_materialSelection; - - // If the material library is still not set, we can't update the material selection - if (!materialSelection.IsMaterialLibraryValid()) - { - AZ_Warning("PhysX", false, - "UpdateMaterialSelection: Material Selection tried to use an invalid/non-existing Physics material library: \"%s\". " - "Please make sure the file exists or re-assign another library", materialSelection.GetMaterialLibraryAssetHint().c_str()); - return false; - } - - // If there's no material library data loaded, try to load it - if (materialSelection.GetMaterialLibraryAssetData() == nullptr) - { - AZ::Data::AssetId materialLibraryAssetId = materialSelection.GetMaterialLibraryAssetId(); - materialSelection.SetMaterialLibrary(materialLibraryAssetId); - } - - // If there's still not material library data, we can't update the material selection - if (materialSelection.GetMaterialLibraryAssetData() == nullptr) - { - AZ::Data::AssetId materialLibraryAssetId = materialSelection.GetMaterialLibraryAssetId(); - - auto materialLibraryAsset = - AZ::Data::AssetManager::Instance().GetAsset(materialLibraryAssetId, AZ::Data::AssetLoadBehavior::Default); - - materialLibraryAsset.BlockUntilLoadComplete(); - - // Log the asset path to help find out the incorrect library reference - AZStd::string assetPath = materialLibraryAsset.GetHint(); - AZ_Warning("PhysX", false, - "UpdateMaterialSelection: Unable to load the material library for a material selection." - " Please check if the asset %s exists in the asset cache.", assetPath.c_str()); - - return false; - } - - if (shapeConfiguration.GetShapeType() == Physics::ShapeType::PhysicsAsset) - { - const Physics::PhysicsAssetShapeConfiguration& assetConfiguration = - static_cast(shapeConfiguration); - - // Use the materials data from the asset to update the collider data - return UpdateMaterialSelectionFromPhysicsAsset(assetConfiguration, colliderConfiguration); - } - - return true; - } - void SystemComponent::OnTick(float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time) { if (m_physXSystem) @@ -614,65 +541,4 @@ namespace PhysX m_windProvider = AZStd::make_unique(); } - - bool SystemComponent::UpdateMaterialSelectionFromPhysicsAsset( - const Physics::PhysicsAssetShapeConfiguration& assetConfiguration, - Physics::ColliderConfiguration& colliderConfiguration) - { - Physics::MaterialSelection& materialSelection = colliderConfiguration.m_materialSelection; - - if (!assetConfiguration.m_asset.GetId().IsValid()) - { - // Set the default selection if there's no physics asset. - materialSelection.SetMaterialSlots(Physics::MaterialSelection::SlotsArray()); - return false; - } - - if (!assetConfiguration.m_asset.IsReady()) - { - // The asset is valid but is still loading, - // Do not set the empty slots in this case to avoid the entity being in invalid state - return false; - } - - Pipeline::MeshAsset* meshAsset = assetConfiguration.m_asset.GetAs(); - if (!meshAsset) - { - materialSelection.SetMaterialSlots(Physics::MaterialSelection::SlotsArray()); - AZ_Warning("PhysX", false, "UpdateMaterialSelectionFromPhysicsAsset: MeshAsset is invalid"); - return false; - } - - // Set the slots from the mesh asset - materialSelection.SetMaterialSlots(meshAsset->m_assetData.m_surfaceNames); - - if (!assetConfiguration.m_useMaterialsFromAsset) - { - return false; - } - - const Physics::MaterialLibraryAsset* materialLibrary = materialSelection.GetMaterialLibraryAssetData(); - const AZStd::vector& meshMaterialNames = meshAsset->m_assetData.m_materialNames; - - // Update material IDs in the selection for each slot - int slotIndex = 0; - for (const AZStd::string& meshMaterialName : meshMaterialNames) - { - Physics::MaterialFromAssetConfiguration materialData; - bool found = materialLibrary->GetDataForMaterialName(meshMaterialName, materialData); - - AZ_Warning("PhysX", found, - "UpdateMaterialSelectionFromPhysicsAsset: No material found for surfaceType (%s) in the collider material library", - meshMaterialName.c_str()); - - if (found) - { - materialSelection.SetMaterialId(materialData.m_id, slotIndex); - } - - slotIndex++; - } - - return true; - } } // namespace PhysX diff --git a/Gems/PhysX/Code/Source/SystemComponent.h b/Gems/PhysX/Code/Source/SystemComponent.h index 8871adfeeb..4609fde0ce 100644 --- a/Gems/PhysX/Code/Source/SystemComponent.h +++ b/Gems/PhysX/Code/Source/SystemComponent.h @@ -114,8 +114,6 @@ namespace PhysX // Physics::SystemRequestBus::Handler AZStd::shared_ptr CreateShape(const Physics::ColliderConfiguration& colliderConfiguration, const Physics::ShapeConfiguration& configuration) override; AZStd::shared_ptr CreateMaterial(const Physics::MaterialConfiguration& materialConfiguration) override; - AZStd::shared_ptr GetDefaultMaterial() override; - AZStd::vector> CreateMaterialsFromLibrary(const Physics::MaterialSelection& materialSelection) override; AZStd::vector GetSupportedJointTypes() override; AZStd::shared_ptr CreateJointLimitConfiguration(AZ::TypeId jointType) override; @@ -147,8 +145,6 @@ namespace PhysX static bool VersionConverter(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement); - bool UpdateMaterialSelection(const Physics::ShapeConfiguration& shapeConfiguration, - Physics::ColliderConfiguration& colliderConfiguration) override; private: // AZ::TickBus::Handler ... void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; @@ -157,9 +153,6 @@ namespace PhysX void EnableAutoManagedPhysicsTick(bool shouldTick); void ActivatePhysXSystem(); - bool UpdateMaterialSelectionFromPhysicsAsset( - const Physics::PhysicsAssetShapeConfiguration& assetConfiguration, - Physics::ColliderConfiguration& colliderConfiguration); bool m_enabled; ///< If false, this component will not activate itself in the Activate() function. diff --git a/Gems/PhysX/Code/Source/Utils.cpp b/Gems/PhysX/Code/Source/Utils.cpp index 55be7c92f7..70091ba970 100644 --- a/Gems/PhysX/Code/Source/Utils.cpp +++ b/Gems/PhysX/Code/Source/Utils.cpp @@ -607,48 +607,6 @@ namespace PhysX return true; } - void GetMaterialList( - AZStd::vector& pxMaterials, const AZStd::vector& terrainSurfaceIdIndexMapping, - const Physics::TerrainMaterialSurfaceIdMap& terrainMaterialsToSurfaceIds) - { - pxMaterials.reserve(terrainSurfaceIdIndexMapping.size()); - - AZStd::shared_ptr defaultMaterial; - MaterialManagerRequestsBus::BroadcastResult(defaultMaterial, &MaterialManagerRequestsBus::Events::GetDefaultMaterial); - - if (terrainSurfaceIdIndexMapping.empty()) - { - pxMaterials.push_back(defaultMaterial->GetPxMaterial()); - return; - } - - AZStd::vector materials; - - for (auto& surfaceId : terrainSurfaceIdIndexMapping) - { - const auto& userAssignedMaterials = terrainMaterialsToSurfaceIds; - const auto& matSelectionIterator = userAssignedMaterials.find(surfaceId); - if (matSelectionIterator != userAssignedMaterials.end()) - { - MaterialManagerRequestsBus::Broadcast(&MaterialManagerRequests::GetPxMaterials, matSelectionIterator->second, materials); - - if (!materials.empty()) - { - pxMaterials.push_back(materials.front()); - } - else - { - AZ_Error("PhysX", false, "Creating materials: array with materials can't be empty"); - pxMaterials.push_back(defaultMaterial->GetPxMaterial()); - } - } - else - { - pxMaterials.push_back(defaultMaterial->GetPxMaterial()); - } - } - } - AZStd::string ReplaceAll(AZStd::string str, const AZStd::string& fromString, const AZStd::string& toString) { size_t positionBegin = 0; while ((positionBegin = str.find(fromString, positionBegin)) != AZStd::string::npos) diff --git a/Gems/PhysX/Code/Source/Utils.h b/Gems/PhysX/Code/Source/Utils.h index 2885e86a09..73ce813b77 100644 --- a/Gems/PhysX/Code/Source/Utils.h +++ b/Gems/PhysX/Code/Source/Utils.h @@ -115,9 +115,6 @@ namespace PhysX bool MeshDataToPxGeometry(physx::PxBase* meshData, physx::PxGeometryHolder &pxGeometry, const AZ::Vector3& scale); - void GetMaterialList( - AZStd::vector& pxMaterials, const AZStd::vector& materialIndexMapping, - const Physics::TerrainMaterialSurfaceIdMap& terrainMaterialsToSurfaceIds); //! Returns all connected busIds of the specified type. template AZStd::vector FindConnectedBusIds() diff --git a/Gems/PhysX/Code/Tests/PhysXMaterialLibraryTest.cpp b/Gems/PhysX/Code/Tests/PhysXMaterialLibraryTest.cpp deleted file mode 100644 index 2e09ec8dca..0000000000 --- a/Gems/PhysX/Code/Tests/PhysXMaterialLibraryTest.cpp +++ /dev/null @@ -1,181 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#include - -#include -#include -#include -#include -#include -#include -#include - -namespace PhysX -{ - class MaterialLibraryTest_MockCatalog - : public AZ::Data::AssetCatalog - , public AZ::Data::AssetCatalogRequestBus::Handler - { - - private: - AZ::Uuid m_randomUuid = AZ::Uuid::CreateRandom(); - AZStd::vector m_mockAssetIds; - - public: - AZ_CLASS_ALLOCATOR(MaterialLibraryTest_MockCatalog, AZ::SystemAllocator, 0); - - MaterialLibraryTest_MockCatalog() - { - AZ::Data::AssetCatalogRequestBus::Handler::BusConnect(); - } - - ~MaterialLibraryTest_MockCatalog() - { - AZ::Data::AssetCatalogRequestBus::Handler::BusDisconnect(); - } - - AZ::Data::AssetId GenerateMockAssetId() - { - AZ::Data::AssetId assetId = AZ::Data::AssetId(AZ::Uuid::CreateRandom(), 0); - m_mockAssetIds.push_back(assetId); - return assetId; - } - - ////////////////////////////////////////////////////////////////////////// - // AssetCatalogRequestBus - AZ::Data::AssetInfo GetAssetInfoById(const AZ::Data::AssetId& id) override - { - AZ::Data::AssetInfo result; - result.m_assetType = AZ::AzTypeInfo::Uuid(); - auto foundId = AZStd::find(m_mockAssetIds.begin(), m_mockAssetIds.end(), id); - if (foundId != m_mockAssetIds.end()) - { - result.m_assetId = *foundId; - } - - return result; - } - ////////////////////////////////////////////////////////////////////////// - - AZ::Data::AssetStreamInfo GetStreamInfoForLoad(const AZ::Data::AssetId& id, const AZ::Data::AssetType& type) override - { - EXPECT_TRUE(type == AZ::AzTypeInfo::Uuid()); - AZ::Data::AssetStreamInfo info; - info.m_dataOffset = 0; - info.m_streamFlags = AZ::IO::OpenMode::ModeRead; - - for (int i = 0; i < m_mockAssetIds.size(); ++i) - { - if (m_mockAssetIds[i] == id) - { - info.m_streamName = AZStd::string::format("MaterialLibraryAssetName%d", i); - } - } - - if (!info.m_streamName.empty()) - { - // this ensures tha parallel running unit tests do not overlap their files that they use. - AZStd::string fullName = AZStd::string::format("%s-%s", m_randomUuid.ToString().c_str(), info.m_streamName.c_str()); - info.m_streamName = fullName; - info.m_dataLen = static_cast(AZ::IO::SystemFile::Length(info.m_streamName.c_str())); - } - else - { - info.m_dataLen = 0; - } - - return info; - } - - AZ::Data::AssetStreamInfo GetStreamInfoForSave(const AZ::Data::AssetId& id, const AZ::Data::AssetType& type) override - { - AZ::Data::AssetStreamInfo info; - info = GetStreamInfoForLoad(id, type); - info.m_streamFlags = AZ::IO::OpenMode::ModeWrite; - return info; - } - - bool SaveAsset(AZ::Data::Asset& asset) - { - volatile bool isDone = false; - volatile bool succeeded = false; - AZ::Data::AssetBusCallbacks callbacks; - callbacks.SetCallbacks(nullptr, nullptr, nullptr, - [&isDone, &succeeded](const AZ::Data::Asset& /*asset*/, bool isSuccessful, AZ::Data::AssetBusCallbacks& /*callbacks*/) - { - isDone = true; - succeeded = isSuccessful; - }, nullptr, nullptr, nullptr); - - callbacks.BusConnect(asset.GetId()); - asset.Save(); - - while (!isDone) - { - AZ::Data::AssetManager::Instance().DispatchEvents(); - } - return succeeded; - } - }; - - class DISABLED_PhysXMaterialLibraryTest - : public ::testing::Test - { - protected: - void SetUp() override - { - m_catalog = AZStd::make_unique(); - AZ::Data::AssetManager::Instance().RegisterCatalog(m_catalog.get(), AZ::AzTypeInfo::Uuid()); - } - - void TearDown() override - { - AZ::Data::AssetManager::Instance().UnregisterCatalog(m_catalog.get()); - } - - AZStd::unique_ptr m_catalog; - }; - - TEST_F(DISABLED_PhysXMaterialLibraryTest, DISABLED_DefaultMaterialLibrary_CorrectMaterialLibraryIsInferred) - { - AZ::Data::Asset materialLibrary = AZ::Interface::Get()->GetDefaultMaterialLibrary(); - - AZ::Data::AssetId dummyAssetId = AZ::Data::AssetId(AZ::Uuid::CreateName("DummyLibrary.physmaterial")); - AZ::Data::Asset dummyMaterialLibAsset = AZ::Data::AssetManager::Instance().GetAsset(dummyAssetId, AZ::Data::AssetLoadBehavior::Default); - materialLibrary = dummyMaterialLibAsset; - AZ::Interface::Get()->UpdateDefaultMaterialLibrary(materialLibrary); - - // We must have now a default material library setup - ASSERT_TRUE(materialLibrary.GetId().IsValid()); - - AZ::Data::AssetId otherDummyAssetId = AZ::Data::AssetId(AZ::Uuid::CreateName("OtherDummyLibrary.physmaterial")); - AZ::Data::Asset otherDummyMaterialLibAsset = AZ::Data::AssetManager::Instance().GetAsset(otherDummyAssetId, AZ::Data::AssetLoadBehavior::Default); - - // Set selection's material library to a different one than default material library - Physics::MaterialSelection selectionTest; - selectionTest.SetMaterialLibrary(otherDummyAssetId); - - ASSERT_TRUE(selectionTest.GetMaterialLibraryAssetId().IsValid()); - ASSERT_EQ(selectionTest.GetMaterialLibraryAssetId(), selectionTest.GetMaterialLibraryAssetId()); - ASSERT_NE(selectionTest.GetMaterialLibraryAssetId(), materialLibrary.GetId()); - - // By reseting the selection, now it should infer to the default material library set in the global configuration - selectionTest.ResetToDefaultMaterialLibrary(); - - ASSERT_TRUE(selectionTest.GetMaterialLibraryAssetId().IsValid()); - ASSERT_EQ(selectionTest.GetMaterialLibraryAssetId(), materialLibrary.GetId()); - - // Release material library so we exit gracefully - materialLibrary = {}; - AZ::Interface::Get()->UpdateDefaultMaterialLibrary(materialLibrary); - } -} diff --git a/Gems/PhysX/Code/physx_tests_files.cmake b/Gems/PhysX/Code/physx_tests_files.cmake index 406aed64a7..79999c5f74 100644 --- a/Gems/PhysX/Code/physx_tests_files.cmake +++ b/Gems/PhysX/Code/physx_tests_files.cmake @@ -23,7 +23,6 @@ set(FILES Tests/PhysXGenericTest.cpp Tests/PhysXSpecificTest.cpp Tests/PhysXForceRegionTest.cpp - Tests/PhysXMaterialLibraryTest.cpp Tests/PhysXCollisionFilteringTest.cpp Tests/PhysXJointsTest.cpp Tests/PhysXSceneTests.cpp diff --git a/Gems/ScriptCanvasPhysics/Code/Tests/ScriptCanvasPhysicsTest.cpp b/Gems/ScriptCanvasPhysics/Code/Tests/ScriptCanvasPhysicsTest.cpp index 4b04434e13..07ccdc5011 100644 --- a/Gems/ScriptCanvasPhysics/Code/Tests/ScriptCanvasPhysicsTest.cpp +++ b/Gems/ScriptCanvasPhysics/Code/Tests/ScriptCanvasPhysicsTest.cpp @@ -207,8 +207,8 @@ namespace ScriptCanvasPhysicsTests { public: MOCK_CONST_METHOD0(GetSurfaceType, AZ::Crc32()); - MOCK_METHOD1(SetSurfaceType, void(AZ::Crc32)); MOCK_CONST_METHOD0(GetSurfaceTypeName, const AZStd::string&()); + MOCK_METHOD1(SetSurfaceTypeName, void(const AZStd::string&)); MOCK_CONST_METHOD0(GetDynamicFriction, float()); MOCK_METHOD1(SetDynamicFriction, void(float)); MOCK_CONST_METHOD0(GetStaticFriction, float()); @@ -223,6 +223,8 @@ namespace ScriptCanvasPhysicsTests MOCK_METHOD0(GetNativePointer, void*()); MOCK_CONST_METHOD0(GetDensity, float()); MOCK_METHOD1(SetDensity, void(float)); + MOCK_CONST_METHOD0(GetDebugColor, AZ::Color()); + MOCK_METHOD1(SetDebugColor, void(const AZ::Color&)); }; class ScriptCanvasPhysicsTestEnvironment