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.
This commit is contained in:
@@ -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<Physics::MaterialId> { 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
|
||||
|
||||
@@ -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<AzPhysics::SceneHandle>;
|
||||
|
||||
//! 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<const AZ::Data::AssetId&>;
|
||||
using OnMaterialLibraryChangedEvent = AZ::Event<const AZ::Data::AssetId&>;
|
||||
|
||||
enum class MaterialLibraryLoadErrorType : uint8_t
|
||||
{
|
||||
InvalidId,
|
||||
ErrorLoading
|
||||
};
|
||||
|
||||
//! Event that triggers when the default material library has loaded with errors.
|
||||
using OnMaterialLibraryLoadErrorEvent = AZ::Event<MaterialLibraryLoadErrorType>;
|
||||
|
||||
//! Event that triggers when the default scene configuration changes.
|
||||
//! When triggered the event will send the new default scene configuration.
|
||||
|
||||
+5
-1
@@ -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
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
#include <AzCore/RTTI/RTTI.h>
|
||||
#include <AzFramework/Physics/Configuration/CollisionConfiguration.h>
|
||||
#include <AzFramework/Physics/Material.h>
|
||||
|
||||
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<Physics::MaterialLibraryAsset> 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;
|
||||
|
||||
@@ -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<AZ::SerializeContext*>(context);
|
||||
if (serializeContext)
|
||||
{
|
||||
serializeContext->Class<Physics::MaterialLibraryAssetReflectionWrapper>()
|
||||
->Version(1)
|
||||
->Field("Asset", &MaterialLibraryAssetReflectionWrapper::m_asset)
|
||||
;
|
||||
|
||||
AZ::EditContext* editContext = serializeContext->GetEditContext();
|
||||
if (editContext)
|
||||
{
|
||||
editContext->Class<Physics::MaterialLibraryAssetReflectionWrapper>("", "")
|
||||
->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<AZ::SerializeContext*>(context);
|
||||
if (serializeContext)
|
||||
{
|
||||
serializeContext->Class<Physics::DefaultMaterialLibraryAssetReflectionWrapper>()
|
||||
serializeContext->Class<Physics::MaterialInfoReflectionWrapper>()
|
||||
->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<Physics::DefaultMaterialLibraryAssetReflectionWrapper>("", "")
|
||||
editContext->Class<Physics::MaterialInfoReflectionWrapper>("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<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<Physics::MaterialSelection>()
|
||||
->Version(2, &ClassConverters::MaterialSelectionConverter)
|
||||
->Version(3, &ClassConverters::MaterialSelectionConverter)
|
||||
->EventHandler<MaterialSelectionEventHandler>()
|
||||
->Field("Material", &MaterialSelection::m_materialLibrary)
|
||||
->Field("MaterialIds", &MaterialSelection::m_materialIdsAssignedToSlots)
|
||||
;
|
||||
|
||||
@@ -381,14 +380,8 @@ namespace Physics
|
||||
editContext->Class<Physics::MaterialSelection>("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<Physics::MaterialLibraryAsset>(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<Physics::MaterialLibraryAsset> MaterialSelection::LoadAsset() const
|
||||
{
|
||||
AZ::Data::Asset<MaterialLibraryAsset> asset = AZ::Data::AssetManager::Instance()
|
||||
.GetAsset<Physics::MaterialLibraryAsset>(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<Physics::MaterialLibraryAsset>(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<Physics::MaterialLibraryAsset>& MaterialSelection::GetMaterialLibraryAsset() const
|
||||
{
|
||||
if (IsDefaultMaterialLibraryAsset())
|
||||
{
|
||||
const AZ::Data::Asset<Physics::MaterialLibraryAsset>& defaultMaterialLibrary = GetDefaultMaterialLibrary();
|
||||
return defaultMaterialLibrary;
|
||||
}
|
||||
|
||||
return m_materialLibrary;
|
||||
}
|
||||
|
||||
bool MaterialSelection::IsDefaultMaterialLibraryAsset() const
|
||||
{
|
||||
return !m_materialLibrary.GetId().IsValid();
|
||||
}
|
||||
|
||||
const AZ::Data::Asset<Physics::MaterialLibraryAsset>& MaterialSelection::GetDefaultMaterialLibrary()
|
||||
const AZ::Data::Asset<Physics::MaterialLibraryAsset>& MaterialSelection::GetMaterialLibrary()
|
||||
{
|
||||
if (auto* physicsSystem = AZ::Interface<AzPhysics::SystemInterface>::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
|
||||
|
||||
@@ -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<Physics::Material> newMaterial = AZ::Interface<Physics::System>::Get()->CreateMaterial(materialProperties);
|
||||
///
|
||||
/// To get PxMaterial use GetNativePointer function
|
||||
///
|
||||
/// physx::PxMaterial* material = static_cast<physx::PxMaterial*>(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<MaterialFromAssetConfiguration> 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<Physics::MaterialLibraryAsset> m_asset =
|
||||
Physics::MaterialConfiguration m_defaultMaterialConfiguration;
|
||||
AZ::Data::Asset<Physics::MaterialLibraryAsset> 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<Physics::MaterialLibraryAsset> 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<Physics::MaterialId>& 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<Physics::MaterialLibraryAsset> m_materialLibrary { AZ::Data::AssetLoadBehavior::NoLoad };
|
||||
AZStd::vector<Physics::MaterialId> m_materialIdsAssignedToSlots;
|
||||
SlotsArray m_materialSlots;
|
||||
bool m_slotsReadOnly = false;
|
||||
|
||||
const AZ::Data::Asset<Physics::MaterialLibraryAsset>& GetMaterialLibraryAsset() const;
|
||||
AZ::Data::Asset<Physics::MaterialLibraryAsset> LoadAsset() const;
|
||||
bool IsDefaultMaterialLibraryAsset() const;
|
||||
void SyncSelectionToMaterialLibrary();
|
||||
|
||||
static const AZ::Data::Asset<Physics::MaterialLibraryAsset>& GetDefaultMaterialLibrary();
|
||||
static const AZ::Data::AssetId& GetDefaultMaterialLibraryId();
|
||||
static const AZ::Data::Asset<Physics::MaterialLibraryAsset>& GetMaterialLibrary();
|
||||
static const AZ::Data::AssetId& GetMaterialLibraryId();
|
||||
|
||||
bool AreMaterialSlotsReadOnly() const;
|
||||
|
||||
// EditorContext callbacks
|
||||
AZ::u32 OnMaterialLibraryChanged();
|
||||
AZStd::string GetMaterialSlotLabel(int index);
|
||||
};
|
||||
|
||||
|
||||
@@ -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<Physics::Material> 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<AZStd::weak_ptr<Physics::Material>>& outMaterials) = 0;
|
||||
, AZStd::vector<AZStd::shared_ptr<Physics::Material>>& outMaterials) = 0;
|
||||
|
||||
/// Returns a weak pointer to physics material with the given id.
|
||||
virtual AZStd::shared_ptr<Physics::Material> GetMaterialById(Physics::MaterialId id) = 0;
|
||||
|
||||
/// Returns a weak pointer to physics material with the given name.
|
||||
virtual AZStd::weak_ptr<Physics::Material> GetMaterialByName(const AZStd::string& name) = 0;
|
||||
virtual AZStd::shared_ptr<Physics::Material> 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<PhysicsMaterialRequests>;
|
||||
|
||||
|
||||
@@ -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<Physics::MaterialLibraryAsset>& materialLibrary) = 0;
|
||||
|
||||
//! Accessor to get the current Material Library. This is also available in the PhysXSystemConfiguration.
|
||||
virtual const AZ::Data::Asset<Physics::MaterialLibraryAsset>& 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
|
||||
|
||||
@@ -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<AZ::SerializeContext*>(context))
|
||||
@@ -166,10 +181,9 @@ namespace Physics
|
||||
->RegisterGenericType<AZStd::shared_ptr<PhysicsAssetShapeConfiguration>>();
|
||||
|
||||
serializeContext->Class<PhysicsAssetShapeConfiguration, ShapeConfiguration>()
|
||||
->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")
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,7 +140,7 @@ namespace Physics
|
||||
|
||||
AZ::Data::Asset<AZ::Data::AssetData> 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.
|
||||
};
|
||||
|
||||
|
||||
@@ -142,24 +142,12 @@ namespace Physics
|
||||
|
||||
virtual AZStd::shared_ptr<Shape> CreateShape(const ColliderConfiguration& colliderConfiguration, const ShapeConfiguration& configuration) = 0;
|
||||
|
||||
virtual AZStd::shared_ptr<Material> 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<Material> CreateMaterial(const Physics::MaterialConfiguration& materialConfiguration) = 0;
|
||||
virtual AZStd::shared_ptr<Material> GetDefaultMaterial() = 0;
|
||||
virtual AZStd::vector<AZStd::shared_ptr<Material>> 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
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user