00e860f326
- 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.
609 lines
21 KiB
C++
609 lines
21 KiB
C++
/*
|
|
* 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 <PhysX_precompiled.h>
|
|
|
|
#include "Material.h"
|
|
#include <AzCore/std/smart_ptr/make_shared.h>
|
|
#include <PxPhysicsAPI.h>
|
|
#include <AzFramework/Physics/PhysicsSystem.h>
|
|
#include <PhysX/MeshAsset.h>
|
|
|
|
namespace PhysX
|
|
{
|
|
Material::Material(Material&& material)
|
|
: 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;
|
|
}
|
|
|
|
Material& Material::operator=(Material&& material)
|
|
{
|
|
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;
|
|
}
|
|
|
|
static Material::CombineMode FromPxCombineMode(physx::PxCombineMode::Enum pxMode)
|
|
{
|
|
switch (pxMode)
|
|
{
|
|
case physx::PxCombineMode::eAVERAGE: return Material::CombineMode::Average;
|
|
case physx::PxCombineMode::eMULTIPLY: return Material::CombineMode::Multiply;
|
|
case physx::PxCombineMode::eMAX: return Material::CombineMode::Maximum;
|
|
case physx::PxCombineMode::eMIN: return Material::CombineMode::Minimum;
|
|
default: return Material::CombineMode::Average;
|
|
}
|
|
}
|
|
|
|
static physx::PxCombineMode::Enum ToPxCombineMode(Material::CombineMode mode)
|
|
{
|
|
switch (mode)
|
|
{
|
|
case Material::CombineMode::Average: return physx::PxCombineMode::eAVERAGE;
|
|
case Material::CombineMode::Multiply: return physx::PxCombineMode::eMULTIPLY;
|
|
case Material::CombineMode::Maximum: return physx::PxCombineMode::eMAX;
|
|
case Material::CombineMode::Minimum: return physx::PxCombineMode::eMIN;
|
|
default: return physx::PxCombineMode::eAVERAGE;
|
|
}
|
|
}
|
|
|
|
Material::Material(const Physics::MaterialConfiguration& materialConfiguration)
|
|
{
|
|
float staticFriction = materialConfiguration.m_staticFriction;
|
|
AZ_Warning("PhysX Material", staticFriction >= 0.0f, "Static friction %f for material %s is out of range [0, PX_MAX_F32)",
|
|
staticFriction, materialConfiguration.m_surfaceType.c_str());
|
|
|
|
float dynamicFriction = materialConfiguration.m_dynamicFriction;
|
|
AZ_Warning("PhysX Material", dynamicFriction >= 0.0f, "Dynamic friction %f for material %s is out of range [0, PX_MAX_F32)",
|
|
dynamicFriction, materialConfiguration.m_surfaceType.c_str());
|
|
|
|
float restitution = materialConfiguration.m_restitution;
|
|
AZ_Warning("PhysX Material", restitution >= 0 && restitution <= 1.0f, "Restitution %f for material %s is out of range [0, 1]",
|
|
restitution, materialConfiguration.m_surfaceType.c_str());
|
|
|
|
// Clamp the values to valid ranges
|
|
staticFriction = AZ::GetMax(0.0f, staticFriction);
|
|
dynamicFriction = AZ::GetMax(0.0f, dynamicFriction);
|
|
restitution = AZ::GetClamp(restitution, 0.0f, 1.0f);
|
|
|
|
SetDensity(materialConfiguration.m_density);
|
|
|
|
auto pxMaterial = PxGetPhysics().createMaterial(staticFriction, dynamicFriction, restitution);
|
|
|
|
auto materialDestructor = [](auto material)
|
|
{
|
|
material->release();
|
|
material->userData = nullptr;
|
|
};
|
|
|
|
pxMaterial->setFrictionCombineMode(ToPxCombineMode(materialConfiguration.m_frictionCombine));
|
|
pxMaterial->setRestitutionCombineMode(ToPxCombineMode(materialConfiguration.m_restitutionCombine));
|
|
pxMaterial->userData = this;
|
|
|
|
m_pxMaterial = PxMaterialUniquePtr(pxMaterial, materialDestructor);
|
|
|
|
SetSurfaceTypeName(materialConfiguration.m_surfaceType);
|
|
|
|
SetDebugColor(materialConfiguration.m_debugColor);
|
|
|
|
Physics::LegacySurfaceTypeRequestsBus::BroadcastResult(
|
|
m_cryEngineSurfaceId,
|
|
&Physics::LegacySurfaceTypeRequestsBus::Events::GetLegacySurfaceTypeFronName,
|
|
m_surfaceString);
|
|
}
|
|
|
|
void Material::UpdateWithConfiguration(const Physics::MaterialConfiguration& configuration)
|
|
{
|
|
AZ_Assert(m_pxMaterial != nullptr, "Material can't be null!");
|
|
|
|
SetRestitution(configuration.m_restitution);
|
|
SetStaticFriction(configuration.m_staticFriction);
|
|
SetDynamicFriction(configuration.m_dynamicFriction);
|
|
|
|
SetFrictionCombineMode(configuration.m_frictionCombine);
|
|
SetRestitutionCombineMode(configuration.m_restitutionCombine);
|
|
|
|
SetDensity(configuration.m_density);
|
|
|
|
SetSurfaceTypeName(configuration.m_surfaceType);
|
|
|
|
SetDebugColor(configuration.m_debugColor);
|
|
|
|
Physics::LegacySurfaceTypeRequestsBus::BroadcastResult(
|
|
m_cryEngineSurfaceId,
|
|
&Physics::LegacySurfaceTypeRequestsBus::Events::GetLegacySurfaceTypeFronName,
|
|
m_surfaceString);
|
|
}
|
|
|
|
physx::PxMaterial* Material::GetPxMaterial()
|
|
{
|
|
return m_pxMaterial.get();
|
|
}
|
|
|
|
AZ::Crc32 Material::GetSurfaceType() const
|
|
{
|
|
return m_surfaceType;
|
|
}
|
|
|
|
const AZStd::string& Material::GetSurfaceTypeName() const
|
|
{
|
|
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
|
|
{
|
|
return m_pxMaterial ? m_pxMaterial->getDynamicFriction() : 0.0f;
|
|
}
|
|
|
|
void Material::SetDynamicFriction(float dynamicFriction)
|
|
{
|
|
AZ_Warning("PhysX Material", dynamicFriction >= 0.0f,
|
|
"SetDynamicFriction: Dynamic friction %f for material %s is out of range [0, PX_MAX_F32)",
|
|
dynamicFriction, m_surfaceString.c_str());
|
|
|
|
if (m_pxMaterial)
|
|
{
|
|
m_pxMaterial->setDynamicFriction(AZ::GetMax(0.0f, dynamicFriction));
|
|
}
|
|
}
|
|
|
|
float Material::GetStaticFriction() const
|
|
{
|
|
return m_pxMaterial ? m_pxMaterial->getStaticFriction() : 0.0f;
|
|
}
|
|
|
|
void Material::SetStaticFriction(float staticFriction)
|
|
{
|
|
AZ_Warning("PhysX Material", staticFriction >= 0.0f,
|
|
"SetStaticFriction: Static friction %f for material %s is out of range [0, PX_MAX_F32)",
|
|
staticFriction, m_surfaceString.c_str());
|
|
|
|
if (m_pxMaterial)
|
|
{
|
|
m_pxMaterial->setStaticFriction(AZ::GetMax(0.0f, staticFriction));
|
|
}
|
|
}
|
|
|
|
float Material::GetRestitution() const
|
|
{
|
|
return m_pxMaterial ? m_pxMaterial->getRestitution() : 0.0f;
|
|
}
|
|
|
|
void Material::SetRestitution(float restitution)
|
|
{
|
|
AZ_Warning("PhysX Material", restitution >= 0 && restitution <= 1.0f,
|
|
"SetRestitution: Restitution %f for material %s is out of range [0, 1]",
|
|
restitution, m_surfaceString.c_str());
|
|
|
|
if (m_pxMaterial)
|
|
{
|
|
m_pxMaterial->setRestitution(AZ::GetClamp(restitution, 0.0f, 1.0f));
|
|
}
|
|
}
|
|
|
|
Material::CombineMode Material::GetFrictionCombineMode() const
|
|
{
|
|
return m_pxMaterial ? FromPxCombineMode(m_pxMaterial->getFrictionCombineMode()) : CombineMode::Average;
|
|
}
|
|
|
|
void Material::SetFrictionCombineMode(CombineMode mode)
|
|
{
|
|
if (m_pxMaterial)
|
|
{
|
|
m_pxMaterial->setFrictionCombineMode(ToPxCombineMode(mode));
|
|
}
|
|
}
|
|
|
|
Material::CombineMode Material::GetRestitutionCombineMode() const
|
|
{
|
|
return m_pxMaterial ? FromPxCombineMode(m_pxMaterial->getRestitutionCombineMode()) : CombineMode::Average;
|
|
}
|
|
|
|
void Material::SetRestitutionCombineMode(CombineMode mode)
|
|
{
|
|
if (m_pxMaterial)
|
|
{
|
|
m_pxMaterial->setRestitutionCombineMode(ToPxCombineMode(mode));
|
|
}
|
|
}
|
|
|
|
float Material::GetDensity() const
|
|
{
|
|
return m_density;
|
|
}
|
|
|
|
void Material::SetDensity(const float density)
|
|
{
|
|
using Physics::MaterialConfiguration;
|
|
|
|
AZ_Warning("PhysX Material", density >= MaterialConfiguration::MinDensityLimit && density <= MaterialConfiguration::MaxDensityLimit,
|
|
"Density %f for material %s should be in range [%f, %f].", density, m_surfaceString.c_str(),
|
|
MaterialConfiguration::MinDensityLimit, MaterialConfiguration::MaxDensityLimit);
|
|
m_density = AZ::GetClamp(density,
|
|
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;
|
|
}
|
|
|
|
void* Material::GetNativePointer()
|
|
{
|
|
return m_pxMaterial.get();
|
|
}
|
|
|
|
MaterialsManager::MaterialsManager()
|
|
: m_physicsConfigChangedHandler(
|
|
[this](const AzPhysics::SystemConfiguration* config)
|
|
{
|
|
OnPhysicsConfigurationChanged(config);
|
|
})
|
|
, m_materialLibraryChangedHandler(
|
|
[this](const AZ::Data::AssetId& materialLibraryAssetId)
|
|
{
|
|
OnMaterialLibraryChanged(materialLibraryAssetId);
|
|
})
|
|
{
|
|
}
|
|
|
|
MaterialsManager::~MaterialsManager()
|
|
{
|
|
}
|
|
|
|
void MaterialsManager::Connect()
|
|
{
|
|
Physics::PhysicsMaterialRequestBus::Handler::BusConnect();
|
|
MaterialManagerRequestsBus::Handler::BusConnect();
|
|
|
|
if (auto* physicsSystem = AZ::Interface<AzPhysics::SystemInterface>::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<AZStd::shared_ptr<Physics::Material>>& outMaterials)
|
|
{
|
|
outMaterials.clear();
|
|
|
|
const auto& materialIdsAssignedToSlots = materialSelection.GetMaterialIdsAssignedToSlots();
|
|
if (materialIdsAssignedToSlots.empty())
|
|
{
|
|
// 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())
|
|
{
|
|
outMaterials[slotIndex] = iterator->second;
|
|
}
|
|
}
|
|
}
|
|
|
|
AZStd::shared_ptr<Physics::Material> MaterialsManager::GetMaterialById(Physics::MaterialId id)
|
|
{
|
|
if (auto it = FindOrCreateMaterial(id);
|
|
it != m_materials.end())
|
|
{
|
|
return it->second;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
AZStd::shared_ptr<Physics::Material> MaterialsManager::GetMaterialByName(const AZStd::string& name)
|
|
{
|
|
if (auto it = FindOrCreateMaterial(name);
|
|
it != m_materials.end())
|
|
{
|
|
return it->second;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
void MaterialsManager::GetPxMaterials(const Physics::MaterialSelection& materialSelection
|
|
, AZStd::vector<physx::PxMaterial*>& outMaterials)
|
|
{
|
|
AZStd::vector<AZStd::shared_ptr<Physics::Material>> materials;
|
|
GetMaterials(materialSelection, materials);
|
|
|
|
outMaterials.reserve(materials.size());
|
|
for (const auto& material : materials)
|
|
{
|
|
PhysX::Material* physxMaterial = azrtti_cast<PhysX::Material*>(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)
|
|
{
|
|
return;
|
|
}
|
|
|
|
const Physics::PhysicsAssetShapeConfiguration& assetConfiguration =
|
|
static_cast<const Physics::PhysicsAssetShapeConfiguration&>(shapeConfiguration);
|
|
|
|
if (!assetConfiguration.m_asset.GetId().IsValid())
|
|
{
|
|
// 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<Pipeline::MeshAsset>();
|
|
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<AZStd::string>& meshMaterialNames = meshAsset->m_assetData.m_materialNames;
|
|
for (size_t slotIndex = 0; slotIndex < meshMaterialNames.size(); ++slotIndex)
|
|
{
|
|
const AZStd::string& physicsMaterialNameFromPhysicsAsset = meshMaterialNames[slotIndex];
|
|
if (physicsMaterialNameFromPhysicsAsset == DefaultPhysicsMaterialNameFromPhysicsAsset)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (auto it = FindOrCreateMaterial(physicsMaterialNameFromPhysicsAsset);
|
|
it != m_materials.end())
|
|
{
|
|
materialSelection.SetMaterialId(Physics::MaterialId::FromUUID(it->first), slotIndex);
|
|
}
|
|
else
|
|
{
|
|
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());
|
|
}
|
|
}
|
|
}
|
|
|
|
AZStd::shared_ptr<Physics::Material> MaterialsManager::GetGenericDefaultMaterial()
|
|
{
|
|
return GetDefaultMaterial();
|
|
}
|
|
|
|
AZStd::shared_ptr<Material> MaterialsManager::GetDefaultMaterial()
|
|
{
|
|
if (!m_defaultMaterial)
|
|
{
|
|
// Get default material from physics configuration
|
|
if (auto* physicsSystem = AZ::Interface<AzPhysics::SystemInterface>::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<Material>(m_defaultMaterialConfiguration);
|
|
}
|
|
|
|
return m_defaultMaterial;
|
|
}
|
|
|
|
void MaterialsManager::ReleaseAllMaterials()
|
|
{
|
|
m_defaultMaterial = nullptr;
|
|
m_materials.clear();
|
|
Physics::PhysicsMaterialNotificationsBus::Broadcast(&Physics::PhysicsMaterialNotificationsBus::Events::MaterialsReleased);
|
|
}
|
|
|
|
MaterialsManager::Materials::iterator MaterialsManager::FindOrCreateMaterial(Physics::MaterialId materialId)
|
|
{
|
|
if (materialId.IsNull())
|
|
{
|
|
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<Material>(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<Material>(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<AzPhysics::SystemInterface>::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<AZ::Uuid> materialsToRemove;
|
|
|
|
for (auto& idMaterialPair : m_materials)
|
|
{
|
|
const Physics::MaterialId materialId = Physics::MaterialId::FromUUID(idMaterialPair.first);
|
|
|
|
// Remove null materials
|
|
if (materialId.IsNull())
|
|
{
|
|
materialsToRemove.push_back(materialId.GetUuid());
|
|
continue;
|
|
}
|
|
|
|
Physics::MaterialFromAssetConfiguration configuration;
|
|
if (materialLibrary->GetDataForMaterialId(materialId, configuration))
|
|
{
|
|
// Update materials found in the library.
|
|
idMaterialPair.second->UpdateWithConfiguration(configuration.m_configuration);
|
|
}
|
|
else
|
|
{
|
|
// 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);
|
|
}
|
|
}
|
|
}
|