Changing material component property inspector to dockable view pane

• Inspector is locked to a specific entity and material assignment ID
• All modifications are made via the material component request bus
• Removed complicated configuration management in editor material component
• Multiple material property inspectors can be opened
• Multiple materials across different entities can be edited simultaneously
• No longer blocks the viewport or other interactions
• Added functions to material component request bus for retrieving material slot labels, default materials, getting and setting property and UV overrides
• Added more asset related types to material property value conversion from any
• Added support for static heading widget on top of atom tools inspector, currently used for menus and messages

WIP: Still investigating intermittent crash because of corrupt asset property
Signed-off-by: Guthrie Adams <guthadam@amazon.com>
This commit is contained in:
Guthrie Adams
2021-09-14 19:11:11 -05:00
parent e69238d4de
commit f7d4b8e70f
19 changed files with 826 additions and 556 deletions
@@ -35,6 +35,8 @@ namespace AZ
->Attribute(AZ::Script::Attributes::Module, "render")
->Event("GetOriginalMaterialAssignments", &MaterialComponentRequestBus::Events::GetOriginalMaterialAssignments)
->Event("FindMaterialAssignmentId", &MaterialComponentRequestBus::Events::FindMaterialAssignmentId)
->Event("GetDefaultMaterialAssetId", &MaterialComponentRequestBus::Events::GetDefaultMaterialAssetId)
->Event("GetMaterialSlotLabel", &MaterialComponentRequestBus::Events::GetMaterialSlotLabel)
->Event("SetMaterialOverrides", &MaterialComponentRequestBus::Events::SetMaterialOverrides)
->Event("GetMaterialOverrides", &MaterialComponentRequestBus::Events::GetMaterialOverrides)
->Event("ClearAllMaterialOverrides", &MaterialComponentRequestBus::Events::ClearAllMaterialOverrides)
@@ -71,6 +73,7 @@ namespace AZ
->Event("ClearPropertyOverride", &MaterialComponentRequestBus::Events::ClearPropertyOverride)
->Event("ClearPropertyOverrides", &MaterialComponentRequestBus::Events::ClearPropertyOverrides)
->Event("ClearAllPropertyOverrides", &MaterialComponentRequestBus::Events::ClearAllPropertyOverrides)
->Event("SetPropertyOverrides", &MaterialComponentRequestBus::Events::SetPropertyOverrides)
->Event("GetPropertyOverrides", &MaterialComponentRequestBus::Events::GetPropertyOverrides)
;
}
@@ -168,19 +171,26 @@ namespace AZ
const auto& propertyOverrides2 = materialIt->second.m_propertyOverrides;
for (auto& propertyPair : propertyOverrides2)
{
const auto& materialPropertyIndex = materialInstance->FindPropertyIndex(propertyPair.first);
if (!materialPropertyIndex.IsNull())
if (propertyPair.second.empty())
{
if (propertyPair.second.is<Data::AssetId>())
{
const auto& assetId = *AZStd::any_cast<Data::AssetId>(&propertyPair.second);
Data::Asset<RPI::ImageAsset> imageAsset(assetId, azrtti_typeid<RPI::StreamingImageAsset>());
materialInstance->SetPropertyValue(materialPropertyIndex, AZ::RPI::MaterialPropertyValue(imageAsset));
}
else
{
materialInstance->SetPropertyValue(materialPropertyIndex, AZ::RPI::MaterialPropertyValue::FromAny(propertyPair.second));
}
continue;
}
const auto& materialPropertyIndex = materialInstance->FindPropertyIndex(propertyPair.first);
if (materialPropertyIndex.IsNull())
{
continue;
}
if (propertyPair.second.is<Data::AssetId>())
{
const auto& assetId = *AZStd::any_cast<Data::AssetId>(&propertyPair.second);
Data::Asset<RPI::ImageAsset> imageAsset(assetId, azrtti_typeid<RPI::StreamingImageAsset>());
materialInstance->SetPropertyValue(materialPropertyIndex, AZ::RPI::MaterialPropertyValue(imageAsset));
}
else
{
materialInstance->SetPropertyValue(materialPropertyIndex, AZ::RPI::MaterialPropertyValue::FromAny(propertyPair.second));
}
}
@@ -288,6 +298,40 @@ namespace AZ
return materialAssignmentId;
}
AZ::Data::AssetId MaterialComponentController::GetDefaultMaterialAssetId(const MaterialAssignmentId& materialAssignmentId) const
{
RPI::ModelMaterialSlotMap modelMaterialSlots;
MaterialReceiverRequestBus::EventResult(
modelMaterialSlots, m_entityId, &MaterialReceiverRequestBus::Events::GetModelMaterialSlots);
auto slotIter = modelMaterialSlots.find(materialAssignmentId.m_materialSlotStableId);
return slotIter != modelMaterialSlots.end() ? slotIter->second.m_defaultMaterialAsset.GetId() : AZ::Data::AssetId();
}
AZStd::string MaterialComponentController::GetMaterialSlotLabel(const MaterialAssignmentId& materialAssignmentId) const
{
if (materialAssignmentId == DefaultMaterialAssignmentId)
{
return "Default Material";
}
RPI::ModelMaterialSlotMap modelMaterialSlots;
MaterialReceiverRequestBus::EventResult(
modelMaterialSlots, m_entityId, &MaterialReceiverRequestBus::Events::GetModelMaterialSlots);
auto slotIter = modelMaterialSlots.find(materialAssignmentId.m_materialSlotStableId);
if (slotIter != modelMaterialSlots.end())
{
const Name& displayName = slotIter->second.m_displayName;
if (!displayName.IsEmpty())
{
return displayName.GetStringView();
}
}
return "<unknown>";
}
void MaterialComponentController::SetMaterialOverrides(const MaterialAssignmentMap& materials)
{
// this function is called twice once material asset is changed, a temp variable is
@@ -309,7 +353,6 @@ namespace AZ
{
m_configuration.m_materials.clear();
QueueMaterialUpdateNotification();
MaterialComponentNotificationBus::Event(m_entityId, &MaterialComponentNotifications::OnMaterialsEdited, m_configuration.m_materials);
}
}
@@ -334,12 +377,11 @@ namespace AZ
LoadMaterials();
}
const AZ::Data::AssetId MaterialComponentController::GetMaterialOverride(const MaterialAssignmentId& materialAssignmentId) const
AZ::Data::AssetId MaterialComponentController::GetMaterialOverride(const MaterialAssignmentId& materialAssignmentId) const
{
auto materialIt = m_configuration.m_materials.find(materialAssignmentId);
if (materialIt == m_configuration.m_materials.end())
{
AZ_Error("MaterialComponentController", false, "MaterialAssignmentId not found.");
return {};
}
@@ -351,7 +393,6 @@ namespace AZ
if (m_configuration.m_materials.erase(materialAssignmentId) > 0)
{
QueueMaterialUpdateNotification();
MaterialComponentNotificationBus::Event(m_entityId, &MaterialComponentNotifications::OnMaterialsEdited, m_configuration.m_materials);
}
}
@@ -372,7 +413,6 @@ namespace AZ
}
QueuePropertyChanges(materialAssignmentId);
MaterialComponentNotificationBus::Event(m_entityId, &MaterialComponentNotifications::OnMaterialsEdited, m_configuration.m_materials);
}
void MaterialComponentController::SetPropertyOverrideBool(
@@ -450,14 +490,12 @@ namespace AZ
const auto materialIt = m_configuration.m_materials.find(materialAssignmentId);
if (materialIt == m_configuration.m_materials.end())
{
AZ_Error("MaterialComponentController", false, "MaterialAssignmentId not found.");
return {};
}
const auto propertyIt = materialIt->second.m_propertyOverrides.find(AZ::Name(propertyName));
if (propertyIt == materialIt->second.m_propertyOverrides.end())
{
AZ_Error("MaterialComponentController", false, "Property not found: %s.", propertyName.c_str());
return {};
}
@@ -546,14 +584,12 @@ namespace AZ
auto materialIt = m_configuration.m_materials.find(materialAssignmentId);
if (materialIt == m_configuration.m_materials.end())
{
AZ_Error("MaterialComponentController", false, "MaterialAssignmentId not found.");
return;
}
auto propertyIt = materialIt->second.m_propertyOverrides.find(AZ::Name(propertyName));
if (propertyIt == materialIt->second.m_propertyOverrides.end())
{
AZ_Error("MaterialComponentController", false, "Property not found: %s.", propertyName.c_str());
return;
}
@@ -565,7 +601,6 @@ namespace AZ
}
QueuePropertyChanges(materialAssignmentId);
MaterialComponentNotificationBus::Event(m_entityId, &MaterialComponentNotifications::OnMaterialsEdited, m_configuration.m_materials);
}
void MaterialComponentController::ClearPropertyOverrides(const MaterialAssignmentId& materialAssignmentId)
@@ -573,7 +608,6 @@ namespace AZ
auto materialIt = m_configuration.m_materials.find(materialAssignmentId);
if (materialIt == m_configuration.m_materials.end())
{
AZ_Error("MaterialComponentController", false, "MaterialAssignmentId not found.");
return;
}
@@ -582,7 +616,6 @@ namespace AZ
materialIt->second.m_propertyOverrides = {};
materialIt->second.RebuildInstance();
QueueMaterialUpdateNotification();
MaterialComponentNotificationBus::Event(m_entityId, &MaterialComponentNotifications::OnMaterialsEdited, m_configuration.m_materials);
}
}
@@ -602,21 +635,62 @@ namespace AZ
if (cleared)
{
MaterialComponentNotificationBus::Event(m_entityId, &MaterialComponentNotifications::OnMaterialsEdited, m_configuration.m_materials);
}
}
void MaterialComponentController::SetPropertyOverrides(
const MaterialAssignmentId& materialAssignmentId, const MaterialPropertyOverrideMap& propertyOverrides)
{
auto& materialAssignment = m_configuration.m_materials[materialAssignmentId];
const bool wasEmpty = materialAssignment.m_propertyOverrides.empty();
materialAssignment.m_propertyOverrides = propertyOverrides;
if (wasEmpty != materialAssignment.m_propertyOverrides.empty())
{
materialAssignment.RebuildInstance();
QueueMaterialUpdateNotification();
}
QueuePropertyChanges(materialAssignmentId);
}
MaterialPropertyOverrideMap MaterialComponentController::GetPropertyOverrides(const MaterialAssignmentId& materialAssignmentId) const
{
const auto materialIt = m_configuration.m_materials.find(materialAssignmentId);
if (materialIt == m_configuration.m_materials.end())
{
AZ_Warning("MaterialComponentController", false, "MaterialAssignmentId not found.");
return {};
}
return materialIt->second.m_propertyOverrides;
}
void MaterialComponentController::SetModelUvOverrides(
const MaterialAssignmentId& materialAssignmentId, const AZ::RPI::MaterialModelUvOverrideMap& modelUvOverrides)
{
auto& materialAssignment = m_configuration.m_materials[materialAssignmentId];
const bool wasEmpty = materialAssignment.m_matModUvOverrides.empty();
materialAssignment.m_matModUvOverrides = modelUvOverrides;
if (wasEmpty != materialAssignment.m_matModUvOverrides.empty())
{
materialAssignment.RebuildInstance();
QueueMaterialUpdateNotification();
}
QueuePropertyChanges(materialAssignmentId);
}
AZ::RPI::MaterialModelUvOverrideMap MaterialComponentController::GetModelUvOverrides(
const MaterialAssignmentId& materialAssignmentId) const
{
const auto materialIt = m_configuration.m_materials.find(materialAssignmentId);
if (materialIt == m_configuration.m_materials.end())
{
return {};
}
return materialIt->second.m_matModUvOverrides;
}
void MaterialComponentController::QueuePropertyChanges(const MaterialAssignmentId& materialAssignmentId)
{
m_queuedPropertyOverrides.emplace(materialAssignmentId);