Add material property names to material assets, disable FBX dependency on materialtype files. (#3408)
* Add material property names to material assets, disable FBX dependency on materialtype files. Signed-off-by: Robin <rbarrand@amazon.com> * Add reflection for MaterialAssets. Update member variable comment. Signed-off-by: Robin <rbarrand@amazon.com> * Switch cvar to using bus value. Refine comments. Signed-off-by: Robin <rbarrand@amazon.com> * Refactor functions and refine comments. Signed-off-by: Robin <rbarrand@amazon.com> * Realign property values when material property names are populated. Signed-off-by: Robin <rbarrand@amazon.com> * Switch PostLoadInit check to on asset status ready. Add realign property values code to PostLoadInit as well. Signed-off-by: Robin <rbarrand@amazon.com> * Stash@{1} code. Signed-off-by: Robin <rbarrand@amazon.com> * Refactor realignment code into the right places. Signed-off-by: Robin <rbarrand@amazon.com> * Remove pragma optmize off. Signed-off-by: Robin <rbarrand@amazon.com> * More refactoring. Signed-off-by: Robin <rbarrand@amazon.com> * Refactor comments and remove code no longer needed. Signed-off-by: Robin <rbarrand@amazon.com> * Refactor comments and remove unused include. Signed-off-by: Robin <rbarrand@amazon.com> * Comment refactor, corrected some code. Signed-off-by: Robin <rbarrand@amazon.com> Co-authored-by: Robin <rbarrand@amazon.com>
This commit is contained in:
@@ -26,9 +26,10 @@ namespace AZ
|
||||
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<MaterialConverterSettings>()
|
||||
->Version(1)
|
||||
->Version(2)
|
||||
->Field("Enable", &MaterialConverterSettings::m_enable)
|
||||
->Field("DefaultMaterial", &MaterialConverterSettings::m_defaultMaterial);
|
||||
->Field("DefaultMaterial", &MaterialConverterSettings::m_defaultMaterial)
|
||||
->Field("IncludeMaterialPropertyNames", &MaterialConverterSettings::m_includeMaterialPropertyNames);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,6 +70,11 @@ namespace AZ
|
||||
return m_settings.m_enable;
|
||||
}
|
||||
|
||||
bool MaterialConverterSystemComponent::ShouldIncludeMaterialPropertyNames() const
|
||||
{
|
||||
return m_settings.m_includeMaterialPropertyNames;
|
||||
}
|
||||
|
||||
bool MaterialConverterSystemComponent::ConvertMaterial(
|
||||
const AZ::SceneAPI::DataTypes::IMaterialData& materialData, RPI::MaterialSourceData& sourceData)
|
||||
{
|
||||
|
||||
@@ -26,6 +26,11 @@ namespace AZ
|
||||
|
||||
bool m_enable = true;
|
||||
AZStd::string m_defaultMaterial;
|
||||
//! Sets whether to include material property names when generating material assets. If this
|
||||
//! setting is true, material property name resolution and validation is deferred into load
|
||||
//! time rather than at build time, allowing to break some dependencies (e.g. fbx files will no
|
||||
//! longer need to be dependent on materialtype files).
|
||||
bool m_includeMaterialPropertyNames = true;
|
||||
};
|
||||
|
||||
//! Atom's implementation of converting SceneAPI data into Atom's default material: StandardPBR
|
||||
@@ -45,6 +50,7 @@ namespace AZ
|
||||
|
||||
// MaterialConverterBus overrides ...
|
||||
bool IsEnabled() const override;
|
||||
bool ShouldIncludeMaterialPropertyNames() const override;
|
||||
bool ConvertMaterial(const AZ::SceneAPI::DataTypes::IMaterialData& materialData, RPI::MaterialSourceData& out) override;
|
||||
AZStd::string GetMaterialTypePath() const override;
|
||||
AZStd::string GetDefaultMaterialPath() const override;
|
||||
|
||||
@@ -32,6 +32,10 @@ namespace AZ
|
||||
|
||||
virtual bool IsEnabled() const = 0;
|
||||
|
||||
//! Returns true if material property names should be included in azmaterials. This allows unlinking of dependencies for some
|
||||
//! file types to materialtype files (e.g. fbx).
|
||||
virtual bool ShouldIncludeMaterialPropertyNames() const = 0;
|
||||
|
||||
//! Converts data from a IMaterialData object to an Atom MaterialSourceData.
|
||||
//! Only works when IsEnabled() is true.
|
||||
//! @return true if the MaterialSourceData output was populated with converted material data.
|
||||
|
||||
@@ -68,12 +68,12 @@ namespace AZ
|
||||
//! @param assetId ID for the MaterialAsset
|
||||
//! @param materialSourceFilePath Indicates the path of the .material file that the MaterialSourceData represents. Used for resolving file-relative paths.
|
||||
//! @param elevateWarnings Indicates whether to treat warnings as errors
|
||||
//! @param materialTypeSourceData The function sometimes needs metadata from the .materialtype file.
|
||||
//! It will either load the .materialtype file from disk, or use this MaterialTypeSourceData if it's provided.
|
||||
//! @param includeMaterialPropertyNames Indicates whether to save material property names into the material asset file
|
||||
Outcome<Data::Asset<MaterialAsset>> CreateMaterialAsset(
|
||||
Data::AssetId assetId,
|
||||
AZStd::string_view materialSourceFilePath = "",
|
||||
bool elevateWarnings = true
|
||||
bool elevateWarnings = true,
|
||||
bool includeMaterialPropertyNames = true
|
||||
) const;
|
||||
};
|
||||
} // namespace RPI
|
||||
|
||||
@@ -108,6 +108,11 @@ namespace AZ
|
||||
private:
|
||||
bool PostLoadInit() override;
|
||||
|
||||
//! Realigns property value and name indices with MaterialProperiesLayout by using m_propertyNames. Property names not found in the
|
||||
//! MaterialPropertiesLayout are discarded, while property names not included in m_propertyNames will use the default value
|
||||
//! from m_materialTypeAsset.
|
||||
void RealignPropertyValuesAndNames();
|
||||
|
||||
//! Called by asset creators to assign the asset to a ready state.
|
||||
void SetReady();
|
||||
|
||||
@@ -121,11 +126,20 @@ namespace AZ
|
||||
// MaterialReloadNotificationBus overrides...
|
||||
void OnMaterialTypeAssetReinitialized(const Data::Asset<MaterialTypeAsset>& materialTypeAsset) override;
|
||||
|
||||
static const char* s_debugTraceName;
|
||||
|
||||
Data::Asset<MaterialTypeAsset> m_materialTypeAsset;
|
||||
|
||||
//! Holds values for each material property, used to initialize Material instances.
|
||||
//! This is indexed by MaterialPropertyIndex and aligns with entries in m_materialPropertiesLayout.
|
||||
AZStd::vector<MaterialPropertyValue> m_propertyValues;
|
||||
//! This is used to realign m_propertyValues as well as itself with MaterialPropertiesLayout when not empty.
|
||||
//! If empty, this implies that m_propertyValues is aligned with the entries in m_materialPropertiesLayout.
|
||||
AZStd::vector<AZ::Name> m_propertyNames;
|
||||
|
||||
//! A flag to determine if m_propertyValues needs to be aligned with MaterialPropertiesLayout. Set to true whenever
|
||||
//! m_materialTypeAsset is reinitializing.
|
||||
bool m_isDirty = true;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -26,11 +26,13 @@ namespace AZ
|
||||
public:
|
||||
friend class MaterialSourceData;
|
||||
|
||||
void Begin(const Data::AssetId& assetId, MaterialAsset& parentMaterial);
|
||||
void Begin(const Data::AssetId& assetId, MaterialTypeAsset& materialType);
|
||||
void Begin(const Data::AssetId& assetId, MaterialAsset& parentMaterial, bool includeMaterialPropertyNames = true);
|
||||
void Begin(const Data::AssetId& assetId, MaterialTypeAsset& materialType, bool includeMaterialPropertyNames = true);
|
||||
bool End(Data::Asset<MaterialAsset>& result);
|
||||
|
||||
private:
|
||||
void PopulatePropertyNameList();
|
||||
|
||||
const MaterialPropertiesLayout* m_materialPropertiesLayout = nullptr;
|
||||
};
|
||||
} // namespace RPI
|
||||
|
||||
@@ -78,7 +78,9 @@ namespace AZ
|
||||
AZStd::string materialTypePath;
|
||||
RPI::MaterialConverterBus::BroadcastResult(materialTypePath, &RPI::MaterialConverterBus::Events::GetMaterialTypePath);
|
||||
|
||||
if (conversionEnabled && !materialTypePath.empty())
|
||||
bool includeMaterialPropertyNames = true;
|
||||
RPI::MaterialConverterBus::BroadcastResult(includeMaterialPropertyNames, &RPI::MaterialConverterBus::Events::ShouldIncludeMaterialPropertyNames);
|
||||
if (conversionEnabled && !materialTypePath.empty() && !includeMaterialPropertyNames)
|
||||
{
|
||||
AssetBuilderSDK::SourceFileDependency materialTypeSource;
|
||||
materialTypeSource.m_sourceFileDependencyPath = materialTypePath;
|
||||
@@ -101,6 +103,10 @@ namespace AZ
|
||||
RPI::MaterialConverterBus::BroadcastResult(conversionEnabled, &RPI::MaterialConverterBus::Events::IsEnabled);
|
||||
fingerprintInfo.insert(AZStd::string::format("[MaterialConverter enabled=%d]", conversionEnabled));
|
||||
|
||||
bool includeMaterialPropertyNames = true;
|
||||
RPI::MaterialConverterBus::BroadcastResult(includeMaterialPropertyNames, &RPI::MaterialConverterBus::Events::ShouldIncludeMaterialPropertyNames);
|
||||
fingerprintInfo.insert(AZStd::string::format("[MaterialConverter includeMaterialPropertyNames=%d]", includeMaterialPropertyNames));
|
||||
|
||||
if (!conversionEnabled)
|
||||
{
|
||||
AZStd::string defaultMaterialPath;
|
||||
@@ -219,6 +225,8 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
bool includeMaterialPropertyNames = true;
|
||||
RPI::MaterialConverterBus::BroadcastResult(includeMaterialPropertyNames, &RPI::MaterialConverterBus::Events::ShouldIncludeMaterialPropertyNames);
|
||||
// Build material assets.
|
||||
for (auto& itr : materialSourceDataByUid)
|
||||
{
|
||||
@@ -226,7 +234,7 @@ namespace AZ
|
||||
Data::AssetId assetId(sourceSceneUuid, GetMaterialAssetSubId(materialUid));
|
||||
|
||||
auto materialSourceData = itr.second;
|
||||
Outcome<Data::Asset<MaterialAsset>> result = materialSourceData.m_data.CreateMaterialAsset(assetId, "", false);
|
||||
Outcome<Data::Asset<MaterialAsset>> result = materialSourceData.m_data.CreateMaterialAsset(assetId, "", false, includeMaterialPropertyNames);
|
||||
if (result.IsSuccess())
|
||||
{
|
||||
context.m_outputMaterialsByUid[materialUid] = { result.GetValue(), materialSourceData.m_name };
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <Atom/RPI.Edit/Material/MaterialTypeSourceData.h>
|
||||
#include <Atom/RPI.Edit/Material/MaterialPropertyId.h>
|
||||
#include <Atom/RPI.Edit/Material/MaterialUtils.h>
|
||||
#include <Atom/RPI.Edit/Material/MaterialConverterBus.h>
|
||||
|
||||
#include <Atom/RPI.Edit/Common/AssetUtils.h>
|
||||
#include <Atom/RPI.Edit/Common/JsonFileLoadContext.h>
|
||||
@@ -72,7 +73,7 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
Outcome<Data::Asset<MaterialAsset> > MaterialSourceData::CreateMaterialAsset(Data::AssetId assetId, AZStd::string_view materialSourceFilePath, bool elevateWarnings) const
|
||||
Outcome<Data::Asset<MaterialAsset> > MaterialSourceData::CreateMaterialAsset(Data::AssetId assetId, AZStd::string_view materialSourceFilePath, bool elevateWarnings, bool includeMaterialPropertyNames) const
|
||||
{
|
||||
MaterialAssetCreator materialAssetCreator;
|
||||
materialAssetCreator.SetElevateWarnings(elevateWarnings);
|
||||
@@ -85,7 +86,7 @@ namespace AZ
|
||||
return Failure();
|
||||
}
|
||||
|
||||
materialAssetCreator.Begin(assetId, *materialTypeAsset.GetValue().Get());
|
||||
materialAssetCreator.Begin(assetId, *materialTypeAsset.GetValue().Get(), includeMaterialPropertyNames);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -115,7 +116,7 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
materialAssetCreator.Begin(assetId, *parentMaterialAsset.GetValue().Get());
|
||||
materialAssetCreator.Begin(assetId, *parentMaterialAsset.GetValue().Get(), includeMaterialPropertyNames);
|
||||
}
|
||||
|
||||
for (auto& group : m_properties)
|
||||
|
||||
@@ -20,6 +20,8 @@ namespace AZ
|
||||
{
|
||||
namespace RPI
|
||||
{
|
||||
const char* MaterialAsset::s_debugTraceName = "MaterialAsset";
|
||||
|
||||
const char* MaterialAsset::DisplayName = "MaterialAsset";
|
||||
const char* MaterialAsset::Group = "Material";
|
||||
const char* MaterialAsset::Extension = "azmaterial";
|
||||
@@ -29,9 +31,10 @@ namespace AZ
|
||||
if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<MaterialAsset, AZ::Data::AssetData>()
|
||||
->Version(9)
|
||||
->Version(10)
|
||||
->Field("materialTypeAsset", &MaterialAsset::m_materialTypeAsset)
|
||||
->Field("propertyValues", &MaterialAsset::m_propertyValues)
|
||||
->Field("propertyNames", &MaterialAsset::m_propertyNames)
|
||||
;
|
||||
}
|
||||
}
|
||||
@@ -99,6 +102,11 @@ namespace AZ
|
||||
|
||||
AZStd::array_view<MaterialPropertyValue> MaterialAsset::GetPropertyValues() const
|
||||
{
|
||||
if (!m_propertyNames.empty() && m_isDirty)
|
||||
{
|
||||
const_cast<MaterialAsset*>(this)->RealignPropertyValuesAndNames();
|
||||
}
|
||||
|
||||
return m_propertyValues;
|
||||
}
|
||||
|
||||
@@ -146,6 +154,34 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialAsset::RealignPropertyValuesAndNames()
|
||||
{
|
||||
const MaterialPropertiesLayout* propertyLayout = GetMaterialPropertiesLayout();
|
||||
AZStd::vector<MaterialPropertyValue> alignedPropertyValues(m_materialTypeAsset->GetDefaultPropertyValues().begin(), m_materialTypeAsset->GetDefaultPropertyValues().end());
|
||||
for (size_t i = 0; i < m_propertyNames.size(); ++i)
|
||||
{
|
||||
const MaterialPropertyIndex propertyIndex = propertyLayout->FindPropertyIndex(m_propertyNames[i]);
|
||||
if (propertyIndex.IsValid())
|
||||
{
|
||||
alignedPropertyValues[propertyIndex.GetIndex()] = m_propertyValues[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Warning(s_debugTraceName, false, "Material property name \"%s\" is not found in the material properties layout and will not be used.", m_propertyNames[i].GetCStr());
|
||||
}
|
||||
}
|
||||
m_propertyValues.swap(alignedPropertyValues);
|
||||
|
||||
const size_t propertyCount = propertyLayout->GetPropertyCount();
|
||||
m_propertyNames.resize(propertyCount);
|
||||
for (size_t i = 0; i < propertyCount; ++i)
|
||||
{
|
||||
m_propertyNames[i] = propertyLayout->GetPropertyDescriptor(MaterialPropertyIndex{ i })->GetName();
|
||||
}
|
||||
|
||||
m_isDirty = false;
|
||||
}
|
||||
|
||||
void MaterialAsset::ReinitializeMaterialTypeAsset(Data::Asset<Data::AssetData> asset)
|
||||
{
|
||||
Data::Asset<MaterialTypeAsset> newMaterialTypeAsset = { asset.GetAs<MaterialTypeAsset>(), AZ::Data::AssetLoadBehavior::PreLoad };
|
||||
@@ -157,6 +193,8 @@ namespace AZ
|
||||
// This also covers the case where just the MaterialTypeAsset is reloaded and not the MaterialAsset.
|
||||
m_materialTypeAsset = newMaterialTypeAsset;
|
||||
|
||||
m_isDirty = true;
|
||||
|
||||
// Notify interested parties that this MaterialAsset is changed and may require other data to reinitialize as well
|
||||
MaterialReloadNotificationBus::Event(GetId(), &MaterialReloadNotifications::OnMaterialAssetReinitialized, Data::Asset<MaterialAsset>{this, AZ::Data::AssetLoadBehavior::PreLoad});
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace AZ
|
||||
{
|
||||
namespace RPI
|
||||
{
|
||||
void MaterialAssetCreator::Begin(const Data::AssetId& assetId, MaterialAsset& parentMaterial)
|
||||
void MaterialAssetCreator::Begin(const Data::AssetId& assetId, MaterialAsset& parentMaterial, bool includeMaterialPropertyNames)
|
||||
{
|
||||
BeginCommon(assetId);
|
||||
|
||||
@@ -36,6 +36,10 @@ namespace AZ
|
||||
ReportError("MaterialPropertiesLayout is null");
|
||||
return;
|
||||
}
|
||||
if (includeMaterialPropertyNames)
|
||||
{
|
||||
PopulatePropertyNameList();
|
||||
}
|
||||
|
||||
// Note we don't have to check the validity of these property values because the parent material's AssetCreator already did that.
|
||||
m_asset->m_propertyValues.assign(parentMaterial.GetPropertyValues().begin(), parentMaterial.GetPropertyValues().end());
|
||||
@@ -52,14 +56,14 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialAssetCreator::Begin(const Data::AssetId& assetId, MaterialTypeAsset& materialType)
|
||||
void MaterialAssetCreator::Begin(const Data::AssetId& assetId, MaterialTypeAsset& materialType, bool includeMaterialPropertyNames)
|
||||
{
|
||||
BeginCommon(assetId);
|
||||
|
||||
if (ValidateIsReady())
|
||||
{
|
||||
m_asset->m_materialTypeAsset = { &materialType, AZ::Data::AssetLoadBehavior::PreLoad };
|
||||
|
||||
|
||||
if (!m_asset->m_materialTypeAsset)
|
||||
{
|
||||
ReportError("MaterialTypeAsset is null");
|
||||
@@ -67,6 +71,11 @@ namespace AZ
|
||||
}
|
||||
|
||||
m_materialPropertiesLayout = m_asset->GetMaterialPropertiesLayout();
|
||||
if (includeMaterialPropertyNames)
|
||||
{
|
||||
PopulatePropertyNameList();
|
||||
}
|
||||
|
||||
if (!m_materialPropertiesLayout)
|
||||
{
|
||||
ReportError("MaterialPropertiesLayout is null");
|
||||
@@ -101,5 +110,16 @@ namespace AZ
|
||||
m_asset->SetReady();
|
||||
return EndCommon(result);
|
||||
}
|
||||
|
||||
void MaterialAssetCreator::PopulatePropertyNameList()
|
||||
{
|
||||
for (int i = 0; i < m_materialPropertiesLayout->GetPropertyCount(); ++i)
|
||||
{
|
||||
MaterialPropertyIndex propertyIndex{ i };
|
||||
auto& propertyName = m_materialPropertiesLayout->GetPropertyDescriptor(propertyIndex)->GetName();
|
||||
m_asset->m_propertyNames.emplace_back(propertyName);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace RPI
|
||||
} // namespace AZ
|
||||
|
||||
Reference in New Issue
Block a user