Merge branch 'development' into Atom/santorac/RemixableMaterialTypes3
There were lots of material system conflicts that had to be resolved. I expect the build is broken at this commit, and I'll fix it in followup commits. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com>
This commit is contained in:
+44
-11
@@ -6,23 +6,24 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Material/EditorMaterialComponent.h>
|
||||
#include <Material/EditorMaterialComponentExporter.h>
|
||||
|
||||
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
|
||||
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
|
||||
#include <AzCore/RTTI/BehaviorContext.h>
|
||||
#include <Atom/RPI.Edit/Common/AssetUtils.h>
|
||||
#include <Atom/RPI.Edit/Material/MaterialPropertyId.h>
|
||||
#include <Atom/RPI.Public/Image/StreamingImage.h>
|
||||
#include <Atom/RPI.Reflect/Material/MaterialAsset.h>
|
||||
#include <Atom/RPI.Reflect/Material/MaterialTypeAsset.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/Mesh/MeshComponentBus.h>
|
||||
#include <AzCore/RTTI/BehaviorContext.h>
|
||||
#include <AzCore/Serialization/Json/RegistrationContext.h>
|
||||
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
|
||||
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
|
||||
#include <Material/EditorMaterialComponent.h>
|
||||
#include <Material/EditorMaterialComponentExporter.h>
|
||||
#include <Material/EditorMaterialComponentSerializer.h>
|
||||
|
||||
AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT
|
||||
#include <QMenu>
|
||||
#include <QAction>
|
||||
#include <QCursor>
|
||||
#include <QMenu>
|
||||
AZ_POP_DISABLE_WARNING
|
||||
|
||||
namespace AZ
|
||||
@@ -59,7 +60,12 @@ namespace AZ
|
||||
BaseClass::Reflect(context);
|
||||
EditorMaterialComponentSlot::Reflect(context);
|
||||
|
||||
if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
if (auto jsonContext = azrtti_cast<JsonRegistrationContext*>(context))
|
||||
{
|
||||
jsonContext->Serializer<JsonEditorMaterialComponentSerializer>()->HandlesType<EditorMaterialComponent>();
|
||||
}
|
||||
|
||||
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->RegisterGenericType<EditorMaterialComponentSlotContainer>();
|
||||
serializeContext->RegisterGenericType<EditorMaterialComponentSlotsByLodContainer>();
|
||||
@@ -76,7 +82,7 @@ namespace AZ
|
||||
serializeContext->RegisterGenericType<AZStd::unordered_map<MaterialAssignmentId, Data::AssetId, AZStd::hash<MaterialAssignmentId>, AZStd::equal_to<MaterialAssignmentId>, AZStd::allocator>>();
|
||||
serializeContext->RegisterGenericType<AZStd::unordered_map<MaterialAssignmentId, MaterialPropertyOverrideMap, AZStd::hash<MaterialAssignmentId>, AZStd::equal_to<MaterialAssignmentId>, AZStd::allocator>>();
|
||||
|
||||
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
|
||||
if (auto editContext = serializeContext->GetEditContext())
|
||||
{
|
||||
editContext->Class<EditorMaterialComponent>(
|
||||
"Material", "The material component specifies the material to use for this entity")
|
||||
@@ -86,7 +92,7 @@ namespace AZ
|
||||
->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/Component_Placeholder.svg")
|
||||
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c))
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/atom/")
|
||||
->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/atom/material/")
|
||||
->Attribute(AZ::Edit::Attributes::PrimaryAssetType, AZ::AzTypeInfo<RPI::MaterialAsset>::Uuid())
|
||||
->DataElement(AZ::Edit::UIHandlers::MultiLineEdit, &EditorMaterialComponent::m_message, "Message", "")
|
||||
->Attribute(AZ_CRC("PlaceholderText", 0xa23ec278), "Component cannot be edited with multiple entities selected")
|
||||
@@ -129,7 +135,7 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
|
||||
if (auto behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
|
||||
{
|
||||
behaviorContext->ConstantProperty("EditorMaterialComponentTypeId", BehaviorConstant(Uuid(EditorMaterialComponentTypeId)))
|
||||
->Attribute(AZ::Script::Attributes::Module, "render")
|
||||
@@ -148,11 +154,13 @@ namespace AZ
|
||||
BaseClass::Activate();
|
||||
MaterialReceiverNotificationBus::Handler::BusConnect(GetEntityId());
|
||||
MaterialComponentNotificationBus::Handler::BusConnect(GetEntityId());
|
||||
EditorMaterialSystemComponentNotificationBus::Handler::BusConnect();
|
||||
UpdateMaterialSlots();
|
||||
}
|
||||
|
||||
void EditorMaterialComponent::Deactivate()
|
||||
{
|
||||
EditorMaterialSystemComponentNotificationBus::Handler::BusDisconnect();
|
||||
MaterialReceiverNotificationBus::Handler::BusDisconnect();
|
||||
MaterialComponentNotificationBus::Handler::BusDisconnect();
|
||||
BaseClass::Deactivate();
|
||||
@@ -238,6 +246,19 @@ namespace AZ
|
||||
UpdateMaterialSlots();
|
||||
});
|
||||
action->setToolTip("Repair materials that reference missing assets by assigning the default asset.");
|
||||
|
||||
action = menu->addAction("Apply Automatic Property Updates", [this]() {
|
||||
AzToolsFramework::ScopedUndoBatch undoBatch("Applying automatic property updates.");
|
||||
SetDirty();
|
||||
|
||||
uint32_t propertiesUpdated = 0;
|
||||
MaterialComponentRequestBus::EventResult(propertiesUpdated, GetEntityId(), &MaterialComponentRequestBus::Events::ApplyAutomaticPropertyUpdates);
|
||||
|
||||
AZ_Printf("EditorMaterialComponent", "Updated %u property(s).", propertiesUpdated);
|
||||
|
||||
UpdateMaterialSlots();
|
||||
});
|
||||
action->setToolTip("Repair material property overrides that reference missing properties by auto-renaming them where possible.");
|
||||
}
|
||||
|
||||
void EditorMaterialComponent::SetPrimaryAsset(const AZ::Data::AssetId& assetId)
|
||||
@@ -260,6 +281,18 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
void EditorMaterialComponent::OnRenderMaterialPreviewComplete(
|
||||
[[maybe_unused]] const AZ::EntityId& entityId,
|
||||
[[maybe_unused]] const AZ::Render::MaterialAssignmentId& materialAssignmentId,
|
||||
[[maybe_unused]] const QPixmap& pixmap)
|
||||
{
|
||||
if (entityId == GetEntityId())
|
||||
{
|
||||
AzToolsFramework::ToolsApplicationEvents::Bus::Broadcast(
|
||||
&AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay, AzToolsFramework::Refresh_AttributesAndValues);
|
||||
}
|
||||
}
|
||||
|
||||
AZ::u32 EditorMaterialComponent::OnConfigurationChanged()
|
||||
{
|
||||
return AZ::Edit::PropertyRefreshLevels::AttributesAndValues;
|
||||
|
||||
+10
-2
@@ -9,6 +9,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <Atom/Feature/Utils/EditorRenderComponentAdapter.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentNotificationBus.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentConstants.h>
|
||||
#include <Material/EditorMaterialComponentSlot.h>
|
||||
@@ -21,10 +22,13 @@ namespace AZ
|
||||
//! In-editor material component for displaying and editing material assignments.
|
||||
class EditorMaterialComponent final
|
||||
: public EditorRenderComponentAdapter<MaterialComponentController, MaterialComponent, MaterialComponentConfig>
|
||||
, private MaterialReceiverNotificationBus::Handler
|
||||
, private MaterialComponentNotificationBus::Handler
|
||||
, public MaterialReceiverNotificationBus::Handler
|
||||
, public MaterialComponentNotificationBus::Handler
|
||||
, public EditorMaterialSystemComponentNotificationBus::Handler
|
||||
{
|
||||
public:
|
||||
friend class JsonEditorMaterialComponentSerializer;
|
||||
|
||||
using BaseClass = EditorRenderComponentAdapter<MaterialComponentController, MaterialComponent, MaterialComponentConfig>;
|
||||
AZ_EDITOR_COMPONENT(EditorMaterialComponent, EditorMaterialComponentTypeId, BaseClass);
|
||||
|
||||
@@ -52,6 +56,10 @@ namespace AZ
|
||||
//! MaterialComponentNotificationBus::Handler overrides...
|
||||
void OnMaterialInstanceCreated(const MaterialAssignment& materialAssignment) override;
|
||||
|
||||
//! EditorMaterialSystemComponentNotificationBus::Handler overrides...
|
||||
void OnRenderMaterialPreviewComplete(
|
||||
const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId, const QPixmap& pixmap) override;
|
||||
|
||||
// Regenerates the editor component material slots based on the material and
|
||||
// LOD mapping from the model or other consumer of materials.
|
||||
// If any corresponding material assignments are found in the component
|
||||
|
||||
+163
-102
@@ -23,10 +23,6 @@
|
||||
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
|
||||
#include <AzToolsFramework/API/EditorWindowRequestBus.h>
|
||||
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
|
||||
#include <AzToolsFramework/AssetBrowser/Thumbnails/ProductThumbnail.h>
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailContext.h>
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailWidget.h>
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailerBus.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentRequestBus.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentConfig.h>
|
||||
@@ -49,29 +45,18 @@ namespace AZ
|
||||
MaterialPropertyInspector::MaterialPropertyInspector(QWidget* parent)
|
||||
: AtomToolsFramework::InspectorWidget(parent)
|
||||
{
|
||||
// Create the menu button
|
||||
QToolButton* menuButton = new QToolButton(this);
|
||||
menuButton->setAutoRaise(true);
|
||||
menuButton->setIcon(QIcon(":/Cards/img/UI20/Cards/menu_ico.svg"));
|
||||
menuButton->setVisible(true);
|
||||
QObject::connect(menuButton, &QToolButton::clicked, this, [this]() { OpenMenu(); });
|
||||
AddHeading(menuButton);
|
||||
|
||||
m_messageLabel = new QLabel(this);
|
||||
m_messageLabel->setWordWrap(true);
|
||||
m_messageLabel->setVisible(true);
|
||||
m_messageLabel->setAlignment(Qt::AlignCenter);
|
||||
m_messageLabel->setText(tr("Material not available"));
|
||||
AddHeading(m_messageLabel);
|
||||
|
||||
CreateHeading();
|
||||
AZ::TickBus::Handler::BusConnect();
|
||||
AZ::EntitySystemBus::Handler::BusConnect();
|
||||
EditorMaterialSystemComponentNotificationBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
MaterialPropertyInspector::~MaterialPropertyInspector()
|
||||
{
|
||||
AtomToolsFramework::InspectorRequestBus::Handler::BusDisconnect();
|
||||
AZ::EntitySystemBus::Handler::BusDisconnect();
|
||||
AZ::TickBus::Handler::BusDisconnect();
|
||||
AZ::EntitySystemBus::Handler::BusDisconnect();
|
||||
EditorMaterialSystemComponentNotificationBus::Handler::BusDisconnect();
|
||||
MaterialComponentNotificationBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
@@ -88,6 +73,12 @@ namespace AZ
|
||||
AZ::Data::AssetId materialAssetId = {};
|
||||
MaterialComponentRequestBus::EventResult(
|
||||
materialAssetId, m_entityId, &MaterialComponentRequestBus::Events::GetMaterialOverride, m_materialAssignmentId);
|
||||
if (!materialAssetId.IsValid())
|
||||
{
|
||||
MaterialComponentRequestBus::EventResult(
|
||||
materialAssetId, m_entityId, &MaterialComponentRequestBus::Events::GetDefaultMaterialAssetId,
|
||||
m_materialAssignmentId);
|
||||
}
|
||||
|
||||
if (!materialAssetId.IsValid())
|
||||
{
|
||||
@@ -134,7 +125,7 @@ namespace AZ
|
||||
}
|
||||
|
||||
Populate();
|
||||
m_messageLabel->setVisible(false);
|
||||
LoadOverridesFromEntity();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -146,8 +137,9 @@ namespace AZ
|
||||
m_dirtyPropertyFlags.set();
|
||||
m_editorFunctors = {};
|
||||
m_internalEditNotification = {};
|
||||
m_messageLabel->setVisible(true);
|
||||
m_messageLabel->setText(tr("Material not available"));
|
||||
m_updateUI = {};
|
||||
m_updatePreview = {};
|
||||
UpdateHeading();
|
||||
}
|
||||
|
||||
bool MaterialPropertyInspector::IsLoaded() const
|
||||
@@ -162,49 +154,63 @@ namespace AZ
|
||||
m_dirtyPropertyFlags.set();
|
||||
m_internalEditNotification = {};
|
||||
|
||||
AZ::TickBus::Handler::BusDisconnect();
|
||||
AtomToolsFramework::InspectorRequestBus::Handler::BusDisconnect();
|
||||
AtomToolsFramework::InspectorWidget::Reset();
|
||||
}
|
||||
|
||||
void MaterialPropertyInspector::AddDetailsGroup()
|
||||
void MaterialPropertyInspector::CreateHeading()
|
||||
{
|
||||
const AZStd::string& groupName = "Details";
|
||||
const AZStd::string& groupDisplayName = "Details";
|
||||
const AZStd::string& groupDescription = "";
|
||||
// Create the menu button
|
||||
QToolButton* menuButton = new QToolButton(this);
|
||||
menuButton->setAutoRaise(true);
|
||||
menuButton->setIcon(QIcon(":/Cards/img/UI20/Cards/menu_ico.svg"));
|
||||
menuButton->setVisible(true);
|
||||
QObject::connect(menuButton, &QToolButton::clicked, this, [this]() { OpenMenu(); });
|
||||
AddHeading(menuButton);
|
||||
|
||||
auto propertyGroupContainer = new QWidget(this);
|
||||
propertyGroupContainer->setLayout(new QHBoxLayout());
|
||||
m_overviewImage = new QLabel(this);
|
||||
m_overviewImage->setFixedSize(QSize(120, 120));
|
||||
m_overviewImage->setScaledContents(true);
|
||||
m_overviewImage->setVisible(false);
|
||||
|
||||
AzToolsFramework::Thumbnailer::SharedThumbnailKey thumbnailKey =
|
||||
MAKE_TKEY(AzToolsFramework::AssetBrowser::ProductThumbnailKey, m_editData.m_materialAssetId);
|
||||
auto thumbnailWidget = new AzToolsFramework::Thumbnailer::ThumbnailWidget(this);
|
||||
thumbnailWidget->setFixedSize(QSize(120, 120));
|
||||
thumbnailWidget->setVisible(true);
|
||||
thumbnailWidget->SetThumbnailKey(thumbnailKey, AzToolsFramework::Thumbnailer::ThumbnailContext::DefaultContext);
|
||||
propertyGroupContainer->layout()->addWidget(thumbnailWidget);
|
||||
|
||||
auto materialInfoWidget = new QLabel(this);
|
||||
m_overviewText = new QLabel(this);
|
||||
QSizePolicy sizePolicy1(QSizePolicy::Ignored, QSizePolicy::Preferred);
|
||||
sizePolicy1.setHorizontalStretch(0);
|
||||
sizePolicy1.setVerticalStretch(0);
|
||||
sizePolicy1.setHeightForWidth(materialInfoWidget->sizePolicy().hasHeightForWidth());
|
||||
materialInfoWidget->setSizePolicy(sizePolicy1);
|
||||
materialInfoWidget->setMinimumSize(QSize(0, 0));
|
||||
materialInfoWidget->setMaximumSize(QSize(16777215, 16777215));
|
||||
materialInfoWidget->setTextFormat(Qt::AutoText);
|
||||
materialInfoWidget->setScaledContents(false);
|
||||
materialInfoWidget->setAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignTop);
|
||||
materialInfoWidget->setWordWrap(true);
|
||||
sizePolicy1.setHeightForWidth(m_overviewText->sizePolicy().hasHeightForWidth());
|
||||
m_overviewText->setSizePolicy(sizePolicy1);
|
||||
m_overviewText->setMinimumSize(QSize(0, 0));
|
||||
m_overviewText->setMaximumSize(QSize(16777215, 16777215));
|
||||
m_overviewText->setTextFormat(Qt::AutoText);
|
||||
m_overviewText->setScaledContents(false);
|
||||
m_overviewText->setWordWrap(true);
|
||||
m_overviewText->setVisible(true);
|
||||
|
||||
auto overviewContainer = new QWidget(this);
|
||||
overviewContainer->setLayout(new QHBoxLayout());
|
||||
overviewContainer->layout()->addWidget(m_overviewImage);
|
||||
overviewContainer->layout()->addWidget(m_overviewText);
|
||||
AddHeading(overviewContainer);
|
||||
}
|
||||
|
||||
void MaterialPropertyInspector::UpdateHeading()
|
||||
{
|
||||
if (!IsLoaded())
|
||||
{
|
||||
m_overviewText->setText(tr("Material not available"));
|
||||
m_overviewText->setAlignment(Qt::AlignCenter);
|
||||
m_overviewImage->setVisible(false);
|
||||
return;
|
||||
}
|
||||
|
||||
QFileInfo materialFileInfo(AZ::RPI::AssetUtils::GetProductPathByAssetId(m_editData.m_materialAsset.GetId()).c_str());
|
||||
QFileInfo materialSourceFileInfo(m_editData.m_materialSourcePath.c_str());
|
||||
QFileInfo materialTypeSourceFileInfo(m_editData.m_materialTypeSourcePath.c_str());
|
||||
QFileInfo materialParentSourceFileInfo(AZ::RPI::AssetUtils::GetSourcePathByAssetId(m_editData.m_materialParentAsset.GetId()).c_str());
|
||||
QFileInfo materialParentSourceFileInfo(
|
||||
AZ::RPI::AssetUtils::GetSourcePathByAssetId(m_editData.m_materialParentAsset.GetId()).c_str());
|
||||
|
||||
AZStd::string entityName;
|
||||
AZ::ComponentApplicationBus::BroadcastResult(
|
||||
entityName, &AZ::ComponentApplicationBus::Events::GetEntityName, m_entityId);
|
||||
AZ::ComponentApplicationBus::BroadcastResult(entityName, &AZ::ComponentApplicationBus::Events::GetEntityName, m_entityId);
|
||||
|
||||
AZStd::string slotName;
|
||||
MaterialComponentRequestBus::EventResult(
|
||||
@@ -220,7 +226,8 @@ namespace AZ
|
||||
}
|
||||
if (!materialTypeSourceFileInfo.fileName().isEmpty())
|
||||
{
|
||||
materialInfo += tr("<tr><td><b>Material Type </b></td><td>%1</td></tr>").arg(materialTypeSourceFileInfo.fileName());
|
||||
materialInfo +=
|
||||
tr("<tr><td><b>Material Type </b></td><td>%1</td></tr>").arg(materialTypeSourceFileInfo.fileName());
|
||||
}
|
||||
if (!materialSourceFileInfo.fileName().isEmpty())
|
||||
{
|
||||
@@ -228,14 +235,21 @@ namespace AZ
|
||||
}
|
||||
if (!materialParentSourceFileInfo.fileName().isEmpty())
|
||||
{
|
||||
materialInfo += tr("<tr><td><b>Material Parent </b></td><td>%1</td></tr>").arg(materialParentSourceFileInfo.fileName());
|
||||
materialInfo +=
|
||||
tr("<tr><td><b>Material Parent </b></td><td>%1</td></tr>").arg(materialParentSourceFileInfo.fileName());
|
||||
}
|
||||
materialInfo += tr("</table>");
|
||||
materialInfoWidget->setText(materialInfo);
|
||||
|
||||
propertyGroupContainer->layout()->addWidget(materialInfoWidget);
|
||||
m_overviewText->setText(materialInfo);
|
||||
m_overviewText->setAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignTop);
|
||||
|
||||
AddGroup(groupName, groupDisplayName, groupDescription, propertyGroupContainer);
|
||||
QPixmap pixmap;
|
||||
EditorMaterialSystemComponentRequestBus::BroadcastResult(
|
||||
pixmap, &EditorMaterialSystemComponentRequestBus::Events::GetRenderedMaterialPreview, m_entityId,
|
||||
m_materialAssignmentId);
|
||||
m_overviewImage->setPixmap(pixmap);
|
||||
m_overviewImage->setVisible(true);
|
||||
m_updatePreview |= pixmap.isNull();
|
||||
}
|
||||
|
||||
void MaterialPropertyInspector::AddUvNamesGroup()
|
||||
@@ -271,17 +285,13 @@ namespace AZ
|
||||
|
||||
// Passing in same group as main and comparison instance to enable custom value comparison for highlighting modified properties
|
||||
auto propertyGroupWidget = new AtomToolsFramework::InspectorPropertyGroupWidget(
|
||||
&group, nullptr, group.TYPEINFO_Uuid(), this, this, GetSaveStateKeyForGroup(groupName));
|
||||
&group, &group, group.TYPEINFO_Uuid(), this, this, GetGroupSaveStateKey(groupName), {},
|
||||
[this](const auto node) { return GetInstanceNodePropertyIndicator(node); }, 0);
|
||||
AddGroup(groupName, groupDisplayName, groupDescription, propertyGroupWidget);
|
||||
}
|
||||
|
||||
void MaterialPropertyInspector::Populate()
|
||||
void MaterialPropertyInspector::AddPropertiesGroup()
|
||||
{
|
||||
AddGroupsBegin();
|
||||
|
||||
AddDetailsGroup();
|
||||
AddUvNamesGroup();
|
||||
|
||||
// Copy all of the properties from the material asset to the source data that will be exported
|
||||
// TODO: Support populating the Material Editor with nested property sets, not just the top level.
|
||||
for (const AZStd::unique_ptr<AZ::RPI::MaterialTypeSourceData::PropertySet>& propertySet : m_editData.m_materialTypeSourceData.GetPropertyLayout().m_propertySets)
|
||||
@@ -301,24 +311,38 @@ namespace AZ
|
||||
|
||||
AtomToolsFramework::ConvertToPropertyConfig(propertyConfig, *propertyDefinition.get());
|
||||
|
||||
const auto& propertyIndex =
|
||||
m_editData.m_materialAsset->GetMaterialPropertiesLayout()->FindPropertyIndex(propertyConfig.m_id);
|
||||
|
||||
propertyConfig.m_groupName = groupDisplayName;
|
||||
const auto& propertyIndex = m_editData.m_materialAsset->GetMaterialPropertiesLayout()->FindPropertyIndex(propertyConfig.m_id);
|
||||
propertyConfig.m_showThumbnail = true;
|
||||
propertyConfig.m_defaultValue = AtomToolsFramework::ConvertToEditableType(m_editData.m_materialTypeAsset->GetDefaultPropertyValues()[propertyIndex.GetIndex()]);
|
||||
propertyConfig.m_parentValue = AtomToolsFramework::ConvertToEditableType(m_editData.m_materialTypeAsset->GetDefaultPropertyValues()[propertyIndex.GetIndex()]);
|
||||
propertyConfig.m_originalValue = AtomToolsFramework::ConvertToEditableType(m_editData.m_materialAsset->GetPropertyValues()[propertyIndex.GetIndex()]);
|
||||
propertyConfig.m_defaultValue = AtomToolsFramework::ConvertToEditableType(
|
||||
m_editData.m_materialTypeAsset->GetDefaultPropertyValues()[propertyIndex.GetIndex()]);
|
||||
|
||||
// There is no explicit parent material here. Material instance property overrides replace the values from the
|
||||
// assigned material asset. Its values should be treated as parent, for comparison, in this case.
|
||||
propertyConfig.m_parentValue = AtomToolsFramework::ConvertToEditableType(
|
||||
m_editData.m_materialTypeAsset->GetDefaultPropertyValues()[propertyIndex.GetIndex()]);
|
||||
|
||||
propertyConfig.m_originalValue = AtomToolsFramework::ConvertToEditableType(
|
||||
m_editData.m_materialAsset->GetPropertyValues()[propertyIndex.GetIndex()]);
|
||||
group.m_properties.emplace_back(propertyConfig);
|
||||
}
|
||||
|
||||
// Passing in same group as main and comparison instance to enable custom value comparison for highlighting modified properties
|
||||
auto propertyGroupWidget = new AtomToolsFramework::InspectorPropertyGroupWidget(
|
||||
&group, nullptr, group.TYPEINFO_Uuid(), this, this, GetSaveStateKeyForGroup(groupName));
|
||||
&group, &group, group.TYPEINFO_Uuid(), this, this, GetGroupSaveStateKey(groupName), {},
|
||||
[this](const auto node) { return GetInstanceNodePropertyIndicator(node); }, 0);
|
||||
AddGroup(groupName, groupDisplayName, groupDescription, propertyGroupWidget);
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialPropertyInspector::Populate()
|
||||
{
|
||||
AddGroupsBegin();
|
||||
AddUvNamesGroup();
|
||||
AddPropertiesGroup();
|
||||
AddGroupsEnd();
|
||||
|
||||
LoadOverridesFromEntity();
|
||||
}
|
||||
|
||||
void MaterialPropertyInspector::LoadOverridesFromEntity()
|
||||
@@ -333,6 +357,25 @@ namespace AZ
|
||||
m_editData.m_materialPropertyOverrideMap, m_entityId, &MaterialComponentRequestBus::Events::GetPropertyOverrides,
|
||||
m_materialAssignmentId);
|
||||
|
||||
// Apply any automatic property renames so that the material inspector will be properly initialized with the right values
|
||||
// for properties that have new names.
|
||||
{
|
||||
AZStd::vector<AZStd::pair<Name, Name>> renamedProperties;
|
||||
for (auto& propertyOverridePair : m_editData.m_materialPropertyOverrideMap)
|
||||
{
|
||||
Name name = propertyOverridePair.first;
|
||||
if (m_materialInstance->GetAsset()->GetMaterialTypeAsset()->ApplyPropertyRenames(name))
|
||||
{
|
||||
renamedProperties.emplace_back(propertyOverridePair.first, name);
|
||||
}
|
||||
}
|
||||
for (const auto& [oldName, newName] : renamedProperties)
|
||||
{
|
||||
m_editData.m_materialPropertyOverrideMap[newName] = m_editData.m_materialPropertyOverrideMap[oldName];
|
||||
m_editData.m_materialPropertyOverrideMap.erase(oldName);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& group : m_groups)
|
||||
{
|
||||
for (auto& property : group.second.m_properties)
|
||||
@@ -363,6 +406,7 @@ namespace AZ
|
||||
m_dirtyPropertyFlags.set();
|
||||
RunEditorMaterialFunctors();
|
||||
RebuildAll();
|
||||
UpdateHeading();
|
||||
}
|
||||
|
||||
void MaterialPropertyInspector::SaveOverridesToEntity(bool commitChanges)
|
||||
@@ -386,6 +430,9 @@ namespace AZ
|
||||
MaterialComponentNotificationBus::Event(m_entityId, &MaterialComponentNotifications::OnMaterialsEdited);
|
||||
m_internalEditNotification = false;
|
||||
}
|
||||
|
||||
// m_updatePreview should be set to true here for continuous preview updates as slider/color properties change but needs
|
||||
// throttling
|
||||
}
|
||||
|
||||
void MaterialPropertyInspector::RunEditorMaterialFunctors()
|
||||
@@ -492,25 +539,32 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
AZ::Crc32 MaterialPropertyInspector::GetSaveStateKeyForGroup(const AZStd::string& groupName) const
|
||||
AZ::Crc32 MaterialPropertyInspector::GetGroupSaveStateKey(const AZStd::string& groupName) const
|
||||
{
|
||||
return AZ::Crc32(AZStd::string::format(
|
||||
"MaterialPropertyInspector::PropertyGroup::%s::%s", m_editData.m_materialAssetId.ToString<AZStd::string>().c_str(),
|
||||
groupName.c_str()));
|
||||
}
|
||||
|
||||
bool MaterialPropertyInspector::AreNodePropertyValuesEqual(
|
||||
const AzToolsFramework::InstanceDataNode* source, const AzToolsFramework::InstanceDataNode* target)
|
||||
bool MaterialPropertyInspector::IsInstanceNodePropertyModifed(const AzToolsFramework::InstanceDataNode* node) const
|
||||
{
|
||||
AZ_UNUSED(source);
|
||||
const AtomToolsFramework::DynamicProperty* property = AtomToolsFramework::FindDynamicPropertyForInstanceDataNode(target);
|
||||
return property && AtomToolsFramework::ArePropertyValuesEqual(property->GetValue(), property->GetConfig().m_parentValue);
|
||||
const AtomToolsFramework::DynamicProperty* property = AtomToolsFramework::FindDynamicPropertyForInstanceDataNode(node);
|
||||
return property && !AtomToolsFramework::ArePropertyValuesEqual(property->GetValue(), property->GetConfig().m_parentValue);
|
||||
}
|
||||
|
||||
const char* MaterialPropertyInspector::GetInstanceNodePropertyIndicator(const AzToolsFramework::InstanceDataNode* node) const
|
||||
{
|
||||
if (IsInstanceNodePropertyModifed(node))
|
||||
{
|
||||
return ":/Icons/changed_property.svg";
|
||||
}
|
||||
return ":/Icons/blank.png";
|
||||
}
|
||||
|
||||
bool MaterialPropertyInspector::SaveMaterial() const
|
||||
{
|
||||
const QString defaultPath = AtomToolsFramework::GetUniqueFileInfo(
|
||||
QString(AZ::IO::FileIOBase::GetInstance()->GetAlias("@devassets@")) +
|
||||
QString(AZ::IO::FileIOBase::GetInstance()->GetAlias("@projectroot@")) +
|
||||
AZ_CORRECT_FILESYSTEM_SEPARATOR + "Materials" +
|
||||
AZ_CORRECT_FILESYSTEM_SEPARATOR + "untitled." +
|
||||
AZ::RPI::MaterialSourceData::Extension).absoluteFilePath();
|
||||
@@ -588,7 +642,8 @@ namespace AZ
|
||||
MaterialComponentRequestBus::Event(
|
||||
m_entityId, &MaterialComponentRequestBus::Events::SetPropertyOverrides, m_materialAssignmentId,
|
||||
MaterialPropertyOverrideMap());
|
||||
QueueUpdateUI();
|
||||
m_updateUI = true;
|
||||
m_updatePreview = true;
|
||||
});
|
||||
action->setEnabled(IsLoaded());
|
||||
|
||||
@@ -683,10 +738,7 @@ namespace AZ
|
||||
|
||||
void MaterialPropertyInspector::OnEntityActivated(const AZ::EntityId& entityId)
|
||||
{
|
||||
if (m_entityId == entityId)
|
||||
{
|
||||
QueueUpdateUI();
|
||||
}
|
||||
m_updateUI |= (m_entityId == entityId);
|
||||
}
|
||||
|
||||
void MaterialPropertyInspector::OnEntityDeactivated(const AZ::EntityId& entityId)
|
||||
@@ -700,35 +752,54 @@ namespace AZ
|
||||
void MaterialPropertyInspector::OnEntityNameChanged(const AZ::EntityId& entityId, const AZStd::string& name)
|
||||
{
|
||||
AZ_UNUSED(name);
|
||||
if (m_entityId == entityId)
|
||||
{
|
||||
QueueUpdateUI();
|
||||
}
|
||||
m_updateUI |= (m_entityId == entityId);
|
||||
}
|
||||
|
||||
void MaterialPropertyInspector::OnTick(float deltaTime, ScriptTimePoint time)
|
||||
{
|
||||
AZ_UNUSED(time);
|
||||
AZ_UNUSED(deltaTime);
|
||||
UpdateUI();
|
||||
AZ::TickBus::Handler::BusDisconnect();
|
||||
if (m_updateUI)
|
||||
{
|
||||
m_updateUI = false;
|
||||
UpdateUI();
|
||||
}
|
||||
|
||||
if (m_updatePreview)
|
||||
{
|
||||
m_updatePreview = false;
|
||||
EditorMaterialSystemComponentRequestBus::Broadcast(
|
||||
&EditorMaterialSystemComponentRequestBus::Events::RenderMaterialPreview, m_entityId, m_materialAssignmentId);
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialPropertyInspector::OnMaterialsEdited()
|
||||
{
|
||||
if (!m_internalEditNotification)
|
||||
m_updateUI |= !m_internalEditNotification;
|
||||
m_updatePreview = true;
|
||||
}
|
||||
|
||||
void MaterialPropertyInspector::OnRenderMaterialPreviewComplete(
|
||||
const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId, const QPixmap& pixmap)
|
||||
{
|
||||
if (m_overviewImage && m_entityId == entityId && m_materialAssignmentId == materialAssignmentId)
|
||||
{
|
||||
QueueUpdateUI();
|
||||
m_overviewImage->setPixmap(pixmap);
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialPropertyInspector::UpdateUI()
|
||||
{
|
||||
AZ::Data::AssetId assetId;
|
||||
AZ::Data::AssetId materialAssetId = {};
|
||||
MaterialComponentRequestBus::EventResult(
|
||||
assetId, m_entityId, &MaterialComponentRequestBus::Events::GetMaterialOverride, m_materialAssignmentId);
|
||||
materialAssetId, m_entityId, &MaterialComponentRequestBus::Events::GetMaterialOverride, m_materialAssignmentId);
|
||||
if (!materialAssetId.IsValid())
|
||||
{
|
||||
MaterialComponentRequestBus::EventResult(
|
||||
materialAssetId, m_entityId, &MaterialComponentRequestBus::Events::GetDefaultMaterialAssetId, m_materialAssignmentId);
|
||||
}
|
||||
|
||||
if (IsLoaded() && m_editData.m_materialAssetId == assetId)
|
||||
if (IsLoaded() && m_editData.m_materialAssetId == materialAssetId)
|
||||
{
|
||||
LoadOverridesFromEntity();
|
||||
}
|
||||
@@ -737,16 +808,6 @@ namespace AZ
|
||||
LoadMaterial(m_entityId, m_materialAssignmentId);
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialPropertyInspector::QueueUpdateUI()
|
||||
{
|
||||
if (!AZ::TickBus::Handler::BusIsConnected())
|
||||
{
|
||||
AZ::TickBus::Handler::BusConnect();
|
||||
}
|
||||
}
|
||||
} // namespace EditorMaterialComponentInspector
|
||||
} // namespace Render
|
||||
} // namespace AZ
|
||||
|
||||
//#include <AtomLyIntegration/CommonFeatures/moc_EditorMaterialComponentInspector.cpp>
|
||||
|
||||
+20
-9
@@ -9,6 +9,7 @@
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentNotificationBus.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h>
|
||||
#include <AtomToolsFramework/DynamicProperty/DynamicPropertyGroup.h>
|
||||
#include <AtomToolsFramework/Inspector/InspectorWidget.h>
|
||||
@@ -31,14 +32,13 @@ namespace AZ
|
||||
{
|
||||
namespace EditorMaterialComponentInspector
|
||||
{
|
||||
using PropertyChangedCallback = AZStd::function<void(const MaterialPropertyOverrideMap&)>;
|
||||
|
||||
class MaterialPropertyInspector
|
||||
: public AtomToolsFramework::InspectorWidget
|
||||
, public AzToolsFramework::IPropertyEditorNotify
|
||||
, public AZ::EntitySystemBus::Handler
|
||||
, public AZ::TickBus::Handler
|
||||
, public MaterialComponentNotificationBus::Handler
|
||||
, public EditorMaterialSystemComponentNotificationBus::Handler
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
@@ -89,20 +89,28 @@ namespace AZ
|
||||
//! MaterialComponentNotificationBus::Handler overrides...
|
||||
void OnMaterialsEdited() override;
|
||||
|
||||
void UpdateUI();
|
||||
void QueueUpdateUI();
|
||||
//! EditorMaterialSystemComponentNotificationBus::Handler overrides...
|
||||
void OnRenderMaterialPreviewComplete(
|
||||
const AZ::EntityId& entityId,
|
||||
const AZ::Render::MaterialAssignmentId& materialAssignmentId,
|
||||
const QPixmap& pixmap) override;
|
||||
|
||||
void UpdateUI();
|
||||
|
||||
void CreateHeading();
|
||||
void UpdateHeading();
|
||||
|
||||
void AddDetailsGroup();
|
||||
void AddUvNamesGroup();
|
||||
void AddPropertiesGroup();
|
||||
|
||||
void LoadOverridesFromEntity();
|
||||
void SaveOverridesToEntity(bool commitChanges);
|
||||
void RunEditorMaterialFunctors();
|
||||
void UpdateMaterialInstanceProperty(const AtomToolsFramework::DynamicProperty& property);
|
||||
|
||||
AZ::Crc32 GetSaveStateKeyForGroup(const AZStd::string& groupName) const;
|
||||
static bool AreNodePropertyValuesEqual(
|
||||
const AzToolsFramework::InstanceDataNode* source, const AzToolsFramework::InstanceDataNode* target);
|
||||
AZ::Crc32 GetGroupSaveStateKey(const AZStd::string& groupName) const;
|
||||
bool IsInstanceNodePropertyModifed(const AzToolsFramework::InstanceDataNode* node) const;
|
||||
const char* GetInstanceNodePropertyIndicator(const AzToolsFramework::InstanceDataNode* node) const;
|
||||
|
||||
// Tracking the property that is actively being edited in the inspector
|
||||
const AtomToolsFramework::DynamicProperty* m_activeProperty = {};
|
||||
@@ -115,7 +123,10 @@ namespace AZ
|
||||
AZ::RPI::MaterialPropertyFlags m_dirtyPropertyFlags = {};
|
||||
AZStd::unordered_map<AZStd::string, AtomToolsFramework::DynamicPropertyGroup> m_groups = {};
|
||||
bool m_internalEditNotification = {};
|
||||
QLabel* m_messageLabel = {};
|
||||
bool m_updateUI = {};
|
||||
bool m_updatePreview = {};
|
||||
QLabel* m_overviewText = {};
|
||||
QLabel* m_overviewImage = {};
|
||||
};
|
||||
} // namespace EditorMaterialComponentInspector
|
||||
} // namespace Render
|
||||
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/Serialization/Json/JsonSerializationResult.h>
|
||||
#include <Material/EditorMaterialComponent.h>
|
||||
#include <Material/EditorMaterialComponentSerializer.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace Render
|
||||
{
|
||||
AZ_CLASS_ALLOCATOR_IMPL(JsonEditorMaterialComponentSerializer, AZ::SystemAllocator, 0);
|
||||
|
||||
AZ::JsonSerializationResult::Result JsonEditorMaterialComponentSerializer::Load(
|
||||
void* outputValue,
|
||||
[[maybe_unused]] const AZ::Uuid& outputValueTypeId,
|
||||
const rapidjson::Value& inputValue,
|
||||
AZ::JsonDeserializerContext& context)
|
||||
{
|
||||
namespace JSR = AZ::JsonSerializationResult;
|
||||
|
||||
AZ_Assert(
|
||||
azrtti_typeid<EditorMaterialComponent>() == outputValueTypeId,
|
||||
"Unable to deserialize EditorMaterialComponent from json because the provided type is %s.",
|
||||
outputValueTypeId.ToString<AZStd::string>().c_str());
|
||||
|
||||
auto componentInstance = reinterpret_cast<EditorMaterialComponent*>(outputValue);
|
||||
AZ_Assert(componentInstance, "Output value for JsonEditorMaterialComponentSerializer can't be null.");
|
||||
|
||||
JSR::ResultCode result(JSR::Tasks::ReadField);
|
||||
|
||||
result.Combine(ContinueLoadingFromJsonObjectField(
|
||||
&componentInstance->m_id, azrtti_typeid<decltype(componentInstance->m_id)>(), inputValue, "Id", context));
|
||||
|
||||
result.Combine(ContinueLoadingFromJsonObjectField(
|
||||
&componentInstance->m_controller, azrtti_typeid<decltype(componentInstance->m_controller)>(), inputValue, "Controller",
|
||||
context));
|
||||
|
||||
result.Combine(ContinueLoadingFromJsonObjectField(
|
||||
&componentInstance->m_materialSlotsByLodEnabled, azrtti_typeid<decltype(componentInstance->m_materialSlotsByLodEnabled)>(),
|
||||
inputValue, "materialSlotsByLodEnabled", context));
|
||||
|
||||
return context.Report(
|
||||
result,
|
||||
result.GetProcessing() != JSR::Processing::Halted ? "Successfully loaded EditorMaterialComponent information."
|
||||
: "Failed to load EditorMaterialComponent information.");
|
||||
}
|
||||
|
||||
AZ::JsonSerializationResult::Result JsonEditorMaterialComponentSerializer::Store(
|
||||
rapidjson::Value& outputValue,
|
||||
const void* inputValue,
|
||||
const void* defaultValue,
|
||||
[[maybe_unused]] const AZ::Uuid& valueTypeId,
|
||||
AZ::JsonSerializerContext& context)
|
||||
{
|
||||
namespace JSR = AZ::JsonSerializationResult;
|
||||
|
||||
AZ_Assert(
|
||||
azrtti_typeid<EditorMaterialComponent>() == valueTypeId,
|
||||
"Unable to Serialize EditorMaterialComponent because the provided type is %s.",
|
||||
valueTypeId.ToString<AZStd::string>().c_str());
|
||||
|
||||
auto componentInstance = reinterpret_cast<const EditorMaterialComponent*>(inputValue);
|
||||
AZ_Assert(componentInstance, "Input value for JsonEditorMaterialComponentSerializer can't be null.");
|
||||
auto defaultComponentInstance = reinterpret_cast<const EditorMaterialComponent*>(defaultValue);
|
||||
|
||||
JSR::ResultCode result(JSR::Tasks::WriteValue);
|
||||
{
|
||||
AZ::ScopedContextPath subPathName(context, "m_id");
|
||||
const auto componentId = &componentInstance->m_id;
|
||||
const auto defaultComponentId = defaultComponentInstance ? &defaultComponentInstance->m_id : nullptr;
|
||||
|
||||
result.Combine(ContinueStoringToJsonObjectField(
|
||||
outputValue, "Id", componentId, defaultComponentId, azrtti_typeid<decltype(componentInstance->m_id)>(), context));
|
||||
}
|
||||
|
||||
{
|
||||
AZ::ScopedContextPath subPathName(context, "Controller");
|
||||
const auto controller = &componentInstance->m_controller;
|
||||
const auto defaultController = defaultComponentInstance ? &defaultComponentInstance->m_controller : nullptr;
|
||||
|
||||
result.Combine(ContinueStoringToJsonObjectField(
|
||||
outputValue, "Controller", controller, defaultController, azrtti_typeid<decltype(componentInstance->m_controller)>(),
|
||||
context));
|
||||
}
|
||||
|
||||
{
|
||||
AZ::ScopedContextPath subPathName(context, "materialSlotsByLodEnabled");
|
||||
const auto enabled = &componentInstance->m_materialSlotsByLodEnabled;
|
||||
const auto defaultEnabled = defaultComponentInstance ? &defaultComponentInstance->m_materialSlotsByLodEnabled : nullptr;
|
||||
|
||||
result.Combine(ContinueStoringToJsonObjectField(
|
||||
outputValue, "materialSlotsByLodEnabled", enabled, defaultEnabled,
|
||||
azrtti_typeid<decltype(componentInstance->m_materialSlotsByLodEnabled)>(), context));
|
||||
}
|
||||
|
||||
return context.Report(
|
||||
result,
|
||||
result.GetProcessing() != JSR::Processing::Halted ? "Successfully stored EditorMaterialComponent information."
|
||||
: "Failed to store EditorMaterialComponent information.");
|
||||
}
|
||||
|
||||
} // namespace Render
|
||||
} // namespace AZ
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Memory/Memory.h>
|
||||
#include <AzCore/Serialization/Json/BaseJsonSerializer.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace Render
|
||||
{
|
||||
// JsonEditorMaterialComponentSerializer skips serialization of EditorMaterialComponentSlot(s) which are only needed at runtime in
|
||||
// the editor
|
||||
class JsonEditorMaterialComponentSerializer : public AZ::BaseJsonSerializer
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(JsonEditorMaterialComponentSerializer, "{D354FE3C-34D2-4E80-B3F9-49450D252336}", BaseJsonSerializer);
|
||||
AZ_CLASS_ALLOCATOR_DECL;
|
||||
|
||||
AZ::JsonSerializationResult::Result Load(
|
||||
void* outputValue,
|
||||
const AZ::Uuid& outputValueTypeId,
|
||||
const rapidjson::Value& inputValue,
|
||||
AZ::JsonDeserializerContext& context) override;
|
||||
|
||||
AZ::JsonSerializationResult::Result Store(
|
||||
rapidjson::Value& outputValue,
|
||||
const void* inputValue,
|
||||
const void* defaultValue,
|
||||
const AZ::Uuid& valueTypeId,
|
||||
AZ::JsonSerializerContext& context) override;
|
||||
};
|
||||
|
||||
} // namespace Render
|
||||
} // namespace AZ
|
||||
+58
-25
@@ -6,22 +6,25 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Material/EditorMaterialComponentSlot.h>
|
||||
#include <Material/EditorMaterialComponentExporter.h>
|
||||
#include <Material/EditorMaterialComponentInspector.h>
|
||||
#include <Material/EditorMaterialModelUvNameMapInspector.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
#include <AzCore/RTTI/BehaviorContext.h>
|
||||
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
|
||||
#include <Atom/RPI.Edit/Common/AssetUtils.h>
|
||||
#include <Atom/RPI.Edit/Material/MaterialSourceData.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentRequestBus.h>
|
||||
#include <AzCore/Asset/AssetSerializer.h>
|
||||
#include <AzCore/RTTI/BehaviorContext.h>
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
|
||||
#include <Material/EditorMaterialComponentExporter.h>
|
||||
#include <Material/EditorMaterialComponentInspector.h>
|
||||
#include <Material/EditorMaterialComponentSlot.h>
|
||||
#include <Material/EditorMaterialModelUvNameMapInspector.h>
|
||||
|
||||
AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT
|
||||
#include <QMenu>
|
||||
#include <QAction>
|
||||
#include <QAction>
|
||||
#include <QByteArray>
|
||||
#include <QCursor>
|
||||
#include <QDataStream>
|
||||
#include <QMenu>
|
||||
AZ_POP_DISABLE_WARNING
|
||||
|
||||
namespace AZ
|
||||
@@ -99,6 +102,7 @@ namespace AZ
|
||||
->Attribute(AZ::Edit::Attributes::NameLabelOverride, &EditorMaterialComponentSlot::GetLabel)
|
||||
->Attribute(AZ::Edit::Attributes::ShowProductAssetFileName, true)
|
||||
->Attribute("ThumbnailCallback", &EditorMaterialComponentSlot::OpenPopupMenu)
|
||||
->Attribute("ThumbnailIcon", &EditorMaterialComponentSlot::GetPreviewPixmapData)
|
||||
;
|
||||
}
|
||||
}
|
||||
@@ -117,10 +121,43 @@ namespace AZ
|
||||
}
|
||||
};
|
||||
|
||||
AZStd::vector<char> EditorMaterialComponentSlot::GetPreviewPixmapData() const
|
||||
{
|
||||
if (!GetActiveAssetId().IsValid())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
QPixmap pixmap;
|
||||
EditorMaterialSystemComponentRequestBus::BroadcastResult(
|
||||
pixmap, &EditorMaterialSystemComponentRequestBus::Events::GetRenderedMaterialPreview, m_entityId, m_id);
|
||||
if (pixmap.isNull())
|
||||
{
|
||||
if (m_updatePreview)
|
||||
{
|
||||
EditorMaterialSystemComponentRequestBus::Broadcast(
|
||||
&EditorMaterialSystemComponentRequestBus::Events::RenderMaterialPreview, m_entityId, m_id);
|
||||
m_updatePreview = false;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
QByteArray pixmapBytes;
|
||||
QDataStream stream(&pixmapBytes, QIODevice::WriteOnly);
|
||||
stream << pixmap;
|
||||
return AZStd::vector<char>(pixmapBytes.begin(), pixmapBytes.end());
|
||||
}
|
||||
|
||||
AZ::Data::AssetId EditorMaterialComponentSlot::GetActiveAssetId() const
|
||||
{
|
||||
return m_materialAsset.GetId().IsValid() ? m_materialAsset.GetId() : GetDefaultAssetId();
|
||||
}
|
||||
|
||||
AZ::Data::AssetId EditorMaterialComponentSlot::GetDefaultAssetId() const
|
||||
{
|
||||
AZ::Data::AssetId assetId;
|
||||
MaterialComponentRequestBus::EventResult(assetId, m_entityId, &MaterialComponentRequestBus::Events::GetDefaultMaterialAssetId, m_id);
|
||||
MaterialComponentRequestBus::EventResult(
|
||||
assetId, m_entityId, &MaterialComponentRequestBus::Events::GetDefaultMaterialAssetId, m_id);
|
||||
return assetId;
|
||||
}
|
||||
|
||||
@@ -134,7 +171,7 @@ namespace AZ
|
||||
bool EditorMaterialComponentSlot::HasSourceData() const
|
||||
{
|
||||
// The slot only has valid source data if the source path is valid and the file has the correct extension
|
||||
const AZStd::string& sourcePath = AZ::RPI::AssetUtils::GetSourcePathByAssetId(m_materialAsset.GetId());
|
||||
const AZStd::string& sourcePath = AZ::RPI::AssetUtils::GetSourcePathByAssetId(GetActiveAssetId());
|
||||
return !sourcePath.empty() && AZ::StringFunc::Path::IsExtension(sourcePath.c_str(), AZ::RPI::MaterialSourceData::Extension);
|
||||
}
|
||||
|
||||
@@ -162,14 +199,6 @@ namespace AZ
|
||||
ClearOverrides();
|
||||
}
|
||||
|
||||
void EditorMaterialComponentSlot::ClearToDefaultAsset()
|
||||
{
|
||||
m_materialAsset = AZ::Data::Asset<AZ::RPI::MaterialAsset>(GetDefaultAssetId(), AZ::AzTypeInfo<AZ::RPI::MaterialAsset>::Uuid());
|
||||
MaterialComponentRequestBus::Event(
|
||||
m_entityId, &MaterialComponentRequestBus::Events::SetMaterialOverride, m_id, m_materialAsset.GetId());
|
||||
ClearOverrides();
|
||||
}
|
||||
|
||||
void EditorMaterialComponentSlot::ClearOverrides()
|
||||
{
|
||||
MaterialComponentRequestBus::Event(
|
||||
@@ -219,7 +248,7 @@ namespace AZ
|
||||
|
||||
void EditorMaterialComponentSlot::OpenMaterialEditor() const
|
||||
{
|
||||
const AZStd::string& sourcePath = AZ::RPI::AssetUtils::GetSourcePathByAssetId(m_materialAsset.GetId());
|
||||
const AZStd::string& sourcePath = AZ::RPI::AssetUtils::GetSourcePathByAssetId(GetActiveAssetId());
|
||||
if (!sourcePath.empty() && AZ::StringFunc::Path::IsExtension(sourcePath.c_str(), AZ::RPI::MaterialSourceData::Extension))
|
||||
{
|
||||
EditorMaterialSystemComponentRequestBus::Broadcast(
|
||||
@@ -235,7 +264,7 @@ namespace AZ
|
||||
|
||||
void EditorMaterialComponentSlot::OpenUvNameMapInspector()
|
||||
{
|
||||
if (m_materialAsset.GetId().IsValid())
|
||||
if (GetActiveAssetId().IsValid())
|
||||
{
|
||||
AZStd::unordered_set<AZ::Name> modelUvNames;
|
||||
MaterialReceiverRequestBus::EventResult(modelUvNames, m_entityId, &MaterialReceiverRequestBus::Events::GetModelUvNames);
|
||||
@@ -251,7 +280,7 @@ namespace AZ
|
||||
};
|
||||
|
||||
if (EditorMaterialComponentInspector::OpenInspectorDialog(
|
||||
m_materialAsset.GetId(), matModUvOverrides, modelUvNames, applyMatModUvOverrideChangedCallback))
|
||||
GetActiveAssetId(), matModUvOverrides, modelUvNames, applyMatModUvOverrideChangedCallback))
|
||||
{
|
||||
OnDataChanged();
|
||||
}
|
||||
@@ -273,10 +302,10 @@ namespace AZ
|
||||
action->setEnabled(HasSourceData());
|
||||
|
||||
action = menu.addAction("Edit Material Instance...", [this]() { OpenMaterialInspector(); });
|
||||
action->setEnabled(m_materialAsset.GetId().IsValid());
|
||||
action->setEnabled(GetActiveAssetId().IsValid());
|
||||
|
||||
action = menu.addAction("Edit Material Instance UV Map...", [this]() { OpenUvNameMapInspector(); });
|
||||
action->setEnabled(m_materialAsset.GetId().IsValid());
|
||||
action->setEnabled(GetActiveAssetId().IsValid());
|
||||
|
||||
menu.addSeparator();
|
||||
|
||||
@@ -308,6 +337,10 @@ namespace AZ
|
||||
AzToolsFramework::ToolsApplicationRequests::Bus::Broadcast(
|
||||
&AzToolsFramework::ToolsApplicationRequests::Bus::Events::AddDirtyEntity, m_entityId);
|
||||
|
||||
EditorMaterialSystemComponentRequestBus::Broadcast(
|
||||
&EditorMaterialSystemComponentRequestBus::Events::RenderMaterialPreview, m_entityId, m_id);
|
||||
m_updatePreview = false;
|
||||
|
||||
MaterialComponentNotificationBus::Event(m_entityId, &MaterialComponentNotifications::OnMaterialsEdited);
|
||||
|
||||
AzToolsFramework::ToolsApplicationEvents::Bus::Broadcast(
|
||||
|
||||
+28
-11
@@ -8,36 +8,52 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/std/string/string.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
|
||||
#include <AzCore/Asset/AssetCommon.h>
|
||||
#include <Atom/RPI.Reflect/Material/MaterialAsset.h>
|
||||
#include <Atom/Feature/Material/MaterialAssignment.h>
|
||||
#include <Atom/RPI.Reflect/Material/MaterialAsset.h>
|
||||
#include <AzCore/Asset/AssetCommon.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
#include <QPixmap>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace Render
|
||||
{
|
||||
static const size_t DefaultMaterialSlotIndex = std::numeric_limits<size_t>::max();
|
||||
|
||||
//! Details for a single editable material assignment
|
||||
struct EditorMaterialComponentSlot final
|
||||
{
|
||||
AZ_RTTI(EditorMaterialComponentSlot, "{344066EB-7C3D-4E92-B53D-3C9EBD546488}");
|
||||
AZ_CLASS_ALLOCATOR(EditorMaterialComponentSlot, SystemAllocator, 0);
|
||||
|
||||
static void Reflect(ReflectContext* context);
|
||||
static bool ConvertVersion(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement);
|
||||
static void Reflect(ReflectContext* context);
|
||||
|
||||
//! Get cached preview image as a buffer to use as an RPE attribute
|
||||
//! If a cached image isn't avalible then a request will be made to render one
|
||||
AZStd::vector<char> GetPreviewPixmapData() const;
|
||||
|
||||
//! Returns the overridden asset id if it's valid, otherwise gets the default asseet id
|
||||
AZ::Data::AssetId GetActiveAssetId() const;
|
||||
|
||||
//! Returns the default asseet id of the material provded by the model
|
||||
AZ::Data::AssetId GetDefaultAssetId() const;
|
||||
|
||||
//! Returns the display name of the material slot
|
||||
AZStd::string GetLabel() const;
|
||||
|
||||
//! Returns true if the active material asset has a source material
|
||||
bool HasSourceData() const;
|
||||
|
||||
//! Assign a new material override asset
|
||||
void SetAsset(const Data::AssetId& assetId);
|
||||
|
||||
//! Assign a new material override asset
|
||||
void SetAsset(const Data::Asset<RPI::MaterialAsset>& asset);
|
||||
|
||||
//! Remove material and prperty overrides
|
||||
void Clear();
|
||||
void ClearToDefaultAsset();
|
||||
|
||||
//! Remove prperty overrides
|
||||
void ClearOverrides();
|
||||
|
||||
void OpenMaterialExporter();
|
||||
@@ -53,6 +69,7 @@ namespace AZ
|
||||
void OpenPopupMenu(const AZ::Data::AssetId& assetId, const AZ::Data::AssetType& assetType);
|
||||
void OnMaterialChanged() const;
|
||||
void OnDataChanged() const;
|
||||
mutable bool m_updatePreview = true;
|
||||
};
|
||||
|
||||
// Vector of slots for assignable or overridable material data.
|
||||
@@ -61,8 +78,8 @@ namespace AZ
|
||||
// Table containing all editable material data that is displayed in the edit context and inspector
|
||||
// The vector represents all the LODs that can have material overrides.
|
||||
// The container will be populated with every potential material slot on an associated model, using its default values.
|
||||
// Whenever changes are made to this container, the modified values are copied into the controller configuration material assignment map
|
||||
// as overrides that will be applied to material instances
|
||||
// Whenever changes are made to this container, the modified values are copied into the controller configuration material assignment
|
||||
// map as overrides that will be applied to material instances
|
||||
using EditorMaterialComponentSlotsByLodContainer = AZStd::vector<EditorMaterialComponentSlotContainer>;
|
||||
} // namespace Render
|
||||
} // namespace AZ
|
||||
|
||||
+18
-41
@@ -17,6 +17,7 @@
|
||||
#include <Atom/RPI.Reflect/Material/MaterialAsset.h>
|
||||
#include <Atom/RPI.Reflect/Material/MaterialPropertiesLayout.h>
|
||||
#include <Atom/RPI.Reflect/Material/MaterialTypeAsset.h>
|
||||
#include <AtomToolsFramework/Util/MaterialPropertyUtil.h>
|
||||
#include <AzFramework/API/ApplicationAPI.h>
|
||||
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
|
||||
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
|
||||
@@ -97,56 +98,31 @@ namespace AZ
|
||||
|
||||
bool SaveSourceMaterialFromEditData(const AZStd::string& path, const MaterialEditData& editData)
|
||||
{
|
||||
// Construct the material source data object that will be exported
|
||||
AZ::RPI::MaterialSourceData exportData;
|
||||
exportData.m_propertyLayoutVersion = editData.m_materialTypeSourceData.GetPropertyLayout().m_version;
|
||||
|
||||
// Converting absolute material paths to relative paths
|
||||
bool result = false;
|
||||
AZ::Data::AssetInfo info;
|
||||
AZStd::string watchFolder;
|
||||
AzToolsFramework::AssetSystemRequestBus::BroadcastResult(
|
||||
result, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath,
|
||||
editData.m_materialTypeSourcePath.c_str(), info, watchFolder);
|
||||
if (!result)
|
||||
if (path.empty() || !editData.m_materialAsset.IsReady() || !editData.m_materialTypeAsset.IsReady() ||
|
||||
editData.m_materialTypeSourcePath.empty())
|
||||
{
|
||||
AZ_Error(
|
||||
"AZ::Render::EditorMaterialComponentUtil", false,
|
||||
"Failed to get material type source file info while attempting to export: %s", path.c_str());
|
||||
AZ_Error("AZ::Render::EditorMaterialComponentUtil", false, "Can not export: %s", path.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
exportData.m_materialType = info.m_relativePath;
|
||||
|
||||
if (!editData.m_materialParentSourcePath.empty())
|
||||
{
|
||||
result = false;
|
||||
AzToolsFramework::AssetSystemRequestBus::BroadcastResult(
|
||||
result, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath,
|
||||
editData.m_materialParentSourcePath.c_str(), info, watchFolder);
|
||||
if (!result)
|
||||
{
|
||||
AZ_Error(
|
||||
"AZ::Render::EditorMaterialComponentUtil", false,
|
||||
"Failed to get parent material source file info while attempting to export: %s", path.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
exportData.m_parentMaterial = info.m_relativePath;
|
||||
}
|
||||
// Construct the material source data object that will be exported
|
||||
AZ::RPI::MaterialSourceData exportData;
|
||||
exportData.m_materialTypeVersion = editData.m_materialTypeAsset->GetVersion();
|
||||
exportData.m_materialType = AtomToolsFramework::GetExteralReferencePath(path, editData.m_materialTypeSourcePath);
|
||||
exportData.m_parentMaterial = AtomToolsFramework::GetExteralReferencePath(path, editData.m_materialParentSourcePath);
|
||||
|
||||
// Copy all of the properties from the material asset to the source data that will be exported
|
||||
result = true;
|
||||
bool result = true;
|
||||
editData.m_materialTypeSourceData.EnumerateProperties([&](const AZStd::string& propertyIdContext, const AZ::RPI::MaterialTypeSourceData::PropertyDefinition* propertyDefinition)
|
||||
{
|
||||
AZ::Name propertyId(propertyIdContext + propertyDefinition->m_name);
|
||||
|
||||
const AZ::RPI::MaterialPropertyIndex propertyIndex =
|
||||
editData.m_materialAsset->GetMaterialPropertiesLayout()->FindPropertyIndex(propertyId);
|
||||
|
||||
AZ::RPI::MaterialPropertyValue propertyValue = editData.m_materialAsset->GetPropertyValues()[propertyIndex.GetIndex()];
|
||||
AZ::RPI::MaterialPropertyValue propertyValue =
|
||||
editData.m_materialAsset->GetPropertyValues()[propertyIndex.GetIndex()];
|
||||
|
||||
AZ::RPI::MaterialPropertyValue propertyValueDefault = propertyDefinition->m_value;
|
||||
AZ::RPI::MaterialPropertyValue propertyValueDefault = propertyDefinition.m_value;
|
||||
if (editData.m_materialParentAsset.IsReady())
|
||||
{
|
||||
propertyValueDefault = editData.m_materialParentAsset->GetPropertyValues()[propertyIndex.GetIndex()];
|
||||
@@ -154,12 +130,12 @@ namespace AZ
|
||||
|
||||
// Check for and apply any property overrides before saving property values
|
||||
auto propertyOverrideItr = editData.m_materialPropertyOverrideMap.find(propertyId);
|
||||
if(propertyOverrideItr != editData.m_materialPropertyOverrideMap.end())
|
||||
if (propertyOverrideItr != editData.m_materialPropertyOverrideMap.end())
|
||||
{
|
||||
propertyValue = AZ::RPI::MaterialPropertyValue::FromAny(propertyOverrideItr->second);
|
||||
}
|
||||
|
||||
if (!editData.m_materialTypeSourceData.ConvertPropertyValueToSourceDataFormat(*propertyDefinition, propertyValue))
|
||||
if (!AtomToolsFramework::ConvertToExportFormat(path, propertyId, propertyDefinition, propertyValue))
|
||||
{
|
||||
AZ_Error("AZ::Render::EditorMaterialComponentUtil", false, "Failed to export: %s", path.c_str());
|
||||
result = false;
|
||||
@@ -171,10 +147,11 @@ namespace AZ
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// TODO: Support populating the Material Editor with nested property sets, not just the top level.
|
||||
const AZStd::string groupName = propertyId.GetStringView().substr(0, propertyId.GetStringView().size() - propertyDefinition->m_name.size() - 1);
|
||||
exportData.m_properties[groupName][propertyDefinition->m_name].m_value = propertyValue;
|
||||
exportData.m_properties[groupName][propertyDefinition.m_name].m_value = propertyValue;
|
||||
return true;
|
||||
});
|
||||
|
||||
|
||||
+16
-8
@@ -290,14 +290,22 @@ namespace AZ
|
||||
menuButton->setAutoRaise(true);
|
||||
menuButton->setIcon(QIcon(":/Cards/img/UI20/Cards/menu_ico.svg"));
|
||||
menuButton->setVisible(true);
|
||||
QObject::connect(menuButton, &QToolButton::clicked, &dialog, [&]() {
|
||||
QAction* action = nullptr;
|
||||
|
||||
QMenu menu(&dialog);
|
||||
action = menu.addAction("Clear", [&] { inspector->SetUvNameMap(RPI::MaterialModelUvOverrideMap()); });
|
||||
action = menu.addAction("Revert", [&] { inspector->SetUvNameMap(matModUvOverrides);; });
|
||||
menu.exec(QCursor::pos());
|
||||
});
|
||||
QObject::connect(
|
||||
menuButton, &QToolButton::clicked, &dialog, [&]()
|
||||
{
|
||||
QMenu menu(&dialog);
|
||||
menu.addAction(
|
||||
"Clear", [&]
|
||||
{
|
||||
inspector->SetUvNameMap(RPI::MaterialModelUvOverrideMap());
|
||||
});
|
||||
menu.addAction(
|
||||
"Revert", [&]
|
||||
{
|
||||
inspector->SetUvNameMap(matModUvOverrides);
|
||||
});
|
||||
menu.exec(QCursor::pos());
|
||||
});
|
||||
|
||||
QDialogButtonBox* buttonBox = new QDialogButtonBox(&dialog);
|
||||
buttonBox->setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::Ok);
|
||||
|
||||
+108
-34
@@ -7,6 +7,11 @@
|
||||
*/
|
||||
|
||||
#include <Atom/RHI/Factory.h>
|
||||
#include <Atom/RPI.Reflect/Asset/AssetUtils.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentNotificationBus.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h>
|
||||
#include <AtomToolsFramework/PreviewRenderer/PreviewRendererCaptureRequest.h>
|
||||
#include <AtomToolsFramework/PreviewRenderer/PreviewRendererInterface.h>
|
||||
#include <AtomToolsFramework/Util/Util.h>
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
#include <AzCore/Serialization/EditContextConstants.inl>
|
||||
@@ -16,11 +21,10 @@
|
||||
#include <AzFramework/Application/Application.h>
|
||||
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
|
||||
#include <AzToolsFramework/API/ViewPaneOptions.h>
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailContext.h>
|
||||
#include <Editor/LyViewPaneNames.h>
|
||||
#include <Material/EditorMaterialComponentInspector.h>
|
||||
#include <Material/EditorMaterialSystemComponent.h>
|
||||
#include <Material/MaterialThumbnail.h>
|
||||
#include <SharedPreview/SharedPreviewContent.h>
|
||||
|
||||
// Disables warning messages triggered by the Qt library
|
||||
// 4251: class needs to have dll-interface to be used by clients of class
|
||||
@@ -30,6 +34,8 @@ AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option")
|
||||
#include <QApplication>
|
||||
#include <QDockWidget>
|
||||
#include <QObject>
|
||||
#include <QPixmap>
|
||||
#include <QImage>
|
||||
#include <QProcessEnvironment>
|
||||
AZ_POP_DISABLE_WARNING
|
||||
|
||||
@@ -55,7 +61,7 @@ namespace AZ
|
||||
{
|
||||
ec->Class<EditorMaterialSystemComponent>("EditorMaterialSystemComponent", "System component that manages launching and maintaining connections the material editor.")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("System", 0xc94d118b))
|
||||
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("System"))
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
;
|
||||
}
|
||||
@@ -64,17 +70,17 @@ namespace AZ
|
||||
|
||||
void EditorMaterialSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
|
||||
{
|
||||
provided.push_back(AZ_CRC("EditorMaterialSystem", 0x5c93bc4e));
|
||||
provided.push_back(AZ_CRC_CE("EditorMaterialSystem"));
|
||||
}
|
||||
|
||||
void EditorMaterialSystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
|
||||
{
|
||||
incompatible.push_back(AZ_CRC("EditorMaterialSystem", 0x5c93bc4e));
|
||||
incompatible.push_back(AZ_CRC_CE("EditorMaterialSystem"));
|
||||
}
|
||||
|
||||
void EditorMaterialSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
|
||||
{
|
||||
required.push_back(AZ_CRC("ThumbnailerService", 0x65422b97));
|
||||
required.push_back(AZ_CRC_CE("PreviewRendererSystem"));
|
||||
}
|
||||
|
||||
void EditorMaterialSystemComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent)
|
||||
@@ -89,25 +95,25 @@ namespace AZ
|
||||
|
||||
void EditorMaterialSystemComponent::Activate()
|
||||
{
|
||||
AZ::EntitySystemBus::Handler::BusConnect();
|
||||
EditorMaterialSystemComponentNotificationBus::Handler::BusConnect();
|
||||
EditorMaterialSystemComponentRequestBus::Handler::BusConnect();
|
||||
AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusConnect();
|
||||
AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler::BusConnect();
|
||||
AzToolsFramework::EditorMenuNotificationBus::Handler::BusConnect();
|
||||
AzToolsFramework::EditorEvents::Bus::Handler::BusConnect();
|
||||
|
||||
SetupThumbnails();
|
||||
m_materialBrowserInteractions.reset(aznew MaterialBrowserInteractions);
|
||||
}
|
||||
|
||||
void EditorMaterialSystemComponent::Deactivate()
|
||||
{
|
||||
AZ::EntitySystemBus::Handler::BusDisconnect();
|
||||
EditorMaterialSystemComponentNotificationBus::Handler::BusDisconnect();
|
||||
EditorMaterialSystemComponentRequestBus::Handler::BusDisconnect();
|
||||
AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusDisconnect();
|
||||
AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler::BusDisconnect();
|
||||
AzToolsFramework::EditorMenuNotificationBus::Handler::BusDisconnect();
|
||||
AzToolsFramework::EditorEvents::Bus::Handler::BusDisconnect();
|
||||
|
||||
TeardownThumbnails();
|
||||
m_materialBrowserInteractions.reset();
|
||||
|
||||
if (m_openMaterialEditorAction)
|
||||
@@ -137,7 +143,7 @@ namespace AZ
|
||||
arguments.append(QString("--project-path=%1").arg(projectPath.c_str()));
|
||||
}
|
||||
|
||||
AtomToolsFramework::LaunchTool("MaterialEditor", ".exe", arguments);
|
||||
AtomToolsFramework::LaunchTool("MaterialEditor", arguments);
|
||||
}
|
||||
|
||||
void EditorMaterialSystemComponent::OpenMaterialInspector(
|
||||
@@ -154,11 +160,85 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
void EditorMaterialSystemComponent::OnApplicationAboutToStop()
|
||||
void EditorMaterialSystemComponent::RenderMaterialPreview(
|
||||
const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId)
|
||||
{
|
||||
TeardownThumbnails();
|
||||
static constexpr const char* DefaultModelPath = "models/sphere.azmodel";
|
||||
static constexpr const char* DefaultLightingPresetPath = "lightingpresets/thumbnail.lightingpreset.azasset";
|
||||
|
||||
if (auto previewRenderer = AZ::Interface<AtomToolsFramework::PreviewRendererInterface>::Get())
|
||||
{
|
||||
AZ::Data::AssetId materialAssetId = {};
|
||||
MaterialComponentRequestBus::EventResult(
|
||||
materialAssetId, entityId, &MaterialComponentRequestBus::Events::GetMaterialOverride, materialAssignmentId);
|
||||
if (!materialAssetId.IsValid())
|
||||
{
|
||||
MaterialComponentRequestBus::EventResult(
|
||||
materialAssetId, entityId, &MaterialComponentRequestBus::Events::GetDefaultMaterialAssetId, materialAssignmentId);
|
||||
if (!materialAssetId.IsValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
AZ::Render::MaterialPropertyOverrideMap propertyOverrides;
|
||||
AZ::Render::MaterialComponentRequestBus::EventResult(
|
||||
propertyOverrides, entityId, &AZ::Render::MaterialComponentRequestBus::Events::GetPropertyOverrides,
|
||||
materialAssignmentId);
|
||||
|
||||
previewRenderer->AddCaptureRequest(
|
||||
{ MaterialPreviewResolution,
|
||||
AZStd::make_shared<AZ::LyIntegration::SharedPreviewContent>(
|
||||
previewRenderer->GetScene(), previewRenderer->GetView(), previewRenderer->GetEntityContextId(),
|
||||
AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultModelPath), materialAssetId,
|
||||
AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultLightingPresetPath), propertyOverrides),
|
||||
[entityId, materialAssignmentId]()
|
||||
{
|
||||
AZ_UNUSED(entityId);
|
||||
AZ_UNUSED(materialAssignmentId);
|
||||
|
||||
AZ_Warning(
|
||||
"EditorMaterialSystemComponent", false, "RenderMaterialPreview capture failed for entity %s slot %s.",
|
||||
entityId.ToString().c_str(), materialAssignmentId.ToString().c_str());
|
||||
},
|
||||
[entityId, materialAssignmentId](const QPixmap& pixmap)
|
||||
{
|
||||
AZ::Render::EditorMaterialSystemComponentNotificationBus::Broadcast(
|
||||
&AZ::Render::EditorMaterialSystemComponentNotificationBus::Events::OnRenderMaterialPreviewComplete, entityId,
|
||||
materialAssignmentId, pixmap);
|
||||
} });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QPixmap EditorMaterialSystemComponent::GetRenderedMaterialPreview(
|
||||
const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId) const
|
||||
{
|
||||
const auto& itr1 = m_materialPreviews.find(entityId);
|
||||
if (itr1 != m_materialPreviews.end())
|
||||
{
|
||||
const auto& itr2 = itr1->second.find(materialAssignmentId);
|
||||
if (itr2 != itr1->second.end())
|
||||
{
|
||||
return itr2->second;
|
||||
}
|
||||
}
|
||||
return QPixmap();
|
||||
}
|
||||
|
||||
void EditorMaterialSystemComponent::OnEntityDestroyed(const AZ::EntityId& entityId)
|
||||
{
|
||||
m_materialPreviews.erase(entityId);
|
||||
}
|
||||
|
||||
void EditorMaterialSystemComponent::OnRenderMaterialPreviewComplete(
|
||||
[[maybe_unused]] const AZ::EntityId& entityId,
|
||||
[[maybe_unused]] const AZ::Render::MaterialAssignmentId& materialAssignmentId,
|
||||
[[maybe_unused]] const QPixmap& pixmap)
|
||||
{
|
||||
PurgePreviews();
|
||||
m_materialPreviews[entityId][materialAssignmentId] = pixmap;
|
||||
}
|
||||
|
||||
void EditorMaterialSystemComponent::OnPopulateToolMenuItems()
|
||||
{
|
||||
if (!m_openMaterialEditorAction)
|
||||
@@ -201,26 +281,6 @@ namespace AZ
|
||||
"Material Property Inspector", LyViewPane::CategoryTools, inspectorOptions);
|
||||
}
|
||||
|
||||
void EditorMaterialSystemComponent::SetupThumbnails()
|
||||
{
|
||||
using namespace AzToolsFramework::Thumbnailer;
|
||||
using namespace LyIntegration;
|
||||
|
||||
ThumbnailerRequestsBus::Broadcast(
|
||||
&ThumbnailerRequests::RegisterThumbnailProvider, MAKE_TCACHE(Thumbnails::MaterialThumbnailCache),
|
||||
ThumbnailContext::DefaultContext);
|
||||
}
|
||||
|
||||
void EditorMaterialSystemComponent::TeardownThumbnails()
|
||||
{
|
||||
using namespace AzToolsFramework::Thumbnailer;
|
||||
using namespace LyIntegration;
|
||||
|
||||
ThumbnailerRequestsBus::Broadcast(
|
||||
&ThumbnailerRequests::UnregisterThumbnailProvider, Thumbnails::MaterialThumbnailCache::ProviderName,
|
||||
ThumbnailContext::DefaultContext);
|
||||
}
|
||||
|
||||
AzToolsFramework::AssetBrowser::SourceFileDetails EditorMaterialSystemComponent::GetSourceFileDetails(
|
||||
const char* fullSourceFileName)
|
||||
{
|
||||
@@ -232,5 +292,19 @@ namespace AZ
|
||||
}
|
||||
return AzToolsFramework::AssetBrowser::SourceFileDetails();
|
||||
}
|
||||
|
||||
void EditorMaterialSystemComponent::PurgePreviews()
|
||||
{
|
||||
size_t materialPreviewCount = 0;
|
||||
for (const auto& materialPreviewPair : m_materialPreviews)
|
||||
{
|
||||
materialPreviewCount += materialPreviewPair.second.size();
|
||||
}
|
||||
|
||||
if (materialPreviewCount > MaterialPreviewLimit)
|
||||
{
|
||||
m_materialPreviews.clear();
|
||||
}
|
||||
}
|
||||
} // namespace Render
|
||||
} // namespace AZ
|
||||
|
||||
+25
-16
@@ -5,31 +5,32 @@
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentRequestBus.h>
|
||||
#include <AzCore/Asset/AssetCommon.h>
|
||||
#include <AzCore/Component/Component.h>
|
||||
#include <AzFramework/Application/Application.h>
|
||||
#include <AzCore/Component/EntityBus.h>
|
||||
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
|
||||
#include <AzToolsFramework/AssetBrowser/AssetBrowserBus.h>
|
||||
#include <AzToolsFramework/Thumbnails/Thumbnail.h>
|
||||
#include <AzToolsFramework/Viewport/ActionBus.h>
|
||||
|
||||
#include <AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentRequestBus.h>
|
||||
|
||||
#include <Material/MaterialBrowserInteractions.h>
|
||||
#include <QPixmap>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace Render
|
||||
{
|
||||
//! System component that manages launching and maintaining connections with the material editor.
|
||||
class EditorMaterialSystemComponent
|
||||
class EditorMaterialSystemComponent final
|
||||
: public AZ::Component
|
||||
, private EditorMaterialSystemComponentRequestBus::Handler
|
||||
, private AzFramework::ApplicationLifecycleEvents::Bus::Handler
|
||||
, private AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler
|
||||
, private AzToolsFramework::EditorMenuNotificationBus::Handler
|
||||
, private AzToolsFramework::EditorEvents::Bus::Handler
|
||||
, public AZ::EntitySystemBus::Handler
|
||||
, public EditorMaterialSystemComponentNotificationBus::Handler
|
||||
, public EditorMaterialSystemComponentRequestBus::Handler
|
||||
, public AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler
|
||||
, public AzToolsFramework::EditorMenuNotificationBus::Handler
|
||||
, public AzToolsFramework::EditorEvents::Bus::Handler
|
||||
{
|
||||
public:
|
||||
AZ_COMPONENT(EditorMaterialSystemComponent, "{96652157-DA0B-420F-B49C-0207C585144C}");
|
||||
@@ -51,9 +52,16 @@ namespace AZ
|
||||
//! EditorMaterialSystemComponentRequestBus::Handler overrides...
|
||||
void OpenMaterialEditor(const AZStd::string& sourcePath) override;
|
||||
void OpenMaterialInspector(const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId) override;
|
||||
void RenderMaterialPreview(const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId) override;
|
||||
QPixmap GetRenderedMaterialPreview(
|
||||
const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId) const override;
|
||||
|
||||
// AzFramework::ApplicationLifecycleEvents overrides...
|
||||
void OnApplicationAboutToStop() override;
|
||||
// AZ::EntitySystemBus::Handler overrides...
|
||||
void OnEntityDestroyed(const AZ::EntityId& entityId) override;
|
||||
|
||||
//! EditorMaterialSystemComponentNotificationBus::Handler overrides...
|
||||
void OnRenderMaterialPreviewComplete(
|
||||
const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId, const QPixmap& pixmap) override;
|
||||
|
||||
//! AssetBrowserInteractionNotificationBus::Handler overrides...
|
||||
AzToolsFramework::AssetBrowser::SourceFileDetails GetSourceFileDetails(const char* fullSourceFileName) override;
|
||||
@@ -65,12 +73,13 @@ namespace AZ
|
||||
// AztoolsFramework::EditorEvents::Bus::Handler overrides...
|
||||
void NotifyRegisterViews() override;
|
||||
|
||||
void SetupThumbnails();
|
||||
void TeardownThumbnails();
|
||||
void PurgePreviews();
|
||||
|
||||
QAction* m_openMaterialEditorAction = nullptr;
|
||||
|
||||
AZStd::unique_ptr<MaterialBrowserInteractions> m_materialBrowserInteractions;
|
||||
AZStd::unordered_map<AZ::EntityId, AZStd::unordered_map<AZ::Render::MaterialAssignmentId, QPixmap>> m_materialPreviews;
|
||||
static constexpr const size_t MaterialPreviewLimit = 100;
|
||||
static constexpr const int MaterialPreviewResolution = 128;
|
||||
};
|
||||
} // namespace Render
|
||||
} // namespace AZ
|
||||
|
||||
+184
-250
@@ -9,6 +9,7 @@
|
||||
#include <Material/MaterialComponentController.h>
|
||||
#include <Atom/RPI.Reflect/Material/MaterialAsset.h>
|
||||
#include <Atom/RPI.Reflect/Asset/AssetUtils.h>
|
||||
#include <AzCore/Asset/AssetSerializer.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AtomCore/Instance/InstanceDatabase.h>
|
||||
|
||||
@@ -48,33 +49,34 @@ namespace AZ
|
||||
->Event("ClearIncompatibleMaterialOverrides", &MaterialComponentRequestBus::Events::ClearIncompatibleMaterialOverrides)
|
||||
->Event("ClearInvalidMaterialOverrides", &MaterialComponentRequestBus::Events::ClearInvalidMaterialOverrides)
|
||||
->Event("RepairInvalidMaterialOverrides", &MaterialComponentRequestBus::Events::RepairInvalidMaterialOverrides)
|
||||
->Event("ApplyAutomaticPropertyUpdates", &MaterialComponentRequestBus::Events::ApplyAutomaticPropertyUpdates)
|
||||
->Event("SetMaterialOverride", &MaterialComponentRequestBus::Events::SetMaterialOverride)
|
||||
->Event("GetMaterialOverride", &MaterialComponentRequestBus::Events::GetMaterialOverride)
|
||||
->Event("ClearMaterialOverride", &MaterialComponentRequestBus::Events::ClearMaterialOverride)
|
||||
->Event("SetPropertyOverride", &MaterialComponentRequestBus::Events::SetPropertyOverride)
|
||||
->Event("SetPropertyOverrideBool", &MaterialComponentRequestBus::Events::SetPropertyOverrideBool)
|
||||
->Event("SetPropertyOverrideInt32", &MaterialComponentRequestBus::Events::SetPropertyOverrideInt32)
|
||||
->Event("SetPropertyOverrideUInt32", &MaterialComponentRequestBus::Events::SetPropertyOverrideUInt32)
|
||||
->Event("SetPropertyOverrideFloat", &MaterialComponentRequestBus::Events::SetPropertyOverrideFloat)
|
||||
->Event("SetPropertyOverrideVector2", &MaterialComponentRequestBus::Events::SetPropertyOverrideVector2)
|
||||
->Event("SetPropertyOverrideVector3", &MaterialComponentRequestBus::Events::SetPropertyOverrideVector3)
|
||||
->Event("SetPropertyOverrideVector4", &MaterialComponentRequestBus::Events::SetPropertyOverrideVector4)
|
||||
->Event("SetPropertyOverrideColor", &MaterialComponentRequestBus::Events::SetPropertyOverrideColor)
|
||||
->Event("SetPropertyOverrideImageAsset", &MaterialComponentRequestBus::Events::SetPropertyOverrideImageAsset)
|
||||
->Event("SetPropertyOverrideImageInstance", &MaterialComponentRequestBus::Events::SetPropertyOverrideImageInstance)
|
||||
->Event("SetPropertyOverrideString", &MaterialComponentRequestBus::Events::SetPropertyOverrideString)
|
||||
->Event("SetPropertyOverrideBool", &MaterialComponentRequestBus::Events::SetPropertyOverrideT<bool>)
|
||||
->Event("SetPropertyOverrideInt32", &MaterialComponentRequestBus::Events::SetPropertyOverrideT<int32_t>)
|
||||
->Event("SetPropertyOverrideUInt32", &MaterialComponentRequestBus::Events::SetPropertyOverrideT<uint32_t>)
|
||||
->Event("SetPropertyOverrideFloat", &MaterialComponentRequestBus::Events::SetPropertyOverrideT<float>)
|
||||
->Event("SetPropertyOverrideVector2", &MaterialComponentRequestBus::Events::SetPropertyOverrideT<AZ::Vector2>)
|
||||
->Event("SetPropertyOverrideVector3", &MaterialComponentRequestBus::Events::SetPropertyOverrideT<AZ::Vector3>)
|
||||
->Event("SetPropertyOverrideVector4", &MaterialComponentRequestBus::Events::SetPropertyOverrideT<AZ::Vector4>)
|
||||
->Event("SetPropertyOverrideColor", &MaterialComponentRequestBus::Events::SetPropertyOverrideT<AZ::Color>)
|
||||
->Event("SetPropertyOverrideImage", &MaterialComponentRequestBus::Events::SetPropertyOverrideT<AZ::Data::AssetId>)
|
||||
->Event("SetPropertyOverrideString", &MaterialComponentRequestBus::Events::SetPropertyOverrideT<AZStd::string>)
|
||||
->Event("SetPropertyOverrideEnum", &MaterialComponentRequestBus::Events::SetPropertyOverrideT<uint32_t>)
|
||||
->Event("GetPropertyOverride", &MaterialComponentRequestBus::Events::GetPropertyOverride)
|
||||
->Event("GetPropertyOverrideBool", &MaterialComponentRequestBus::Events::GetPropertyOverrideBool)
|
||||
->Event("GetPropertyOverrideInt32", &MaterialComponentRequestBus::Events::GetPropertyOverrideInt32)
|
||||
->Event("GetPropertyOverrideUInt32", &MaterialComponentRequestBus::Events::GetPropertyOverrideUInt32)
|
||||
->Event("GetPropertyOverrideFloat", &MaterialComponentRequestBus::Events::GetPropertyOverrideFloat)
|
||||
->Event("GetPropertyOverrideVector2", &MaterialComponentRequestBus::Events::GetPropertyOverrideVector2)
|
||||
->Event("GetPropertyOverrideVector3", &MaterialComponentRequestBus::Events::GetPropertyOverrideVector3)
|
||||
->Event("GetPropertyOverrideVector4", &MaterialComponentRequestBus::Events::GetPropertyOverrideVector4)
|
||||
->Event("GetPropertyOverrideColor", &MaterialComponentRequestBus::Events::GetPropertyOverrideColor)
|
||||
->Event("GetPropertyOverrideImageAsset", &MaterialComponentRequestBus::Events::GetPropertyOverrideImageAsset)
|
||||
->Event("GetPropertyOverrideImageInstance", &MaterialComponentRequestBus::Events::GetPropertyOverrideImageInstance)
|
||||
->Event("GetPropertyOverrideString", &MaterialComponentRequestBus::Events::GetPropertyOverrideString)
|
||||
->Event("GetPropertyOverrideBool", &MaterialComponentRequestBus::Events::GetPropertyOverrideT<bool>)
|
||||
->Event("GetPropertyOverrideInt32", &MaterialComponentRequestBus::Events::GetPropertyOverrideT<int32_t>)
|
||||
->Event("GetPropertyOverrideUInt32", &MaterialComponentRequestBus::Events::GetPropertyOverrideT<uint32_t>)
|
||||
->Event("GetPropertyOverrideFloat", &MaterialComponentRequestBus::Events::GetPropertyOverrideT<float>)
|
||||
->Event("GetPropertyOverrideVector2", &MaterialComponentRequestBus::Events::GetPropertyOverrideT<AZ::Vector2>)
|
||||
->Event("GetPropertyOverrideVector3", &MaterialComponentRequestBus::Events::GetPropertyOverrideT<AZ::Vector3>)
|
||||
->Event("GetPropertyOverrideVector4", &MaterialComponentRequestBus::Events::GetPropertyOverrideT<AZ::Vector4>)
|
||||
->Event("GetPropertyOverrideColor", &MaterialComponentRequestBus::Events::GetPropertyOverrideT<AZ::Color>)
|
||||
->Event("GetPropertyOverrideImage", &MaterialComponentRequestBus::Events::GetPropertyOverrideT<AZ::Data::AssetId>)
|
||||
->Event("GetPropertyOverrideString", &MaterialComponentRequestBus::Events::GetPropertyOverrideT<AZStd::string>)
|
||||
->Event("GetPropertyOverrideEnum", &MaterialComponentRequestBus::Events::GetPropertyOverrideT<uint32_t>)
|
||||
->Event("ClearPropertyOverride", &MaterialComponentRequestBus::Events::ClearPropertyOverride)
|
||||
->Event("ClearPropertyOverrides", &MaterialComponentRequestBus::Events::ClearPropertyOverrides)
|
||||
->Event("ClearAllPropertyOverrides", &MaterialComponentRequestBus::Events::ClearAllPropertyOverrides)
|
||||
@@ -102,6 +104,7 @@ namespace AZ
|
||||
MaterialComponentController::MaterialComponentController(const MaterialComponentConfig& config)
|
||||
: m_configuration(config)
|
||||
{
|
||||
ConvertAssetsForSerialization();
|
||||
}
|
||||
|
||||
void MaterialComponentController::Activate(EntityId entityId)
|
||||
@@ -110,15 +113,22 @@ namespace AZ
|
||||
m_queuedMaterialUpdateNotification = false;
|
||||
|
||||
MaterialComponentRequestBus::Handler::BusConnect(m_entityId);
|
||||
MaterialReceiverNotificationBus::Handler::BusConnect(m_entityId);
|
||||
LoadMaterials();
|
||||
}
|
||||
|
||||
void MaterialComponentController::Deactivate()
|
||||
{
|
||||
MaterialComponentRequestBus::Handler::BusDisconnect();
|
||||
MaterialReceiverNotificationBus::Handler::BusDisconnect();
|
||||
TickBus::Handler::BusDisconnect();
|
||||
|
||||
ReleaseMaterials();
|
||||
|
||||
// Sending notification to wipe any previously assigned material overrides
|
||||
MaterialComponentNotificationBus::Event(
|
||||
m_entityId, &MaterialComponentNotifications::OnMaterialsUpdated, MaterialAssignmentMap());
|
||||
|
||||
m_queuedMaterialUpdateNotification = false;
|
||||
m_entityId = AZ::EntityId(AZ::EntityId::InvalidEntityId);
|
||||
}
|
||||
@@ -126,6 +136,7 @@ namespace AZ
|
||||
void MaterialComponentController::SetConfiguration(const MaterialComponentConfig& config)
|
||||
{
|
||||
m_configuration = config;
|
||||
ConvertAssetsForSerialization();
|
||||
}
|
||||
|
||||
const MaterialComponentConfig& MaterialComponentController::GetConfiguration() const
|
||||
@@ -142,59 +153,29 @@ namespace AZ
|
||||
{
|
||||
InitializeMaterialInstance(asset);
|
||||
}
|
||||
|
||||
|
||||
void MaterialComponentController::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time)
|
||||
{
|
||||
AZStd::unordered_set<MaterialAssignmentId> propertyOverrides;
|
||||
AZStd::swap(m_queuedPropertyOverrides, propertyOverrides);
|
||||
AZStd::unordered_set<MaterialAssignmentId> materialsWithDirtyProperties;
|
||||
AZStd::swap(m_materialsWithDirtyProperties, materialsWithDirtyProperties);
|
||||
|
||||
// Iterate through all MaterialAssignmentId's that have property overrides and attempt to apply them
|
||||
// if material instance is already compiling, delay application of property overrides until next frame
|
||||
for (const auto& materialAssignmentId : propertyOverrides)
|
||||
for (const auto& materialAssignmentId : materialsWithDirtyProperties)
|
||||
{
|
||||
const auto materialIt = m_configuration.m_materials.find(materialAssignmentId);
|
||||
if (materialIt == m_configuration.m_materials.end())
|
||||
if (materialIt != m_configuration.m_materials.end())
|
||||
{
|
||||
//Skip materials that do not exist in the map
|
||||
continue;
|
||||
}
|
||||
|
||||
auto materialInstance = materialIt->second.m_materialInstance;
|
||||
if (!materialInstance)
|
||||
{
|
||||
//Skip materials with an invalid instances
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!materialInstance->CanCompile())
|
||||
{
|
||||
//If a material cannot currently be compiled then it must be queued again
|
||||
m_queuedPropertyOverrides.emplace(materialAssignmentId);
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto& propertyOverrides2 = materialIt->second.m_propertyOverrides;
|
||||
for (auto& propertyPair : propertyOverrides2)
|
||||
{
|
||||
if (propertyPair.second.empty())
|
||||
if (!materialIt->second.ApplyProperties())
|
||||
{
|
||||
continue;
|
||||
// If a material cannot currently be compiled then it must be queued again
|
||||
m_materialsWithDirtyProperties.emplace(materialAssignmentId);
|
||||
}
|
||||
|
||||
const auto& materialPropertyIndex = materialInstance->FindPropertyIndex(propertyPair.first);
|
||||
if (materialPropertyIndex.IsNull())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
materialInstance->SetPropertyValue(materialPropertyIndex, AZ::RPI::MaterialPropertyValue::FromAny(propertyPair.second));
|
||||
}
|
||||
|
||||
materialInstance->Compile();
|
||||
}
|
||||
|
||||
// Only disconnect from tick bus and send notification after all pending properties have been applied
|
||||
if (m_queuedPropertyOverrides.empty())
|
||||
// Only disconnect from tick bus and send notification after all pending properties have been applied
|
||||
if (m_materialsWithDirtyProperties.empty())
|
||||
{
|
||||
if (m_queuedMaterialUpdateNotification)
|
||||
{
|
||||
@@ -212,31 +193,54 @@ namespace AZ
|
||||
Data::AssetBus::MultiHandler::BusDisconnect();
|
||||
|
||||
bool anyQueued = false;
|
||||
for (auto& materialPair : m_configuration.m_materials)
|
||||
auto queueAsset = [&anyQueued, this](AZ::Data::Asset<AZ::RPI::MaterialAsset>& materialAsset) -> bool
|
||||
{
|
||||
auto& materialAsset = materialPair.second.m_materialAsset;
|
||||
|
||||
if (materialAsset.GetId().IsValid() && !Data::AssetBus::MultiHandler::BusIsConnectedId(materialAsset.GetId()))
|
||||
if (materialAsset.GetId().IsValid() && !this->Data::AssetBus::MultiHandler::BusIsConnectedId(materialAsset.GetId()))
|
||||
{
|
||||
anyQueued = true;
|
||||
materialAsset.QueueLoad();
|
||||
Data::AssetBus::MultiHandler::BusConnect(materialAsset.GetId());
|
||||
this->Data::AssetBus::MultiHandler::BusConnect(materialAsset.GetId());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
for (auto& materialPair : m_configuration.m_materials)
|
||||
{
|
||||
if (materialPair.second.m_materialInstancePreCreated)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
materialPair.second.m_defaultMaterialAsset = {};
|
||||
if (!queueAsset(materialPair.second.m_materialAsset))
|
||||
{
|
||||
// Only assign and load the default material if there was no material override and there are propoerties to apply
|
||||
if (!materialPair.second.m_propertyOverrides.empty() || !materialPair.second.m_matModUvOverrides.empty())
|
||||
{
|
||||
materialPair.second.m_defaultMaterialAsset = AZ::Data::Asset<AZ::RPI::MaterialAsset>(
|
||||
GetDefaultMaterialAssetId(materialPair.first), AZ::AzTypeInfo<AZ::RPI::MaterialAsset>::Uuid());
|
||||
queueAsset(materialPair.second.m_defaultMaterialAsset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!anyQueued)
|
||||
{
|
||||
ReleaseMaterials();
|
||||
|
||||
// If no other materials were loaded, the notification must still be sent in case there are externally managed material
|
||||
// instances in the configuration
|
||||
MaterialComponentNotificationBus::Event(
|
||||
m_entityId, &MaterialComponentNotifications::OnMaterialsUpdated, m_configuration.m_materials);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MaterialComponentController::InitializeMaterialInstance(const Data::Asset<Data::AssetData>& asset)
|
||||
{
|
||||
bool allReady = true;
|
||||
|
||||
for (auto& materialPair : m_configuration.m_materials)
|
||||
auto updateAsset = [&](AZ::Data::Asset<AZ::RPI::MaterialAsset>& materialAsset)
|
||||
{
|
||||
auto& materialAsset = materialPair.second.m_materialAsset;
|
||||
if (materialAsset.GetId() == asset.GetId())
|
||||
{
|
||||
materialAsset = asset;
|
||||
@@ -246,6 +250,12 @@ namespace AZ
|
||||
{
|
||||
allReady = false;
|
||||
}
|
||||
};
|
||||
|
||||
for (auto& materialPair : m_configuration.m_materials)
|
||||
{
|
||||
updateAsset(materialPair.second.m_materialAsset);
|
||||
updateAsset(materialPair.second.m_defaultMaterialAsset);
|
||||
}
|
||||
|
||||
if (allReady)
|
||||
@@ -268,14 +278,8 @@ namespace AZ
|
||||
|
||||
for (auto& materialPair : m_configuration.m_materials)
|
||||
{
|
||||
if (materialPair.second.m_materialAsset.GetId().IsValid())
|
||||
{
|
||||
materialPair.second.m_materialAsset.Release();
|
||||
materialPair.second.m_materialInstance = nullptr;
|
||||
}
|
||||
materialPair.second.Release();
|
||||
}
|
||||
|
||||
MaterialComponentNotificationBus::Event(m_entityId, &MaterialComponentNotifications::OnMaterialsUpdated, m_configuration.m_materials);
|
||||
}
|
||||
|
||||
MaterialAssignmentMap MaterialComponentController::GetOriginalMaterialAssignments() const
|
||||
@@ -334,8 +338,9 @@ namespace AZ
|
||||
// this function is called twice once material asset is changed, a temp variable is
|
||||
// needed to prevent material asset going out of scope during second call
|
||||
// before LoadMaterials() is called [LYN-2249]
|
||||
auto temp = m_configuration.m_materials;
|
||||
auto temp = m_configuration.m_materials;
|
||||
m_configuration.m_materials = materials;
|
||||
ConvertAssetsForSerialization();
|
||||
LoadMaterials();
|
||||
}
|
||||
|
||||
@@ -413,6 +418,37 @@ namespace AZ
|
||||
}
|
||||
LoadMaterials();
|
||||
}
|
||||
|
||||
uint32_t MaterialComponentController::ApplyAutomaticPropertyUpdates()
|
||||
{
|
||||
uint32_t propertiesUpdated = 0;
|
||||
|
||||
for (auto& materialAssignmentPair : m_configuration.m_materials)
|
||||
{
|
||||
MaterialAssignment& materialAssignment = materialAssignmentPair.second;
|
||||
|
||||
AZStd::vector<AZStd::pair<Name, Name>> renamedProperties;
|
||||
|
||||
for (const auto& propertyPair : materialAssignment.m_propertyOverrides)
|
||||
{
|
||||
Name propertyId = propertyPair.first;
|
||||
|
||||
if (materialAssignment.m_materialInstance->GetAsset()->GetMaterialTypeAsset()->ApplyPropertyRenames(propertyId))
|
||||
{
|
||||
renamedProperties.emplace_back(propertyPair.first, propertyId);
|
||||
++propertiesUpdated;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& [oldName, newName] : renamedProperties)
|
||||
{
|
||||
materialAssignment.m_propertyOverrides[newName] = materialAssignment.m_propertyOverrides[oldName];
|
||||
materialAssignment.m_propertyOverrides.erase(oldName);
|
||||
}
|
||||
}
|
||||
|
||||
return propertiesUpdated;
|
||||
}
|
||||
|
||||
void MaterialComponentController::SetDefaultMaterialOverride(const AZ::Data::AssetId& materialAssetId)
|
||||
{
|
||||
@@ -440,12 +476,7 @@ namespace AZ
|
||||
AZ::Data::AssetId MaterialComponentController::GetMaterialOverride(const MaterialAssignmentId& materialAssignmentId) const
|
||||
{
|
||||
auto materialIt = m_configuration.m_materials.find(materialAssignmentId);
|
||||
if (materialIt == m_configuration.m_materials.end())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
return materialIt->second.m_materialAsset.GetId();
|
||||
return materialIt != m_configuration.m_materials.end() ? materialIt->second.m_materialAsset.GetId() : AZ::Data::AssetId();
|
||||
}
|
||||
|
||||
void MaterialComponentController::ClearMaterialOverride(const MaterialAssignmentId& materialAssignmentId)
|
||||
@@ -459,93 +490,27 @@ namespace AZ
|
||||
void MaterialComponentController::SetPropertyOverride(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const AZStd::any& value)
|
||||
{
|
||||
auto& materialAssignment = m_configuration.m_materials[materialAssignmentId];
|
||||
const bool wasEmpty = materialAssignment.m_propertyOverrides.empty();
|
||||
materialAssignment.m_propertyOverrides[AZ::Name(propertyName)] = value;
|
||||
ConvertAssetsForSerialization();
|
||||
|
||||
// When applying property overrides for the first time, new instance needs to be created in case the current instance is already used somewhere else to keep overrides local
|
||||
if (materialAssignment.m_propertyOverrides.empty())
|
||||
if (materialAssignment.RequiresLoading())
|
||||
{
|
||||
materialAssignment.m_propertyOverrides[AZ::Name(propertyName)] = value;
|
||||
materialAssignment.RebuildInstance();
|
||||
MaterialComponentNotificationBus::Event(m_entityId, &MaterialComponentNotifications::OnMaterialInstanceCreated, materialAssignment);
|
||||
QueueMaterialUpdateNotification();
|
||||
LoadMaterials();
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
||||
if (wasEmpty != materialAssignment.m_propertyOverrides.empty())
|
||||
{
|
||||
materialAssignment.m_propertyOverrides[AZ::Name(propertyName)] = value;
|
||||
materialAssignment.RebuildInstance();
|
||||
MaterialComponentNotificationBus::Event(
|
||||
m_entityId, &MaterialComponentNotifications::OnMaterialInstanceCreated, materialAssignment);
|
||||
QueueMaterialUpdateNotification();
|
||||
}
|
||||
|
||||
QueuePropertyChanges(materialAssignmentId);
|
||||
}
|
||||
|
||||
void MaterialComponentController::SetPropertyOverrideBool(
|
||||
const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const bool& value)
|
||||
{
|
||||
SetPropertyOverride(materialAssignmentId, propertyName, AZStd::any(value));
|
||||
}
|
||||
|
||||
void MaterialComponentController::SetPropertyOverrideInt32(
|
||||
const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const int32_t& value)
|
||||
{
|
||||
SetPropertyOverride(materialAssignmentId, propertyName, AZStd::any(value));
|
||||
}
|
||||
|
||||
void MaterialComponentController::SetPropertyOverrideUInt32(
|
||||
const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const uint32_t& value)
|
||||
{
|
||||
SetPropertyOverride(materialAssignmentId, propertyName, AZStd::any(value));
|
||||
}
|
||||
|
||||
void MaterialComponentController::SetPropertyOverrideFloat(
|
||||
const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const float& value)
|
||||
{
|
||||
SetPropertyOverride(materialAssignmentId, propertyName, AZStd::any(value));
|
||||
}
|
||||
|
||||
void MaterialComponentController::SetPropertyOverrideVector2(
|
||||
const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const AZ::Vector2& value)
|
||||
{
|
||||
SetPropertyOverride(materialAssignmentId, propertyName, AZStd::any(value));
|
||||
}
|
||||
|
||||
void MaterialComponentController::SetPropertyOverrideVector3(
|
||||
const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const AZ::Vector3& value)
|
||||
{
|
||||
SetPropertyOverride(materialAssignmentId, propertyName, AZStd::any(value));
|
||||
}
|
||||
|
||||
void MaterialComponentController::SetPropertyOverrideVector4(
|
||||
const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const AZ::Vector4& value)
|
||||
{
|
||||
SetPropertyOverride(materialAssignmentId, propertyName, AZStd::any(value));
|
||||
}
|
||||
|
||||
void MaterialComponentController::SetPropertyOverrideColor(
|
||||
const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const AZ::Color& value)
|
||||
{
|
||||
SetPropertyOverride(materialAssignmentId, propertyName, AZStd::any(value));
|
||||
}
|
||||
|
||||
void MaterialComponentController::SetPropertyOverrideImageAsset(
|
||||
const MaterialAssignmentId& materialAssignmentId,
|
||||
const AZStd::string& propertyName,
|
||||
const AZ::Data::Asset<AZ::RPI::ImageAsset>& value)
|
||||
{
|
||||
SetPropertyOverride(materialAssignmentId, propertyName, AZStd::any(value));
|
||||
}
|
||||
|
||||
void MaterialComponentController::SetPropertyOverrideImageInstance(
|
||||
const MaterialAssignmentId& materialAssignmentId,
|
||||
const AZStd::string& propertyName,
|
||||
const AZ::Data::Instance<AZ::RPI::Image>& value)
|
||||
{
|
||||
SetPropertyOverride(materialAssignmentId, propertyName, AZStd::any(value));
|
||||
}
|
||||
|
||||
void MaterialComponentController::SetPropertyOverrideString(
|
||||
const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const AZStd::string& value)
|
||||
{
|
||||
SetPropertyOverride(materialAssignmentId, propertyName, AZStd::any(value));
|
||||
}
|
||||
|
||||
AZStd::any MaterialComponentController::GetPropertyOverride(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const
|
||||
{
|
||||
const auto materialIt = m_configuration.m_materials.find(materialAssignmentId);
|
||||
@@ -563,83 +528,6 @@ namespace AZ
|
||||
return propertyIt->second;
|
||||
}
|
||||
|
||||
bool MaterialComponentController::GetPropertyOverrideBool(
|
||||
const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const
|
||||
{
|
||||
const AZStd::any& value = GetPropertyOverride(materialAssignmentId, propertyName);
|
||||
return !value.empty() && value.is<bool>() ? AZStd::any_cast<bool>(value) : false;
|
||||
}
|
||||
|
||||
int32_t MaterialComponentController::GetPropertyOverrideInt32(
|
||||
const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const
|
||||
{
|
||||
const AZStd::any& value = GetPropertyOverride(materialAssignmentId, propertyName);
|
||||
return !value.empty() && value.is<int32_t>() ? AZStd::any_cast<int32_t>(value) : 0;
|
||||
}
|
||||
|
||||
uint32_t MaterialComponentController::GetPropertyOverrideUInt32(
|
||||
const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const
|
||||
{
|
||||
const AZStd::any& value = GetPropertyOverride(materialAssignmentId, propertyName);
|
||||
return !value.empty() && value.is<uint32_t>() ? AZStd::any_cast<uint32_t>(value) : 0;
|
||||
}
|
||||
|
||||
float MaterialComponentController::GetPropertyOverrideFloat(
|
||||
const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const
|
||||
{
|
||||
const AZStd::any& value = GetPropertyOverride(materialAssignmentId, propertyName);
|
||||
return !value.empty() && value.is<float>() ? AZStd::any_cast<float>(value) : 0.0f;
|
||||
}
|
||||
|
||||
AZ::Vector2 MaterialComponentController::GetPropertyOverrideVector2(
|
||||
const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const
|
||||
{
|
||||
const AZStd::any& value = GetPropertyOverride(materialAssignmentId, propertyName);
|
||||
return !value.empty() && value.is<AZ::Vector2>() ? AZStd::any_cast<AZ::Vector2>(value) : AZ::Vector2::CreateZero();
|
||||
}
|
||||
|
||||
AZ::Vector3 MaterialComponentController::GetPropertyOverrideVector3(
|
||||
const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const
|
||||
{
|
||||
const AZStd::any& value = GetPropertyOverride(materialAssignmentId, propertyName);
|
||||
return !value.empty() && value.is<AZ::Vector3>() ? AZStd::any_cast<AZ::Vector3>(value) : AZ::Vector3::CreateZero();
|
||||
}
|
||||
|
||||
AZ::Vector4 MaterialComponentController::GetPropertyOverrideVector4(
|
||||
const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const
|
||||
{
|
||||
const AZStd::any& value = GetPropertyOverride(materialAssignmentId, propertyName);
|
||||
return !value.empty() && value.is<AZ::Vector4>() ? AZStd::any_cast<AZ::Vector4>(value) : AZ::Vector4::CreateZero();
|
||||
}
|
||||
|
||||
AZ::Color MaterialComponentController::GetPropertyOverrideColor(
|
||||
const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const
|
||||
{
|
||||
const AZStd::any& value = GetPropertyOverride(materialAssignmentId, propertyName);
|
||||
return !value.empty() && value.is<AZ::Color>() ? AZStd::any_cast<AZ::Color>(value) : AZ::Color::CreateZero();
|
||||
}
|
||||
|
||||
AZ::Data::Asset<AZ::RPI::ImageAsset> MaterialComponentController::GetPropertyOverrideImageAsset(
|
||||
const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const
|
||||
{
|
||||
const AZStd::any& value = GetPropertyOverride(materialAssignmentId, propertyName);
|
||||
return !value.empty() && value.is<AZ::Data::Asset<AZ::RPI::ImageAsset>>() ? AZStd::any_cast<AZ::Data::Asset<AZ::RPI::ImageAsset>>(value) : AZ::Data::Asset<AZ::RPI::ImageAsset>();
|
||||
}
|
||||
|
||||
AZ::Data::Instance<AZ::RPI::Image> MaterialComponentController::GetPropertyOverrideImageInstance(
|
||||
const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const
|
||||
{
|
||||
const AZStd::any& value = GetPropertyOverride(materialAssignmentId, propertyName);
|
||||
return !value.empty() && value.is<AZ::Data::Instance<AZ::RPI::Image>>() ? AZStd::any_cast<AZ::Data::Instance<AZ::RPI::Image>>(value) : AZ::Data::Instance<AZ::RPI::Image>();
|
||||
}
|
||||
|
||||
AZStd::string MaterialComponentController::GetPropertyOverrideString(
|
||||
const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const
|
||||
{
|
||||
const AZStd::any& value = GetPropertyOverride(materialAssignmentId, propertyName);
|
||||
return !value.empty() && value.is<AZStd::string>() ? AZStd::any_cast<AZStd::string>(value) : AZStd::string();
|
||||
}
|
||||
|
||||
void MaterialComponentController::ClearPropertyOverride(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName)
|
||||
{
|
||||
auto materialIt = m_configuration.m_materials.find(materialAssignmentId);
|
||||
@@ -702,6 +590,13 @@ namespace AZ
|
||||
auto& materialAssignment = m_configuration.m_materials[materialAssignmentId];
|
||||
const bool wasEmpty = materialAssignment.m_propertyOverrides.empty();
|
||||
materialAssignment.m_propertyOverrides = propertyOverrides;
|
||||
ConvertAssetsForSerialization();
|
||||
|
||||
if (materialAssignment.RequiresLoading())
|
||||
{
|
||||
LoadMaterials();
|
||||
return;
|
||||
}
|
||||
|
||||
if (wasEmpty != materialAssignment.m_propertyOverrides.empty())
|
||||
{
|
||||
@@ -712,14 +607,11 @@ namespace AZ
|
||||
QueuePropertyChanges(materialAssignmentId);
|
||||
}
|
||||
|
||||
MaterialPropertyOverrideMap MaterialComponentController::GetPropertyOverrides(const MaterialAssignmentId& materialAssignmentId) const
|
||||
MaterialPropertyOverrideMap MaterialComponentController::GetPropertyOverrides(
|
||||
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_propertyOverrides;
|
||||
return materialIt != m_configuration.m_materials.end() ? materialIt->second.m_propertyOverrides : MaterialPropertyOverrideMap();
|
||||
}
|
||||
|
||||
void MaterialComponentController::SetModelUvOverrides(
|
||||
@@ -729,6 +621,12 @@ namespace AZ
|
||||
const bool wasEmpty = materialAssignment.m_matModUvOverrides.empty();
|
||||
materialAssignment.m_matModUvOverrides = modelUvOverrides;
|
||||
|
||||
if (materialAssignment.RequiresLoading())
|
||||
{
|
||||
LoadMaterials();
|
||||
return;
|
||||
}
|
||||
|
||||
if (wasEmpty != materialAssignment.m_matModUvOverrides.empty())
|
||||
{
|
||||
materialAssignment.RebuildInstance();
|
||||
@@ -742,16 +640,24 @@ namespace AZ
|
||||
const MaterialAssignmentId& materialAssignmentId) const
|
||||
{
|
||||
const auto materialIt = m_configuration.m_materials.find(materialAssignmentId);
|
||||
if (materialIt == m_configuration.m_materials.end())
|
||||
return materialIt != m_configuration.m_materials.end() ? materialIt->second.m_matModUvOverrides : AZ::RPI::MaterialModelUvOverrideMap();
|
||||
}
|
||||
|
||||
void MaterialComponentController::OnMaterialAssignmentsChanged()
|
||||
{
|
||||
for (const auto& materialPair : m_configuration.m_materials)
|
||||
{
|
||||
return {};
|
||||
if (materialPair.second.RequiresLoading())
|
||||
{
|
||||
LoadMaterials();
|
||||
return;
|
||||
}
|
||||
}
|
||||
return materialIt->second.m_matModUvOverrides;
|
||||
}
|
||||
|
||||
void MaterialComponentController::QueuePropertyChanges(const MaterialAssignmentId& materialAssignmentId)
|
||||
{
|
||||
m_queuedPropertyOverrides.emplace(materialAssignmentId);
|
||||
m_materialsWithDirtyProperties.emplace(materialAssignmentId);
|
||||
if (!TickBus::Handler::BusIsConnected())
|
||||
{
|
||||
TickBus::Handler::BusConnect();
|
||||
@@ -766,5 +672,33 @@ namespace AZ
|
||||
TickBus::Handler::BusConnect();
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialComponentController::ConvertAssetsForSerialization()
|
||||
{
|
||||
for (auto& materialAssignmentPair : m_configuration.m_materials)
|
||||
{
|
||||
MaterialAssignment& materialAssignment = materialAssignmentPair.second;
|
||||
for (auto& propertyPair : materialAssignment.m_propertyOverrides)
|
||||
{
|
||||
auto& value = propertyPair.second;
|
||||
if (value.is<AZ::Data::Asset<AZ::Data::AssetData>>())
|
||||
{
|
||||
value = AZStd::any_cast<AZ::Data::Asset<AZ::Data::AssetData>>(value).GetId();
|
||||
}
|
||||
else if (value.is<AZ::Data::Asset<AZ::RPI::StreamingImageAsset>>())
|
||||
{
|
||||
value = AZStd::any_cast<AZ::Data::Asset<AZ::RPI::StreamingImageAsset>>(value).GetId();
|
||||
}
|
||||
else if (value.is<AZ::Data::Asset<AZ::RPI::ImageAsset>>())
|
||||
{
|
||||
value = AZStd::any_cast<AZ::Data::Asset<AZ::RPI::ImageAsset>>(value).GetId();
|
||||
}
|
||||
else if (value.is<AZ::Data::Instance<AZ::RPI::Image>>())
|
||||
{
|
||||
value = AZStd::any_cast<AZ::Data::Instance<AZ::RPI::Image>>(value)->GetAssetId();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace Render
|
||||
} // namespace AZ
|
||||
|
||||
+11
-26
@@ -22,6 +22,7 @@ namespace AZ
|
||||
//! to provide material overrides on a per-entity basis.
|
||||
class MaterialComponentController final
|
||||
: MaterialComponentRequestBus::Handler
|
||||
, MaterialReceiverNotificationBus::Handler
|
||||
, Data::AssetBus::MultiHandler
|
||||
, TickBus::Handler
|
||||
{
|
||||
@@ -57,39 +58,15 @@ namespace AZ
|
||||
void ClearIncompatibleMaterialOverrides() override;
|
||||
void ClearInvalidMaterialOverrides() override;
|
||||
void RepairInvalidMaterialOverrides() override;
|
||||
uint32_t ApplyAutomaticPropertyUpdates() override;
|
||||
void SetDefaultMaterialOverride(const AZ::Data::AssetId& materialAssetId) override;
|
||||
const AZ::Data::AssetId GetDefaultMaterialOverride() const override;
|
||||
void ClearDefaultMaterialOverride() override;
|
||||
void SetMaterialOverride(const MaterialAssignmentId& materialAssignmentId, const AZ::Data::AssetId& materialAssetId) override;
|
||||
AZ::Data::AssetId GetMaterialOverride(const MaterialAssignmentId& materialAssignmentId) const override;
|
||||
void ClearMaterialOverride(const MaterialAssignmentId& materialAssignmentId) override;
|
||||
|
||||
void SetPropertyOverride(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const AZStd::any& value) override;
|
||||
void SetPropertyOverrideBool(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const bool& value) override;
|
||||
void SetPropertyOverrideInt32(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const int32_t& value) override;
|
||||
void SetPropertyOverrideUInt32(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const uint32_t& value) override;
|
||||
void SetPropertyOverrideFloat(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const float& value) override;
|
||||
void SetPropertyOverrideVector2(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const AZ::Vector2& value) override;
|
||||
void SetPropertyOverrideVector3(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const AZ::Vector3& value) override;
|
||||
void SetPropertyOverrideVector4(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const AZ::Vector4& value) override;
|
||||
void SetPropertyOverrideColor(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const AZ::Color& value) override;
|
||||
void SetPropertyOverrideImageAsset(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const AZ::Data::Asset<AZ::RPI::ImageAsset>& value) override;
|
||||
void SetPropertyOverrideImageInstance(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const AZ::Data::Instance<AZ::RPI::Image>& value) override;
|
||||
void SetPropertyOverrideString(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const AZStd::string& value) override;
|
||||
|
||||
AZStd::any GetPropertyOverride(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const override;
|
||||
bool GetPropertyOverrideBool(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const override;
|
||||
int32_t GetPropertyOverrideInt32(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const override;
|
||||
uint32_t GetPropertyOverrideUInt32(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const override;
|
||||
float GetPropertyOverrideFloat(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const override;
|
||||
AZ::Vector2 GetPropertyOverrideVector2(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const override;
|
||||
AZ::Vector3 GetPropertyOverrideVector3(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const override;
|
||||
AZ::Vector4 GetPropertyOverrideVector4(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const override;
|
||||
AZ::Color GetPropertyOverrideColor(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const override;
|
||||
AZ::Data::Asset<AZ::RPI::ImageAsset> GetPropertyOverrideImageAsset(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const override;
|
||||
AZ::Data::Instance<AZ::RPI::Image> GetPropertyOverrideImageInstance(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const override;
|
||||
AZStd::string GetPropertyOverrideString(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) const override;
|
||||
|
||||
void ClearPropertyOverride(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) override;
|
||||
void ClearPropertyOverrides(const MaterialAssignmentId& materialAssignmentId) override;
|
||||
void ClearAllPropertyOverrides() override;
|
||||
@@ -100,6 +77,9 @@ namespace AZ
|
||||
const MaterialAssignmentId& materialAssignmentId, const AZ::RPI::MaterialModelUvOverrideMap& modelUvOverrides) override;
|
||||
AZ::RPI::MaterialModelUvOverrideMap GetModelUvOverrides(const MaterialAssignmentId& materialAssignmentId) const override;
|
||||
|
||||
//! MaterialReceiverNotificationBus::Handler overrides...
|
||||
void OnMaterialAssignmentsChanged() override;
|
||||
|
||||
private:
|
||||
|
||||
AZ_DISABLE_COPY(MaterialComponentController);
|
||||
@@ -119,9 +99,14 @@ namespace AZ
|
||||
//! Queue material instance recreation notifiucations until tick
|
||||
void QueueMaterialUpdateNotification();
|
||||
|
||||
//! Converts property overrides storing image asset references into asset IDs. This addresses a problem where image property
|
||||
//! overrides are lost during prefab serialization and patching. This suboptimal function will be removed once the underlying
|
||||
//! problem is resolved.
|
||||
void ConvertAssetsForSerialization();
|
||||
|
||||
EntityId m_entityId;
|
||||
MaterialComponentConfig m_configuration;
|
||||
AZStd::unordered_set<MaterialAssignmentId> m_queuedPropertyOverrides;
|
||||
AZStd::unordered_set<MaterialAssignmentId> m_materialsWithDirtyProperties;
|
||||
bool m_queuedMaterialUpdateNotification = false;
|
||||
};
|
||||
} // namespace Render
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
|
||||
#include <QtConcurrent/QtConcurrent>
|
||||
#include <Source/Material/MaterialThumbnail.h>
|
||||
#include <Source/Thumbnails/ThumbnailUtils.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace LyIntegration
|
||||
{
|
||||
namespace Thumbnails
|
||||
{
|
||||
static constexpr const int MaterialThumbnailSize = 512; // 512 is the default size in render to texture pass
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// MaterialThumbnail
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
MaterialThumbnail::MaterialThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key)
|
||||
: Thumbnail(key)
|
||||
{
|
||||
m_assetId = GetAssetId(key, RPI::MaterialAsset::RTTI_Type());
|
||||
if (!m_assetId.IsValid())
|
||||
{
|
||||
AZ_Error("MaterialThumbnail", false, "Failed to find matching assetId for the thumbnailKey.");
|
||||
m_state = State::Failed;
|
||||
return;
|
||||
}
|
||||
|
||||
AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler::BusConnect(key);
|
||||
AzFramework::AssetCatalogEventBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
void MaterialThumbnail::LoadThread()
|
||||
{
|
||||
AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::QueueEvent(
|
||||
RPI::MaterialAsset::RTTI_Type(),
|
||||
&AzToolsFramework::Thumbnailer::ThumbnailerRendererRequests::RenderThumbnail,
|
||||
m_key,
|
||||
MaterialThumbnailSize);
|
||||
// wait for response from thumbnail renderer
|
||||
m_renderWait.acquire();
|
||||
}
|
||||
|
||||
MaterialThumbnail::~MaterialThumbnail()
|
||||
{
|
||||
AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler::BusDisconnect();
|
||||
AzFramework::AssetCatalogEventBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
void MaterialThumbnail::ThumbnailRendered(QPixmap& thumbnailImage)
|
||||
{
|
||||
m_pixmap = thumbnailImage;
|
||||
m_renderWait.release();
|
||||
}
|
||||
|
||||
void MaterialThumbnail::ThumbnailFailedToRender()
|
||||
{
|
||||
m_state = State::Failed;
|
||||
m_renderWait.release();
|
||||
}
|
||||
|
||||
void MaterialThumbnail::OnCatalogAssetChanged([[maybe_unused]] const AZ::Data::AssetId& assetId)
|
||||
{
|
||||
if (m_assetId == assetId &&
|
||||
m_state == State::Ready)
|
||||
{
|
||||
m_state = State::Unloaded;
|
||||
Load();
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// MaterialThumbnailCache
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
MaterialThumbnailCache::MaterialThumbnailCache()
|
||||
: ThumbnailCache<MaterialThumbnail>()
|
||||
{
|
||||
}
|
||||
|
||||
MaterialThumbnailCache::~MaterialThumbnailCache() = default;
|
||||
|
||||
int MaterialThumbnailCache::GetPriority() const
|
||||
{
|
||||
// Material thumbnails override default source thumbnails, so carry higher priority
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char* MaterialThumbnailCache::GetProviderName() const
|
||||
{
|
||||
return ProviderName;
|
||||
}
|
||||
|
||||
bool MaterialThumbnailCache::IsSupportedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) const
|
||||
{
|
||||
return
|
||||
GetAssetId(key, RPI::MaterialAsset::RTTI_Type()).IsValid() &&
|
||||
// in case it's a source scene file, it will contain both material and model products
|
||||
// model thumbnails are handled by MeshThumbnail
|
||||
!GetAssetId(key, RPI::ModelAsset::RTTI_Type()).IsValid();
|
||||
}
|
||||
} // namespace Thumbnails
|
||||
} // namespace LyIntegration
|
||||
} // namespace AZ
|
||||
|
||||
#include <Material/moc_MaterialThumbnail.cpp>
|
||||
@@ -1,73 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <AzCore/std/parallel/binary_semaphore.h>
|
||||
#include <AzFramework/Asset/AssetCatalogBus.h>
|
||||
#include <AzToolsFramework/Thumbnails/Thumbnail.h>
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailerBus.h>
|
||||
#include <Thumbnails/Rendering/CommonThumbnailRenderer.h>
|
||||
#endif
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace LyIntegration
|
||||
{
|
||||
namespace Thumbnails
|
||||
{
|
||||
/**
|
||||
* Custom material or model thumbnail that detects when an asset changes and updates the thumbnail
|
||||
*/
|
||||
class MaterialThumbnail
|
||||
: public AzToolsFramework::Thumbnailer::Thumbnail
|
||||
, public AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler
|
||||
, private AzFramework::AssetCatalogEventBus::Handler
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
MaterialThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key);
|
||||
~MaterialThumbnail() override;
|
||||
|
||||
//! AzToolsFramework::ThumbnailerRendererNotificationBus::Handler overrides...
|
||||
void ThumbnailRendered(QPixmap& thumbnailImage) override;
|
||||
void ThumbnailFailedToRender() override;
|
||||
|
||||
protected:
|
||||
void LoadThread() override;
|
||||
|
||||
private:
|
||||
// AzFramework::AssetCatalogEventBus::Handler interface overrides...
|
||||
void OnCatalogAssetChanged(const AZ::Data::AssetId& assetId) override;
|
||||
|
||||
AZStd::binary_semaphore m_renderWait;
|
||||
Data::AssetId m_assetId;
|
||||
};
|
||||
|
||||
/**
|
||||
* Cache configuration for large material thumbnails
|
||||
*/
|
||||
class MaterialThumbnailCache
|
||||
: public AzToolsFramework::Thumbnailer::ThumbnailCache<MaterialThumbnail>
|
||||
{
|
||||
public:
|
||||
MaterialThumbnailCache();
|
||||
~MaterialThumbnailCache() override;
|
||||
|
||||
int GetPriority() const override;
|
||||
const char* GetProviderName() const override;
|
||||
|
||||
static constexpr const char* ProviderName = "Material Thumbnails";
|
||||
|
||||
protected:
|
||||
bool IsSupportedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) const override;
|
||||
};
|
||||
} // namespace Thumbnails
|
||||
} // namespace LyIntegration
|
||||
} // namespace AZ
|
||||
Reference in New Issue
Block a user