material editor loads source data
Signed-off-by: Guthrie Adams <guthadam@amazon.com>
This commit is contained in:
@@ -31,6 +31,7 @@ namespace AZ
|
||||
static constexpr const char UvGroupName[] = "uvSets";
|
||||
|
||||
class MaterialAsset;
|
||||
class MaterialAssetCreator;
|
||||
|
||||
//! This is a simple data structure for serializing in/out material source files.
|
||||
class MaterialSourceData final
|
||||
@@ -78,15 +79,33 @@ namespace AZ
|
||||
|
||||
//! Creates a MaterialAsset from the MaterialSourceData content.
|
||||
//! @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 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 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 includeMaterialPropertyNames = true
|
||||
) const;
|
||||
bool includeMaterialPropertyNames = true) const;
|
||||
|
||||
//! Creates a MaterialAsset from the MaterialSourceData content.
|
||||
//! @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 includeMaterialPropertyNames Indicates whether to save material property names into the material asset file
|
||||
Outcome<Data::Asset<MaterialAsset>> CreateMaterialAssetFromSourceData(
|
||||
Data::AssetId assetId,
|
||||
AZStd::string_view materialSourceFilePath = "",
|
||||
bool elevateWarnings = true,
|
||||
bool includeMaterialPropertyNames = true) const;
|
||||
|
||||
private:
|
||||
static void ApplyMaterialSourceDataPropertiesToAssetCreator(
|
||||
AZ::RPI::MaterialAssetCreator& materialAssetCreator,
|
||||
const AZStd::string_view& materialSourceFilePath,
|
||||
const MaterialSourceData& materialSourceData);
|
||||
};
|
||||
} // namespace RPI
|
||||
} // namespace AZ
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <Atom/RPI.Edit/Common/AssetUtils.h>
|
||||
#include <Atom/RPI.Edit/Common/JsonFileLoadContext.h>
|
||||
#include <Atom/RPI.Edit/Common/JsonReportingHelper.h>
|
||||
#include <Atom/RPI.Edit/Common/JsonUtils.h>
|
||||
|
||||
#include <Atom/RPI.Reflect/Material/MaterialAssetCreator.h>
|
||||
#include <Atom/RPI.Reflect/Material/MaterialPropertiesLayout.h>
|
||||
@@ -126,7 +127,8 @@ namespace AZ
|
||||
return changesWereApplied ? ApplyVersionUpdatesResult::UpdatesApplied : ApplyVersionUpdatesResult::NoUpdates;
|
||||
}
|
||||
|
||||
Outcome<Data::Asset<MaterialAsset> > MaterialSourceData::CreateMaterialAsset(Data::AssetId assetId, AZStd::string_view materialSourceFilePath, bool elevateWarnings, bool includeMaterialPropertyNames) const
|
||||
Outcome<Data::Asset<MaterialAsset>> MaterialSourceData::CreateMaterialAsset(
|
||||
Data::AssetId assetId, AZStd::string_view materialSourceFilePath, bool elevateWarnings, bool includeMaterialPropertyNames) const
|
||||
{
|
||||
MaterialAssetCreator materialAssetCreator;
|
||||
materialAssetCreator.SetElevateWarnings(elevateWarnings);
|
||||
@@ -172,66 +174,7 @@ namespace AZ
|
||||
materialAssetCreator.Begin(assetId, *parentMaterialAsset.GetValue().Get(), includeMaterialPropertyNames);
|
||||
}
|
||||
|
||||
for (auto& group : m_properties)
|
||||
{
|
||||
for (auto& property : group.second)
|
||||
{
|
||||
MaterialPropertyId propertyId{ group.first, property.first };
|
||||
if (!property.second.m_value.IsValid())
|
||||
{
|
||||
AZ_Warning("Material source data", false, "Source data for material property value is invalid.");
|
||||
}
|
||||
else
|
||||
{
|
||||
MaterialPropertyIndex propertyIndex = materialAssetCreator.m_materialPropertiesLayout->FindPropertyIndex(propertyId.GetFullName());
|
||||
if (propertyIndex.IsValid())
|
||||
{
|
||||
const MaterialPropertyDescriptor* propertyDescriptor = materialAssetCreator.m_materialPropertiesLayout->GetPropertyDescriptor(propertyIndex);
|
||||
switch (propertyDescriptor->GetDataType())
|
||||
{
|
||||
case MaterialPropertyDataType::Image:
|
||||
{
|
||||
Outcome<Data::Asset<ImageAsset>> imageAssetResult = MaterialUtils::GetImageAssetReference(materialSourceFilePath, property.second.m_value.GetValue<AZStd::string>());
|
||||
|
||||
if (imageAssetResult.IsSuccess())
|
||||
{
|
||||
auto& imageAsset = imageAssetResult.GetValue();
|
||||
// Load referenced images when load material
|
||||
imageAsset.SetAutoLoadBehavior(Data::AssetLoadBehavior::PreLoad);
|
||||
materialAssetCreator.SetPropertyValue(propertyId.GetFullName(), imageAsset);
|
||||
}
|
||||
else
|
||||
{
|
||||
materialAssetCreator.ReportError("Material property '%s': Could not find the image '%s'", propertyId.GetFullName().GetCStr(), property.second.m_value.GetValue<AZStd::string>().data());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MaterialPropertyDataType::Enum:
|
||||
{
|
||||
AZ::Name enumName = AZ::Name(property.second.m_value.GetValue<AZStd::string>());
|
||||
uint32_t enumValue = propertyDescriptor->GetEnumValue(enumName);
|
||||
if (enumValue == MaterialPropertyDescriptor::InvalidEnumValue)
|
||||
{
|
||||
materialAssetCreator.ReportError("Enum value '%s' couldn't be found in the 'enumValues' list", enumName.GetCStr());
|
||||
}
|
||||
else
|
||||
{
|
||||
materialAssetCreator.SetPropertyValue(propertyId.GetFullName(), enumValue);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
materialAssetCreator.SetPropertyValue(propertyId.GetFullName(), property.second.m_value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
materialAssetCreator.ReportWarning("Can not find property id '%s' in MaterialPropertyLayout", propertyId.GetFullName().GetStringView().data());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ApplyMaterialSourceDataPropertiesToAssetCreator(materialAssetCreator, materialSourceFilePath, *this);
|
||||
|
||||
Data::Asset<MaterialAsset> material;
|
||||
if (materialAssetCreator.End(material))
|
||||
@@ -244,5 +187,149 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
Outcome<Data::Asset<MaterialAsset>> MaterialSourceData::CreateMaterialAssetFromSourceData(
|
||||
Data::AssetId assetId, AZStd::string_view materialSourceFilePath, bool elevateWarnings, bool includeMaterialPropertyNames) const
|
||||
{
|
||||
MaterialAssetCreator materialAssetCreator;
|
||||
materialAssetCreator.SetElevateWarnings(elevateWarnings);
|
||||
|
||||
MaterialTypeSourceData materialTypeSourceData;
|
||||
AZStd::string materialTypeSourcePath = AssetUtils::ResolvePathReference(materialSourceFilePath, m_materialType);
|
||||
if (!AZ::RPI::JsonUtils::LoadObjectFromFile(materialTypeSourcePath, materialTypeSourceData))
|
||||
{
|
||||
return Failure();
|
||||
}
|
||||
|
||||
materialTypeSourceData.ResolveUvEnums();
|
||||
|
||||
auto materialTypeAsset =
|
||||
materialTypeSourceData.CreateMaterialTypeAsset(AZ::Uuid::CreateRandom(), materialTypeSourcePath, elevateWarnings);
|
||||
if (!materialTypeAsset.IsSuccess())
|
||||
{
|
||||
return Failure();
|
||||
}
|
||||
|
||||
materialAssetCreator.Begin(assetId, *materialTypeAsset.GetValue().Get(), includeMaterialPropertyNames);
|
||||
|
||||
AZStd::vector<MaterialSourceData> parentMaterialSourceDataVec;
|
||||
|
||||
AZStd::string parentMaterialPath = m_parentMaterial;
|
||||
AZStd::string parentMaterialSourcePath = AssetUtils::ResolvePathReference(materialSourceFilePath, parentMaterialPath);
|
||||
while (!parentMaterialPath.empty())
|
||||
{
|
||||
MaterialSourceData parentMaterialSourceData;
|
||||
if (!AZ::RPI::JsonUtils::LoadObjectFromFile(parentMaterialSourcePath, parentMaterialSourceData))
|
||||
{
|
||||
return Failure();
|
||||
}
|
||||
|
||||
// Make sure the parent material has the same material type
|
||||
auto materialTypeIdOutcome1 = AssetUtils::MakeAssetId(materialSourceFilePath, m_materialType, 0);
|
||||
auto materialTypeIdOutcome2 = AssetUtils::MakeAssetId(parentMaterialSourcePath, parentMaterialSourceData.m_materialType, 0);
|
||||
if (!materialTypeIdOutcome1.IsSuccess() || !materialTypeIdOutcome2.IsSuccess() ||
|
||||
materialTypeIdOutcome1.GetValue() != materialTypeIdOutcome2.GetValue())
|
||||
{
|
||||
AZ_Error("MaterialSourceData", false, "This material and its parent material do not share the same material type.");
|
||||
return Failure();
|
||||
}
|
||||
|
||||
parentMaterialPath = parentMaterialSourceData.m_parentMaterial;
|
||||
parentMaterialSourcePath = AssetUtils::ResolvePathReference(parentMaterialSourcePath, parentMaterialPath);
|
||||
parentMaterialSourceDataVec.push_back(parentMaterialSourceData);
|
||||
}
|
||||
|
||||
AZStd::reverse(parentMaterialSourceDataVec.begin(), parentMaterialSourceDataVec.end());
|
||||
for (const auto& parentMaterialSourceData : parentMaterialSourceDataVec)
|
||||
{
|
||||
ApplyMaterialSourceDataPropertiesToAssetCreator(materialAssetCreator, materialSourceFilePath, parentMaterialSourceData);
|
||||
}
|
||||
|
||||
ApplyMaterialSourceDataPropertiesToAssetCreator(materialAssetCreator, materialSourceFilePath, *this);
|
||||
|
||||
Data::Asset<MaterialAsset> material;
|
||||
if (materialAssetCreator.End(material))
|
||||
{
|
||||
return Success(material);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Failure();
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialSourceData::ApplyMaterialSourceDataPropertiesToAssetCreator(
|
||||
AZ::RPI::MaterialAssetCreator& materialAssetCreator,
|
||||
const AZStd::string_view& materialSourceFilePath,
|
||||
const MaterialSourceData& materialSourceData)
|
||||
{
|
||||
for (auto& group : materialSourceData.m_properties)
|
||||
{
|
||||
for (auto& property : group.second)
|
||||
{
|
||||
MaterialPropertyId propertyId{ group.first, property.first };
|
||||
if (!property.second.m_value.IsValid())
|
||||
{
|
||||
AZ_Warning("Material source data", false, "Source data for material property value is invalid.");
|
||||
}
|
||||
else
|
||||
{
|
||||
MaterialPropertyIndex propertyIndex =
|
||||
materialAssetCreator.m_materialPropertiesLayout->FindPropertyIndex(propertyId.GetFullName());
|
||||
if (propertyIndex.IsValid())
|
||||
{
|
||||
const MaterialPropertyDescriptor* propertyDescriptor =
|
||||
materialAssetCreator.m_materialPropertiesLayout->GetPropertyDescriptor(propertyIndex);
|
||||
switch (propertyDescriptor->GetDataType())
|
||||
{
|
||||
case MaterialPropertyDataType::Image:
|
||||
{
|
||||
Outcome<Data::Asset<ImageAsset>> imageAssetResult = MaterialUtils::GetImageAssetReference(
|
||||
materialSourceFilePath, property.second.m_value.GetValue<AZStd::string>());
|
||||
|
||||
if (imageAssetResult.IsSuccess())
|
||||
{
|
||||
auto& imageAsset = imageAssetResult.GetValue();
|
||||
// Load referenced images when load material
|
||||
imageAsset.SetAutoLoadBehavior(Data::AssetLoadBehavior::PreLoad);
|
||||
materialAssetCreator.SetPropertyValue(propertyId.GetFullName(), imageAsset);
|
||||
}
|
||||
else
|
||||
{
|
||||
materialAssetCreator.ReportError(
|
||||
"Material property '%s': Could not find the image '%s'", propertyId.GetFullName().GetCStr(),
|
||||
property.second.m_value.GetValue<AZStd::string>().data());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MaterialPropertyDataType::Enum:
|
||||
{
|
||||
AZ::Name enumName = AZ::Name(property.second.m_value.GetValue<AZStd::string>());
|
||||
uint32_t enumValue = propertyDescriptor->GetEnumValue(enumName);
|
||||
if (enumValue == MaterialPropertyDescriptor::InvalidEnumValue)
|
||||
{
|
||||
materialAssetCreator.ReportError(
|
||||
"Enum value '%s' couldn't be found in the 'enumValues' list", enumName.GetCStr());
|
||||
}
|
||||
else
|
||||
{
|
||||
materialAssetCreator.SetPropertyValue(propertyId.GetFullName(), enumValue);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
materialAssetCreator.SetPropertyValue(propertyId.GetFullName(), property.second.m_value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
materialAssetCreator.ReportWarning(
|
||||
"Can not find property id '%s' in MaterialPropertyLayout", propertyId.GetFullName().GetStringView().data());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace RPI
|
||||
} // namespace AZ
|
||||
|
||||
@@ -43,6 +43,7 @@ namespace AZ
|
||||
return false;
|
||||
}
|
||||
|
||||
m_asset->PostLoadInit();
|
||||
m_asset->SetReady();
|
||||
|
||||
m_materialShaderResourceGroupLayout = nullptr;
|
||||
|
||||
@@ -722,7 +722,7 @@ namespace MaterialEditor
|
||||
// we can create the asset dynamically from the source data.
|
||||
// Long term, the material document should not be concerned with assets at all. The viewport window should be the
|
||||
// only thing concerned with assets or instances.
|
||||
auto createResult = m_materialSourceData.CreateMaterialAsset(Uuid::CreateRandom(), m_absolutePath, true);
|
||||
auto createResult = m_materialSourceData.CreateMaterialAssetFromSourceData(Uuid::CreateRandom(), m_absolutePath, true);
|
||||
if (!createResult)
|
||||
{
|
||||
AZ_Error("MaterialDocument", false, "Material asset could not be created from source data: '%s'.", m_absolutePath.c_str());
|
||||
|
||||
Reference in New Issue
Block a user