From 00e860f32600520cd9fa93132c647233738b0411 Mon Sep 17 00:00:00 2001 From: Aaron Ruiz Mora Date: Fri, 28 May 2021 20:16:25 +0100 Subject: [PATCH] Physics material system for spectra launch - Invalidate 'Physics Materials From Mesh' boolean from collider component - Removed material library from material selector. Default material library will always be used instead. - Marking failing automated test as xfail - Added default material to physics configuration. - Moved material library asset from physx configuration to physics configuration, as it doesn't need to be physx specific. - Refactor physics material system having into account that there is only one material library in the project. - Renaming code from DefaultMaterialLibrary to MaterialLibrary. - All queries about physics materials unified under PhysicsMaterialRequests bus. - PhysXSystem only manages the material library asset. - Saving and reloading the same physics material asset with different content didn't trigger a events that the material library has changed. - Changing Physics Material Request interface to use shared_ptr instead of weak_ptr to be simpler to handle the returned materials and having a more consistent code. - Refactored Material Manager to improve its implementation. Still following the same approach of "creating materials on the fly as they are requested", but now it's doing it consistently across the interface, with private helpers functions FindOrCreateMaterial that simplify vastly the implementation. - Material Manager now listens to change event of material library asset and default material configuration so it updates its materials accordingly. - Complete Material move constructor and operator. --- .../Gem/PythonTests/physics/TestSuite_Main.py | 1 + ...4_Collider_CollisionGroups.setreg_override | 3 + ...9_Material_DynamicFriction.setreg_override | 118 ++++++ ...C4976227_Collider_NewGroup.setreg_override | 3 + ...ameGroupSameLayerCollision.setreg_override | 3 + ...ollider_CollisionLayerTest.setreg_override | 3 + ...ysXCollider_CollisionLayer.setreg_override | 3 + .../Registry/physxsystemconfiguration.setreg | 3 + .../surfacetypemateriallibrary.physmaterial | 11 +- .../AzFramework/Physics/ClassConverters.cpp | 9 +- .../Physics/Common/PhysicsEvents.h | 13 +- .../Configuration/SystemConfiguration.cpp | 6 +- .../Configuration/SystemConfiguration.h | 4 + .../AzFramework/Physics/Material.cpp | 224 +++------- .../AzFramework/Physics/Material.h | 101 ++--- .../AzFramework/Physics/MaterialBus.h | 19 +- .../AzFramework/Physics/PhysicsSystem.h | 17 +- .../Physics/ShapeConfiguration.cpp | 19 +- .../AzFramework/Physics/ShapeConfiguration.h | 2 +- .../AzFramework/Physics/SystemBus.h | 16 +- .../AzFramework/AzFramework/Physics/Utils.cpp | 3 +- .../Code/Source/Actor/BlastActorImpl.cpp | 2 - .../Components/BlastFamilyComponent.cpp | 22 +- .../Editor/EditorBlastFamilyComponent.cpp | 2 +- .../Code/Tests/Mocks/PhysicsSystem.h | 5 - .../Ragdoll/CanCopyPasteColliders.cpp | 3 - .../Ragdoll/CanCopyPasteJointLimits.cpp | 3 - Gems/PhysX/Code/Editor/DebugDraw.cpp | 15 +- Gems/PhysX/Code/Editor/SettingsWidget.cpp | 8 +- Gems/PhysX/Code/Editor/SettingsWidget.h | 2 +- .../Components/EditorSystemComponent.cpp | 77 ++-- .../Source/Components/EditorSystemComponent.h | 4 +- .../PhysX/Configuration/PhysXConfiguration.h | 2 - .../Include/PhysX/MeshColliderComponentBus.h | 4 - .../Configuration/PhysXConfiguration.cpp | 16 +- .../Code/Source/EditorColliderComponent.cpp | 24 +- .../Code/Source/EditorColliderComponent.h | 3 +- .../Source/EditorShapeColliderComponent.cpp | 13 +- .../Source/EditorShapeColliderComponent.h | 2 +- Gems/PhysX/Code/Source/Material.cpp | 388 +++++++++++++----- Gems/PhysX/Code/Source/Material.h | 92 +++-- .../Code/Source/MeshColliderComponent.cpp | 19 +- .../PhysX/Code/Source/MeshColliderComponent.h | 1 - .../PhysXCharacters/API/CharacterUtils.cpp | 38 +- .../Code/Source/Pipeline/MeshExporter.cpp | 8 +- Gems/PhysX/Code/Source/System/PhysXSystem.cpp | 84 ++-- Gems/PhysX/Code/Source/System/PhysXSystem.h | 12 +- Gems/PhysX/Code/Source/SystemComponent.cpp | 134 ------ Gems/PhysX/Code/Source/SystemComponent.h | 7 - Gems/PhysX/Code/Source/Utils.cpp | 42 -- Gems/PhysX/Code/Source/Utils.h | 3 - .../Code/Tests/PhysXMaterialLibraryTest.cpp | 181 -------- Gems/PhysX/Code/physx_tests_files.cmake | 1 - .../Code/Tests/ScriptCanvasPhysicsTest.cpp | 4 +- 54 files changed, 859 insertions(+), 943 deletions(-) create mode 100644 AutomatedTesting/Registry/C4044459_Material_DynamicFriction.setreg_override delete mode 100644 Gems/PhysX/Code/Tests/PhysXMaterialLibraryTest.cpp 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