From 55eb85d5460523b60196df4eaa9b2d833a886735 Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Sat, 18 Sep 2021 23:57:52 -0700 Subject: [PATCH 01/20] Updated MaterialPropertyId class in preparation for nested material property sets. Here the class has been generalized for a list of group names and a final property name, rather than assuming a single group containing the property. This included removing the unused GetPropertyName and GetGroupName functions. All that's really need from this class is conversion to a full property ID string. Testing: New unit test. Reprocessed all core material types and StandardPBR test materials used in Atom Sample Viewer's material screenshot test. Atom Sample Viewer material screenshot test script. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../RPI.Edit/Material/MaterialPropertyId.h | 18 +-- .../RPI.Edit/Material/MaterialPropertyId.cpp | 79 +++++++---- .../RPI.Edit/Material/MaterialSourceData.cpp | 12 +- .../Material/MaterialTypeSourceData.cpp | 12 +- .../Material/MaterialPropertyIdTests.cpp | 131 ++++++++++++++++++ Gems/Atom/RPI/Code/atom_rpi_tests_files.cmake | 1 + .../Code/Source/Document/MaterialDocument.cpp | 8 +- .../MaterialInspector/MaterialInspector.cpp | 4 +- .../EditorMaterialComponentInspector.cpp | 2 +- .../Material/EditorMaterialComponentUtil.cpp | 4 +- .../EditorMaterialModelUvNameMapInspector.cpp | 4 +- 11 files changed, 214 insertions(+), 61 deletions(-) create mode 100644 Gems/Atom/RPI/Code/Tests/Material/MaterialPropertyIdTests.cpp diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialPropertyId.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialPropertyId.h index 77d49f3407..4b6d78c092 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialPropertyId.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialPropertyId.h @@ -9,6 +9,7 @@ #pragma once #include +#include namespace AZ { @@ -16,27 +17,28 @@ namespace AZ { class MaterialAsset; - //! Utility for building material property names consisting of a group name and a property sub-name. - //! Represented as "[groupName].[propertyName]". - //! The group name is optional, in which case the ID will just be "[propertyName]". + //! Utility for building material property IDs. + //! These IDs are represented like "groupA.groupB.[...].propertyName". + //! The groups are optional, in which case the full property ID will just be like "propertyName". class MaterialPropertyId { public: static bool IsValidName(AZStd::string_view name); static bool IsValidName(const AZ::Name& name); - //! Creates a MaterialPropertyId from a full name string like "[groupName].[propertyName]" or just "[propertyName]" + //! Creates a MaterialPropertyId from a full name string like "groupA.groupB.[...].propertyName" or just "propertyName". + //! Also checks the name for validity. static MaterialPropertyId Parse(AZStd::string_view fullPropertyId); MaterialPropertyId() = default; + explicit MaterialPropertyId(AZStd::string_view propertyName); MaterialPropertyId(AZStd::string_view groupName, AZStd::string_view propertyName); MaterialPropertyId(const Name& groupName, const Name& propertyName); + MaterialPropertyId(const AZStd::array_view names); AZ_DEFAULT_COPY_MOVE(MaterialPropertyId); - const Name& GetGroupName() const; - const Name& GetPropertyName() const; - const Name& GetFullName() const; + operator const Name&() const; //! Returns a pointer to the full name ("[groupName].[propertyName]"). //! This is included for convenience so it can be used for error messages in the same way an AZ::Name is used. @@ -52,8 +54,6 @@ namespace AZ private: Name m_fullName; - Name m_groupName; - Name m_propertyName; }; } // namespace RPI diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyId.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyId.cpp index e74ec3e6e0..1be5c4485c 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyId.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyId.cpp @@ -27,63 +27,84 @@ namespace AZ bool MaterialPropertyId::IsValid() const { - const bool groupNameIsValid = m_groupName.IsEmpty() || IsValidName(m_groupName); - const bool propertyNameIsValid = IsValidName(m_propertyName); - return groupNameIsValid && propertyNameIsValid; + return !m_fullName.IsEmpty(); } MaterialPropertyId MaterialPropertyId::Parse(AZStd::string_view fullPropertyId) { AZStd::vector tokens; - AzFramework::StringFunc::Tokenize(fullPropertyId.data(), tokens, '.', true, true); + AzFramework::StringFunc::Tokenize(fullPropertyId, tokens, '.', true, true); - if (tokens.size() == 1) + if (tokens.empty()) { - return MaterialPropertyId{"", tokens[0]}; + AZ_Error("MaterialPropertyId", false, "Property ID is empty.", fullPropertyId.data()); + return MaterialPropertyId{}; } - else if (tokens.size() == 2) + + for (const auto& token : tokens) + { + if (!IsValidName(token)) + { + AZ_Error("MaterialPropertyId", false, "Property ID '%.*s' is not a valid identifier.", AZ_STRING_ARG(fullPropertyId)); + return MaterialPropertyId{}; + } + } + + MaterialPropertyId id; + id.m_fullName = fullPropertyId; + return id; + } + + MaterialPropertyId::MaterialPropertyId(AZStd::string_view propertyName) + { + if (!IsValidName(propertyName)) { - return MaterialPropertyId{tokens[0], tokens[1]}; + AZ_Error("MaterialPropertyId", false, "Property name '%.*s' is not a valid identifier.", AZ_STRING_ARG(propertyName)); } else { - AZ_Error("MaterialPropertyId", false, "Property ID '%s' is not a valid identifier.", fullPropertyId.data()); - return MaterialPropertyId{}; + m_fullName = propertyName; } } MaterialPropertyId::MaterialPropertyId(AZStd::string_view groupName, AZStd::string_view propertyName) - : MaterialPropertyId(Name{groupName}, Name{propertyName}) - { - } - - MaterialPropertyId::MaterialPropertyId(const Name& groupName, const Name& propertyName) { - AZ_Error("MaterialPropertyId", groupName.IsEmpty() || IsValidName(groupName), "Group name '%s' is not a valid identifier.", groupName.GetCStr()); - AZ_Error("MaterialPropertyId", IsValidName(propertyName), "Property name '%s' is not a valid identifier.", propertyName.GetCStr()); - m_groupName = groupName; - m_propertyName = propertyName; - if (groupName.IsEmpty()) + if (!IsValidName(groupName)) { - m_fullName = m_propertyName.GetStringView(); + AZ_Error("MaterialPropertyId", false, "Group name '%.*s' is not a valid identifier.", AZ_STRING_ARG(groupName)); + } + else if (!IsValidName(propertyName)) + { + AZ_Error("MaterialPropertyId", false, "Property name '%.*s' is not a valid identifier.", AZ_STRING_ARG(propertyName)); } else { - m_fullName = AZStd::string::format("%s.%s", m_groupName.GetCStr(), m_propertyName.GetCStr()); + m_fullName = AZStd::string::format("%.*s.%.*s", AZ_STRING_ARG(groupName), AZ_STRING_ARG(propertyName)); } } - - const Name& MaterialPropertyId::GetGroupName() const + + MaterialPropertyId::MaterialPropertyId(const Name& groupName, const Name& propertyName) + : MaterialPropertyId(groupName.GetStringView(), propertyName.GetStringView()) { - return m_groupName; } - - const Name& MaterialPropertyId::GetPropertyName() const + + MaterialPropertyId::MaterialPropertyId(const AZStd::array_view names) { - return m_propertyName; + for (const auto& name : names) + { + if (!IsValidName(name)) + { + AZ_Error("MaterialPropertyId", false, "'%s' is not a valid identifier.", name.c_str()); + return; + } + } + + AZStd::string fullName; + AzFramework::StringFunc::Join(fullName, names.begin(), names.end(), "."); + m_fullName = fullName; } - const Name& MaterialPropertyId::GetFullName() const + MaterialPropertyId::operator const Name&() const { return m_fullName; } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp index f697f33a3f..b48d0938a7 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp @@ -130,7 +130,7 @@ namespace AZ } else { - MaterialPropertyIndex propertyIndex = materialAssetCreator.m_materialPropertiesLayout->FindPropertyIndex(propertyId.GetFullName()); + MaterialPropertyIndex propertyIndex = materialAssetCreator.m_materialPropertiesLayout->FindPropertyIndex(propertyId); if (propertyIndex.IsValid()) { const MaterialPropertyDescriptor* propertyDescriptor = materialAssetCreator.m_materialPropertiesLayout->GetPropertyDescriptor(propertyIndex); @@ -145,11 +145,11 @@ namespace AZ auto& imageAsset = imageAssetResult.GetValue(); // Load referenced images when load material imageAsset.SetAutoLoadBehavior(Data::AssetLoadBehavior::PreLoad); - materialAssetCreator.SetPropertyValue(propertyId.GetFullName(), imageAsset); + materialAssetCreator.SetPropertyValue(propertyId, imageAsset); } else { - materialAssetCreator.ReportError("Material property '%s': Could not find the image '%s'", propertyId.GetFullName().GetCStr(), property.second.m_value.GetValue().data()); + materialAssetCreator.ReportError("Material property '%s': Could not find the image '%s'", propertyId.GetCStr(), property.second.m_value.GetValue().data()); } } break; @@ -163,18 +163,18 @@ namespace AZ } else { - materialAssetCreator.SetPropertyValue(propertyId.GetFullName(), enumValue); + materialAssetCreator.SetPropertyValue(propertyId, enumValue); } } break; default: - materialAssetCreator.SetPropertyValue(propertyId.GetFullName(), property.second.m_value); + materialAssetCreator.SetPropertyValue(propertyId, property.second.m_value); break; } } else { - materialAssetCreator.ReportWarning("Can not find property id '%s' in MaterialPropertyLayout", propertyId.GetFullName().GetStringView().data()); + materialAssetCreator.ReportWarning("Can not find property id '%s' in MaterialPropertyLayout", propertyId.GetCStr()); } } } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp index a13a8df16e..7134830fe8 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp @@ -354,7 +354,7 @@ namespace AZ continue; } - materialTypeAssetCreator.BeginMaterialProperty(propertyId.GetFullName(), property.m_dataType); + materialTypeAssetCreator.BeginMaterialProperty(propertyId, property.m_dataType); if (property.m_dataType == MaterialPropertyDataType::Enum) { @@ -404,17 +404,17 @@ namespace AZ if (imageAssetResult.IsSuccess()) { - materialTypeAssetCreator.SetPropertyValue(propertyId.GetFullName(), imageAssetResult.GetValue()); + materialTypeAssetCreator.SetPropertyValue(propertyId, imageAssetResult.GetValue()); } else { - materialTypeAssetCreator.ReportError("Material property '%s': Could not find the image '%s'", propertyId.GetFullName().GetCStr(), property.m_value.GetValue().data()); + materialTypeAssetCreator.ReportError("Material property '%s': Could not find the image '%s'", propertyId.GetCStr(), property.m_value.GetValue().data()); } } break; case MaterialPropertyDataType::Enum: { - MaterialPropertyIndex propertyIndex = materialTypeAssetCreator.GetMaterialPropertiesLayout()->FindPropertyIndex(propertyId.GetFullName()); + MaterialPropertyIndex propertyIndex = materialTypeAssetCreator.GetMaterialPropertiesLayout()->FindPropertyIndex(propertyId); const MaterialPropertyDescriptor* propertyDescriptor = materialTypeAssetCreator.GetMaterialPropertiesLayout()->GetPropertyDescriptor(propertyIndex); AZ::Name enumName = AZ::Name(property.m_value.GetValue()); @@ -425,12 +425,12 @@ namespace AZ } else { - materialTypeAssetCreator.SetPropertyValue(propertyId.GetFullName(), enumValue); + materialTypeAssetCreator.SetPropertyValue(propertyId, enumValue); } } break; default: - materialTypeAssetCreator.SetPropertyValue(propertyId.GetFullName(), property.m_value); + materialTypeAssetCreator.SetPropertyValue(propertyId, property.m_value); break; } } diff --git a/Gems/Atom/RPI/Code/Tests/Material/MaterialPropertyIdTests.cpp b/Gems/Atom/RPI/Code/Tests/Material/MaterialPropertyIdTests.cpp new file mode 100644 index 0000000000..2b729ed8ef --- /dev/null +++ b/Gems/Atom/RPI/Code/Tests/Material/MaterialPropertyIdTests.cpp @@ -0,0 +1,131 @@ +/* + * 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 +#include +#include +#include + +namespace UnitTest +{ + using namespace AZ; + using namespace RPI; + + class MaterialPropertyIdTests + : public RPITestFixture + { + }; + + TEST_F(MaterialPropertyIdTests, TestConstructWithPropertyName) + { + MaterialPropertyId id{"color"}; + EXPECT_TRUE(id.IsValid()); + EXPECT_STREQ(id.GetCStr(), "color"); + AZ::Name idCastedToName = id; + EXPECT_EQ(idCastedToName, AZ::Name{"color"}); + } + + TEST_F(MaterialPropertyIdTests, TestConstructWithPropertyName_BadName) + { + ErrorMessageFinder errorMessageFinder; + errorMessageFinder.AddExpectedErrorMessage("not a valid identifier"); + + MaterialPropertyId id{"color?"}; + EXPECT_FALSE(id.IsValid()); + + errorMessageFinder.CheckExpectedErrorsFound(); + } + + TEST_F(MaterialPropertyIdTests, TestConstructWithTwoNames) + { + MaterialPropertyId id{"baseColor", "factor"}; + EXPECT_TRUE(id.IsValid()); + EXPECT_STREQ(id.GetCStr(), "baseColor.factor"); + AZ::Name idCastedToName = id; + EXPECT_EQ(idCastedToName, AZ::Name{"baseColor.factor"}); + } + + TEST_F(MaterialPropertyIdTests, TestConstructWithTwoNames_BadGroupName) + { + ErrorMessageFinder errorMessageFinder; + errorMessageFinder.AddExpectedErrorMessage("not a valid identifier"); + + MaterialPropertyId id{"layer1.baseColor", "factor"}; + EXPECT_FALSE(id.IsValid()); + + errorMessageFinder.CheckExpectedErrorsFound(); + } + + TEST_F(MaterialPropertyIdTests, TestConstructWithTwoNames_BadPropertyName) + { + ErrorMessageFinder errorMessageFinder; + errorMessageFinder.AddExpectedErrorMessage("not a valid identifier"); + + MaterialPropertyId id{"baseColor", ".factor"}; + EXPECT_FALSE(id.IsValid()); + + errorMessageFinder.CheckExpectedErrorsFound(); + } + + TEST_F(MaterialPropertyIdTests, TestConstructWithMultipleNames) + { + AZStd::vector names{"layer1", "clearCoat", "normal", "factor"}; + MaterialPropertyId id{names}; + EXPECT_TRUE(id.IsValid()); + EXPECT_STREQ(id.GetCStr(), "layer1.clearCoat.normal.factor"); + AZ::Name idCastedToName = id; + EXPECT_EQ(idCastedToName, AZ::Name{"layer1.clearCoat.normal.factor"}); + } + + TEST_F(MaterialPropertyIdTests, TestConstructWithMultipleNames_BadName) + { + ErrorMessageFinder errorMessageFinder; + errorMessageFinder.AddExpectedErrorMessage("not a valid identifier"); + + AZStd::vector names{"layer1", "clear-coat", "normal", "factor"}; + MaterialPropertyId id{names}; + EXPECT_FALSE(id.IsValid()); + + errorMessageFinder.CheckExpectedErrorsFound(); + } + + TEST_F(MaterialPropertyIdTests, TestParse) + { + MaterialPropertyId id = MaterialPropertyId::Parse("layer1.clearCoat.normal.factor"); + EXPECT_TRUE(id.IsValid()); + EXPECT_STREQ(id.GetCStr(), "layer1.clearCoat.normal.factor"); + AZ::Name idCastedToName = id; + EXPECT_EQ(idCastedToName, AZ::Name{"layer1.clearCoat.normal.factor"}); + } + + TEST_F(MaterialPropertyIdTests, TestParse_BadName) + { + ErrorMessageFinder errorMessageFinder; + errorMessageFinder.AddExpectedErrorMessage("not a valid identifier"); + + MaterialPropertyId id = MaterialPropertyId::Parse("layer1.clearCoat.normal,factor"); + EXPECT_FALSE(id.IsValid()); + + errorMessageFinder.CheckExpectedErrorsFound(); + } + + TEST_F(MaterialPropertyIdTests, TestNameValidity) + { + EXPECT_TRUE(MaterialPropertyId::IsValidName("a")); + EXPECT_TRUE(MaterialPropertyId::IsValidName("z")); + EXPECT_TRUE(MaterialPropertyId::IsValidName("A")); + EXPECT_TRUE(MaterialPropertyId::IsValidName("Z")); + EXPECT_TRUE(MaterialPropertyId::IsValidName("_")); + EXPECT_TRUE(MaterialPropertyId::IsValidName("m_layer10bazBAZ")); + EXPECT_FALSE(MaterialPropertyId::IsValidName("")); + EXPECT_FALSE(MaterialPropertyId::IsValidName("1layer")); + EXPECT_FALSE(MaterialPropertyId::IsValidName("base-color")); + EXPECT_FALSE(MaterialPropertyId::IsValidName("base.color")); + EXPECT_FALSE(MaterialPropertyId::IsValidName("base/color")); + } +} diff --git a/Gems/Atom/RPI/Code/atom_rpi_tests_files.cmake b/Gems/Atom/RPI/Code/atom_rpi_tests_files.cmake index e99e4e456b..923fdc9338 100644 --- a/Gems/Atom/RPI/Code/atom_rpi_tests_files.cmake +++ b/Gems/Atom/RPI/Code/atom_rpi_tests_files.cmake @@ -39,6 +39,7 @@ set(FILES Tests/Material/MaterialSourceDataTests.cpp Tests/Material/MaterialFunctorTests.cpp Tests/Material/MaterialFunctorSourceDataSerializerTests.cpp + Tests/Material/MaterialPropertyIdTests.cpp Tests/Material/MaterialPropertyValueSourceDataTests.cpp Tests/Material/MaterialTests.cpp Tests/Model/ModelTests.cpp diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp index 17e292ac16..3f4aa71a9c 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp @@ -596,7 +596,7 @@ namespace MaterialEditor const MaterialPropertyId propertyId(groupName, propertyName); - const auto it = m_properties.find(propertyId.GetFullName()); + const auto it = m_properties.find(propertyId); if (it != m_properties.end() && propertyFilter(it->second)) { MaterialPropertyValue propertyValue = AtomToolsFramework::ConvertToRuntimeType(it->second.GetValue()); @@ -604,7 +604,7 @@ namespace MaterialEditor { if (!m_materialTypeSourceData.ConvertPropertyValueToSourceDataFormat(propertyDefinition, propertyValue)) { - AZ_Error("MaterialDocument", false, "Material document property could not be converted: '%s' in '%s'.", propertyId.GetFullName().GetCStr(), m_absolutePath.c_str()); + AZ_Error("MaterialDocument", false, "Material document property could not be converted: '%s' in '%s'.", propertyId.GetCStr(), m_absolutePath.c_str()); result = false; return false; } @@ -774,7 +774,7 @@ namespace MaterialEditor AtomToolsFramework::DynamicPropertyConfig propertyConfig; // Assign id before conversion so it can be used in dynamic description - propertyConfig.m_id = MaterialPropertyId(groupName, propertyName).GetCStr(); + propertyConfig.m_id = MaterialPropertyId(groupName, propertyName); const auto& propertyIndex = m_materialAsset->GetMaterialPropertiesLayout()->FindPropertyIndex(propertyConfig.m_id); const bool propertyIndexInBounds = propertyIndex.IsValid() && propertyIndex.GetIndex() < m_materialAsset->GetPropertyValues().size(); @@ -845,7 +845,7 @@ namespace MaterialEditor propertyConfig = {}; propertyConfig.m_dataType = AtomToolsFramework::DynamicPropertyType::String; - propertyConfig.m_id = MaterialPropertyId(UvGroupName, shaderInput).GetCStr(); + propertyConfig.m_id = MaterialPropertyId(UvGroupName, shaderInput); propertyConfig.m_name = shaderInput; propertyConfig.m_displayName = shaderInput; propertyConfig.m_groupName = "UV Sets"; diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.cpp index df0b179dc1..f6b42bf13a 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.cpp @@ -145,7 +145,7 @@ namespace MaterialEditor AtomToolsFramework::DynamicProperty property; AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult( property, m_documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::GetProperty, - AZ::RPI::MaterialPropertyId(groupName, uvNamePair.m_shaderInput.ToString()).GetFullName()); + AZ::RPI::MaterialPropertyId(groupName, uvNamePair.m_shaderInput.ToString())); group.m_properties.push_back(property); property.SetValue(property.GetConfig().m_parentValue); @@ -182,7 +182,7 @@ namespace MaterialEditor AtomToolsFramework::DynamicProperty property; AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult( property, m_documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::GetProperty, - AZ::RPI::MaterialPropertyId(groupName, propertyDefinition.m_name).GetFullName()); + AZ::RPI::MaterialPropertyId(groupName, propertyDefinition.m_name)); group.m_properties.push_back(property); } } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp index f10a125456..c05b84db39 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp @@ -300,7 +300,7 @@ namespace AZ AtomToolsFramework::DynamicPropertyConfig propertyConfig; // Assign id before conversion so it can be used in dynamic description - propertyConfig.m_id = AZ::RPI::MaterialPropertyId(groupName, propertyDefinition.m_name).GetFullName(); + propertyConfig.m_id = AZ::RPI::MaterialPropertyId(groupName, propertyDefinition.m_name); AtomToolsFramework::ConvertToPropertyConfig(propertyConfig, propertyDefinition); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp index 070c42fd7c..e851bc5fce 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp @@ -140,7 +140,7 @@ namespace AZ editData.m_materialTypeSourceData.EnumerateProperties([&](const AZStd::string& groupName, const AZStd::string& propertyName, const auto& propertyDefinition) { const AZ::RPI::MaterialPropertyId propertyId(groupName, propertyName); const AZ::RPI::MaterialPropertyIndex propertyIndex = - editData.m_materialAsset->GetMaterialPropertiesLayout()->FindPropertyIndex(propertyId.GetFullName()); + editData.m_materialAsset->GetMaterialPropertiesLayout()->FindPropertyIndex(propertyId); AZ::RPI::MaterialPropertyValue propertyValue = editData.m_materialAsset->GetPropertyValues()[propertyIndex.GetIndex()]; @@ -151,7 +151,7 @@ namespace AZ } // Check for and apply any property overrides before saving property values - auto propertyOverrideItr = editData.m_materialPropertyOverrideMap.find(propertyId.GetFullName()); + auto propertyOverrideItr = editData.m_materialPropertyOverrideMap.find(propertyId); if(propertyOverrideItr != editData.m_materialPropertyOverrideMap.end()) { propertyValue = AZ::RPI::MaterialPropertyValue::FromAny(propertyOverrideItr->second); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialModelUvNameMapInspector.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialModelUvNameMapInspector.cpp index 64bc54bae8..1fa6a4e58d 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialModelUvNameMapInspector.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialModelUvNameMapInspector.cpp @@ -96,7 +96,7 @@ namespace AZ const AZStd::string materialUvName = m_materialUvNames[i].m_uvName.GetStringView(); propertyConfig.m_dataType = AtomToolsFramework::DynamicPropertyType::Enum; - propertyConfig.m_id = AZ::RPI::MaterialPropertyId(groupName, shaderInput).GetFullName(); + propertyConfig.m_id = AZ::RPI::MaterialPropertyId(groupName, shaderInput); propertyConfig.m_name = shaderInput; propertyConfig.m_displayName = materialUvName; propertyConfig.m_description = shaderInput; @@ -248,7 +248,7 @@ namespace AZ const AZStd::string materialUvName = m_materialUvNames[i].m_uvName.GetStringView(); propertyConfig.m_dataType = AtomToolsFramework::DynamicPropertyType::Enum; - propertyConfig.m_id = AZ::RPI::MaterialPropertyId(groupName, shaderInput).GetFullName(); + propertyConfig.m_id = AZ::RPI::MaterialPropertyId(groupName, shaderInput); propertyConfig.m_name = shaderInput; propertyConfig.m_displayName = materialUvName; propertyConfig.m_description = shaderInput; From f0e8af72aed61a6163aa88d741c98480f27d4e5c Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Thu, 30 Sep 2021 01:08:54 -0700 Subject: [PATCH 02/20] Updated StringFunc::Tokenize to support returning a list of string_view instead of string, which should be more efficient. string is still supported as well, but users should prefer the string_view version. Testing: Updated unit tests. Reprocessed Atom material assets. Ran AtomSampleViewer material screenshot test. Opened, edited, saved materail in the Material Editor. Opened a level, edited material property overrides, saved and reloaded. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../AzCore/AzCore/StringFunc/StringFunc.cpp | 24 ++++++++++---- .../AzCore/AzCore/StringFunc/StringFunc.h | 12 ++++--- Code/Framework/AzCore/Tests/StringFunc.cpp | 31 +++++++++++++++---- 3 files changed, 51 insertions(+), 16 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/StringFunc/StringFunc.cpp b/Code/Framework/AzCore/AzCore/StringFunc/StringFunc.cpp index ff30291a70..eec23b6bcb 100644 --- a/Code/Framework/AzCore/AzCore/StringFunc/StringFunc.cpp +++ b/Code/Framework/AzCore/AzCore/StringFunc/StringFunc.cpp @@ -759,13 +759,18 @@ namespace AZ } return value; } - - void Tokenize(AZStd::string_view in, AZStd::vector& tokens, const char delimiter, bool keepEmptyStrings, bool keepSpaceStrings) + + template + void Tokenize(AZStd::string_view in, AZStd::vector& tokens, const char delimiter, bool keepEmptyStrings, bool keepSpaceStrings) { return Tokenize(in, tokens, { &delimiter, 1 }, keepEmptyStrings, keepSpaceStrings); } - void Tokenize(AZStd::string_view in, AZStd::vector& tokens, AZStd::string_view delimiters, bool keepEmptyStrings, bool keepSpaceStrings) + template void Tokenize(AZStd::string_view in, AZStd::vector& tokens, const char delimiter, bool keepEmptyStrings, bool keepSpaceStrings); + template void Tokenize(AZStd::string_view in, AZStd::vector& tokens, const char delimiter, bool keepEmptyStrings, bool keepSpaceStrings); + + template + void Tokenize(AZStd::string_view in, AZStd::vector& tokens, AZStd::string_view delimiters, bool keepEmptyStrings, bool keepSpaceStrings) { auto insertVisitor = [&tokens](AZStd::string_view token) { @@ -773,6 +778,9 @@ namespace AZ }; return TokenizeVisitor(in, insertVisitor, delimiters, keepEmptyStrings, keepSpaceStrings); } + + template void Tokenize(AZStd::string_view in, AZStd::vector& tokens, AZStd::string_view delimiters, bool keepEmptyStrings, bool keepSpaceStrings); + template void Tokenize(AZStd::string_view in, AZStd::vector& tokens, AZStd::string_view delimiters, bool keepEmptyStrings, bool keepSpaceStrings); void TokenizeVisitor(AZStd::string_view in, const TokenVisitor& tokenVisitor, const char delimiter, bool keepEmptyStrings, bool keepSpaceStrings) { @@ -920,8 +928,9 @@ namespace AZ return found; } - - void Tokenize(AZStd::string_view input, AZStd::vector& tokens, const AZStd::vector& delimiters, bool keepEmptyStrings /*= false*/, bool keepSpaceStrings /*= false*/) + + template + void Tokenize(AZStd::string_view input, AZStd::vector& tokens, const AZStd::vector& delimiters, bool keepEmptyStrings /*= false*/, bool keepSpaceStrings /*= false*/) { if (input.empty()) { @@ -941,7 +950,7 @@ namespace AZ } // Take the substring, not including the separator, and increment our offset - AZStd::string nextSubstring = input.substr(offset, nextOffset - offset); + AZStd::string_view nextSubstring = input.substr(offset, nextOffset - offset); if (keepEmptyStrings || keepSpaceStrings || !nextSubstring.empty()) { tokens.push_back(nextSubstring); @@ -950,6 +959,9 @@ namespace AZ offset = nextOffset + delimiters[nextMatch].size(); } } + + template void Tokenize(AZStd::string_view input, AZStd::vector& tokens, const AZStd::vector& delimiters, bool keepEmptyStrings /*= false*/, bool keepSpaceStrings /*= false*/); + template void Tokenize(AZStd::string_view input, AZStd::vector& tokens, const AZStd::vector& delimiters, bool keepEmptyStrings /*= false*/, bool keepSpaceStrings /*= false*/); int ToInt(const char* in) { diff --git a/Code/Framework/AzCore/AzCore/StringFunc/StringFunc.h b/Code/Framework/AzCore/AzCore/StringFunc/StringFunc.h index 1e651afc93..51357312bc 100644 --- a/Code/Framework/AzCore/AzCore/StringFunc/StringFunc.h +++ b/Code/Framework/AzCore/AzCore/StringFunc/StringFunc.h @@ -258,17 +258,21 @@ namespace AZ bool Strip(AZStd::string& inout, const char* stripCharacters = " ", bool bCaseSensitive = false, bool bStripBeginning = false, bool bStripEnding = false); //! Tokenize - /*! Tokenize a c-string, into a vector of AZStd::string(s) optionally keeping empty string + /*! Tokenize a c-string, into a vector of strings optionally keeping empty string *! and optionally keeping space only strings + *! (The string type may be AZStd::string or AZStd::string_view. New code should use AZStd::string_view for better performance. AZStd::string version is preserved for compatibility.) Example: Tokenize the words of a sentence. StringFunc::Tokenize("Hello World", d, ' '); s[0] == "Hello", s[1] == "World" Example: Tokenize a comma and end line delimited string StringFunc::Tokenize("Hello,World\nHello,World", d, ' '); s[0] == "Hello", s[1] == "World" s[2] == "Hello", s[3] == "World" */ - void Tokenize(AZStd::string_view in, AZStd::vector& tokens, const char delimiter, bool keepEmptyStrings = false, bool keepSpaceStrings = false); - void Tokenize(AZStd::string_view in, AZStd::vector& tokens, AZStd::string_view delimiters = "\\//, \t\n", bool keepEmptyStrings = false, bool keepSpaceStrings = false); - void Tokenize(AZStd::string_view in, AZStd::vector& tokens, const AZStd::vector& delimiters, bool keepEmptyStrings = false, bool keepSpaceStrings = false); + template + void Tokenize(AZStd::string_view in, AZStd::vector& tokens, const char delimiter, bool keepEmptyStrings = false, bool keepSpaceStrings = false); + template + void Tokenize(AZStd::string_view in, AZStd::vector& tokens, AZStd::string_view delimiters = "\\//, \t\n", bool keepEmptyStrings = false, bool keepSpaceStrings = false); + template + void Tokenize(AZStd::string_view in, AZStd::vector& tokens, const AZStd::vector& delimiters, bool keepEmptyStrings = false, bool keepSpaceStrings = false); //! TokenizeVisitor /*! Tokenize a string_view and invoke a handler for each token found. diff --git a/Code/Framework/AzCore/Tests/StringFunc.cpp b/Code/Framework/AzCore/Tests/StringFunc.cpp index 68821ba3f9..79dabe3462 100644 --- a/Code/Framework/AzCore/Tests/StringFunc.cpp +++ b/Code/Framework/AzCore/Tests/StringFunc.cpp @@ -199,7 +199,7 @@ namespace AZ TEST_F(StringFuncTest, Tokenize_SingleDelimeter_Empty) { AZStd::string input = ""; - AZStd::vector tokens; + AZStd::vector tokens; AZ::StringFunc::Tokenize(input.c_str(), tokens, ' '); ASSERT_EQ(tokens.size(), 0); } @@ -207,7 +207,7 @@ namespace AZ TEST_F(StringFuncTest, Tokenize_SingleDelimeter) { AZStd::string input = "a b,c"; - AZStd::vector tokens; + AZStd::vector tokens; AZ::StringFunc::Tokenize(input.c_str(), tokens, ' '); ASSERT_EQ(tokens.size(), 2); @@ -218,7 +218,7 @@ namespace AZ TEST_F(StringFuncTest, Tokenize_MultiDelimeter_Empty) { AZStd::string input = ""; - AZStd::vector tokens; + AZStd::vector tokens; AZ::StringFunc::Tokenize(input.c_str(), tokens, " ,"); ASSERT_EQ(tokens.size(), 0); } @@ -226,7 +226,7 @@ namespace AZ TEST_F(StringFuncTest, Tokenize_MultiDelimeters) { AZStd::string input = " -a +b +c -d-e"; - AZStd::vector tokens; + AZStd::vector tokens; AZ::StringFunc::Tokenize(input.c_str(), tokens, "-+"); ASSERT_EQ(tokens.size(), 5); @@ -240,7 +240,7 @@ namespace AZ TEST_F(StringFuncTest, Tokenize_SubstringDelimeters_Empty) { AZStd::string input = ""; - AZStd::vector tokens; + AZStd::vector tokens; AZStd::vector delimeters = {" -", " +"}; AZ::StringFunc::Tokenize(input.c_str(), tokens, delimeters); ASSERT_EQ(tokens.size(), 0); @@ -249,7 +249,7 @@ namespace AZ TEST_F(StringFuncTest, Tokenize_SubstringDelimeters) { AZStd::string input = " -a +b +c -d-e"; - AZStd::vector tokens; + AZStd::vector tokens; AZStd::vector delimeters = { " -", " +" }; AZ::StringFunc::Tokenize(input.c_str(), tokens, delimeters); @@ -259,6 +259,25 @@ namespace AZ ASSERT_TRUE(tokens[2] == "c"); ASSERT_TRUE(tokens[3] == "d-e"); // Test for something like a guid, which contain typical separator characters } + + TEST_F(StringFuncTest, Tokenize_MultiDelimeters_String) + { + // Test with AZStd::string for backward compatibility. The functions + // use to only work with AZStd::string, and now they are templatized + // to support both AZStd::string and AZStd::string_view (the latter + // being perferred for performance). + + AZStd::string input = " -a +b +c -d-e"; + AZStd::vector tokens; + AZ::StringFunc::Tokenize(input.c_str(), tokens, "-+"); + + ASSERT_EQ(tokens.size(), 5); + ASSERT_TRUE(tokens[0] == "a "); + ASSERT_TRUE(tokens[1] == "b "); + ASSERT_TRUE(tokens[2] == "c "); + ASSERT_TRUE(tokens[3] == "d"); + ASSERT_TRUE(tokens[4] == "e"); + } TEST_F(StringFuncTest, TokenizeVisitor_EmptyString_DoesNotInvokeVisitor) { From 1a99103999e132b21fc67ed4948401f788dc1c59 Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Thu, 30 Sep 2021 01:30:28 -0700 Subject: [PATCH 03/20] Overhauled the .materialtype file format to group all related properties data together. This prepares the way for a number of possible improvements, especially unlocking the ability to factor out material type configuration to be shared by multiple material types. Here we formalize the concept of a Property Set, which replaces property "groups", containing the group name and description, properties, and functors all in one place. The Property Set structure will allow arbitrarily deep nesting, whereas before you only had one level of grouping. This nesting is not fully supported yet throughout the system, particularly in the Material Editor. It was easier to go ahead and put in some of the nesting mechanims, parituclar in the implementation of MaterialTypeSourceData. This change is backward compatible, which is proved with unit tests, and by the fact that only MinimalPBR.materialtype has been updated to the new format. StandardPBR, EnhancedPBR, and others are still using the old format. (In a subsequent commit I'll update these as well, to prove that the new format works correctly). Other changes and improvements... - A new constructor for MaterialPropertyId - Improved API for MaterialTypeSourceData that hides a good deal more of it's data as private, with clear and convenient APIs. Especially AddProperty, AddPropertySet, FindProperty, FindPropertySet, EnumerateProperties, EnumeratePropertySets. - Added lots of new unit tests - Updated MinimalPBR.materialtype to the new format. Testing: - Updated unit tests. - Reprocessed Atom material assets. - Ran AtomSampleViewer material screenshot test. - Opened, edited, saved material in the Material Editor. - Opened a level, edited material property overrides, saved and reloaded. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../RPI.Edit/Material/MaterialPropertyId.h | 4 + .../Material/MaterialTypeSourceData.h | 142 +- .../RPI.Edit/Material/MaterialPropertyId.cpp | 35 + .../MaterialPropertyValueSerializer.cpp | 4 +- .../Material/MaterialSourceDataSerializer.cpp | 1 + .../Material/MaterialTypeSourceData.cpp | 731 ++++++++--- .../RPI.Edit/Material/MaterialUtils.cpp | 1 + .../Code/Tests/Common/ErrorMessageFinder.cpp | 2 +- .../Material/MaterialPropertyIdTests.cpp | 34 + .../Material/MaterialSourceDataTests.cpp | 117 +- .../Material/MaterialTypeSourceDataTests.cpp | 1142 +++++++++++++---- .../Materials/Types/MinimalPBR.materialtype | 80 +- .../Code/Source/Document/MaterialDocument.cpp | 109 +- .../MaterialInspector/MaterialInspector.cpp | 31 +- .../EditorMaterialComponentInspector.cpp | 42 +- .../Material/EditorMaterialComponentUtil.cpp | 76 +- 16 files changed, 1886 insertions(+), 665 deletions(-) diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialPropertyId.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialPropertyId.h index 4b6d78c092..496485d0d6 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialPropertyId.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialPropertyId.h @@ -35,6 +35,7 @@ namespace AZ MaterialPropertyId(AZStd::string_view groupName, AZStd::string_view propertyName); MaterialPropertyId(const Name& groupName, const Name& propertyName); MaterialPropertyId(const AZStd::array_view names); + MaterialPropertyId(const AZStd::array_view groupNames, AZStd::string_view propertyName); AZ_DEFAULT_COPY_MOVE(MaterialPropertyId); @@ -44,6 +45,9 @@ namespace AZ //! This is included for convenience so it can be used for error messages in the same way an AZ::Name is used. const char* GetCStr() const; + //! Wraps Name::GetStringView() for convenience. + AZStd::string_view GetStringView() const; + //! Returns a hash of the full name. This is needed for compatibility with NameIdReflectionMap. Name::Hash GetHash() const; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialTypeSourceData.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialTypeSourceData.h index 04b6222404..56f7c4612c 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialTypeSourceData.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialTypeSourceData.h @@ -68,8 +68,9 @@ namespace AZ struct PropertyDefinition { + AZ_CLASS_ALLOCATOR(PropertyDefinition, SystemAllocator, 0); AZ_TYPE_INFO(AZ::RPI::MaterialTypeSourceData::PropertyDefinition, "{E0DB3C0D-75DB-4ADB-9E79-30DA63FA18B7}"); - + static const float DefaultMin; static const float DefaultMax; static const float DefaultStep; @@ -117,68 +118,159 @@ namespace AZ AZStd::unordered_map m_shaderOptionValues; }; - using PropertyList = AZStd::vector; + using PropertyList = AZStd::vector>; + + struct PropertySet + { + friend class MaterialTypeSourceData; + + AZ_CLASS_ALLOCATOR(PropertySet, SystemAllocator, 0); + AZ_TYPE_INFO(AZ::RPI::MaterialTypeSourceData::PropertySet, "{BA3AA0E4-C74D-4FD0-ADB2-00B060F06314}"); + + public: + + PropertySet() = default; + AZ_DISABLE_COPY(PropertySet) + + const AZStd::string& GetName() const { return m_name; } + const AZStd::string& GetDisplayName() const { return m_displayName; } + const AZStd::string& GetDescription() const { return m_description; } + const PropertyList& GetProperties() const { return m_properties; } + const AZStd::vector>& GetPropertySets() const { return m_propertySets; } + const AZStd::vector>& GetFunctors() const { return m_materialFunctorSourceData; } + + void SetDisplayName(AZStd::string_view displayName) { m_displayName = displayName; } + void SetDescription(AZStd::string_view description) { m_description = description; } + + PropertyDefinition* AddProperty(AZStd::string_view name); + PropertySet* AddPropertySet(AZStd::string_view name); + + private: + + static PropertySet* AddPropertySet(AZStd::string_view name, AZStd::vector>& toPropertySetList); + + AZStd::string m_name; + AZStd::string m_displayName; + AZStd::string m_description; + PropertyList m_properties; + AZStd::vector> m_propertySets; + AZStd::vector> m_materialFunctorSourceData; + }; + struct PropertyLayout { AZ_TYPE_INFO(AZ::RPI::MaterialTypeSourceData::PropertyLayout, "{AE53CF3F-5C3B-44F5-B2FB-306F0EB06393}"); + PropertyLayout() = default; + AZ_DISABLE_COPY(PropertyLayout) + //! Indicates the version of the set of available properties. Can be used to detect materials that might need to be updated. uint32_t m_version = 0; + //! [Deprecated] Use m_propertySets instead //! List of groups that will contain the available properties AZStd::vector m_groups; + //! [Deprecated] Use m_propertySets instead //! Collection of all available user-facing properties - AZStd::map m_properties; + AZStd::map> m_properties; + + AZStd::vector> m_propertySets; }; + + PropertySet* AddPropertySet(AZStd::string_view propertySetId); + //PropertySet* AddPropertySet(AZStd::string_view parentPropertySetId, AZStd::string_view name); + PropertyDefinition* AddProperty(AZStd::string_view propertyId); + //PropertyDefinition* AddProperty(AZStd::string_view parentPropertySetId, AZStd::string_view name); - AZStd::string m_description; + const PropertyLayout& GetPropertyLayout() const { return m_propertyLayout; } - PropertyLayout m_propertyLayout; + AZStd::string m_description; //< TODO: Make this private //! A list of shader variants that are always used at runtime; they cannot be turned off - AZStd::vector m_shaderCollection; + AZStd::vector m_shaderCollection; //< TODO: Make this private //! Material functors provide custom logic and calculations to configure shaders, render states, and more. See MaterialFunctor.h for details. - AZStd::vector> m_materialFunctorSourceData; + AZStd::vector> m_materialFunctorSourceData; //< TODO: Make this private //! Override names for UV input in the shaders of this material type. //! Using ordered map to sort names on loading. using UvNameMap = AZStd::map; - UvNameMap m_uvNameMap; + UvNameMap m_uvNameMap; //< TODO: Make this private //! Copy over UV custom names to the properties enum values. void ResolveUvEnums(); + + const PropertySet* FindPropertySet(AZStd::string_view propertySetId) const; - const GroupDefinition* FindGroup(AZStd::string_view groupName) const; + const PropertyDefinition* FindProperty(AZStd::string_view propertyId) const; - const PropertyDefinition* FindProperty(AZStd::string_view groupName, AZStd::string_view propertyName) const; + //! Tokenizes an ID string like "itemA.itemB.itemC" into a vector like ["itemA", "itemB", "itemC"] + static AZStd::vector TokenizeId(AZStd::string_view id); + + //! Splits an ID string like "itemA.itemB.itemC" into a vector like ["itemA.itemB", "itemC"] + static AZStd::vector SplitId(AZStd::string_view id); - //! Construct a complete list of group definitions, including implicit groups, arranged in the same order as the source data - //! Groups with the same name will be consolidated into a single entry - AZStd::vector GetGroupDefinitionsInDisplayOrder() const; + //! Call back function type used with the enumeration functions + using EnumeratePropertySetsCallback = AZStd::function; + //! Recursively traverses all of the property sets contained in the material type, executing a callback function for each. + //! @return false if the enumeration was terminated early by the callback returning false. + bool EnumeratePropertySets(const EnumeratePropertySetsCallback& callback) const; //! Call back function type used with the numeration functions using EnumeratePropertiesCallback = AZStd::function; - - //! Traverse all of the properties contained in the source data executing a callback function - //! Traversal will occur in group alphabetical order and stop once all properties have been enumerated or the callback function returns false - void EnumerateProperties(const EnumeratePropertiesCallback& callback) const; - - //! Traverse all of the properties in the source data in display/storage order executing a callback function - //! Traversal will stop once all properties have been enumerated or the callback function returns false - void EnumeratePropertiesInDisplayOrder(const EnumeratePropertiesCallback& callback) const; + + //! Recursively traverses all of the properties contained in the material type, executing a callback function for each. + //! @return false if the enumeration was terminated early by the callback returning false. + bool EnumerateProperties(const EnumeratePropertiesCallback& callback) const; //! Convert the property value into the format that will be stored in the source data //! This is primarily needed to support conversions of special types like enums and images bool ConvertPropertyValueToSourceDataFormat(const PropertyDefinition& propertyDefinition, MaterialPropertyValue& propertyValue) const; Outcome> CreateMaterialTypeAsset(Data::AssetId assetId, AZStd::string_view materialTypeSourceFilePath = "", bool elevateWarnings = true) const; + + bool ConvertToNewDataFormat(); + + private: + + //PropertySet* FindPropertySet(AZStd::array_view parsedPropertySetId, AZStd::array_view> inPropertySetList); + const PropertySet* FindPropertySet(AZStd::array_view parsedPropertySetId, AZStd::array_view> inPropertySetList) const; + + //PropertyDefinition* FindProperty(AZStd::array_view parsedPropertyId, AZStd::array_view> inPropertySetList); + const PropertyDefinition* FindProperty(AZStd::array_view parsedPropertyId, AZStd::array_view> inPropertySetList) const; + + //PropertyDefinition* FindProperty(AZStd::array_view parsedPropertyId, PropertySet& inPropertySet); + //const PropertyDefinition* FindProperty(AZStd::array_view parsedPropertyId, const PropertySet& inPropertySet) const; + + // Function overloads for recursion, returns false to indicate that recursion should end. + bool EnumeratePropertySets(const EnumeratePropertySetsCallback& callback, AZStd::string propertyIdContext, const AZStd::vector>& inPropertySetList) const; + bool EnumerateProperties(const EnumeratePropertiesCallback& callback, AZStd::string propertyIdContext, const AZStd::vector>& inPropertySetList) const; + + //! Recursively populates a material asset with properties from the tree of material property sets. + //! @param materialTypeSourceFilePath path to the material type file that is being processed, used to look up relative paths + //! @param propertyNameContext the accumulated prefix that should be applied to any property names encountered in the current @propertySet + //! @param propertySet the current PropertySet that is being processed + //! @return false if errors are detected and processing should abort + bool BuildPropertyList( + const AZStd::string& materialTypeSourceFilePath, + MaterialTypeAssetCreator& materialTypeAssetCreator, + AZStd::vector& propertyNameContext, + const MaterialTypeSourceData::PropertySet* propertySet) const; + + //! Construct a complete list of group definitions, including implicit groups, arranged in the same order as the source data. + //! Groups with the same name will be consolidated into a single entry. + //! Operates on the old format PropertyLayout::m_groups, used for conversion to the new format. + AZStd::vector GetOldFormatGroupDefinitionsInDisplayOrder() const; + + PropertyLayout m_propertyLayout; }; //! The wrapper class for derived material functors. @@ -207,7 +299,7 @@ namespace AZ return m_actualSourceData ? m_actualSourceData->CreateFunctor(editorContext) : Failure(); } - const Ptr GetActualSourceData() const { return m_actualSourceData; } + Ptr GetActualSourceData() const { return m_actualSourceData; } private: Ptr m_actualSourceData = nullptr; // The derived material functor instance. }; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyId.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyId.cpp index 1be5c4485c..47e41fa6fa 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyId.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyId.cpp @@ -103,6 +103,36 @@ namespace AZ AzFramework::StringFunc::Join(fullName, names.begin(), names.end(), "."); m_fullName = fullName; } + + MaterialPropertyId::MaterialPropertyId(const AZStd::array_view groupNames, AZStd::string_view propertyName) + { + for (const auto& name : groupNames) + { + if (!IsValidName(name)) + { + AZ_Error("MaterialPropertyId", false, "'%s' is not a valid identifier.", name.c_str()); + return; + } + } + + if (!IsValidName(propertyName)) + { + AZ_Error("MaterialPropertyId", false, "'%.*s' is not a valid identifier.", AZ_STRING_ARG(propertyName)); + return; + } + + if (groupNames.empty()) + { + m_fullName = propertyName; + } + else + { + AZStd::string fullName; + AzFramework::StringFunc::Join(fullName, groupNames.begin(), groupNames.end(), "."); + fullName = AZStd::string::format("%s.%.*s", fullName.c_str(), AZ_STRING_ARG(propertyName)); + m_fullName = fullName; + } + } MaterialPropertyId::operator const Name&() const { @@ -113,6 +143,11 @@ namespace AZ { return m_fullName.GetCStr(); } + + AZStd::string_view MaterialPropertyId::GetStringView() const + { + return m_fullName.GetStringView(); + } Name::Hash MaterialPropertyId::GetHash() const { diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyValueSerializer.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyValueSerializer.cpp index 3b2d36451a..5bf78d1639 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyValueSerializer.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyValueSerializer.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -63,6 +64,7 @@ namespace AZ } // Construct the full property name (groupName.propertyName) by parsing it from the JSON path string. + // Note we don't yet support full nested property sets, but eventually this should not be limited to just one group with one list of properties... size_t startPropertyName = context.GetPath().Get().rfind('/'); size_t startGroupName = context.GetPath().Get().rfind('/', startPropertyName-1); AZStd::string_view groupName = context.GetPath().Get().substr(startGroupName + 1, startPropertyName - startGroupName - 1); @@ -70,7 +72,7 @@ namespace AZ JSR::ResultCode result(JSR::Tasks::ReadField); - auto propertyDefinition = materialType->FindProperty(groupName, propertyName); + auto propertyDefinition = materialType->FindProperty(MaterialPropertyId{groupName, propertyName}.GetStringView()); if (!propertyDefinition) { AZStd::string message = AZStd::string::format("Property '%.*s.%.*s' not found in material type.", AZ_STRING_ARG(groupName), AZ_STRING_ARG(propertyName)); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceDataSerializer.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceDataSerializer.cpp index 5e4af07aae..e24655b7a6 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceDataSerializer.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceDataSerializer.cpp @@ -103,6 +103,7 @@ namespace AZ settings.m_clearContainers = context.ShouldClearContainers(); JsonSerializationResult::ResultCode materialTypeLoadResult = JsonSerialization::Load(materialTypeData, materialTypeJson.GetValue(), settings); + materialTypeData.ConvertToNewDataFormat(); materialTypeData.ResolveUvEnums(); // Restore prior configuration diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp index f69b082292..de55cbecb5 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp @@ -56,7 +56,11 @@ namespace AZ serializeContext->Class()->Version(3); serializeContext->Class()->Version(4); serializeContext->Class()->Version(1); - + + serializeContext->RegisterGenericType>(); + serializeContext->RegisterGenericType>(); + serializeContext->RegisterGenericType>>(); + serializeContext->RegisterGenericType>>(); serializeContext->RegisterGenericType(); serializeContext->Class() @@ -66,11 +70,22 @@ namespace AZ ->Field("options", &ShaderVariantReferenceData::m_shaderOptionValues) ; + serializeContext->Class() + ->Version(1) + ->Field("name", &PropertySet::m_name) + ->Field("displayName", &PropertySet::m_displayName) + ->Field("description", &PropertySet::m_description) + ->Field("properties", &PropertySet::m_properties) + ->Field("propertySets", &PropertySet::m_propertySets) + ->Field("functors", &PropertySet::m_materialFunctorSourceData) + ; + serializeContext->Class() ->Version(1) ->Field("version", &PropertyLayout::m_version) - ->Field("groups", &PropertyLayout::m_groups) - ->Field("properties", &PropertyLayout::m_properties) + ->Field("groups", &PropertyLayout::m_groups) //< Old, preserved for backward compatibility, replaced by propertySets + ->Field("properties", &PropertyLayout::m_properties) //< Old, preserved for backward compatibility, replaced by propertySets + ->Field("propertySets", &PropertyLayout::m_propertySets) ; serializeContext->RegisterGenericType(); @@ -92,146 +107,453 @@ namespace AZ , m_shaderIndex(shaderIndex) { } - + const float MaterialTypeSourceData::PropertyDefinition::DefaultMin = std::numeric_limits::lowest(); const float MaterialTypeSourceData::PropertyDefinition::DefaultMax = std::numeric_limits::max(); const float MaterialTypeSourceData::PropertyDefinition::DefaultStep = 0.1f; - - const MaterialTypeSourceData::GroupDefinition* MaterialTypeSourceData::FindGroup(AZStd::string_view groupName) const + + /*static*/ MaterialTypeSourceData::PropertySet* MaterialTypeSourceData::PropertySet::AddPropertySet(AZStd::string_view name, AZStd::vector>& toPropertySetList) { - for (const GroupDefinition& group : m_propertyLayout.m_groups) - { - if (group.m_name == groupName) + auto iter = AZStd::find_if(toPropertySetList.begin(), toPropertySetList.end(), [name](const AZStd::unique_ptr& existingPropertySet) { - return &group; - } + return existingPropertySet->m_name == name; + }); + + if (iter != toPropertySetList.end()) + { + AZ_Error("Material source data", false, "PropertySet named '%.*s' already exists", AZ_STRING_ARG(name)); + return nullptr; + } + + if (!MaterialPropertyId::IsValidName(name)) + { + AZ_Error("Material source data", false, "'%.*s' is not a valid identifier", AZ_STRING_ARG(name)); + return nullptr; } - return nullptr; + toPropertySetList.push_back(AZStd::make_unique()); + toPropertySetList.back()->m_name = name; + return toPropertySetList.back().get(); } - const MaterialTypeSourceData::PropertyDefinition* MaterialTypeSourceData::FindProperty(AZStd::string_view groupName, AZStd::string_view propertyName) const + MaterialTypeSourceData::PropertyDefinition* MaterialTypeSourceData::PropertySet::AddProperty(AZStd::string_view name) { - auto groupIter = m_propertyLayout.m_properties.find(groupName); - if (groupIter == m_propertyLayout.m_properties.end()) + auto propertyIter = AZStd::find_if(m_properties.begin(), m_properties.end(), [name](const AZStd::unique_ptr& existingProperty) + { + return existingProperty->m_name == name; + }); + + if (propertyIter != m_properties.end()) + { + AZ_Error("Material source data", false, "PropertySet '%s' already contains a property named '%.*s'", m_name.c_str(), AZ_STRING_ARG(name)); + return nullptr; + } + + auto propertySetIter = AZStd::find_if(m_propertySets.begin(), m_propertySets.end(), [name](const AZStd::unique_ptr& existingPropertySet) + { + return existingPropertySet->m_name == name; + }); + + if (propertySetIter != m_propertySets.end()) { + AZ_Error("Material source data", false, "Property name '%.*s' collides with a PropertySet of the same name", AZ_STRING_ARG(name)); return nullptr; } - for (const PropertyDefinition& property : groupIter->second) + if (!MaterialPropertyId::IsValidName(name)) { - if (property.m_name == propertyName) + AZ_Error("Material source data", false, "'%.*s' is not a valid identifier", AZ_STRING_ARG(name)); + return nullptr; + } + + m_properties.emplace_back(AZStd::make_unique()); + m_properties.back()->m_name = name; + return m_properties.back().get(); + } + + MaterialTypeSourceData::PropertySet* MaterialTypeSourceData::PropertySet::AddPropertySet(AZStd::string_view name) + { + auto iter = AZStd::find_if(m_properties.begin(), m_properties.end(), [name](const AZStd::unique_ptr& existingProperty) { - return &property; - } + return existingProperty->m_name == name; + }); + + if (iter != m_properties.end()) + { + AZ_Error("Material source data", false, "PropertySet name '%.*s' collides with a Property of the same name", AZ_STRING_ARG(name)); + return nullptr; } - return nullptr; + return AddPropertySet(name, m_propertySets); } + + MaterialTypeSourceData::PropertySet* MaterialTypeSourceData::AddPropertySet(AZStd::string_view propertySetId) + { + AZStd::vector splitPropertySetId = SplitId(propertySetId); - void MaterialTypeSourceData::ResolveUvEnums() + if (splitPropertySetId.size() == 1) + { + return PropertySet::AddPropertySet(propertySetId, m_propertyLayout.m_propertySets); + } + + // TODO: Delete + //return AddPropertySet(splitPropertySetId[0], splitPropertySetId[1]); + + PropertySet* parentPropertySet = const_cast(const_cast(this)->FindPropertySet(splitPropertySetId[0])); + + if (!parentPropertySet) + { + AZ_Error("Material source data", false, "PropertySet '%.*s' does not exists", AZ_STRING_ARG(splitPropertySetId[0])); + return nullptr; + } + + return parentPropertySet->AddPropertySet(splitPropertySetId[1]); + } + + // TODO: Delete + //MaterialTypeSourceData::PropertySet* MaterialTypeSourceData::AddPropertySet(AZStd::string_view parentPropertySetId, AZStd::string_view name) + //{ + // PropertySet* parentPropertySet = const_cast(const_cast(this)->FindPropertySet(parentPropertySetId)); + // + // if (!parentPropertySet) + // { + // AZ_Error("Material source data", false, "PropertySet '%.*s' does not exists", AZ_STRING_ARG(parentPropertySetId)); + // return nullptr; + // } + + // return parentPropertySet->AddPropertySet(name); + //} + + MaterialTypeSourceData::PropertyDefinition* MaterialTypeSourceData::AddProperty(AZStd::string_view propertyId) { - AZStd::vector enumValues; - enumValues.reserve(m_uvNameMap.size()); - for (const auto& uvNamePair : m_uvNameMap) + AZStd::vector splitPropertyId = SplitId(propertyId); + //if (splitPropertyId.empty()) + //{ + // return nullptr; + //} + + if (splitPropertyId.size() == 1) { - enumValues.push_back(uvNamePair.second); + AZ_Error("Material source data", false, "Property id '%.*s' is invalid. Properties must be added to a PropertySet (i.e. \"general.%.*s\").", AZ_STRING_ARG(propertyId), AZ_STRING_ARG(propertyId)); + return nullptr; + } + + // TODO: Delete + //return AddProperty(splitPropertyId[0], splitPropertyId[1]); + + PropertySet* parentPropertySet = const_cast(const_cast(this)->FindPropertySet(splitPropertyId[0])); + + if (!parentPropertySet) + { + AZ_Error("Material source data", false, "PropertySet '%.*s' does not exists", AZ_STRING_ARG(splitPropertyId[0])); + return nullptr; } - for (auto& group : m_propertyLayout.m_properties) + return parentPropertySet->AddProperty(splitPropertyId[1]); + } + + // TODO: Delete + //MaterialTypeSourceData::PropertyDefinition* MaterialTypeSourceData::AddProperty(AZStd::string_view parentPropertySetId, AZStd::string_view name) + //{ + // PropertySet* parentPropertySet = const_cast(const_cast(this)->FindPropertySet(parentPropertySetId)); + // + // if (!parentPropertySet) + // { + // AZ_Error("Material source data", false, "PropertySet '%.*s' does not exists", AZ_STRING_ARG(parentPropertySetId)); + // return nullptr; + // } + + // return parentPropertySet->AddProperty(name); + //} + + const MaterialTypeSourceData::PropertySet* MaterialTypeSourceData::FindPropertySet(AZStd::array_view parsedPropertySetId, AZStd::array_view> inPropertySetList) const + { + for (const auto& propertySet : inPropertySetList) { - for (PropertyDefinition& property : group.second) + if (propertySet->m_name != parsedPropertySetId[0]) + { + continue; + } + else if (parsedPropertySetId.size() == 1) + { + return propertySet.get(); + } + else { - if (property.m_dataType == AZ::RPI::MaterialPropertyDataType::Enum && property.m_enumIsUv) + AZStd::array_view subPath{parsedPropertySetId.begin() + 1, parsedPropertySetId.end()}; + + if (!subPath.empty()) { - property.m_enumValues = enumValues; + const MaterialTypeSourceData::PropertySet* propertySubset = FindPropertySet(subPath, propertySet->m_propertySets); + if (propertySubset) + { + return propertySubset; + } } } } + + return nullptr; } - AZStd::vector MaterialTypeSourceData::GetGroupDefinitionsInDisplayOrder() const - { - AZStd::vector groupDefinitions; - groupDefinitions.reserve(m_propertyLayout.m_properties.size()); + //MaterialTypeSourceData::PropertySet* MaterialTypeSourceData::FindPropertySet(AZStd::array_view parsedPropertySetId, AZStd::array_view> inPropertySetList) + //{ + // return const_cast(const_cast(this)->FindPropertySet(parsedPropertySetId, inPropertySetList)); + //} - // Some groups are defined explicitly in the .materialtype file's "groups" section. This is the primary way groups are sorted in the UI. - AZStd::unordered_set foundGroups; - for (const auto& groupDefinition : m_propertyLayout.m_groups) + const MaterialTypeSourceData::PropertySet* MaterialTypeSourceData::FindPropertySet(AZStd::string_view propertySetId) const + { + AZStd::vector tokens = TokenizeId(propertySetId); + return FindPropertySet(tokens, m_propertyLayout.m_propertySets); + } + + //MaterialTypeSourceData::PropertyDefinition* MaterialTypeSourceData::FindProperty(AZStd::array_view parsedPropertyId, PropertySet& inPropertySet) + //{ + // if (parsedPropertyId.size() == 1) + // { + // for (AZStd::unique_ptr& property : inPropertySet.m_properties) + // { + // if (property->m_name == parsedPropertyId[0]) + // { + // return property.get(); + // } + // } + // } + + // return FindProperty(parsedPropertyId, inPropertySet.m_propertySets); + //} + + //const MaterialTypeSourceData::PropertyDefinition* MaterialTypeSourceData::FindProperty(AZStd::array_view parsedPropertyId, const PropertySet& inPropertySet) const + //{ + // MaterialTypeSourceData* nonConstThis = const_cast(this); + // PropertySet& nonConstPropertySet = *const_cast(&inPropertySet); + // return const_cast(nonConstThis->FindProperty(parsedPropertyId, nonConstPropertySet)); + //} + + const MaterialTypeSourceData::PropertyDefinition* MaterialTypeSourceData::FindProperty( + AZStd::array_view parsedPropertyId, + AZStd::array_view> inPropertySetList) const + { + for (const auto& propertySet : inPropertySetList) { - if (foundGroups.insert(groupDefinition.m_name).second) - { - groupDefinitions.push_back(groupDefinition); - } - else + if (propertySet->m_name == parsedPropertyId[0]) { - AZ_Warning("Material source data", false, "Duplicate group '%s' found.", groupDefinition.m_name.c_str()); + AZStd::array_view subPath {parsedPropertyId.begin() + 1, parsedPropertyId.end()}; + + if (subPath.size() == 1) + { + for (AZStd::unique_ptr& property : propertySet->m_properties) + { + if (property->m_name == subPath[0]) + { + return property.get(); + } + } + } + else if(subPath.size() > 1) + { + const MaterialTypeSourceData::PropertyDefinition* property = FindProperty(subPath, propertySet->m_propertySets); + if (property) + { + return property; + } + } } } - // Some groups are defined implicitly, in the "properties" section where a group name is used but not explicitly defined in the "groups" section. - for (const auto& propertyListPair : m_propertyLayout.m_properties) + return nullptr; + } + + //MaterialTypeSourceData::PropertyDefinition* MaterialTypeSourceData::FindProperty(AZStd::array_view parsedPropertyId, AZStd::array_view> inPropertySetList) + //{ + // return const_cast(const_cast(this)->FindProperty(parsedPropertyId, inPropertySetList)); + //} + + const MaterialTypeSourceData::PropertyDefinition* MaterialTypeSourceData::FindProperty(AZStd::string_view propertyId) const + { + AZStd::vector tokens = TokenizeId(propertyId); + return FindProperty(tokens, m_propertyLayout.m_propertySets); + } + + AZStd::vector MaterialTypeSourceData::TokenizeId(AZStd::string_view id) + { + AZStd::vector tokens; + AzFramework::StringFunc::Tokenize(id, tokens, "./", true, true); + return tokens; + } + + AZStd::vector MaterialTypeSourceData::SplitId(AZStd::string_view id) + { + AZStd::vector parts; + parts.reserve(2); + size_t lastDelim = id.rfind('.', id.size()-1); + if (lastDelim == AZStd::string::npos) { - const AZStd::string& groupName = propertyListPair.first; - if (foundGroups.insert(groupName).second) + parts.push_back(id); + } + else + { + parts.push_back(AZStd::string_view{id.begin(), id.begin()+lastDelim}); + parts.push_back(AZStd::string_view{id.begin()+lastDelim+1, id.end()}); + } + + return parts; + } + + bool MaterialTypeSourceData::EnumeratePropertySets(const EnumeratePropertySetsCallback& callback, AZStd::string propertyNameContext, const AZStd::vector>& inPropertySetList) const + { + for (auto& propertySet : inPropertySetList) + { + if (!callback(propertyNameContext, propertySet.get())) { - MaterialTypeSourceData::GroupDefinition groupDefinition; - groupDefinition.m_name = groupName; - groupDefinitions.push_back(groupDefinition); + return false; // Stop processing + } + + const AZStd::string propertyNameContext2 = propertyNameContext + propertySet->m_name + "."; + + if (!EnumeratePropertySets(callback, propertyNameContext2, propertySet->m_propertySets)) + { + return false; // Stop processing } } - return groupDefinitions; + return true; } - void MaterialTypeSourceData::EnumerateProperties(const EnumeratePropertiesCallback& callback) const + bool MaterialTypeSourceData::EnumeratePropertySets(const EnumeratePropertySetsCallback& callback) const { if (!callback) { - return; + return false; } - for (const auto& propertyListPair : m_propertyLayout.m_properties) + return EnumeratePropertySets(callback, {}, m_propertyLayout.m_propertySets); + } + + bool MaterialTypeSourceData::EnumerateProperties(const EnumeratePropertiesCallback& callback, AZStd::string propertyNameContext, const AZStd::vector>& inPropertySetList) const + { + + for (auto& propertySet : inPropertySetList) { - const AZStd::string& groupName = propertyListPair.first; - const auto& propertyList = propertyListPair.second; - for (const auto& propertyDefinition : propertyList) + const AZStd::string propertyNameContext2 = propertyNameContext + propertySet->m_name + "."; + + for (auto& property : propertySet->m_properties) { - const AZStd::string& propertyName = propertyDefinition.m_name; - if (!callback(groupName, propertyName, propertyDefinition)) + if (!callback(propertyNameContext2, property.get())) { - return; + return false; // Stop processing } } + + if (!EnumerateProperties(callback, propertyNameContext2, propertySet->m_propertySets)) + { + return false; // Stop processing + } } + + return true; } - void MaterialTypeSourceData::EnumeratePropertiesInDisplayOrder(const EnumeratePropertiesCallback& callback) const + bool MaterialTypeSourceData::EnumerateProperties(const EnumeratePropertiesCallback& callback) const { if (!callback) { - return; + return false; } - for (const auto& groupDefinition : GetGroupDefinitionsInDisplayOrder()) + return EnumerateProperties(callback, {}, m_propertyLayout.m_propertySets); + } + + bool MaterialTypeSourceData::ConvertToNewDataFormat() + { + for (const auto& group : GetOldFormatGroupDefinitionsInDisplayOrder()) { - const AZStd::string& groupName = groupDefinition.m_name; - const auto propertyListItr = m_propertyLayout.m_properties.find(groupName); + auto propertyListItr = m_propertyLayout.m_properties.find(group.m_name); if (propertyListItr != m_propertyLayout.m_properties.end()) { const auto& propertyList = propertyListItr->second; - for (const auto& propertyDefinition : propertyList) + for (auto& propertyDefinition : propertyList) { - const AZStd::string& propertyName = propertyDefinition.m_name; - if (!callback(groupName, propertyName, propertyDefinition)) + PropertySet* propertySet = const_cast(const_cast(this)->FindPropertySet(group.m_name)); + + if (!propertySet) { - return; + m_propertyLayout.m_propertySets.emplace_back(AZStd::make_unique()); + m_propertyLayout.m_propertySets.back()->m_name = group.m_name; + m_propertyLayout.m_propertySets.back()->m_displayName = group.m_displayName; + m_propertyLayout.m_propertySets.back()->m_description = group.m_description; + propertySet = m_propertyLayout.m_propertySets.back().get(); } + + PropertyDefinition* newProperty = propertySet->AddProperty(propertyDefinition.m_name); + + *newProperty = propertyDefinition; } } } + + m_propertyLayout.m_groups.clear(); + m_propertyLayout.m_properties.clear(); + + return true; + } + + void MaterialTypeSourceData::ResolveUvEnums() + { + AZStd::vector enumValues; + enumValues.reserve(m_uvNameMap.size()); + for (const auto& uvNamePair : m_uvNameMap) + { + enumValues.push_back(uvNamePair.second); + } + + EnumerateProperties([&enumValues](const AZStd::string&, const MaterialTypeSourceData::PropertyDefinition* property) + { + if (property->m_dataType == AZ::RPI::MaterialPropertyDataType::Enum && property->m_enumIsUv) + { + // const_cast is safe because this is internal to the MaterialTypeSourceData. It isn't worth complicating things + // by adding another version of EnumerateProperties. + const_cast(property)->m_enumValues = enumValues; + } + return true; + }); + } + + AZStd::vector MaterialTypeSourceData::GetOldFormatGroupDefinitionsInDisplayOrder() const + { + AZStd::vector groupDefinitions; + groupDefinitions.reserve(m_propertyLayout.m_properties.size()); + + // Some groups are defined explicitly in the .materialtype file's "groups" section. This is the primary way groups are sorted in the UI. + AZStd::unordered_set foundGroups; + for (const auto& groupDefinition : m_propertyLayout.m_groups) + { + if (foundGroups.insert(groupDefinition.m_name).second) + { + groupDefinitions.push_back(groupDefinition); + } + else + { + AZ_Warning("Material source data", false, "Duplicate group '%s' found.", groupDefinition.m_name.c_str()); + } + } + + // Some groups are defined implicitly, in the "properties" section where a group name is used but not explicitly defined in the "groups" section. + for (const auto& propertyListPair : m_propertyLayout.m_properties) + { + const AZStd::string& groupName = propertyListPair.first; + if (foundGroups.insert(groupName).second) + { + MaterialTypeSourceData::GroupDefinition groupDefinition; + groupDefinition.m_name = groupName; + groupDefinitions.push_back(groupDefinition); + } + } + + return groupDefinitions; } + // TODO: It looks like this function doesn't operate on MaterialTypeSourceData data, it belongs in MaterialUtils bool MaterialTypeSourceData::ConvertPropertyValueToSourceDataFormat(const PropertyDefinition& propertyDefinition, MaterialPropertyValue& propertyValue) const { if (propertyDefinition.m_dataType == AZ::RPI::MaterialPropertyDataType::Enum && propertyValue.Is()) @@ -274,6 +596,178 @@ namespace AZ return true; } + bool MaterialTypeSourceData::BuildPropertyList( + const AZStd::string& materialTypeSourceFilePath, + MaterialTypeAssetCreator& materialTypeAssetCreator, + AZStd::vector& propertyNameContext, + const MaterialTypeSourceData::PropertySet* propertySet) const + { + for (const AZStd::unique_ptr& property : propertySet->m_properties) + { + // Register the property... + + MaterialPropertyId propertyId{propertyNameContext, property->m_name}; + + if (!propertyId.IsValid()) + { + // MaterialPropertyId reports an error message + return false; + } + + auto propertySetIter = AZStd::find_if(propertySet->GetPropertySets().begin(), propertySet->GetPropertySets().end(), + [&property](const AZStd::unique_ptr& existingPropertySet) + { + return existingPropertySet->GetName() == property->m_name; + }); + + if (propertySetIter != propertySet->GetPropertySets().end()) + { + AZ_Error("Material source data", false, "Material property '%s' collides with a PropertySet with the same ID.", propertyId.GetCStr()); + return false; + } + + materialTypeAssetCreator.BeginMaterialProperty(propertyId, property->m_dataType); + + if (property->m_dataType == MaterialPropertyDataType::Enum) + { + materialTypeAssetCreator.SetMaterialPropertyEnumNames(property->m_enumValues); + } + + for (auto& output : property->m_outputConnections) + { + switch (output.m_type) + { + case MaterialPropertyOutputType::ShaderInput: + { + materialTypeAssetCreator.ConnectMaterialPropertyToShaderInput(Name{output.m_fieldName}); + break; + } + case MaterialPropertyOutputType::ShaderOption: + { + if (output.m_shaderIndex >= 0) + { + materialTypeAssetCreator.ConnectMaterialPropertyToShaderOption(Name{output.m_fieldName}, output.m_shaderIndex); + } + else + { + materialTypeAssetCreator.ConnectMaterialPropertyToShaderOptions(Name{output.m_fieldName}); + } + break; + } + case MaterialPropertyOutputType::Invalid: + // Don't add any output mappings, this is the case when material functors are expected to process the property + break; + default: + AZ_Assert(false, "Unsupported MaterialPropertyOutputType"); + return false; + } + } + + materialTypeAssetCreator.EndMaterialProperty(); + + // Parse and set the property's value... + if (!property->m_value.IsValid()) + { + AZ_Warning("Material source data", false, "Source data for material property value is invalid."); + } + else + { + switch (property->m_dataType) + { + case MaterialPropertyDataType::Image: + { + Outcome> imageAssetResult = MaterialUtils::GetImageAssetReference(materialTypeSourceFilePath, property->m_value.GetValue()); + + if (imageAssetResult.IsSuccess()) + { + materialTypeAssetCreator.SetPropertyValue(propertyId, imageAssetResult.GetValue()); + } + else + { + materialTypeAssetCreator.ReportError("Material property '%s': Could not find the image '%s'", propertyId.GetCStr(), property->m_value.GetValue().data()); + } + } + break; + case MaterialPropertyDataType::Enum: + { + MaterialPropertyIndex propertyIndex = materialTypeAssetCreator.GetMaterialPropertiesLayout()->FindPropertyIndex(propertyId); + const MaterialPropertyDescriptor* propertyDescriptor = materialTypeAssetCreator.GetMaterialPropertiesLayout()->GetPropertyDescriptor(propertyIndex); + + AZ::Name enumName = AZ::Name(property->m_value.GetValue()); + uint32_t enumValue = propertyDescriptor->GetEnumValue(enumName); + if (enumValue == MaterialPropertyDescriptor::InvalidEnumValue) + { + materialTypeAssetCreator.ReportError("Enum value '%s' couldn't be found in the 'enumValues' list", enumName.GetCStr()); + } + else + { + materialTypeAssetCreator.SetPropertyValue(propertyId, enumValue); + } + } + break; + default: + materialTypeAssetCreator.SetPropertyValue(propertyId, property->m_value); + break; + } + } + } + + for (const AZStd::unique_ptr& propertySubset : propertySet->m_propertySets) + { + propertyNameContext.push_back(propertySubset->m_name); + + bool success = BuildPropertyList( + materialTypeSourceFilePath, + materialTypeAssetCreator, + propertyNameContext, + propertySubset.get()); + + propertyNameContext.pop_back(); + + if (!success) + { + return false; + } + } + + // We cannot create the MaterialFunctor until after all the properties are added because + // CreateFunctor() may need to look up properties in the MaterialPropertiesLayout + for (auto& functorData : propertySet->m_materialFunctorSourceData) + { + MaterialFunctorSourceData::FunctorResult result = functorData->CreateFunctor( + MaterialFunctorSourceData::RuntimeContext( + materialTypeSourceFilePath, + materialTypeAssetCreator.GetMaterialPropertiesLayout(), + materialTypeAssetCreator.GetMaterialShaderResourceGroupLayout(), + materialTypeAssetCreator.GetShaderCollection() + ) + ); + + if (result.IsSuccess()) + { + Ptr& functor = result.GetValue(); + if (functor != nullptr) + { + materialTypeAssetCreator.AddMaterialFunctor(functor); + + for (const AZ::Name& optionName : functorData->GetActualSourceData()->GetShaderOptionDependencies()) + { + materialTypeAssetCreator.ClaimShaderOptionOwnership(Name{optionName.GetCStr()}); + } + } + } + else + { + materialTypeAssetCreator.ReportError("Failed to create MaterialFunctor"); + return false; + } + } + + + return true; + } + + Outcome> MaterialTypeSourceData::CreateMaterialTypeAsset(Data::AssetId assetId, AZStd::string_view materialTypeSourceFilePath, bool elevateWarnings) const { MaterialTypeAssetCreator materialTypeAssetCreator; @@ -327,103 +821,16 @@ namespace AZ return Failure(); } } - - for (auto& groupIter : m_propertyLayout.m_properties) + + for (const AZStd::unique_ptr& propertySet : m_propertyLayout.m_propertySets) { - const AZStd::string& groupName = groupIter.first; + AZStd::vector propertyNameContext; + propertyNameContext.push_back(propertySet->m_name); + bool success = BuildPropertyList(materialTypeSourceFilePath, materialTypeAssetCreator, propertyNameContext, propertySet.get()); - for (const PropertyDefinition& property : groupIter.second) + if (!success) { - // Register the property... - - MaterialPropertyId propertyId{ groupName, property.m_name }; - - if (!propertyId.IsValid()) - { - materialTypeAssetCreator.ReportWarning("Cannot create material property with invalid ID '%s'.", propertyId.GetCStr()); - continue; - } - - materialTypeAssetCreator.BeginMaterialProperty(propertyId, property.m_dataType); - - if (property.m_dataType == MaterialPropertyDataType::Enum) - { - materialTypeAssetCreator.SetMaterialPropertyEnumNames(property.m_enumValues); - } - - for (auto& output : property.m_outputConnections) - { - switch (output.m_type) - { - case MaterialPropertyOutputType::ShaderInput: - materialTypeAssetCreator.ConnectMaterialPropertyToShaderInput(Name{ output.m_fieldName.data() }); - break; - case MaterialPropertyOutputType::ShaderOption: - if (output.m_shaderIndex >= 0) - { - materialTypeAssetCreator.ConnectMaterialPropertyToShaderOption(Name{ output.m_fieldName.data() }, output.m_shaderIndex); - } - else - { - materialTypeAssetCreator.ConnectMaterialPropertyToShaderOptions(Name{ output.m_fieldName.data() }); - } - break; - case MaterialPropertyOutputType::Invalid: - // Don't add any output mappings, this is the case when material functors are expected to process the property - break; - default: - AZ_Assert(false, "Unsupported MaterialPropertyOutputType"); - return Failure(); - } - } - - materialTypeAssetCreator.EndMaterialProperty(); - - // Parse and set the property's value... - if (!property.m_value.IsValid()) - { - AZ_Warning("Material source data", false, "Source data for material property value is invalid."); - } - else - { - switch (property.m_dataType) - { - case MaterialPropertyDataType::Image: - { - Outcome> imageAssetResult = MaterialUtils::GetImageAssetReference(materialTypeSourceFilePath, property.m_value.GetValue()); - - if (imageAssetResult.IsSuccess()) - { - materialTypeAssetCreator.SetPropertyValue(propertyId, imageAssetResult.GetValue()); - } - else - { - materialTypeAssetCreator.ReportError("Material property '%s': Could not find the image '%s'", propertyId.GetCStr(), property.m_value.GetValue().data()); - } - } - break; - case MaterialPropertyDataType::Enum: - { - MaterialPropertyIndex propertyIndex = materialTypeAssetCreator.GetMaterialPropertiesLayout()->FindPropertyIndex(propertyId); - const MaterialPropertyDescriptor* propertyDescriptor = materialTypeAssetCreator.GetMaterialPropertiesLayout()->GetPropertyDescriptor(propertyIndex); - - AZ::Name enumName = AZ::Name(property.m_value.GetValue()); - uint32_t enumValue = propertyDescriptor ? propertyDescriptor->GetEnumValue(enumName) : MaterialPropertyDescriptor::InvalidEnumValue; - if (enumValue == MaterialPropertyDescriptor::InvalidEnumValue) - { - materialTypeAssetCreator.ReportError("Enum value '%s' couldn't be found in the 'enumValues' list", enumName.GetCStr()); - } - else - { - materialTypeAssetCreator.SetPropertyValue(propertyId, enumValue); - } - } - break; - default: - materialTypeAssetCreator.SetPropertyValue(propertyId, property.m_value); - break; - } - } + return Failure(); } } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialUtils.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialUtils.cpp index 90ce9e66ce..174a2e682a 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialUtils.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialUtils.cpp @@ -90,6 +90,7 @@ namespace AZ settings.m_metadata.Add(fileLoadContext); JsonSerialization::Load(materialType, *document, settings); + materialType.ConvertToNewDataFormat(); materialType.ResolveUvEnums(); if (reportingHelper.ErrorsReported()) diff --git a/Gems/Atom/RPI/Code/Tests/Common/ErrorMessageFinder.cpp b/Gems/Atom/RPI/Code/Tests/Common/ErrorMessageFinder.cpp index fa88f145a6..06cdb073e9 100644 --- a/Gems/Atom/RPI/Code/Tests/Common/ErrorMessageFinder.cpp +++ b/Gems/Atom/RPI/Code/Tests/Common/ErrorMessageFinder.cpp @@ -84,7 +84,7 @@ namespace UnitTest } } - m_checked = true; + m_checked = true; } void ErrorMessageFinder::ReportFailure(const AZStd::string& failureMessage) diff --git a/Gems/Atom/RPI/Code/Tests/Material/MaterialPropertyIdTests.cpp b/Gems/Atom/RPI/Code/Tests/Material/MaterialPropertyIdTests.cpp index 2b729ed8ef..80da59b430 100644 --- a/Gems/Atom/RPI/Code/Tests/Material/MaterialPropertyIdTests.cpp +++ b/Gems/Atom/RPI/Code/Tests/Material/MaterialPropertyIdTests.cpp @@ -94,6 +94,40 @@ namespace UnitTest errorMessageFinder.CheckExpectedErrorsFound(); } + TEST_F(MaterialPropertyIdTests, TestConstructWithMultipleParentNamesSeparateFromPropertyName) + { + AZStd::vector names{"layer1", "clearCoat", "normal"}; + MaterialPropertyId id{names, "factor"}; + EXPECT_TRUE(id.IsValid()); + EXPECT_STREQ(id.GetCStr(), "layer1.clearCoat.normal.factor"); + AZ::Name idCastedToName = id; + EXPECT_EQ(idCastedToName, AZ::Name{"layer1.clearCoat.normal.factor"}); + } + + TEST_F(MaterialPropertyIdTests, TestConstructWithMultipleParentNamesSeparateFromPropertyName_BadParentName) + { + ErrorMessageFinder errorMessageFinder; + errorMessageFinder.AddExpectedErrorMessage("not a valid identifier"); + + AZStd::vector names{"layer1", "clear-coat", "normal"}; + MaterialPropertyId id{names, "factor"}; + EXPECT_FALSE(id.IsValid()); + + errorMessageFinder.CheckExpectedErrorsFound(); + } + + TEST_F(MaterialPropertyIdTests, TestConstructWithMultipleParentNamesSeparateFromPropertyName_BadPropertyName) + { + ErrorMessageFinder errorMessageFinder; + errorMessageFinder.AddExpectedErrorMessage("not a valid identifier"); + + AZStd::vector names{"layer1", "clearCoat", "normal"}; + MaterialPropertyId id{names, "#factor"}; + EXPECT_FALSE(id.IsValid()); + + errorMessageFinder.CheckExpectedErrorsFound(); + } + TEST_F(MaterialPropertyIdTests, TestParse) { MaterialPropertyId id = MaterialPropertyId::Parse("layer1.clearCoat.normal.factor"); diff --git a/Gems/Atom/RPI/Code/Tests/Material/MaterialSourceDataTests.cpp b/Gems/Atom/RPI/Code/Tests/Material/MaterialSourceDataTests.cpp index dd3b3b2711..293289b00f 100644 --- a/Gems/Atom/RPI/Code/Tests/Material/MaterialSourceDataTests.cpp +++ b/Gems/Atom/RPI/Code/Tests/Material/MaterialSourceDataTests.cpp @@ -201,33 +201,38 @@ namespace UnitTest TEST_F(MaterialSourceDataTests, TestJsonRoundTrip) { const char* materialTypeJson = - "{ \n" - " \"propertyLayout\": { \n" - " \"version\": 1, \n" - " \"groups\": [ \n" - " { \"name\": \"groupA\" }, \n" - " { \"name\": \"groupB\" }, \n" - " { \"name\": \"groupC\" } \n" - " ], \n" - " \"properties\": { \n" - " \"groupA\": [ \n" - " {\"name\": \"MyBool\", \"type\": \"bool\"}, \n" - " {\"name\": \"MyInt\", \"type\": \"int\"}, \n" - " {\"name\": \"MyUInt\", \"type\": \"uint\"} \n" - " ], \n" - " \"groupB\": [ \n" - " {\"name\": \"MyFloat\", \"type\": \"float\"}, \n" - " {\"name\": \"MyFloat2\", \"type\": \"vector2\"}, \n" - " {\"name\": \"MyFloat3\", \"type\": \"vector3\"} \n" - " ], \n" - " \"groupC\": [ \n" - " {\"name\": \"MyFloat4\", \"type\": \"vector4\"}, \n" - " {\"name\": \"MyColor\", \"type\": \"color\"}, \n" - " {\"name\": \"MyImage\", \"type\": \"image\"} \n" - " ] \n" - " } \n" - " } \n" - "} \n"; + R"( + { + "propertyLayout": { + "propertySets": [ + { + "name": "groupA", + "properties": [ + {"name": "MyBool", "type": "bool"}, + {"name": "MyInt", "type": "int"}, + {"name": "MyUInt", "type": "uint"} + ] + }, + { + "name": "groupB", + "properties": [ + {"name": "MyFloat", "type": "float"}, + {"name": "MyFloat2", "type": "vector2"}, + {"name": "MyFloat3", "type": "vector3"} + ] + }, + { + "name": "groupC", + "properties": [ + {"name": "MyFloat4", "type": "vector4"}, + {"name": "MyColor", "type": "color"}, + {"name": "MyImage", "type": "image"} + ] + } + ] + } + } + )"; const char* materialTypeFilePath = "@exefolder@/Gems/Atom/RPI/Code/Tests/Material/Temp/roundTripTest.materialtype"; @@ -259,25 +264,29 @@ namespace UnitTest MaterialSourceData sourceDataCopy; JsonTestResult loadResult = LoadTestDataFromJson(sourceDataCopy, sourceDataSerialized); - + CheckEqual(sourceDataOriginal, sourceDataCopy); } TEST_F(MaterialSourceDataTests, Load_MaterialTypeAfterPropertyList) { const AZStd::string simpleMaterialTypeJson = R"( - { - "propertyLayout": { - "properties": { - "general": [ + { + "propertyLayout": { + "propertySets": + [ { - "name": "testColor", - "type": "color" + "name": "general", + "properties": [ + { + "name": "testColor", + "type": "color" + } + ] } ] } } - } )"; const char* materialTypeFilePath = "@exefolder@/Gems/Atom/RPI/Code/Tests/Material/Temp/simpleMaterialType.materialtype"; @@ -376,18 +385,22 @@ namespace UnitTest TEST_F(MaterialSourceDataTests, Load_MaterialTypeMessagesAreReported) { const AZStd::string simpleMaterialTypeJson = R"( - { - "propertyLayout": { - "properties": { - "general": [ + { + "propertyLayout": { + "propertySets": + [ { - "name": "testColor", - "type": "color" + "name": "general", + "properties": [ + { + "name": "testColor", + "type": "color" + } + ] } ] } } - } )"; const char* materialTypeFilePath = "@exefolder@/Gems/Atom/RPI/Code/Tests/Material/Temp/simpleMaterialType.materialtype"; @@ -416,24 +429,28 @@ namespace UnitTest EXPECT_EQ(AZ::JsonSerializationResult::Processing::Completed, loadResult.m_jsonResultCode.GetProcessing()); // propertyLayout is a field in the material type, not the material - EXPECT_TRUE(loadResult.ContainsMessage("[simpleMaterialType.materialtype]/propertyLayout/properties", "Successfully read")); + EXPECT_TRUE(loadResult.ContainsMessage("[simpleMaterialType.materialtype]/propertyLayout/propertySets", "Successfully read")); } TEST_F(MaterialSourceDataTests, Load_Error_PropertyNotFound) { const AZStd::string simpleMaterialTypeJson = R"( - { - "propertyLayout": { - "properties": { - "general": [ + { + "propertyLayout": { + "propertySets": + [ { - "name": "testColor", - "type": "color" + "name": "general", + "properties": [ + { + "name": "testColor", + "type": "color" + } + ] } ] } } - } )"; const char* materialTypeFilePath = "@exefolder@/Gems/Atom/RPI/Code/Tests/Material/Temp/simpleMaterialType.materialtype"; diff --git a/Gems/Atom/RPI/Code/Tests/Material/MaterialTypeSourceDataTests.cpp b/Gems/Atom/RPI/Code/Tests/Material/MaterialTypeSourceDataTests.cpp index ba4a58b9ff..00523abbd8 100644 --- a/Gems/Atom/RPI/Code/Tests/Material/MaterialTypeSourceDataTests.cpp +++ b/Gems/Atom/RPI/Code/Tests/Material/MaterialTypeSourceDataTests.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -225,6 +226,7 @@ namespace UnitTest { serializeContext->Class() ->Version(1) + ->Field("enableProperty", &SetShaderOptionFunctorSourceData::m_enablePropertyName) ; } } @@ -243,6 +245,8 @@ namespace UnitTest Ptr functor = aznew SetShaderOptionFunctor; return Success(Ptr(functor)); } + + AZStd::string m_enablePropertyName; }; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -350,9 +354,316 @@ namespace UnitTest EXPECT_EQ(propertyDescriptor->GetOutputConnections()[i].m_containerIndex.GetIndex(), expectedValues.m_outputConnections[i].m_shaderIndex); } } - }; + TEST_F(MaterialTypeSourceDataTests, PopulateAndSearchPropertyLayout) + { + MaterialTypeSourceData sourceData; + + // Here we are building up multiple layers of property sets and properties, using a variety of different Add functions, + // going through the MaterialTypeSourceData or going to the PropertySet directly. + + MaterialTypeSourceData::PropertySet* layer1 = sourceData.AddPropertySet("layer1"); + MaterialTypeSourceData::PropertySet* layer2 = sourceData.AddPropertySet("layer2"); + MaterialTypeSourceData::PropertySet* blend = sourceData.AddPropertySet("blend"); + + MaterialTypeSourceData::PropertySet* layer1_baseColor = layer1->AddPropertySet("baseColor"); + MaterialTypeSourceData::PropertySet* layer2_baseColor = layer2->AddPropertySet("baseColor"); + + MaterialTypeSourceData::PropertySet* layer1_roughness = sourceData.AddPropertySet("layer1.roughness"); + MaterialTypeSourceData::PropertySet* layer2_roughness = sourceData.AddPropertySet("layer2.roughness"); + + MaterialTypeSourceData::PropertyDefinition* layer1_baseColor_texture = layer1_baseColor->AddProperty("texture"); + MaterialTypeSourceData::PropertyDefinition* layer2_baseColor_texture = layer2_baseColor->AddProperty("texture"); + + MaterialTypeSourceData::PropertyDefinition* layer1_roughness_texture = sourceData.AddProperty("layer1.roughness.texture"); + MaterialTypeSourceData::PropertyDefinition* layer2_roughness_texture = sourceData.AddProperty("layer2.roughness.texture"); + + // We're doing clear coat only on layer2, for brevity + MaterialTypeSourceData::PropertySet* layer2_clearCoat = layer2->AddPropertySet("clearCoat"); + MaterialTypeSourceData::PropertySet* layer2_clearCoat_roughness = layer2_clearCoat->AddPropertySet("roughness"); + MaterialTypeSourceData::PropertySet* layer2_clearCoat_normal = layer2_clearCoat->AddPropertySet("normal"); + MaterialTypeSourceData::PropertyDefinition* layer2_clearCoat_enabled = layer2_clearCoat->AddProperty("enabled"); + MaterialTypeSourceData::PropertyDefinition* layer2_clearCoat_roughness_texture = layer2_clearCoat_roughness->AddProperty("texture"); + MaterialTypeSourceData::PropertyDefinition* layer2_clearCoat_normal_texture = layer2_clearCoat_normal->AddProperty("texture"); + MaterialTypeSourceData::PropertyDefinition* layer2_clearCoat_normal_factor = layer2_clearCoat_normal->AddProperty("factor"); + + MaterialTypeSourceData::PropertyDefinition* blend_factor = blend->AddProperty("factor"); + + // Check the available Find functions + + EXPECT_EQ(nullptr, sourceData.FindProperty("DoesNotExist")); + EXPECT_EQ(nullptr, sourceData.FindProperty("layer1.DoesNotExist")); + EXPECT_EQ(nullptr, sourceData.FindProperty("layer1.baseColor.DoesNotExist")); + EXPECT_EQ(nullptr, sourceData.FindProperty("baseColor.texture")); + EXPECT_EQ(nullptr, sourceData.FindProperty("baseColor")); // This is a property set, not a property + EXPECT_EQ(nullptr, sourceData.FindPropertySet("baseColor.texture")); // This is a property, not a property set + + EXPECT_EQ(layer1, sourceData.FindPropertySet("layer1")); + EXPECT_EQ(layer2, sourceData.FindPropertySet("layer2")); + EXPECT_EQ(blend, sourceData.FindPropertySet("blend")); + + EXPECT_EQ(layer1_baseColor, sourceData.FindPropertySet("layer1.baseColor")); + EXPECT_EQ(layer2_baseColor, sourceData.FindPropertySet("layer2.baseColor")); + + EXPECT_EQ(layer1_roughness, sourceData.FindPropertySet("layer1.roughness")); + EXPECT_EQ(layer2_roughness, sourceData.FindPropertySet("layer2.roughness")); + + EXPECT_EQ(layer1_baseColor_texture, sourceData.FindProperty("layer1.baseColor.texture")); + EXPECT_EQ(layer2_baseColor_texture, sourceData.FindProperty("layer2.baseColor.texture")); + EXPECT_EQ(layer1_roughness_texture, sourceData.FindProperty("layer1.roughness.texture")); + EXPECT_EQ(layer2_roughness_texture, sourceData.FindProperty("layer2.roughness.texture")); + + EXPECT_EQ(layer2_clearCoat, sourceData.FindPropertySet("layer2.clearCoat")); + EXPECT_EQ(layer2_clearCoat_roughness, sourceData.FindPropertySet("layer2.clearCoat.roughness")); + EXPECT_EQ(layer2_clearCoat_normal, sourceData.FindPropertySet("layer2.clearCoat.normal")); + + EXPECT_EQ(layer2_clearCoat_enabled, sourceData.FindProperty("layer2.clearCoat.enabled")); + EXPECT_EQ(layer2_clearCoat_roughness_texture, sourceData.FindProperty("layer2.clearCoat.roughness.texture")); + EXPECT_EQ(layer2_clearCoat_normal_texture, sourceData.FindProperty("layer2.clearCoat.normal.texture")); + EXPECT_EQ(layer2_clearCoat_normal_factor, sourceData.FindProperty("layer2.clearCoat.normal.factor")); + + EXPECT_EQ(blend_factor, sourceData.FindProperty("blend.factor")); + + // Check EnumeratePropertySets + + struct EnumeratePropertySetsResult + { + AZStd::string m_propertyIdContext; + const MaterialTypeSourceData::PropertySet* m_propertySet; + + void Check(AZStd::string expectedIdContext, const MaterialTypeSourceData::PropertySet* expectedPropertySet) + { + EXPECT_EQ(expectedIdContext, m_propertyIdContext); + EXPECT_EQ(expectedPropertySet, m_propertySet); + } + }; + AZStd::vector enumeratePropertySetsResults; + + sourceData.EnumeratePropertySets([&enumeratePropertySetsResults](const AZStd::string& propertyIdContext, const MaterialTypeSourceData::PropertySet* propertySet) + { + enumeratePropertySetsResults.push_back(EnumeratePropertySetsResult{propertyIdContext, propertySet}); + return true; + }); + + int resultIndex = 0; + enumeratePropertySetsResults[resultIndex++].Check("", layer1); + enumeratePropertySetsResults[resultIndex++].Check("layer1.", layer1_baseColor); + enumeratePropertySetsResults[resultIndex++].Check("layer1.", layer1_roughness); + enumeratePropertySetsResults[resultIndex++].Check("", layer2); + enumeratePropertySetsResults[resultIndex++].Check("layer2.", layer2_baseColor); + enumeratePropertySetsResults[resultIndex++].Check("layer2.", layer2_roughness); + enumeratePropertySetsResults[resultIndex++].Check("layer2.", layer2_clearCoat); + enumeratePropertySetsResults[resultIndex++].Check("layer2.clearCoat.", layer2_clearCoat_roughness); + enumeratePropertySetsResults[resultIndex++].Check("layer2.clearCoat.", layer2_clearCoat_normal); + enumeratePropertySetsResults[resultIndex++].Check("", blend); + EXPECT_EQ(resultIndex, enumeratePropertySetsResults.size()); + + // Check EnumerateProperties + + struct EnumeratePropertiesResult + { + AZStd::string m_propertyIdContext; + const MaterialTypeSourceData::PropertyDefinition* m_propertyDefinition; + + void Check(AZStd::string expectedIdContext, const MaterialTypeSourceData::PropertyDefinition* expectedPropertyDefinition) + { + EXPECT_EQ(expectedIdContext, m_propertyIdContext); + EXPECT_EQ(expectedPropertyDefinition, m_propertyDefinition); + } + }; + AZStd::vector enumeratePropertiesResults; + + sourceData.EnumerateProperties([&enumeratePropertiesResults](const AZStd::string& propertyIdContext, const MaterialTypeSourceData::PropertyDefinition* propertyDefinition) + { + enumeratePropertiesResults.push_back(EnumeratePropertiesResult{propertyIdContext, propertyDefinition}); + return true; + }); + + resultIndex = 0; + enumeratePropertiesResults[resultIndex++].Check("layer1.baseColor.", layer1_baseColor_texture); + enumeratePropertiesResults[resultIndex++].Check("layer1.roughness.", layer1_roughness_texture); + enumeratePropertiesResults[resultIndex++].Check("layer2.baseColor.", layer2_baseColor_texture); + enumeratePropertiesResults[resultIndex++].Check("layer2.roughness.", layer2_roughness_texture); + enumeratePropertiesResults[resultIndex++].Check("layer2.clearCoat.", layer2_clearCoat_enabled); + enumeratePropertiesResults[resultIndex++].Check("layer2.clearCoat.roughness.", layer2_clearCoat_roughness_texture); + enumeratePropertiesResults[resultIndex++].Check("layer2.clearCoat.normal.", layer2_clearCoat_normal_texture); + enumeratePropertiesResults[resultIndex++].Check("layer2.clearCoat.normal.", layer2_clearCoat_normal_factor); + enumeratePropertiesResults[resultIndex++].Check("blend.", blend_factor); + EXPECT_EQ(resultIndex, enumeratePropertiesResults.size()); + } + + TEST_F(MaterialTypeSourceDataTests, AddProperty_Error_AddPropertyWithInvalidName) + { + MaterialTypeSourceData sourceData; + + MaterialTypeSourceData::PropertySet* propertySet = sourceData.AddPropertySet("main"); + + ErrorMessageFinder errorMessageFinder; + errorMessageFinder.AddExpectedErrorMessage("'' is not a valid identifier"); + errorMessageFinder.AddExpectedErrorMessage("'main.' is not a valid identifier"); + errorMessageFinder.AddExpectedErrorMessage("'base-color' is not a valid identifier"); + + EXPECT_FALSE(propertySet->AddProperty("")); + EXPECT_FALSE(propertySet->AddProperty("main.")); + EXPECT_FALSE(sourceData.AddProperty("main.base-color")); + + EXPECT_TRUE(propertySet->GetProperties().empty()); + + errorMessageFinder.CheckExpectedErrorsFound(); + } + + TEST_F(MaterialTypeSourceDataTests, AddPropertySet_Error_InvalidName) + { + MaterialTypeSourceData sourceData; + + MaterialTypeSourceData::PropertySet* propertySet = sourceData.AddPropertySet("general"); + + ErrorMessageFinder errorMessageFinder; + errorMessageFinder.AddExpectedErrorMessage("'' is not a valid identifier", 2); + errorMessageFinder.AddExpectedErrorMessage("'base-color' is not a valid identifier"); + errorMessageFinder.AddExpectedErrorMessage("'look@it' is not a valid identifier"); + + EXPECT_FALSE(propertySet->AddPropertySet("")); + EXPECT_FALSE(sourceData.AddPropertySet("")); + EXPECT_FALSE(sourceData.AddPropertySet("base-color")); + EXPECT_FALSE(sourceData.AddPropertySet("general.look@it")); + + EXPECT_TRUE(propertySet->GetProperties().empty()); + + errorMessageFinder.CheckExpectedErrorsFound(); + } + + TEST_F(MaterialTypeSourceDataTests, AddProperty_Error_AddDuplicateProperty) + { + MaterialTypeSourceData sourceData; + + MaterialTypeSourceData::PropertySet* propertySet = sourceData.AddPropertySet("main"); + + ErrorMessageFinder errorMessageFinder; + errorMessageFinder.AddExpectedErrorMessage("PropertySet 'main' already contains a property named 'foo'", 2); + + EXPECT_TRUE(propertySet->AddProperty("foo")); + EXPECT_FALSE(propertySet->AddProperty("foo")); + EXPECT_FALSE(sourceData.AddProperty("main.foo")); + + EXPECT_EQ(propertySet->GetProperties().size(), 1); + + errorMessageFinder.CheckExpectedErrorsFound(); + } + + TEST_F(MaterialTypeSourceDataTests, AddProperty_Error_AddLooseProperty) + { + MaterialTypeSourceData sourceData; + ErrorMessageFinder errorMessageFinder("Property id 'foo' is invalid. Properties must be added to a PropertySet"); + EXPECT_FALSE(sourceData.AddProperty("foo")); + errorMessageFinder.CheckExpectedErrorsFound(); + } + + TEST_F(MaterialTypeSourceDataTests, AddProperty_Error_PropertySetDoesNotExist ) + { + MaterialTypeSourceData sourceData; + ErrorMessageFinder errorMessageFinder("PropertySet 'DNE' does not exists"); + EXPECT_FALSE(sourceData.AddProperty("DNE.foo")); + errorMessageFinder.CheckExpectedErrorsFound(); + } + + TEST_F(MaterialTypeSourceDataTests, AddPropertySet_Error_PropertySetDoesNotExist ) + { + MaterialTypeSourceData sourceData; + ErrorMessageFinder errorMessageFinder("PropertySet 'DNE' does not exists"); + EXPECT_FALSE(sourceData.AddPropertySet("DNE.foo")); + errorMessageFinder.CheckExpectedErrorsFound(); + } + + TEST_F(MaterialTypeSourceDataTests, AddPropertySet_Error_AddDuplicatePropertySet) + { + MaterialTypeSourceData sourceData; + + MaterialTypeSourceData::PropertySet* propertySet = sourceData.AddPropertySet("main"); + sourceData.AddPropertySet("main.level2"); + + ErrorMessageFinder errorMessageFinder; + errorMessageFinder.AddExpectedErrorMessage("PropertySet named 'main' already exists", 1); + errorMessageFinder.AddExpectedErrorMessage("PropertySet named 'level2' already exists", 2); + + EXPECT_FALSE(sourceData.AddPropertySet("main")); + EXPECT_FALSE(sourceData.AddPropertySet("main.level2")); + EXPECT_FALSE(propertySet->AddPropertySet("level2")); + + errorMessageFinder.CheckExpectedErrorsFound(); + + EXPECT_EQ(sourceData.GetPropertyLayout().m_propertySets.size(), 1); + EXPECT_EQ(propertySet->GetPropertySets().size(), 1); + } + + TEST_F(MaterialTypeSourceDataTests, AddPropertySet_Error_NameCollidesWithProperty ) + { + MaterialTypeSourceData sourceData; + sourceData.AddPropertySet("main"); + sourceData.AddProperty("main.foo"); + + ErrorMessageFinder errorMessageFinder("PropertySet name 'foo' collides with a Property of the same name"); + EXPECT_FALSE(sourceData.AddPropertySet("main.foo")); + errorMessageFinder.CheckExpectedErrorsFound(); + } + + TEST_F(MaterialTypeSourceDataTests, AddProperty_Error_NameCollidesWithPropertySet ) + { + MaterialTypeSourceData sourceData; + sourceData.AddPropertySet("main"); + sourceData.AddPropertySet("main.foo"); + + ErrorMessageFinder errorMessageFinder("Property name 'foo' collides with a PropertySet of the same name"); + EXPECT_FALSE(sourceData.AddProperty("main.foo")); + errorMessageFinder.CheckExpectedErrorsFound(); + } + + TEST_F(MaterialTypeSourceDataTests, ResolveUvStreamAsEnum) + { + MaterialTypeSourceData sourceData; + + sourceData.m_uvNameMap["UV0"] = "Tiled"; + sourceData.m_uvNameMap["UV1"] = "Unwrapped"; + sourceData.m_uvNameMap["UV2"] = "Other"; + + sourceData.AddPropertySet("a"); + sourceData.AddPropertySet("a.b"); + sourceData.AddPropertySet("c"); + sourceData.AddPropertySet("c.d"); + sourceData.AddPropertySet("c.d.e"); + + MaterialTypeSourceData::PropertyDefinition* enum1 = sourceData.AddProperty("a.enum1"); + MaterialTypeSourceData::PropertyDefinition* enum2 = sourceData.AddProperty("a.b.enum2"); + MaterialTypeSourceData::PropertyDefinition* enum3 = sourceData.AddProperty("c.d.e.enum3"); + MaterialTypeSourceData::PropertyDefinition* notEnum = sourceData.AddProperty("c.d.myFloat"); + + enum1->m_dataType = MaterialPropertyDataType::Enum; + enum2->m_dataType = MaterialPropertyDataType::Enum; + enum3->m_dataType = MaterialPropertyDataType::Enum; + notEnum->m_dataType = MaterialPropertyDataType::Float; + + enum1->m_enumIsUv = true; + enum2->m_enumIsUv = false; + enum3->m_enumIsUv = true; + + sourceData.ResolveUvEnums(); + + EXPECT_STREQ(enum1->m_enumValues[0].c_str(), "Tiled"); + EXPECT_STREQ(enum1->m_enumValues[1].c_str(), "Unwrapped"); + EXPECT_STREQ(enum1->m_enumValues[2].c_str(), "Other"); + + EXPECT_STREQ(enum3->m_enumValues[0].c_str(), "Tiled"); + EXPECT_STREQ(enum3->m_enumValues[1].c_str(), "Unwrapped"); + EXPECT_STREQ(enum3->m_enumValues[2].c_str(), "Other"); + + // enum2 is not a UV stream enum + EXPECT_EQ(enum2->m_enumValues.size(), 0); + + // myFloat is not even an enum + EXPECT_EQ(notEnum->m_enumValues.size(), 0); + } + TEST_F(MaterialTypeSourceDataTests, CreateMaterialTypeAsset_GetMaterialSrgAsset) { MaterialTypeSourceData sourceData; @@ -509,15 +820,14 @@ namespace UnitTest sourceData.m_shaderCollection.push_back(MaterialTypeSourceData::ShaderVariantReferenceData{ TestShaderFilename }); - MaterialTypeSourceData::PropertyDefinition propertySource; - propertySource.m_name = "MyBool"; - propertySource.m_displayName = "My Bool"; - propertySource.m_description = "This is a bool"; - propertySource.m_dataType = MaterialPropertyDataType::Bool; - propertySource.m_value = true; - propertySource.m_outputConnections.push_back(MaterialTypeSourceData::PropertyConnection{ MaterialPropertyOutputType::ShaderInput, AZStd::string("m_bool") }); - sourceData.m_propertyLayout.m_properties["general"].push_back(propertySource); - + MaterialTypeSourceData::PropertySet* propertySet = sourceData.AddPropertySet("general"); + MaterialTypeSourceData::PropertyDefinition* property = propertySet->AddProperty("MyBool"); + property->m_displayName = "My Bool"; + property->m_description = "This is a bool"; + property->m_dataType = MaterialPropertyDataType::Bool; + property->m_value = true; + property->m_outputConnections.push_back(MaterialTypeSourceData::PropertyConnection{ MaterialPropertyOutputType::ShaderInput, AZStd::string("m_bool") }); + auto materialTypeOutcome = sourceData.CreateMaterialTypeAsset(Uuid::CreateRandom()); EXPECT_TRUE(materialTypeOutcome.IsSuccess()); Data::Asset materialTypeAsset = materialTypeOutcome.GetValue(); @@ -525,7 +835,7 @@ namespace UnitTest const MaterialPropertyIndex propertyIndex = materialTypeAsset->GetMaterialPropertiesLayout()->FindPropertyIndex(Name{ "general.MyBool" }); const MaterialPropertyDescriptor* propertyDescriptor = materialTypeAsset->GetMaterialPropertiesLayout()->GetPropertyDescriptor(propertyIndex); - ValidateCommonDescriptorFields(propertySource, propertyDescriptor); + ValidateCommonDescriptorFields(*property, propertyDescriptor); EXPECT_EQ(propertyDescriptor->GetOutputConnections()[0].m_itemIndex.GetIndex(), 7); } @@ -534,20 +844,19 @@ namespace UnitTest MaterialTypeSourceData sourceData; sourceData.m_shaderCollection.push_back(MaterialTypeSourceData::ShaderVariantReferenceData{ TestShaderFilename }); - - MaterialTypeSourceData::PropertyDefinition propertySource; - propertySource.m_name = "MyFloat"; - propertySource.m_displayName = "My Float"; - propertySource.m_description = "This is a float"; - propertySource.m_min = 0.0f; - propertySource.m_max = 1.0f; - propertySource.m_softMin = 0.2f; - propertySource.m_softMax = 1.0f; - propertySource.m_step = 0.01f; - propertySource.m_dataType = MaterialPropertyDataType::Float; - propertySource.m_outputConnections.push_back(MaterialTypeSourceData::PropertyConnection{ MaterialPropertyOutputType::ShaderInput, AZStd::string("m_float") }); - sourceData.m_propertyLayout.m_properties["general"].push_back(propertySource); - + + MaterialTypeSourceData::PropertySet* propertySet = sourceData.AddPropertySet("general"); + MaterialTypeSourceData::PropertyDefinition* property = propertySet->AddProperty("MyFloat"); + property->m_displayName = "My Float"; + property->m_description = "This is a float"; + property->m_min = 0.0f; + property->m_max = 1.0f; + property->m_softMin = 0.2f; + property->m_softMax = 1.0f; + property->m_step = 0.01f; + property->m_dataType = MaterialPropertyDataType::Float; + property->m_outputConnections.push_back(MaterialTypeSourceData::PropertyConnection{ MaterialPropertyOutputType::ShaderInput, AZStd::string("m_float") }); + auto materialTypeOutcome = sourceData.CreateMaterialTypeAsset(Uuid::CreateRandom()); EXPECT_TRUE(materialTypeOutcome.IsSuccess()); Data::Asset materialTypeAsset = materialTypeOutcome.GetValue(); @@ -555,7 +864,7 @@ namespace UnitTest const MaterialPropertyIndex propertyIndex = materialTypeAsset->GetMaterialPropertiesLayout()->FindPropertyIndex(Name{"general.MyFloat" }); const MaterialPropertyDescriptor* propertyDescriptor = materialTypeAsset->GetMaterialPropertiesLayout()->GetPropertyDescriptor(propertyIndex); - ValidateCommonDescriptorFields(propertySource, propertyDescriptor); + ValidateCommonDescriptorFields(*property, propertyDescriptor); EXPECT_EQ(propertyDescriptor->GetOutputConnections()[0].m_itemIndex.GetIndex(), 1); } @@ -564,15 +873,14 @@ namespace UnitTest MaterialTypeSourceData sourceData; sourceData.m_shaderCollection.push_back(MaterialTypeSourceData::ShaderVariantReferenceData{ TestShaderFilename }); - - MaterialTypeSourceData::PropertyDefinition propertySource; - propertySource.m_name = "MyImage"; - propertySource.m_displayName = "My Image"; - propertySource.m_description = "This is an image"; - propertySource.m_dataType = MaterialPropertyDataType::Image; - propertySource.m_outputConnections.push_back(MaterialTypeSourceData::PropertyConnection{ MaterialPropertyOutputType::ShaderInput, AZStd::string("m_image") }); - sourceData.m_propertyLayout.m_properties["general"].push_back(propertySource); - + + MaterialTypeSourceData::PropertySet* propertySet = sourceData.AddPropertySet("general"); + MaterialTypeSourceData::PropertyDefinition* property = propertySet->AddProperty("MyImage"); + property->m_displayName = "My Image"; + property->m_description = "This is an image"; + property->m_dataType = MaterialPropertyDataType::Image; + property->m_outputConnections.push_back(MaterialTypeSourceData::PropertyConnection{ MaterialPropertyOutputType::ShaderInput, AZStd::string("m_image") }); + auto materialTypeOutcome = sourceData.CreateMaterialTypeAsset(Uuid::CreateRandom()); EXPECT_TRUE(materialTypeOutcome.IsSuccess()); Data::Asset materialTypeAsset = materialTypeOutcome.GetValue(); @@ -580,7 +888,7 @@ namespace UnitTest const MaterialPropertyIndex propertyIndex = materialTypeAsset->GetMaterialPropertiesLayout()->FindPropertyIndex(Name{"general.MyImage" }); const MaterialPropertyDescriptor* propertyDescriptor = materialTypeAsset->GetMaterialPropertiesLayout()->GetPropertyDescriptor(propertyIndex); - ValidateCommonDescriptorFields(propertySource, propertyDescriptor); + ValidateCommonDescriptorFields(*property, propertyDescriptor); EXPECT_EQ(propertyDescriptor->GetOutputConnections()[0].m_itemIndex.GetIndex(), 0); } @@ -589,21 +897,20 @@ namespace UnitTest MaterialTypeSourceData sourceData; sourceData.m_shaderCollection.push_back(MaterialTypeSourceData::ShaderVariantReferenceData{TestShaderFilename}); - - MaterialTypeSourceData::PropertyDefinition propertySource; - propertySource.m_name = "MyInt"; - propertySource.m_displayName = "My Integer"; - propertySource.m_dataType = MaterialPropertyDataType::Int; - propertySource.m_outputConnections.push_back(MaterialTypeSourceData::PropertyConnection{MaterialPropertyOutputType::ShaderOption, AZStd::string("o_foo"), 0}); - sourceData.m_propertyLayout.m_properties["general"].push_back(propertySource); - + + MaterialTypeSourceData::PropertySet* propertySet = sourceData.AddPropertySet("general"); + MaterialTypeSourceData::PropertyDefinition* property = propertySet->AddProperty("MyInt"); + property->m_displayName = "My Integer"; + property->m_dataType = MaterialPropertyDataType::Int; + property->m_outputConnections.push_back(MaterialTypeSourceData::PropertyConnection{MaterialPropertyOutputType::ShaderOption, AZStd::string("o_foo"), 0}); + auto materialTypeOutcome = sourceData.CreateMaterialTypeAsset(Uuid::CreateRandom()); EXPECT_TRUE(materialTypeOutcome.IsSuccess()); Data::Asset materialTypeAsset = materialTypeOutcome.GetValue(); const MaterialPropertyDescriptor* propertyDescriptor = materialTypeAsset->GetMaterialPropertiesLayout()->GetPropertyDescriptor(MaterialPropertyIndex{0}); - ValidateCommonDescriptorFields(propertySource, propertyDescriptor); + ValidateCommonDescriptorFields(*property, propertyDescriptor); EXPECT_EQ(propertyDescriptor->GetOutputConnections()[0].m_itemIndex.GetIndex(), 1); } @@ -612,13 +919,12 @@ namespace UnitTest MaterialTypeSourceData sourceData; sourceData.m_shaderCollection.push_back(MaterialTypeSourceData::ShaderVariantReferenceData{TestShaderFilename}); - - MaterialTypeSourceData::PropertyDefinition propertySource; - propertySource.m_name = "MyInt"; - propertySource.m_dataType = MaterialPropertyDataType::Int; - propertySource.m_outputConnections.push_back(MaterialTypeSourceData::PropertyConnection{MaterialPropertyOutputType::ShaderOption, AZStd::string("DoesNotExist"), 0}); - sourceData.m_propertyLayout.m_properties["general"].push_back(propertySource); - + + MaterialTypeSourceData::PropertySet* propertySet = sourceData.AddPropertySet("general"); + MaterialTypeSourceData::PropertyDefinition* property = propertySet->AddProperty("MyInt"); + property->m_dataType = MaterialPropertyDataType::Int; + property->m_outputConnections.push_back(MaterialTypeSourceData::PropertyConnection{MaterialPropertyOutputType::ShaderOption, AZStd::string("DoesNotExist"), 0}); + AZ_TEST_START_TRACE_SUPPRESSION; auto materialTypeOutcome = sourceData.CreateMaterialTypeAsset(Uuid::CreateRandom()); AZ_TEST_STOP_TRACE_SUPPRESSION(2); // There happens to be an extra assert for "Cannot continue building MaterialAsset because 1 error(s) reported" @@ -626,66 +932,140 @@ namespace UnitTest EXPECT_FALSE(materialTypeOutcome.IsSuccess()); } - TEST_F(MaterialTypeSourceDataTests, CreateMaterialTypeAsset_Error_InvalidGroupNameId) + TEST_F(MaterialTypeSourceDataTests, CreateMaterialTypeAsset_Error_InvalidGroupName) { - MaterialTypeSourceData sourceData; - - MaterialTypeSourceData::PropertyDefinition propertySource; - propertySource.m_dataType = MaterialPropertyDataType::Int; - - propertySource.m_name = "a"; - sourceData.m_propertyLayout.m_properties["not a valid name because it has spaces"].push_back(propertySource); + const AZStd::string inputJson = R"( + { + "propertyLayout": { + "propertySets": [ + { + "name": "not a valid name because it has spaces", + "properties": [ + { + "name": "foo", + "type": "Bool" + } + ] + } + ] + } + } + )"; - // Expected errors: - // Group name 'not a valid name because it has spaces' is not a valid identifier. - // Warning: Cannot create material property with invalid ID 'not a valid name because it has spaces'. - // Failed to build MaterialAsset because 1 warning(s) reported - AZ_TEST_START_TRACE_SUPPRESSION; + MaterialTypeSourceData sourceData; + JsonTestResult loadResult = LoadTestDataFromJson(sourceData, inputJson); + EXPECT_EQ(loadResult.m_jsonResultCode.GetProcessing(), JsonSerializationResult::Processing::Completed); + + ErrorMessageFinder errorMessageFinder{"'not a valid name because it has spaces' is not a valid identifier"}; auto materialTypeOutcome = sourceData.CreateMaterialTypeAsset(Uuid::CreateRandom()); - AZ_TEST_STOP_TRACE_SUPPRESSION(2); - EXPECT_FALSE(materialTypeOutcome.IsSuccess()); + errorMessageFinder.CheckExpectedErrorsFound(); } - TEST_F(MaterialTypeSourceDataTests, CreateMaterialTypeAsset_Error_InvalidPropertyNameId) + TEST_F(MaterialTypeSourceDataTests, CreateMaterialTypeAsset_Error_InvalidPropertyName) { - MaterialTypeSourceData sourceData; - - MaterialTypeSourceData::PropertyDefinition propertySource; - propertySource.m_dataType = MaterialPropertyDataType::Int; - - propertySource.m_name = "not a valid name because it has spaces"; - sourceData.m_propertyLayout.m_properties["general"].push_back(propertySource); + const AZStd::string inputJson = R"( + { + "propertyLayout": { + "propertySets": [ + { + "name": "general", + "properties": [ + { + "name": "not a valid name because it has spaces", + "type": "Bool" + } + ] + } + ] + } + } + )"; - // Expected errors: - // Property name 'not a valid name because it has spaces' is not a valid identifier. - // Warning: Cannot create material property with invalid ID 'not a valid name because it has spaces'. - // Failed to build MaterialAsset because 1 warning(s) reported - AZ_TEST_START_TRACE_SUPPRESSION; + MaterialTypeSourceData sourceData; + JsonTestResult loadResult = LoadTestDataFromJson(sourceData, inputJson); + EXPECT_EQ(loadResult.m_jsonResultCode.GetProcessing(), JsonSerializationResult::Processing::Completed); + + ErrorMessageFinder errorMessageFinder{"'not a valid name because it has spaces' is not a valid identifier"}; auto materialTypeOutcome = sourceData.CreateMaterialTypeAsset(Uuid::CreateRandom()); - AZ_TEST_STOP_TRACE_SUPPRESSION(2); - EXPECT_FALSE(materialTypeOutcome.IsSuccess()); + errorMessageFinder.CheckExpectedErrorsFound(); } TEST_F(MaterialTypeSourceDataTests, CreateMaterialTypeAsset_Error_DuplicatePropertyId) { - MaterialTypeSourceData sourceData; - - MaterialTypeSourceData::PropertyDefinition propertySource; - propertySource.m_dataType = MaterialPropertyDataType::Int; - propertySource.m_name = "a"; - sourceData.m_propertyLayout.m_properties["general"].push_back(propertySource); - sourceData.m_propertyLayout.m_properties["general"].push_back(propertySource); + const AZStd::string inputJson = R"( + { + "propertyLayout": { + "propertySets": [ + { + "name": "general", + "properties": [ + { + "name": "foo", + "type": "Bool" + }, + { + "name": "foo", + "type": "Bool" + } + ] + } + ] + } + } + )"; - // Expected errors: - // Material property 'general.a': A property with this ID already exists. - // Cannot continue building MaterialAsset because 1 error(s) reported - AZ_TEST_START_TRACE_SUPPRESSION; + MaterialTypeSourceData sourceData; + JsonTestResult loadResult = LoadTestDataFromJson(sourceData, inputJson); + EXPECT_EQ(loadResult.m_jsonResultCode.GetProcessing(), JsonSerializationResult::Processing::Completed); + + ErrorMessageFinder errorMessageFinder("Material property 'general.foo': A property with this ID already exists"); + errorMessageFinder.AddExpectedErrorMessage("Cannot continue building MaterialTypeAsset"); auto materialTypeOutcome = sourceData.CreateMaterialTypeAsset(Uuid::CreateRandom()); - AZ_TEST_STOP_TRACE_SUPPRESSION(2); + EXPECT_FALSE(materialTypeOutcome.IsSuccess()); + errorMessageFinder.CheckExpectedErrorsFound(); + } + + TEST_F(MaterialTypeSourceDataTests, CreateMaterialTypeAsset_Error_PropertyAndPropertySetNameCollision) + { + const AZStd::string inputJson = R"( + { + "propertyLayout": { + "propertySets": [ + { + "name": "general", + "properties": [ + { + "name": "foo", + "type": "Bool" + } + ], + "propertySets": [ + { + "name": "foo", + "properties": [ + { + "name": "bar", + "type": "Bool" + } + ] + } + ] + } + ] + } + } + )"; + MaterialTypeSourceData sourceData; + JsonTestResult loadResult = LoadTestDataFromJson(sourceData, inputJson); + EXPECT_EQ(loadResult.m_jsonResultCode.GetProcessing(), JsonSerializationResult::Processing::Completed); + + ErrorMessageFinder errorMessageFinder("Material property 'general.foo' collides with a PropertySet with the same ID"); + auto materialTypeOutcome = sourceData.CreateMaterialTypeAsset(Uuid::CreateRandom()); EXPECT_FALSE(materialTypeOutcome.IsSuccess()); + errorMessageFinder.CheckExpectedErrorsFound(); } TEST_F(MaterialTypeSourceDataTests, CreateMaterialTypeAsset_PropertyConnectedToMultipleOutputs) @@ -736,25 +1116,25 @@ namespace UnitTest sourceData.m_shaderCollection.push_back(MaterialTypeSourceData::ShaderVariantReferenceData{ "shaderA.shader" }); sourceData.m_shaderCollection.push_back(MaterialTypeSourceData::ShaderVariantReferenceData{ "shaderB.shader" }); sourceData.m_shaderCollection.push_back(MaterialTypeSourceData::ShaderVariantReferenceData{ "shaderC.shader" }); + + MaterialTypeSourceData::PropertySet* propertySet = sourceData.AddPropertySet("general"); + MaterialTypeSourceData::PropertyDefinition* property = propertySet->AddProperty("MyInt"); - MaterialTypeSourceData::PropertyDefinition propertySource; - propertySource.m_name = "MyInt"; - propertySource.m_displayName = "Integer"; - propertySource.m_description = "Integer property that is connected to multiple shader settings"; - propertySource.m_dataType = MaterialPropertyDataType::Int; + property->m_displayName = "Integer"; + property->m_description = "Integer property that is connected to multiple shader settings"; + property->m_dataType = MaterialPropertyDataType::Int; // The value maps to m_int in the SRG - propertySource.m_outputConnections.push_back(MaterialTypeSourceData::PropertyConnection{ MaterialPropertyOutputType::ShaderInput, AZStd::string("m_int") }); + property->m_outputConnections.push_back(MaterialTypeSourceData::PropertyConnection{ MaterialPropertyOutputType::ShaderInput, AZStd::string("m_int") }); // The value also maps to m_uint in the SRG - propertySource.m_outputConnections.push_back(MaterialTypeSourceData::PropertyConnection{ MaterialPropertyOutputType::ShaderInput, AZStd::string("m_uint") }); + property->m_outputConnections.push_back(MaterialTypeSourceData::PropertyConnection{ MaterialPropertyOutputType::ShaderInput, AZStd::string("m_uint") }); // The value also maps to the first shader's "o_speed" option - propertySource.m_outputConnections.push_back(MaterialTypeSourceData::PropertyConnection{ MaterialPropertyOutputType::ShaderOption, AZStd::string("o_speed"), 0 }); + property->m_outputConnections.push_back(MaterialTypeSourceData::PropertyConnection{ MaterialPropertyOutputType::ShaderOption, AZStd::string("o_speed"), 0 }); // The value also maps to the second shader's "o_speed" option - propertySource.m_outputConnections.push_back(MaterialTypeSourceData::PropertyConnection{ MaterialPropertyOutputType::ShaderOption, AZStd::string("o_speed"), 1 }); + property->m_outputConnections.push_back(MaterialTypeSourceData::PropertyConnection{ MaterialPropertyOutputType::ShaderOption, AZStd::string("o_speed"), 1 }); // This case doesn't specify an index, so it will apply to all shaders that have a "o_efficiency", which means it will create two outputs in the property descriptor. - propertySource.m_outputConnections.push_back(MaterialTypeSourceData::PropertyConnection{ MaterialPropertyOutputType::ShaderOption, AZStd::string("o_efficiency") }); - - sourceData.m_propertyLayout.m_properties["general"].push_back(propertySource); + property->m_outputConnections.push_back(MaterialTypeSourceData::PropertyConnection{ MaterialPropertyOutputType::ShaderOption, AZStd::string("o_efficiency") }); + // Do the actual test... @@ -795,15 +1175,15 @@ namespace UnitTest TEST_F(MaterialTypeSourceDataTests, CreateMaterialTypeAsset_PropertyWithShaderInputFunctor) { MaterialTypeSourceData sourceData; + + MaterialTypeSourceData::PropertySet* propertySet = sourceData.AddPropertySet("general"); + MaterialTypeSourceData::PropertyDefinition* property = propertySet->AddProperty("floatForFunctor"); - MaterialTypeSourceData::PropertyDefinition propertySource; - propertySource.m_name = "NonAliasFloat"; - propertySource.m_displayName = "Non-Alias Float"; - propertySource.m_description = "This float is processed by a functor, not with a direct alias"; - propertySource.m_dataType = MaterialPropertyDataType::Float; - // Note that we don't fill propertySource.m_aliasOutputId because this is not an aliased property - sourceData.m_propertyLayout.m_properties["general"].push_back(propertySource); - + property->m_displayName = "Float for Functor"; + property->m_description = "This float is processed by a functor, not with a direct connection"; + property->m_dataType = MaterialPropertyDataType::Float; + // Note that we don't fill property->m_outputConnections because this is not an aliased property + sourceData.m_shaderCollection.push_back(MaterialTypeSourceData::ShaderVariantReferenceData{TestShaderFilename}); sourceData.m_materialFunctorSourceData.push_back( @@ -811,7 +1191,7 @@ namespace UnitTest ( aznew MaterialFunctorSourceDataHolder ( - aznew Splat3FunctorSourceData{ "general.NonAliasFloat", "m_float3" } + aznew Splat3FunctorSourceData{ "general.floatForFunctor", "m_float3" } ) ) ); @@ -820,10 +1200,10 @@ namespace UnitTest EXPECT_TRUE(materialTypeOutcome.IsSuccess()); Data::Asset materialTypeAsset = materialTypeOutcome.GetValue(); - const MaterialPropertyIndex propertyIndex = materialTypeAsset->GetMaterialPropertiesLayout()->FindPropertyIndex(Name{"general.NonAliasFloat" }); + const MaterialPropertyIndex propertyIndex = materialTypeAsset->GetMaterialPropertiesLayout()->FindPropertyIndex(Name{"general.floatForFunctor" }); const MaterialPropertyDescriptor* propertyDescriptor = materialTypeAsset->GetMaterialPropertiesLayout()->GetPropertyDescriptor(propertyIndex); - ValidateCommonDescriptorFields(propertySource, propertyDescriptor); + ValidateCommonDescriptorFields(*property, propertyDescriptor); EXPECT_EQ(1, materialTypeAsset->GetMaterialFunctors().size()); auto shaderInputFunctor = azrtti_cast(materialTypeAsset->GetMaterialFunctors()[0].get()); @@ -841,15 +1221,13 @@ namespace UnitTest sourceData.m_shaderCollection.push_back(MaterialTypeSourceData::ShaderVariantReferenceData{TestShaderFilename}); sourceData.m_shaderCollection.push_back(MaterialTypeSourceData::ShaderVariantReferenceData{TestShaderFilename}); - MaterialTypeSourceData::PropertyDefinition propertySource; - propertySource.m_name = "EnableSpecialPassA"; - propertySource.m_displayName = "Enable Special Pass"; - propertySource.m_description = "This is a bool to enable an extra shader/pass"; - propertySource.m_dataType = MaterialPropertyDataType::Bool; - // Note that we don't fill propertySource.m_outputConnections because this is not a direct-connected property - sourceData.m_propertyLayout.m_properties["general"].push_back(propertySource); - propertySource.m_name = "EnableSpecialPassB"; - sourceData.m_propertyLayout.m_properties["general"].push_back(propertySource); + MaterialTypeSourceData::PropertySet* propertySet = sourceData.AddPropertySet("general"); + MaterialTypeSourceData::PropertyDefinition* property1 = propertySet->AddProperty("EnableSpecialPassA"); + MaterialTypeSourceData::PropertyDefinition* property2 = propertySet->AddProperty("EnableSpecialPassB"); + + property1->m_displayName = property2->m_displayName = "Enable Special Pass"; + property1->m_description = property2->m_description = "This is a bool to enable an extra shader/pass"; + property1->m_dataType = property2->m_dataType = MaterialPropertyDataType::Bool; sourceData.m_materialFunctorSourceData.push_back( Ptr @@ -880,8 +1258,8 @@ namespace UnitTest const MaterialPropertyIndex propertyBIndex = materialTypeAsset->GetMaterialPropertiesLayout()->FindPropertyIndex(Name{"general.EnableSpecialPassB"}); const MaterialPropertyDescriptor* propertyBDescriptor = materialTypeAsset->GetMaterialPropertiesLayout()->GetPropertyDescriptor(propertyBIndex); - ValidateCommonDescriptorFields(propertySource, propertyADescriptor); - ValidateCommonDescriptorFields(propertySource, propertyBDescriptor); + ValidateCommonDescriptorFields(*sourceData.FindProperty("general.EnableSpecialPassA"), propertyADescriptor); + ValidateCommonDescriptorFields(*sourceData.FindProperty("general.EnableSpecialPassB"), propertyBDescriptor); EXPECT_EQ(2, materialTypeAsset->GetMaterialFunctors().size()); auto functorA = azrtti_cast(materialTypeAsset->GetMaterialFunctors()[0].get()); @@ -900,13 +1278,13 @@ namespace UnitTest sourceData.m_shaderCollection.push_back(MaterialTypeSourceData::ShaderVariantReferenceData{TestShaderFilename}); sourceData.m_shaderCollection.push_back(MaterialTypeSourceData::ShaderVariantReferenceData{TestShaderFilename}); + + MaterialTypeSourceData::PropertySet* propertySet = sourceData.AddPropertySet("general"); + MaterialTypeSourceData::PropertyDefinition* property = propertySet->AddProperty("MyProperty"); - MaterialTypeSourceData::PropertyDefinition propertySource; - propertySource.m_name = "MyProperty"; - propertySource.m_dataType = MaterialPropertyDataType::Bool; - // Note that we don't fill propertySource.m_outputConnections because this is not a direct-connected property - sourceData.m_propertyLayout.m_properties["general"].push_back(propertySource); - + property->m_dataType = MaterialPropertyDataType::Bool; + // Note that we don't fill property->m_outputConnections because this is not a direct-connected property + sourceData.m_materialFunctorSourceData.push_back( Ptr ( @@ -928,6 +1306,45 @@ namespace UnitTest EXPECT_TRUE(materialTypeAsset->GetShaderCollection()[0].MaterialOwnsShaderOption(Name{"o_foo"})); EXPECT_TRUE(materialTypeAsset->GetShaderCollection()[0].MaterialOwnsShaderOption(Name{"o_bar"})); } + + TEST_F(MaterialTypeSourceDataTests, CreateMaterialTypeAsset_FunctorIsInsidePropertySet) + { + MaterialTypeSourceData sourceData; + + MaterialTypeSourceData::PropertySet* propertySet = sourceData.AddPropertySet("general"); + MaterialTypeSourceData::PropertyDefinition* property = propertySet->AddProperty("floatForFunctor"); + + property->m_dataType = MaterialPropertyDataType::Float; + + sourceData.m_shaderCollection.push_back(MaterialTypeSourceData::ShaderVariantReferenceData{TestShaderFilename}); + + sourceData.m_materialFunctorSourceData.push_back( + Ptr + ( + aznew MaterialFunctorSourceDataHolder + ( + aznew Splat3FunctorSourceData{ "general.floatForFunctor", "m_float3" } + ) + ) + ); + + auto materialTypeOutcome = sourceData.CreateMaterialTypeAsset(Uuid::CreateRandom()); + EXPECT_TRUE(materialTypeOutcome.IsSuccess()); + Data::Asset materialTypeAsset = materialTypeOutcome.GetValue(); + + const MaterialPropertyIndex propertyIndex = materialTypeAsset->GetMaterialPropertiesLayout()->FindPropertyIndex(Name{"general.floatForFunctor" }); + const MaterialPropertyDescriptor* propertyDescriptor = materialTypeAsset->GetMaterialPropertiesLayout()->GetPropertyDescriptor(propertyIndex); + + ValidateCommonDescriptorFields(*property, propertyDescriptor); + + EXPECT_EQ(1, materialTypeAsset->GetMaterialFunctors().size()); + auto shaderInputFunctor = azrtti_cast(materialTypeAsset->GetMaterialFunctors()[0].get()); + EXPECT_TRUE(nullptr != shaderInputFunctor); + EXPECT_EQ(propertyIndex, shaderInputFunctor->m_floatIndex); + + const RHI::ShaderInputConstantIndex expectedVector3Index = materialTypeAsset->GetMaterialSrgLayout()->FindShaderInputConstantIndex(Name{ "m_float3" }); + EXPECT_EQ(expectedVector3Index, shaderInputFunctor->m_vector3Index); + } TEST_F(MaterialTypeSourceDataTests, CreateMaterialTypeAsset_PropertyValues_AllTypes) { @@ -937,23 +1354,23 @@ namespace UnitTest auto addProperty = [&sourceData](MaterialPropertyDataType dateType, const char* propertyName, const char* srgConstantName, const AZ::RPI::MaterialPropertyValue& value) { - MaterialTypeSourceData::PropertyDefinition propertySource; - propertySource.m_name = propertyName; - propertySource.m_dataType = dateType; - propertySource.m_outputConnections.push_back(MaterialTypeSourceData::PropertyConnection{ MaterialPropertyOutputType::ShaderInput, AZStd::string(srgConstantName) }); - propertySource.m_value = value; - sourceData.m_propertyLayout.m_properties["general"].push_back(propertySource); + MaterialTypeSourceData::PropertyDefinition* property = sourceData.AddProperty(propertyName); + property->m_dataType = dateType; + property->m_outputConnections.push_back(MaterialTypeSourceData::PropertyConnection{ MaterialPropertyOutputType::ShaderInput, AZStd::string(srgConstantName) }); + property->m_value = value; }; - - addProperty(MaterialPropertyDataType::Bool, "MyBool", "m_bool", true); - addProperty(MaterialPropertyDataType::Float, "MyFloat", "m_float", 1.2f); - addProperty(MaterialPropertyDataType::Int, "MyInt", "m_int", -12); - addProperty(MaterialPropertyDataType::UInt, "MyUInt", "m_uint", 12u); - addProperty(MaterialPropertyDataType::Vector2, "MyFloat2", "m_float2", AZ::Vector2{1.1f, 2.2f}); - addProperty(MaterialPropertyDataType::Vector3, "MyFloat3", "m_float3", AZ::Vector3{3.3f, 4.4f, 5.5f}); - addProperty(MaterialPropertyDataType::Vector4, "MyFloat4", "m_float4", AZ::Vector4{6.6f, 7.7f, 8.8f, 9.9f}); - addProperty(MaterialPropertyDataType::Color, "MyColor", "m_color", AZ::Color{0.1f, 0.2f, 0.3f, 0.4f}); - addProperty(MaterialPropertyDataType::Image, "MyImage", "m_image", AZStd::string{TestImageFilename}); + + sourceData.AddPropertySet("general"); + + addProperty(MaterialPropertyDataType::Bool, "general.MyBool", "m_bool", true); + addProperty(MaterialPropertyDataType::Float, "general.MyFloat", "m_float", 1.2f); + addProperty(MaterialPropertyDataType::Int, "general.MyInt", "m_int", -12); + addProperty(MaterialPropertyDataType::UInt, "general.MyUInt", "m_uint", 12u); + addProperty(MaterialPropertyDataType::Vector2, "general.MyFloat2", "m_float2", AZ::Vector2{1.1f, 2.2f}); + addProperty(MaterialPropertyDataType::Vector3, "general.MyFloat3", "m_float3", AZ::Vector3{3.3f, 4.4f, 5.5f}); + addProperty(MaterialPropertyDataType::Vector4, "general.MyFloat4", "m_float4", AZ::Vector4{6.6f, 7.7f, 8.8f, 9.9f}); + addProperty(MaterialPropertyDataType::Color, "general.MyColor", "m_color", AZ::Color{0.1f, 0.2f, 0.3f, 0.4f}); + addProperty(MaterialPropertyDataType::Image, "general.MyImage", "m_image", AZStd::string{TestImageFilename}); auto materialTypeOutcome = sourceData.CreateMaterialTypeAsset(Uuid::CreateRandom()); EXPECT_TRUE(materialTypeOutcome.IsSuccess()); @@ -970,6 +1387,88 @@ namespace UnitTest CheckPropertyValue>(materialTypeAsset, Name{"general.MyImage"}, m_testImageAsset); } + TEST_F(MaterialTypeSourceDataTests, CreateMaterialTypeAsset_NestedPropertySets) + { + RHI::Ptr layeredMaterialSrgLayout = RHI::ShaderResourceGroupLayout::Create(); + layeredMaterialSrgLayout->SetName(Name{"MaterialSrg"}); + layeredMaterialSrgLayout->SetBindingSlot(SrgBindingSlot::Material); + layeredMaterialSrgLayout->AddShaderInput(RHI::ShaderInputImageDescriptor{ Name{ "m_layer1_baseColor_texture" }, RHI::ShaderInputImageAccess::Read, RHI::ShaderInputImageType::Image2D, 1, 1 }); + layeredMaterialSrgLayout->AddShaderInput(RHI::ShaderInputImageDescriptor{ Name{ "m_layer1_roughness_texture" }, RHI::ShaderInputImageAccess::Read, RHI::ShaderInputImageType::Image2D, 1, 1 }); + layeredMaterialSrgLayout->AddShaderInput(RHI::ShaderInputImageDescriptor{ Name{ "m_layer2_baseColor_texture" }, RHI::ShaderInputImageAccess::Read, RHI::ShaderInputImageType::Image2D, 1, 1 }); + layeredMaterialSrgLayout->AddShaderInput(RHI::ShaderInputImageDescriptor{ Name{ "m_layer2_roughness_texture" }, RHI::ShaderInputImageAccess::Read, RHI::ShaderInputImageType::Image2D, 1, 1 }); + layeredMaterialSrgLayout->AddShaderInput(RHI::ShaderInputImageDescriptor{ Name{ "m_layer2_clearCoat_roughness_texture" }, RHI::ShaderInputImageAccess::Read, RHI::ShaderInputImageType::Image2D, 1, 1 }); + layeredMaterialSrgLayout->AddShaderInput(RHI::ShaderInputImageDescriptor{ Name{ "m_layer2_clearCoat_normal_texture" }, RHI::ShaderInputImageAccess::Read, RHI::ShaderInputImageType::Image2D, 1, 1 }); + layeredMaterialSrgLayout->AddShaderInput(RHI::ShaderInputConstantDescriptor{ Name{ "m_layer2_clearCoat_normal_factor" }, 0, 4, 0 }); + layeredMaterialSrgLayout->AddShaderInput(RHI::ShaderInputConstantDescriptor{ Name{ "m_blendFactor" }, 4, 4, 0 }); + layeredMaterialSrgLayout->Finalize(); + + AZStd::vector boolOptionValues; + boolOptionValues.push_back({Name("False"), RPI::ShaderOptionValue(0)}); + boolOptionValues.push_back({Name("True"), RPI::ShaderOptionValue(1)}); + Ptr shaderOptionsLayout = ShaderOptionGroupLayout::Create(); + uint32_t order = 0; + shaderOptionsLayout->AddShaderOption(ShaderOptionDescriptor{Name{"o_layer2_clearCoat_enable"}, ShaderOptionType::Boolean, 0, order++, boolOptionValues, Name{"False"}}); + shaderOptionsLayout->Finalize(); + + Data::Asset layeredMaterialShaderAsset = CreateTestShaderAsset(Uuid::CreateRandom(), layeredMaterialSrgLayout, shaderOptionsLayout); + + Data::AssetInfo testShaderAssetInfo; + testShaderAssetInfo.m_assetId = layeredMaterialShaderAsset.GetId(); + m_assetSystemStub.RegisterSourceInfo("layeredMaterial.shader", testShaderAssetInfo, ""); + + MaterialTypeSourceData sourceData; + + sourceData.m_shaderCollection.push_back(MaterialTypeSourceData::ShaderVariantReferenceData{ "layeredMaterial.shader" }); + + auto addSrgProperty = [&sourceData](MaterialPropertyDataType dateType, MaterialPropertyOutputType connectionType, const char* propertyName, const char* srgConstantName, const AZ::RPI::MaterialPropertyValue& value) + { + MaterialTypeSourceData::PropertyDefinition* property = sourceData.AddProperty(propertyName); + property->m_dataType = dateType; + property->m_outputConnections.push_back(MaterialTypeSourceData::PropertyConnection{ connectionType, AZStd::string(srgConstantName) }); + property->m_value = value; + }; + + sourceData.AddPropertySet("layer1"); + sourceData.AddPropertySet("layer2"); + sourceData.AddPropertySet("blend"); + sourceData.AddPropertySet("layer1.baseColor"); + sourceData.AddPropertySet("layer2.baseColor"); + sourceData.AddPropertySet("layer1.roughness"); + sourceData.AddPropertySet("layer2.roughness"); + sourceData.AddPropertySet("layer2.clearCoat"); + sourceData.AddPropertySet("layer2.clearCoat.roughness"); + sourceData.AddPropertySet("layer2.clearCoat.normal"); + + addSrgProperty(MaterialPropertyDataType::Image, MaterialPropertyOutputType::ShaderInput, "layer1.baseColor.texture", "m_layer1_baseColor_texture", AZStd::string{TestImageFilename}); + addSrgProperty(MaterialPropertyDataType::Image, MaterialPropertyOutputType::ShaderInput, "layer1.roughness.texture", "m_layer1_roughness_texture", AZStd::string{TestImageFilename}); + addSrgProperty(MaterialPropertyDataType::Image, MaterialPropertyOutputType::ShaderInput, "layer2.baseColor.texture", "m_layer2_baseColor_texture", AZStd::string{TestImageFilename}); + addSrgProperty(MaterialPropertyDataType::Image, MaterialPropertyOutputType::ShaderInput, "layer2.roughness.texture", "m_layer2_roughness_texture", AZStd::string{TestImageFilename}); + addSrgProperty(MaterialPropertyDataType::Bool, MaterialPropertyOutputType::ShaderOption, "layer2.clearCoat.enabled", "o_layer2_clearCoat_enable", true); + addSrgProperty(MaterialPropertyDataType::Image, MaterialPropertyOutputType::ShaderInput, "layer2.clearCoat.roughness.texture", "m_layer2_clearCoat_roughness_texture", AZStd::string{TestImageFilename}); + addSrgProperty(MaterialPropertyDataType::Image, MaterialPropertyOutputType::ShaderInput, "layer2.clearCoat.normal.texture", "m_layer2_clearCoat_normal_texture", AZStd::string{TestImageFilename}); + addSrgProperty(MaterialPropertyDataType::Float, MaterialPropertyOutputType::ShaderInput, "layer2.clearCoat.normal.factor", "m_layer2_clearCoat_normal_factor", 0.4f); + addSrgProperty(MaterialPropertyDataType::Float, MaterialPropertyOutputType::ShaderInput, "blend.factor", "m_blendFactor", 0.5f); + + auto materialTypeOutcome = sourceData.CreateMaterialTypeAsset(Uuid::CreateRandom()); + EXPECT_TRUE(materialTypeOutcome.IsSuccess()); + Data::Asset materialTypeAsset = materialTypeOutcome.GetValue(); + + CheckPropertyValue>(materialTypeAsset, Name{"layer1.baseColor.texture"}, m_testImageAsset); + CheckPropertyValue>(materialTypeAsset, Name{"layer1.roughness.texture"}, m_testImageAsset); + CheckPropertyValue>(materialTypeAsset, Name{"layer2.baseColor.texture"}, m_testImageAsset); + CheckPropertyValue>(materialTypeAsset, Name{"layer2.roughness.texture"}, m_testImageAsset); + CheckPropertyValue(materialTypeAsset, Name{"layer2.clearCoat.enabled"}, true); + CheckPropertyValue>(materialTypeAsset, Name{"layer2.clearCoat.roughness.texture"}, m_testImageAsset); + CheckPropertyValue>(materialTypeAsset, Name{"layer2.clearCoat.normal.texture"}, m_testImageAsset); + CheckPropertyValue(materialTypeAsset, Name{"layer2.clearCoat.normal.factor"}, 0.4f); + CheckPropertyValue(materialTypeAsset, Name{"blend.factor"}, 0.5f); + + // Note it might be nice to check that the right property connections are prescribed in the final MaterialTypeAsset, + // but it's not really necessary because CreateMaterialTypeAsset reports errors when a connection target is not found + // in the shader options layout or SRG layout. If one of the output names like "m_layer2_roughness_texture" is wrong + // these errors will cause this test to fail. + } + TEST_F(MaterialTypeSourceDataTests, LoadAndStoreJson_AllFields) { // Note that serialization of individual fields within material properties is thoroughly tested in @@ -980,46 +1479,92 @@ namespace UnitTest "description": "This is a general description about the material", "propertyLayout": { "version": 2, - "groups": [ + "propertySets": [ { "name": "groupA", "displayName": "Property Group A", - "description": "Description of property group A" + "description": "Description of property group A", + "properties": [ + { + "name": "foo", + "type": "Bool", + "defaultValue": true + }, + { + "name": "bar", + "type": "Image", + "defaultValue": "Default.png", + "visibility": "Hidden" + } + ], + "functors": [ + { + "type": "EnableShader", + "args": { + "enablePassProperty": "foo", + "shaderIndex": 1 + } + } + ] }, { "name": "groupB", "displayName": "Property Group B", - "description": "Description of property group B" + "description": "Description of property group B", + "properties": [ + { + "name": "foo", + "type": "Float", + "defaultValue": 0.5 + }, + { + "name": "bar", + "type": "Color", + "defaultValue": [0.5, 0.5, 0.5], + "visibility": "Disabled" + } + ], + "functors": [ + { + "type": "Splat3", + "args": { + "floatPropertyInput": "foo", + "float3ShaderSettingOutput": "m_someFloat3" + } + } + ] + }, + { + "name": "groupC", + "displayName": "Property Group C", + "description": "Property group C has a nested property set", + "propertySets": [ + { + "name": "groupD", + "displayName": "Property Group D", + "description": "Description of property group D", + "properties": [ + { + "name": "foo", + "type": "Int", + "defaultValue": -1 + } + ] + }, + { + "name": "groupE", + "displayName": "Property Group E", + "description": "Description of property group E", + "properties": [ + { + "name": "bar", + "type": "UInt" + } + ] + } + ] } - ], - "properties": { - "groupA": [ - { - "name": "foo", - "type": "Bool", - "defaultValue": true - }, - { - "name": "bar", - "type": "Image", - "defaultValue": "Default.png", - "visibility": "Hidden" - } - ], - "groupB": [ - { - "name": "foo", - "type": "Float", - "defaultValue": 0.5 - }, - { - "name": "bar", - "type": "Color", - "defaultValue": [0.5, 0.5, 0.5], - "visibility": "Disabled" - } - ] - } + ] }, "shaders": [ { @@ -1040,17 +1585,9 @@ namespace UnitTest ], "functors": [ { - "type": "EnableShader", - "args": { - "enablePassProperty": "groupA.foo", - "shaderIndex": 1 - } - }, - { - "type": "Splat3", + "type": "SetShaderOption", "args": { - "floatPropertyInput": "groupB.foo", - "float3ShaderSettingOutput": "m_someFloat3" + "enableProperty": "groupA.foo" } } ] @@ -1062,35 +1599,72 @@ namespace UnitTest EXPECT_EQ(material.m_description, "This is a general description about the material"); - EXPECT_EQ(material.m_propertyLayout.m_version, 2); - - EXPECT_EQ(material.m_propertyLayout.m_groups.size(), 2); - EXPECT_TRUE(material.FindGroup("groupA") != nullptr); - EXPECT_TRUE(material.FindGroup("groupB") != nullptr); - EXPECT_EQ(material.FindGroup("groupA")->m_displayName, "Property Group A"); - EXPECT_EQ(material.FindGroup("groupB")->m_displayName, "Property Group B"); - EXPECT_EQ(material.FindGroup("groupA")->m_description, "Description of property group A"); - EXPECT_EQ(material.FindGroup("groupB")->m_description, "Description of property group B"); - - EXPECT_EQ(material.m_propertyLayout.m_properties.size(), 2); - EXPECT_EQ(material.m_propertyLayout.m_properties["groupA"].size(), 2); - EXPECT_EQ(material.m_propertyLayout.m_properties["groupB"].size(), 2); - EXPECT_EQ(material.m_propertyLayout.m_properties["groupA"][0].m_name, "foo"); - EXPECT_EQ(material.m_propertyLayout.m_properties["groupA"][1].m_name, "bar"); - EXPECT_EQ(material.m_propertyLayout.m_properties["groupB"][0].m_name, "foo"); - EXPECT_EQ(material.m_propertyLayout.m_properties["groupB"][1].m_name, "bar"); - EXPECT_EQ(material.m_propertyLayout.m_properties["groupA"][0].m_dataType, MaterialPropertyDataType::Bool); - EXPECT_EQ(material.m_propertyLayout.m_properties["groupA"][1].m_dataType, MaterialPropertyDataType::Image); - EXPECT_EQ(material.m_propertyLayout.m_properties["groupB"][0].m_dataType, MaterialPropertyDataType::Float); - EXPECT_EQ(material.m_propertyLayout.m_properties["groupB"][1].m_dataType, MaterialPropertyDataType::Color); - EXPECT_EQ(material.m_propertyLayout.m_properties["groupA"][0].m_visibility, MaterialPropertyVisibility::Enabled); - EXPECT_EQ(material.m_propertyLayout.m_properties["groupA"][1].m_visibility, MaterialPropertyVisibility::Hidden); - EXPECT_EQ(material.m_propertyLayout.m_properties["groupB"][0].m_visibility, MaterialPropertyVisibility::Enabled); - EXPECT_EQ(material.m_propertyLayout.m_properties["groupB"][1].m_visibility, MaterialPropertyVisibility::Disabled); - EXPECT_EQ(material.m_propertyLayout.m_properties["groupA"][0].m_value, true); - EXPECT_EQ(material.m_propertyLayout.m_properties["groupA"][1].m_value, AZStd::string{"Default.png"}); - EXPECT_EQ(material.m_propertyLayout.m_properties["groupB"][0].m_value, 0.5f); - EXPECT_EQ(material.m_propertyLayout.m_properties["groupB"][1].m_value, AZ::Color(0.5f, 0.5f, 0.5f, 1.0f)); + EXPECT_EQ(material.GetPropertyLayout().m_version, 2); + + EXPECT_EQ(material.GetPropertyLayout().m_propertySets.size(), 3); + EXPECT_TRUE(material.FindPropertySet("groupA") != nullptr); + EXPECT_TRUE(material.FindPropertySet("groupB") != nullptr); + EXPECT_TRUE(material.FindPropertySet("groupC") != nullptr); + EXPECT_TRUE(material.FindPropertySet("groupC.groupD") != nullptr); + EXPECT_TRUE(material.FindPropertySet("groupC.groupE") != nullptr); + EXPECT_EQ(material.FindPropertySet("groupA")->GetDisplayName(), "Property Group A"); + EXPECT_EQ(material.FindPropertySet("groupB")->GetDisplayName(), "Property Group B"); + EXPECT_EQ(material.FindPropertySet("groupC")->GetDisplayName(), "Property Group C"); + EXPECT_EQ(material.FindPropertySet("groupC.groupD")->GetDisplayName(), "Property Group D"); + EXPECT_EQ(material.FindPropertySet("groupC.groupE")->GetDisplayName(), "Property Group E"); + EXPECT_EQ(material.FindPropertySet("groupA")->GetDescription(), "Description of property group A"); + EXPECT_EQ(material.FindPropertySet("groupB")->GetDescription(), "Description of property group B"); + EXPECT_EQ(material.FindPropertySet("groupC")->GetDescription(), "Property group C has a nested property set"); + EXPECT_EQ(material.FindPropertySet("groupC.groupD")->GetDescription(), "Description of property group D"); + EXPECT_EQ(material.FindPropertySet("groupC.groupE")->GetDescription(), "Description of property group E"); + EXPECT_EQ(material.FindPropertySet("groupA")->GetProperties().size(), 2); + EXPECT_EQ(material.FindPropertySet("groupB")->GetProperties().size(), 2); + EXPECT_EQ(material.FindPropertySet("groupC")->GetProperties().size(), 0); + EXPECT_EQ(material.FindPropertySet("groupC.groupD")->GetProperties().size(), 1); + EXPECT_EQ(material.FindPropertySet("groupC.groupE")->GetProperties().size(), 1); + + EXPECT_NE(material.FindProperty("groupA.foo"), nullptr); + EXPECT_NE(material.FindProperty("groupA.bar"), nullptr); + EXPECT_NE(material.FindProperty("groupB.foo"), nullptr); + EXPECT_NE(material.FindProperty("groupB.bar"), nullptr); + EXPECT_NE(material.FindProperty("groupC.groupD.foo"), nullptr); + EXPECT_NE(material.FindProperty("groupC.groupE.bar"), nullptr); + + EXPECT_EQ(material.FindProperty("groupA.foo")->m_name, "foo"); + EXPECT_EQ(material.FindProperty("groupA.bar")->m_name, "bar"); + EXPECT_EQ(material.FindProperty("groupB.foo")->m_name, "foo"); + EXPECT_EQ(material.FindProperty("groupB.bar")->m_name, "bar"); + EXPECT_EQ(material.FindProperty("groupC.groupD.foo")->m_name, "foo"); + EXPECT_EQ(material.FindProperty("groupC.groupE.bar")->m_name, "bar"); + EXPECT_EQ(material.FindProperty("groupA.foo")->m_dataType, MaterialPropertyDataType::Bool); + EXPECT_EQ(material.FindProperty("groupA.bar")->m_dataType, MaterialPropertyDataType::Image); + EXPECT_EQ(material.FindProperty("groupB.foo")->m_dataType, MaterialPropertyDataType::Float); + EXPECT_EQ(material.FindProperty("groupB.bar")->m_dataType, MaterialPropertyDataType::Color); + EXPECT_EQ(material.FindProperty("groupC.groupD.foo")->m_dataType, MaterialPropertyDataType::Int); + EXPECT_EQ(material.FindProperty("groupC.groupE.bar")->m_dataType, MaterialPropertyDataType::UInt); + EXPECT_EQ(material.FindProperty("groupA.foo")->m_visibility, MaterialPropertyVisibility::Enabled); + EXPECT_EQ(material.FindProperty("groupA.bar")->m_visibility, MaterialPropertyVisibility::Hidden); + EXPECT_EQ(material.FindProperty("groupB.foo")->m_visibility, MaterialPropertyVisibility::Enabled); + EXPECT_EQ(material.FindProperty("groupB.bar")->m_visibility, MaterialPropertyVisibility::Disabled); + EXPECT_EQ(material.FindProperty("groupC.groupD.foo")->m_visibility, MaterialPropertyVisibility::Enabled); + EXPECT_EQ(material.FindProperty("groupC.groupE.bar")->m_visibility, MaterialPropertyVisibility::Enabled); + EXPECT_EQ(material.FindProperty("groupA.foo")->m_value, true); + EXPECT_EQ(material.FindProperty("groupA.bar")->m_value, AZStd::string{"Default.png"}); + EXPECT_EQ(material.FindProperty("groupB.foo")->m_value, 0.5f); + EXPECT_EQ(material.FindProperty("groupB.bar")->m_value, AZ::Color(0.5f, 0.5f, 0.5f, 1.0f)); + EXPECT_EQ(material.FindProperty("groupC.groupD.foo")->m_value, -1); + EXPECT_EQ(material.FindProperty("groupC.groupE.bar")->m_value, 0u); + + EXPECT_EQ(material.FindPropertySet("groupA")->GetFunctors().size(), 1); + EXPECT_EQ(material.FindPropertySet("groupB")->GetFunctors().size(), 1); + Ptr functorA = material.FindPropertySet("groupA")->GetFunctors()[0]->GetActualSourceData(); + Ptr functorB = material.FindPropertySet("groupB")->GetFunctors()[0]->GetActualSourceData(); + EXPECT_TRUE(azrtti_cast(functorA.get())); + EXPECT_EQ(azrtti_cast(functorA.get())->m_enablePassPropertyId, "foo"); + EXPECT_EQ(azrtti_cast(functorA.get())->m_shaderIndex, 1); + EXPECT_TRUE(azrtti_cast(functorB.get())); + EXPECT_EQ(azrtti_cast(functorB.get())->m_floatPropertyInputId, "foo"); + EXPECT_EQ(azrtti_cast(functorB.get())->m_float3ShaderSettingOutputId, "m_someFloat3"); EXPECT_EQ(material.m_shaderCollection.size(), 2); EXPECT_EQ(material.m_shaderCollection[0].m_shaderFilePath, "ForwardPass.shader"); @@ -1103,13 +1677,10 @@ namespace UnitTest EXPECT_EQ(material.m_shaderCollection[1].m_shaderOptionValues[Name{"o_optionD"}], Name{"2"}); EXPECT_EQ(material.m_shaderCollection[0].m_shaderTag, Name{"ForwardPass"}); - EXPECT_EQ(material.m_materialFunctorSourceData.size(), 2); - EXPECT_TRUE(azrtti_cast(material.m_materialFunctorSourceData[0]->GetActualSourceData().get())); - EXPECT_EQ(azrtti_cast(material.m_materialFunctorSourceData[0]->GetActualSourceData().get())->m_enablePassPropertyId, "groupA.foo"); - EXPECT_EQ(azrtti_cast(material.m_materialFunctorSourceData[0]->GetActualSourceData().get())->m_shaderIndex, 1); - EXPECT_TRUE(azrtti_cast(material.m_materialFunctorSourceData[1]->GetActualSourceData().get())); - EXPECT_EQ(azrtti_cast(material.m_materialFunctorSourceData[1]->GetActualSourceData().get())->m_floatPropertyInputId, "groupB.foo"); - EXPECT_EQ(azrtti_cast(material.m_materialFunctorSourceData[1]->GetActualSourceData().get())->m_float3ShaderSettingOutputId, "m_someFloat3"); + EXPECT_EQ(material.m_materialFunctorSourceData.size(), 1); + Ptr functorC = material.m_materialFunctorSourceData[0]->GetActualSourceData(); + EXPECT_TRUE(azrtti_cast(functorC.get())); + EXPECT_EQ(azrtti_cast(functorC.get())->m_enablePropertyName, "groupA.foo"); AZStd::string outputJson; JsonTestResult storeResult = StoreTestDataToJson(material, outputJson); @@ -1120,6 +1691,9 @@ namespace UnitTest { // The content of this test was copied from LoadAndStoreJson_AllFields to prove backward compatibility. // (The "store" part of the test was not included because the saved data will be the new format). + // Notable differences include: + // 1) the key "id" is used instead of "name" + // 2) the group metadata, property definitions, and functors are all defined in different sections rather than in a property set const AZStd::string inputJson = R"( { @@ -1206,37 +1780,57 @@ namespace UnitTest MaterialTypeSourceData material; JsonTestResult loadResult = LoadTestDataFromJson(material, inputJson); + // Before conversion to the new format, the data is in the old place + EXPECT_EQ(material.GetPropertyLayout().m_groups.size(), 2); + EXPECT_EQ(material.GetPropertyLayout().m_properties.size(), 2); + EXPECT_EQ(material.GetPropertyLayout().m_propertySets.size(), 0); + + material.ConvertToNewDataFormat(); + + // After conversion to the new format, the data is in the new place + EXPECT_EQ(material.GetPropertyLayout().m_groups.size(), 0); + EXPECT_EQ(material.GetPropertyLayout().m_properties.size(), 0); + EXPECT_EQ(material.GetPropertyLayout().m_propertySets.size(), 2); + EXPECT_EQ(material.m_description, "This is a general description about the material"); - EXPECT_EQ(material.m_propertyLayout.m_version, 2); - - EXPECT_EQ(material.m_propertyLayout.m_groups.size(), 2); - EXPECT_TRUE(material.FindGroup("groupA") != nullptr); - EXPECT_TRUE(material.FindGroup("groupB") != nullptr); - EXPECT_EQ(material.FindGroup("groupA")->m_displayName, "Property Group A"); - EXPECT_EQ(material.FindGroup("groupB")->m_displayName, "Property Group B"); - EXPECT_EQ(material.FindGroup("groupA")->m_description, "Description of property group A"); - EXPECT_EQ(material.FindGroup("groupB")->m_description, "Description of property group B"); - - EXPECT_EQ(material.m_propertyLayout.m_properties.size(), 2); - EXPECT_EQ(material.m_propertyLayout.m_properties["groupA"].size(), 2); - EXPECT_EQ(material.m_propertyLayout.m_properties["groupB"].size(), 2); - EXPECT_EQ(material.m_propertyLayout.m_properties["groupA"][0].m_name, "foo"); - EXPECT_EQ(material.m_propertyLayout.m_properties["groupA"][1].m_name, "bar"); - EXPECT_EQ(material.m_propertyLayout.m_properties["groupB"][0].m_name, "foo"); - EXPECT_EQ(material.m_propertyLayout.m_properties["groupB"][1].m_name, "bar"); - EXPECT_EQ(material.m_propertyLayout.m_properties["groupA"][0].m_dataType, MaterialPropertyDataType::Bool); - EXPECT_EQ(material.m_propertyLayout.m_properties["groupA"][1].m_dataType, MaterialPropertyDataType::Image); - EXPECT_EQ(material.m_propertyLayout.m_properties["groupB"][0].m_dataType, MaterialPropertyDataType::Float); - EXPECT_EQ(material.m_propertyLayout.m_properties["groupB"][1].m_dataType, MaterialPropertyDataType::Color); - EXPECT_EQ(material.m_propertyLayout.m_properties["groupA"][0].m_visibility, MaterialPropertyVisibility::Enabled); - EXPECT_EQ(material.m_propertyLayout.m_properties["groupA"][1].m_visibility, MaterialPropertyVisibility::Hidden); - EXPECT_EQ(material.m_propertyLayout.m_properties["groupB"][0].m_visibility, MaterialPropertyVisibility::Enabled); - EXPECT_EQ(material.m_propertyLayout.m_properties["groupB"][1].m_visibility, MaterialPropertyVisibility::Disabled); - EXPECT_EQ(material.m_propertyLayout.m_properties["groupA"][0].m_value, true); - EXPECT_EQ(material.m_propertyLayout.m_properties["groupA"][1].m_value, AZStd::string{"Default.png"}); - EXPECT_EQ(material.m_propertyLayout.m_properties["groupB"][0].m_value, 0.5f); - EXPECT_EQ(material.m_propertyLayout.m_properties["groupB"][1].m_value, AZ::Color(0.5f, 0.5f, 0.5f, 1.0f)); + EXPECT_EQ(material.GetPropertyLayout().m_version, 2); + + EXPECT_TRUE(material.FindPropertySet("groupA") != nullptr); + EXPECT_TRUE(material.FindPropertySet("groupB") != nullptr); + EXPECT_EQ(material.FindPropertySet("groupA")->GetDisplayName(), "Property Group A"); + EXPECT_EQ(material.FindPropertySet("groupB")->GetDisplayName(), "Property Group B"); + EXPECT_EQ(material.FindPropertySet("groupA")->GetDescription(), "Description of property group A"); + EXPECT_EQ(material.FindPropertySet("groupB")->GetDescription(), "Description of property group B"); + EXPECT_EQ(material.FindPropertySet("groupA")->GetProperties().size(), 2); + EXPECT_EQ(material.FindPropertySet("groupB")->GetProperties().size(), 2); + + EXPECT_TRUE(material.FindProperty("groupA.foo") != nullptr); + EXPECT_TRUE(material.FindProperty("groupA.bar") != nullptr); + EXPECT_TRUE(material.FindProperty("groupB.foo") != nullptr); + EXPECT_TRUE(material.FindProperty("groupB.bar") != nullptr); + + EXPECT_EQ(material.FindProperty("groupA.foo")->m_name, "foo"); + EXPECT_EQ(material.FindProperty("groupA.bar")->m_name, "bar"); + EXPECT_EQ(material.FindProperty("groupB.foo")->m_name, "foo"); + EXPECT_EQ(material.FindProperty("groupB.bar")->m_name, "bar"); + EXPECT_EQ(material.FindProperty("groupA.foo")->m_dataType, MaterialPropertyDataType::Bool); + EXPECT_EQ(material.FindProperty("groupA.bar")->m_dataType, MaterialPropertyDataType::Image); + EXPECT_EQ(material.FindProperty("groupB.foo")->m_dataType, MaterialPropertyDataType::Float); + EXPECT_EQ(material.FindProperty("groupB.bar")->m_dataType, MaterialPropertyDataType::Color); + EXPECT_EQ(material.FindProperty("groupA.foo")->m_visibility, MaterialPropertyVisibility::Enabled); + EXPECT_EQ(material.FindProperty("groupA.bar")->m_visibility, MaterialPropertyVisibility::Hidden); + EXPECT_EQ(material.FindProperty("groupB.foo")->m_visibility, MaterialPropertyVisibility::Enabled); + EXPECT_EQ(material.FindProperty("groupB.bar")->m_visibility, MaterialPropertyVisibility::Disabled); + EXPECT_EQ(material.FindProperty("groupA.foo")->m_value, true); + EXPECT_EQ(material.FindProperty("groupA.bar")->m_value, AZStd::string{"Default.png"}); + EXPECT_EQ(material.FindProperty("groupB.foo")->m_value, 0.5f); + EXPECT_EQ(material.FindProperty("groupB.bar")->m_value, AZ::Color(0.5f, 0.5f, 0.5f, 1.0f)); + + // The functors can appear either at the top level or within each property set. The format conversion + // function doesn't know how to move the functors, and they will be left at the top level. + EXPECT_EQ(material.FindPropertySet("groupA")->GetFunctors().size(), 0); + EXPECT_EQ(material.FindPropertySet("groupB")->GetFunctors().size(), 0); EXPECT_EQ(material.m_shaderCollection.size(), 2); EXPECT_EQ(material.m_shaderCollection[0].m_shaderFilePath, "ForwardPass.shader"); @@ -1257,7 +1851,7 @@ namespace UnitTest EXPECT_EQ(azrtti_cast(material.m_materialFunctorSourceData[1]->GetActualSourceData().get())->m_floatPropertyInputId, "groupB.foo"); EXPECT_EQ(azrtti_cast(material.m_materialFunctorSourceData[1]->GetActualSourceData().get())->m_float3ShaderSettingOutputId, "m_someFloat3"); } - + TEST_F(MaterialTypeSourceDataTests, CreateMaterialTypeAsset_PropertyImagePath) { char inputJson[2048]; @@ -1267,27 +1861,25 @@ namespace UnitTest "description": "", "propertyLayout": { "version": 2, - "groups": [ + "propertySets": [ { "name": "general", "displayName": "General", - "description": "" + "description": "", + "properties": [ + { + "name": "absolute", + "type": "Image", + "defaultValue": "%s" + }, + { + "name": "relative", + "type": "Image", + "defaultValue": "%s" + } + ] } - ], - "properties": { - "general": [ - { - "name": "absolute", - "type": "Image", - "defaultValue": "%s" - }, - { - "name": "relative", - "type": "Image", - "defaultValue": "%s" - } - ] - } + ] } } )", diff --git a/Gems/Atom/TestData/TestData/Materials/Types/MinimalPBR.materialtype b/Gems/Atom/TestData/TestData/Materials/Types/MinimalPBR.materialtype index 81ebd63c28..ce59ec8b8e 100644 --- a/Gems/Atom/TestData/TestData/Materials/Types/MinimalPBR.materialtype +++ b/Gems/Atom/TestData/TestData/Materials/Types/MinimalPBR.materialtype @@ -2,50 +2,48 @@ "description": "Base Material with properties used to define Standard PBR, a metallic-roughness Physically-Based Rendering (PBR) material shading model.", "propertyLayout": { "version": 3, - "groups": [ + "propertySets": [ { "name": "settings", - "displayName": "Settings" - } - ], - "properties": { - "settings": [ - { - "name": "color", - "displayName": "Color", - "type": "Color", - "defaultValue": [ 1.0, 1.0, 1.0 ], - "connection": { - "type": "ShaderInput", - "name": "m_baseColor" - } - }, - { - "name": "metallic", - "displayName": "Metallic", - "type": "Float", - "defaultValue": 0.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_metallic" - } - }, - { - "name": "roughness", - "displayName": "Roughness", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_roughness" + "displayName": "Settings", + "properties": [ + { + "name": "color", + "displayName": "Color", + "type": "Color", + "defaultValue": [ 1.0, 1.0, 1.0 ], + "connection": { + "type": "ShaderInput", + "name": "m_baseColor" + } + }, + { + "name": "metallic", + "displayName": "Metallic", + "type": "Float", + "defaultValue": 0.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_metallic" + } + }, + { + "name": "roughness", + "displayName": "Roughness", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_roughness" + } } - } - ] - } + ] + } + ] }, "shaders": [ { diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp index 3f4aa71a9c..cf3205a037 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp @@ -230,7 +230,7 @@ namespace MaterialEditor // create source data from properties MaterialSourceData sourceData; - sourceData.m_propertyLayoutVersion = m_materialTypeSourceData.m_propertyLayout.m_version; + sourceData.m_propertyLayoutVersion = m_materialTypeSourceData.GetPropertyLayout().m_version; sourceData.m_materialType = m_materialSourceData.m_materialType; sourceData.m_parentMaterial = m_materialSourceData.m_parentMaterial; @@ -302,7 +302,7 @@ namespace MaterialEditor // create source data from properties MaterialSourceData sourceData; - sourceData.m_propertyLayoutVersion = m_materialTypeSourceData.m_propertyLayout.m_version; + sourceData.m_propertyLayoutVersion = m_materialTypeSourceData.GetPropertyLayout().m_version; sourceData.m_materialType = m_materialSourceData.m_materialType; sourceData.m_parentMaterial = m_materialSourceData.m_parentMaterial; @@ -373,7 +373,7 @@ namespace MaterialEditor // create source data from properties MaterialSourceData sourceData; - sourceData.m_propertyLayoutVersion = m_materialTypeSourceData.m_propertyLayout.m_version; + sourceData.m_propertyLayoutVersion = m_materialTypeSourceData.GetPropertyLayout().m_version; sourceData.m_materialType = m_materialSourceData.m_materialType; // Only assign a parent path if the source was a .material @@ -592,24 +592,26 @@ namespace MaterialEditor bool result = true; // populate sourceData with properties that meet the filter - m_materialTypeSourceData.EnumerateProperties([this, &sourceData, &propertyFilter, &result](const AZStd::string& groupName, const AZStd::string& propertyName, const auto& propertyDefinition) { + m_materialTypeSourceData.EnumerateProperties([this, &sourceData, &propertyFilter, &result](const AZStd::string& propertyIdContext, const auto& propertyDefinition) { - const MaterialPropertyId propertyId(groupName, propertyName); + const AZStd::string propertyId = propertyIdContext + propertyDefinition->m_name; - const auto it = m_properties.find(propertyId); + const auto it = m_properties.find(Name{propertyId}); if (it != m_properties.end() && propertyFilter(it->second)) { MaterialPropertyValue propertyValue = AtomToolsFramework::ConvertToRuntimeType(it->second.GetValue()); if (propertyValue.IsValid()) { - if (!m_materialTypeSourceData.ConvertPropertyValueToSourceDataFormat(propertyDefinition, propertyValue)) + if (!m_materialTypeSourceData.ConvertPropertyValueToSourceDataFormat(*propertyDefinition, propertyValue)) { - AZ_Error("MaterialDocument", false, "Material document property could not be converted: '%s' in '%s'.", propertyId.GetCStr(), m_absolutePath.c_str()); + AZ_Error("MaterialDocument", false, "Material document property could not be converted: '%s' in '%s'.", propertyId.c_str(), m_absolutePath.c_str()); result = false; return false; } - - sourceData.m_properties[groupName][propertyName].m_value = propertyValue; + + // TODO: Support populating the Material Editor with nested property sets, not just the top level. + const AZStd::string groupName = propertyId.substr(0, propertyId.size() - propertyDefinition->m_name.size() - 1); + sourceData.m_properties[groupName][propertyDefinition->m_name].m_value = propertyValue; } } return true; @@ -678,7 +680,7 @@ namespace MaterialEditor AZ_Error("MaterialDocument", false, "Material type source data could not be loaded: '%s'.", materialTypeSourceFilePath.c_str()); return false; } - m_materialTypeSourceData = materialTypeOutcome.GetValue(); + m_materialTypeSourceData = materialTypeOutcome.TakeValue(); } else if (AzFramework::StringFunc::Path::IsExtension(m_absolutePath.c_str(), MaterialTypeSourceData::Extension)) { @@ -691,7 +693,7 @@ namespace MaterialEditor AZ_Error("MaterialDocument", false, "Material type source data could not be loaded: '%s'.", m_absolutePath.c_str()); return false; } - m_materialTypeSourceData = materialTypeOutcome.GetValue(); + m_materialTypeSourceData = materialTypeOutcome.TakeValue(); // The document represents a material, not a material type. // If the input data is a material type file we have to generate the material source data by referencing it. @@ -770,33 +772,41 @@ namespace MaterialEditor // Populate the property map from a combination of source data and assets // Assets must still be used for now because they contain the final accumulated value after all other materials // in the hierarchy are applied - m_materialTypeSourceData.EnumerateProperties([this, &parentPropertyValues](const AZStd::string& groupName, const AZStd::string& propertyName, const auto& propertyDefinition) { - AtomToolsFramework::DynamicPropertyConfig propertyConfig; + m_materialTypeSourceData.EnumeratePropertySets([this, &parentPropertyValues](const AZStd::string& propertyIdContext, const MaterialTypeSourceData::PropertySet* propertySet) + { + AtomToolsFramework::DynamicPropertyConfig propertyConfig; - // Assign id before conversion so it can be used in dynamic description - propertyConfig.m_id = MaterialPropertyId(groupName, propertyName); + for (const auto& propertyDefinition : propertySet->GetProperties()) + { + // Assign id before conversion so it can be used in dynamic description + propertyConfig.m_id = propertyIdContext + propertySet->GetName() + "." + propertyDefinition->m_name; - const auto& propertyIndex = m_materialAsset->GetMaterialPropertiesLayout()->FindPropertyIndex(propertyConfig.m_id); - const bool propertyIndexInBounds = propertyIndex.IsValid() && propertyIndex.GetIndex() < m_materialAsset->GetPropertyValues().size(); - AZ_Warning("MaterialDocument", propertyIndexInBounds, "Failed to add material property '%s' to document '%s'.", propertyConfig.m_id.GetCStr(), m_absolutePath.c_str()); + const auto& propertyIndex = m_materialAsset->GetMaterialPropertiesLayout()->FindPropertyIndex(propertyConfig.m_id); + const bool propertyIndexInBounds = propertyIndex.IsValid() && propertyIndex.GetIndex() < m_materialAsset->GetPropertyValues().size(); + AZ_Warning("MaterialDocument", propertyIndexInBounds, "Failed to add material property '%s' to document '%s'.", propertyConfig.m_id.GetCStr(), m_absolutePath.c_str()); - if (propertyIndexInBounds) - { - AtomToolsFramework::ConvertToPropertyConfig(propertyConfig, propertyDefinition); - propertyConfig.m_showThumbnail = true; - propertyConfig.m_originalValue = AtomToolsFramework::ConvertToEditableType(m_materialAsset->GetPropertyValues()[propertyIndex.GetIndex()]); - propertyConfig.m_parentValue = AtomToolsFramework::ConvertToEditableType(parentPropertyValues[propertyIndex.GetIndex()]); - auto groupDefinition = m_materialTypeSourceData.FindGroup(groupName); - propertyConfig.m_groupName = groupDefinition ? groupDefinition->m_displayName : groupName; - m_properties[propertyConfig.m_id] = AtomToolsFramework::DynamicProperty(propertyConfig); - } - return true; - }); + if (propertyIndexInBounds) + { + AtomToolsFramework::ConvertToPropertyConfig(propertyConfig, *propertyDefinition); + propertyConfig.m_showThumbnail = true; + propertyConfig.m_originalValue = AtomToolsFramework::ConvertToEditableType(m_materialAsset->GetPropertyValues()[propertyIndex.GetIndex()]); + propertyConfig.m_parentValue = AtomToolsFramework::ConvertToEditableType(parentPropertyValues[propertyIndex.GetIndex()]); + + // TODO: Support populating the Material Editor with nested property sets, not just the top level. + // (Does DynamicPropertyConfig really even need m_groupName?) + propertyConfig.m_groupName = propertySet->GetDisplayName(); + m_properties[propertyConfig.m_id] = AtomToolsFramework::DynamicProperty(propertyConfig); + } + } + + return true; + }); // Populate the property group visibility map - for (MaterialTypeSourceData::GroupDefinition& group : m_materialTypeSourceData.GetGroupDefinitionsInDisplayOrder()) + // TODO: Support populating the Material Editor with nested property sets, not just the top level. + for (const AZStd::unique_ptr& propertySet : m_materialTypeSourceData.GetPropertyLayout().m_propertySets) { - m_propertyGroupVisibility[AZ::Name{group.m_name}] = true; + m_propertyGroupVisibility[AZ::Name{propertySet->GetName()}] = true; } // Adding properties for material type and parent as part of making dynamic @@ -877,6 +887,39 @@ namespace MaterialEditor return false; } } + + bool enumerateResult = m_materialTypeSourceData.EnumeratePropertySets( + [this, &materialTypeSourceFilePath](const AZStd::string&, const MaterialTypeSourceData::PropertySet* propertySet) + { + const MaterialFunctorSourceData::EditorContext editorContext = MaterialFunctorSourceData::EditorContext( + materialTypeSourceFilePath, m_materialAsset->GetMaterialPropertiesLayout()); + + for (Ptr functorData : propertySet->GetFunctors()) + { + MaterialFunctorSourceData::FunctorResult result = functorData->CreateFunctor(editorContext); + + if (result.IsSuccess()) + { + Ptr& functor = result.GetValue(); + if (functor != nullptr) + { + m_editorFunctors.push_back(functor); + } + } + else + { + AZ_Error("MaterialDocument", false, "Material functors were not created: '%s'.", m_absolutePath.c_str()); + return false; + } + } + + return true; + }); + + if (!enumerateResult) + { + return false; + } AZ::RPI::MaterialPropertyFlags dirtyFlags; dirtyFlags.set(); // Mark all properties as dirty since we just loaded the material and need to initialize property visibility diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.cpp index f6b42bf13a..e279b7e5b0 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.cpp @@ -163,28 +163,23 @@ namespace MaterialEditor const AZ::RPI::MaterialTypeSourceData* materialTypeSourceData = nullptr; MaterialDocumentRequestBus::EventResult( materialTypeSourceData, m_documentId, &MaterialDocumentRequestBus::Events::GetMaterialTypeSourceData); - - for (const auto& groupDefinition : materialTypeSourceData->GetGroupDefinitionsInDisplayOrder()) + + // TODO: Support populating the Material Editor with nested property sets, not just the top level. + for (const AZStd::unique_ptr& propertySet : materialTypeSourceData->GetPropertyLayout().m_propertySets) { - const AZStd::string& groupName = groupDefinition.m_name; - const AZStd::string& groupDisplayName = !groupDefinition.m_displayName.empty() ? groupDefinition.m_displayName : groupName; - const AZStd::string& groupDescription = - !groupDefinition.m_description.empty() ? groupDefinition.m_description : groupDisplayName; + const AZStd::string& groupName = propertySet->GetName(); + const AZStd::string& groupDisplayName = !propertySet->GetDisplayName().empty() ? propertySet->GetDisplayName() : groupName; + const AZStd::string& groupDescription = !propertySet->GetDescription().empty() ? propertySet->GetDescription() : groupDisplayName; auto& group = m_groups[groupName]; - const auto& propertyLayout = materialTypeSourceData->m_propertyLayout; - const auto& propertyListItr = propertyLayout.m_properties.find(groupName); - if (propertyListItr != propertyLayout.m_properties.end()) + group.m_properties.reserve(propertySet->GetProperties().size()); + for (const auto& propertyDefinition : propertySet->GetProperties()) { - group.m_properties.reserve(propertyListItr->second.size()); - for (const auto& propertyDefinition : propertyListItr->second) - { - AtomToolsFramework::DynamicProperty property; - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult( - property, m_documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::GetProperty, - AZ::RPI::MaterialPropertyId(groupName, propertyDefinition.m_name)); - group.m_properties.push_back(property); - } + AtomToolsFramework::DynamicProperty property; + AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult( + property, m_documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::GetProperty, + AZ::RPI::MaterialPropertyId(groupName, propertyDefinition->m_name)); + group.m_properties.push_back(property); } // Passing in same group as main and comparison instance to enable custom value comparison for highlighting modified properties diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp index c05b84db39..86610ecc93 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp @@ -283,35 +283,31 @@ namespace AZ AddUvNamesGroup(); // Copy all of the properties from the material asset to the source data that will be exported - for (const auto& groupDefinition : m_editData.m_materialTypeSourceData.GetGroupDefinitionsInDisplayOrder()) + // TODO: Support populating the Material Editor with nested property sets, not just the top level. + for (const AZStd::unique_ptr& propertySet : m_editData.m_materialTypeSourceData.GetPropertyLayout().m_propertySets) { - const AZStd::string& groupName = groupDefinition.m_name; - const AZStd::string& groupDisplayName = !groupDefinition.m_displayName.empty() ? groupDefinition.m_displayName : groupName; - const AZStd::string& groupDescription = !groupDefinition.m_description.empty() ? groupDefinition.m_description : groupDisplayName; + const AZStd::string& groupName = propertySet->GetName(); + const AZStd::string& groupDisplayName = !propertySet->GetDisplayName().empty() ? propertySet->GetDisplayName() : groupName; + const AZStd::string& groupDescription = !propertySet->GetDescription().empty() ? propertySet->GetDescription() : groupDisplayName; auto& group = m_groups[groupName]; - - const auto& propertyLayout = m_editData.m_materialTypeSourceData.m_propertyLayout; - const auto& propertyListItr = propertyLayout.m_properties.find(groupName); - if (propertyListItr != propertyLayout.m_properties.end()) + + group.m_properties.reserve(propertySet->GetProperties().size()); + for (const auto& propertyDefinition : propertySet->GetProperties()) { - group.m_properties.reserve(propertyListItr->second.size()); - for (const auto& propertyDefinition : propertyListItr->second) - { - AtomToolsFramework::DynamicPropertyConfig propertyConfig; + AtomToolsFramework::DynamicPropertyConfig propertyConfig; - // Assign id before conversion so it can be used in dynamic description - propertyConfig.m_id = AZ::RPI::MaterialPropertyId(groupName, propertyDefinition.m_name); + // Assign id before conversion so it can be used in dynamic description + propertyConfig.m_id = AZ::RPI::MaterialPropertyId(groupName, propertyDefinition->m_name); - AtomToolsFramework::ConvertToPropertyConfig(propertyConfig, propertyDefinition); + AtomToolsFramework::ConvertToPropertyConfig(propertyConfig, *propertyDefinition.get()); - 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()]); - group.m_properties.emplace_back(propertyConfig); - } + 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()]); + group.m_properties.emplace_back(propertyConfig); } // Passing in same group as main and comparison instance to enable custom value comparison for highlighting modified properties diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp index e851bc5fce..2593a12f19 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp @@ -91,7 +91,7 @@ namespace AZ AZ_Error("AZ::Render::EditorMaterialComponentUtil", false, "Failed to load material type source data: %s", editData.m_materialTypeSourcePath.c_str()); return false; } - editData.m_materialTypeSourceData = materialTypeOutcome.GetValue(); + editData.m_materialTypeSourceData = materialTypeOutcome.TakeValue(); return true; } @@ -99,7 +99,7 @@ namespace AZ { // Construct the material source data object that will be exported AZ::RPI::MaterialSourceData exportData; - exportData.m_propertyLayoutVersion = editData.m_materialTypeSourceData.m_propertyLayout.m_version; + exportData.m_propertyLayoutVersion = editData.m_materialTypeSourceData.GetPropertyLayout().m_version; // Converting absolute material paths to relative paths bool result = false; @@ -137,42 +137,46 @@ namespace AZ // Copy all of the properties from the material asset to the source data that will be exported result = true; - editData.m_materialTypeSourceData.EnumerateProperties([&](const AZStd::string& groupName, const AZStd::string& propertyName, const auto& propertyDefinition) { - const AZ::RPI::MaterialPropertyId propertyId(groupName, propertyName); - const AZ::RPI::MaterialPropertyIndex propertyIndex = - editData.m_materialAsset->GetMaterialPropertiesLayout()->FindPropertyIndex(propertyId); - - AZ::RPI::MaterialPropertyValue propertyValue = editData.m_materialAsset->GetPropertyValues()[propertyIndex.GetIndex()]; - - AZ::RPI::MaterialPropertyValue propertyValueDefault = propertyDefinition.m_value; - if (editData.m_materialParentAsset.IsReady()) - { - propertyValueDefault = editData.m_materialParentAsset->GetPropertyValues()[propertyIndex.GetIndex()]; - } - - // Check for and apply any property overrides before saving property values - auto propertyOverrideItr = editData.m_materialPropertyOverrideMap.find(propertyId); - if(propertyOverrideItr != editData.m_materialPropertyOverrideMap.end()) - { - propertyValue = AZ::RPI::MaterialPropertyValue::FromAny(propertyOverrideItr->second); - } - - if (!editData.m_materialTypeSourceData.ConvertPropertyValueToSourceDataFormat(propertyDefinition, propertyValue)) - { - AZ_Error("AZ::Render::EditorMaterialComponentUtil", false, "Failed to export: %s", path.c_str()); - result = false; - return false; - } - - // Don't export values if they are the same as the material type or parent - if (propertyValueDefault == propertyValue) + 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 propertyValueDefault = propertyDefinition->m_value; + if (editData.m_materialParentAsset.IsReady()) + { + propertyValueDefault = editData.m_materialParentAsset->GetPropertyValues()[propertyIndex.GetIndex()]; + } + + // Check for and apply any property overrides before saving property values + auto propertyOverrideItr = editData.m_materialPropertyOverrideMap.find(propertyId); + if(propertyOverrideItr != editData.m_materialPropertyOverrideMap.end()) + { + propertyValue = AZ::RPI::MaterialPropertyValue::FromAny(propertyOverrideItr->second); + } + + if (!editData.m_materialTypeSourceData.ConvertPropertyValueToSourceDataFormat(*propertyDefinition, propertyValue)) + { + AZ_Error("AZ::Render::EditorMaterialComponentUtil", false, "Failed to export: %s", path.c_str()); + result = false; + return false; + } + + // Don't export values if they are the same as the material type or parent + if (propertyValueDefault == propertyValue) + { + 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; return true; - } - - exportData.m_properties[groupName][propertyDefinition.m_name].m_value = propertyValue; - return true; - }); + }); return result && AZ::RPI::JsonUtils::SaveObjectToFile(path, exportData); } From 9d09656023899e3faa0dcd1e6a6633f8a4dfb1d7 Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Thu, 30 Sep 2021 01:33:05 -0700 Subject: [PATCH 04/20] Removed commented out code. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../Material/MaterialTypeSourceData.h | 8 --- .../Material/MaterialTypeSourceData.cpp | 71 ------------------- 2 files changed, 79 deletions(-) diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialTypeSourceData.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialTypeSourceData.h index 56f7c4612c..1d918702ff 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialTypeSourceData.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialTypeSourceData.h @@ -180,9 +180,7 @@ namespace AZ }; PropertySet* AddPropertySet(AZStd::string_view propertySetId); - //PropertySet* AddPropertySet(AZStd::string_view parentPropertySetId, AZStd::string_view name); PropertyDefinition* AddProperty(AZStd::string_view propertyId); - //PropertyDefinition* AddProperty(AZStd::string_view parentPropertySetId, AZStd::string_view name); const PropertyLayout& GetPropertyLayout() const { return m_propertyLayout; } @@ -241,15 +239,9 @@ namespace AZ private: - //PropertySet* FindPropertySet(AZStd::array_view parsedPropertySetId, AZStd::array_view> inPropertySetList); const PropertySet* FindPropertySet(AZStd::array_view parsedPropertySetId, AZStd::array_view> inPropertySetList) const; - - //PropertyDefinition* FindProperty(AZStd::array_view parsedPropertyId, AZStd::array_view> inPropertySetList); const PropertyDefinition* FindProperty(AZStd::array_view parsedPropertyId, AZStd::array_view> inPropertySetList) const; - //PropertyDefinition* FindProperty(AZStd::array_view parsedPropertyId, PropertySet& inPropertySet); - //const PropertyDefinition* FindProperty(AZStd::array_view parsedPropertyId, const PropertySet& inPropertySet) const; - // Function overloads for recursion, returns false to indicate that recursion should end. bool EnumeratePropertySets(const EnumeratePropertySetsCallback& callback, AZStd::string propertyIdContext, const AZStd::vector>& inPropertySetList) const; bool EnumerateProperties(const EnumeratePropertiesCallback& callback, AZStd::string propertyIdContext, const AZStd::vector>& inPropertySetList) const; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp index de55cbecb5..816e9f4f8d 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp @@ -196,9 +196,6 @@ namespace AZ return PropertySet::AddPropertySet(propertySetId, m_propertyLayout.m_propertySets); } - // TODO: Delete - //return AddPropertySet(splitPropertySetId[0], splitPropertySetId[1]); - PropertySet* parentPropertySet = const_cast(const_cast(this)->FindPropertySet(splitPropertySetId[0])); if (!parentPropertySet) @@ -210,27 +207,9 @@ namespace AZ return parentPropertySet->AddPropertySet(splitPropertySetId[1]); } - // TODO: Delete - //MaterialTypeSourceData::PropertySet* MaterialTypeSourceData::AddPropertySet(AZStd::string_view parentPropertySetId, AZStd::string_view name) - //{ - // PropertySet* parentPropertySet = const_cast(const_cast(this)->FindPropertySet(parentPropertySetId)); - // - // if (!parentPropertySet) - // { - // AZ_Error("Material source data", false, "PropertySet '%.*s' does not exists", AZ_STRING_ARG(parentPropertySetId)); - // return nullptr; - // } - - // return parentPropertySet->AddPropertySet(name); - //} - MaterialTypeSourceData::PropertyDefinition* MaterialTypeSourceData::AddProperty(AZStd::string_view propertyId) { AZStd::vector splitPropertyId = SplitId(propertyId); - //if (splitPropertyId.empty()) - //{ - // return nullptr; - //} if (splitPropertyId.size() == 1) { @@ -238,9 +217,6 @@ namespace AZ return nullptr; } - // TODO: Delete - //return AddProperty(splitPropertyId[0], splitPropertyId[1]); - PropertySet* parentPropertySet = const_cast(const_cast(this)->FindPropertySet(splitPropertyId[0])); if (!parentPropertySet) @@ -252,20 +228,6 @@ namespace AZ return parentPropertySet->AddProperty(splitPropertyId[1]); } - // TODO: Delete - //MaterialTypeSourceData::PropertyDefinition* MaterialTypeSourceData::AddProperty(AZStd::string_view parentPropertySetId, AZStd::string_view name) - //{ - // PropertySet* parentPropertySet = const_cast(const_cast(this)->FindPropertySet(parentPropertySetId)); - // - // if (!parentPropertySet) - // { - // AZ_Error("Material source data", false, "PropertySet '%.*s' does not exists", AZ_STRING_ARG(parentPropertySetId)); - // return nullptr; - // } - - // return parentPropertySet->AddProperty(name); - //} - const MaterialTypeSourceData::PropertySet* MaterialTypeSourceData::FindPropertySet(AZStd::array_view parsedPropertySetId, AZStd::array_view> inPropertySetList) const { for (const auto& propertySet : inPropertySetList) @@ -296,40 +258,12 @@ namespace AZ return nullptr; } - //MaterialTypeSourceData::PropertySet* MaterialTypeSourceData::FindPropertySet(AZStd::array_view parsedPropertySetId, AZStd::array_view> inPropertySetList) - //{ - // return const_cast(const_cast(this)->FindPropertySet(parsedPropertySetId, inPropertySetList)); - //} - const MaterialTypeSourceData::PropertySet* MaterialTypeSourceData::FindPropertySet(AZStd::string_view propertySetId) const { AZStd::vector tokens = TokenizeId(propertySetId); return FindPropertySet(tokens, m_propertyLayout.m_propertySets); } - //MaterialTypeSourceData::PropertyDefinition* MaterialTypeSourceData::FindProperty(AZStd::array_view parsedPropertyId, PropertySet& inPropertySet) - //{ - // if (parsedPropertyId.size() == 1) - // { - // for (AZStd::unique_ptr& property : inPropertySet.m_properties) - // { - // if (property->m_name == parsedPropertyId[0]) - // { - // return property.get(); - // } - // } - // } - - // return FindProperty(parsedPropertyId, inPropertySet.m_propertySets); - //} - - //const MaterialTypeSourceData::PropertyDefinition* MaterialTypeSourceData::FindProperty(AZStd::array_view parsedPropertyId, const PropertySet& inPropertySet) const - //{ - // MaterialTypeSourceData* nonConstThis = const_cast(this); - // PropertySet& nonConstPropertySet = *const_cast(&inPropertySet); - // return const_cast(nonConstThis->FindProperty(parsedPropertyId, nonConstPropertySet)); - //} - const MaterialTypeSourceData::PropertyDefinition* MaterialTypeSourceData::FindProperty( AZStd::array_view parsedPropertyId, AZStd::array_view> inPropertySetList) const @@ -364,11 +298,6 @@ namespace AZ return nullptr; } - //MaterialTypeSourceData::PropertyDefinition* MaterialTypeSourceData::FindProperty(AZStd::array_view parsedPropertyId, AZStd::array_view> inPropertySetList) - //{ - // return const_cast(const_cast(this)->FindProperty(parsedPropertyId, inPropertySetList)); - //} - const MaterialTypeSourceData::PropertyDefinition* MaterialTypeSourceData::FindProperty(AZStd::string_view propertyId) const { AZStd::vector tokens = TokenizeId(propertyId); From 95cfe056a1bc72eb5c77f01a347d538e9e7de8e8 Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Fri, 1 Oct 2021 17:00:45 -0700 Subject: [PATCH 05/20] Updated .materialtype files to use the new format, "propertySets" instead of "groups". First I used some local changes to do an auto-conversion that loaded, upgraded, and then saved each .materialtype but some details were lost in translation. For example, comments were lost, and default values changed slightly. So I grabbed an original copy of each file, and copied/pasted each section from the old file to the new one, while preserving the new layout. I did not update StandardMultilayerPBR because that will be too much work, will wait until after common property sets can be factored out. And I will likely discard that auto-conversion soon. Testing: AtomSampleViewer MaterialScreenshotTest script passed with the same results as before. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../Special/ShadowCatcher.materialtype | 58 +- .../Materials/Types/EnhancedPBR.materialtype | 2761 ++++++++--------- .../Assets/Materials/Types/Skin.materialtype | 1848 ++++++----- .../Materials/Types/StandardPBR.materialtype | 1909 ++++++------ .../Materials/Types/AutoBrick.materialtype | 327 +- 5 files changed, 3446 insertions(+), 3457 deletions(-) diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Special/ShadowCatcher.materialtype b/Gems/Atom/Feature/Common/Assets/Materials/Special/ShadowCatcher.materialtype index 74246f85db..62d3db022b 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Special/ShadowCatcher.materialtype +++ b/Gems/Atom/Feature/Common/Assets/Materials/Special/ShadowCatcher.materialtype @@ -2,38 +2,40 @@ "description": "Base material for the reflection probe visualization model.", "propertyLayout": { "version": 1, - "properties": { - "settings": [ - { - "name": "opacity", - "displayName": "Opacity", - "description": "Opacity of the shadow effect.", - "type": "Float", - "defaultValue": 0.5, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_opacity" + "propertySets": [ + { + "name": "settings", + "properties": [ + { + "name": "opacity", + "displayName": "Opacity", + "description": "Opacity of the shadow effect.", + "type": "Float", + "defaultValue": 0.5, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_opacity" + } + }, + { + "name": "shadeAll", + "displayName": "Shade All", + "description": "Shades the entire geometry with the shadow color, not just what's in shadow. For debugging.", + "type": "Bool", + "connection": { + "type": "ShaderOption", + "name": "o_shadeAll" + } } - }, - { - "name": "shadeAll", - "displayName": "Shade All", - "description": "Shades the entire geometry with the shadow color, not just what's in shadow. For debugging.", - "type": "Bool", - "connection": { - "type": "ShaderOption", - "name": "o_shadeAll" - } - } - ] - } + ] + } + ] }, "shaders": [ { "file": "ShadowCatcher.shader" } ] -} - +} \ No newline at end of file diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR.materialtype b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR.materialtype index bed3b69c4c..3d227a9aa0 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR.materialtype +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR.materialtype @@ -2,1456 +2,1453 @@ "description": "Material Type with properties used to define Enhanced PBR, a metallic-roughness Physically-Based Rendering (PBR) material shading model, with advanced features like subsurface scattering, transmission, and anisotropy.", "propertyLayout": { "version": 3, - "groups": [ + "propertySets": [ { "name": "baseColor", "displayName": "Base Color", - "description": "Properties for configuring the surface reflected color for dielectrics or reflectance values for metals." + "description": "Properties for configuring the surface reflected color for dielectrics or reflectance values for metals.", + "properties": [ + { + "name": "color", + "displayName": "Color", + "description": "Color is displayed as sRGB but the values are stored as linear color.", + "type": "Color", + "defaultValue": [ 1.0, 1.0, 1.0 ], + "connection": { + "type": "ShaderInput", + "name": "m_baseColor" + } + }, + { + "name": "factor", + "displayName": "Factor", + "description": "Strength factor for scaling the base color values. Zero (0.0) is black, white (1.0) is full color.", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_baseColorFactor" + } + }, + { + "name": "textureMap", + "displayName": "Texture", + "description": "Base color texture map", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_baseColorMap" + } + }, + { + "name": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "textureMapUv", + "displayName": "UV", + "description": "Base color map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_baseColorMapUvIndex" + } + }, + { + "name": "textureBlendMode", + "displayName": "Texture Blend Mode", + "description": "Selects the equation to use when combining Color, Factor, and Texture.", + "type": "Enum", + "enumValues": [ "Multiply", "LinearLight", "Lerp", "Overlay" ], + "defaultValue": "Multiply", + "connection": { + "type": "ShaderOption", + "name": "o_baseColorTextureBlendMode" + } + } + ] }, { "name": "metallic", "displayName": "Metallic", - "description": "Properties for configuring whether the surface is metallic or not." + "description": "Properties for configuring whether the surface is metallic or not.", + "properties": [ + { + "name": "factor", + "displayName": "Factor", + "description": "This value is linear, black is non-metal and white means raw metal.", + "type": "Float", + "defaultValue": 0.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_metallicFactor" + } + }, + { + "name": "textureMap", + "displayName": "Texture", + "description": "", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_metallicMap" + } + }, + { + "name": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture, or just default to the Factor value.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "textureMapUv", + "displayName": "UV", + "description": "Metallic map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_metallicMapUvIndex" + } + } + ] }, { "name": "roughness", "displayName": "Roughness", - "description": "Properties for configuring how rough the surface appears." + "description": "Properties for configuring how rough the surface appears.", + "properties": [ + { + "name": "textureMap", + "displayName": "Texture", + "description": "Texture for defining surface roughness.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_roughnessMap" + } + }, + { + "name": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture, or just default to the Factor value.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "textureMapUv", + "displayName": "UV", + "description": "Roughness map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_roughnessMapUvIndex" + } + }, + { + // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. + "name": "lowerBound", + "displayName": "Lower Bound", + "description": "The roughness value that corresponds to black in the texture.", + "type": "Float", + "defaultValue": 0.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_roughnessLowerBound" + } + }, + { + // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. + "name": "upperBound", + "displayName": "Upper Bound", + "description": "The roughness value that corresponds to white in the texture.", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_roughnessUpperBound" + } + }, + { + // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. + "name": "factor", + "displayName": "Factor", + "description": "Controls the roughness value", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_roughnessFactor" + } + } + ] }, { "name": "specularF0", "displayName": "Specular Reflectance f0", - "description": "The constant f0 represents the specular reflectance at normal incidence (Fresnel 0 Angle). Used to adjust reflectance of non-metal surfaces." + "description": "The constant f0 represents the specular reflectance at normal incidence (Fresnel 0 Angle). Used to adjust reflectance of non-metal surfaces.", + "properties": [ + { + "name": "factor", + "displayName": "Factor", + "description": "The default IOR is 1.5, which gives you 0.04 (4% of light reflected at 0 degree angle for dielectric materials). F0 values lie in the range 0-0.08, so that is why the default F0 slider is set on 0.5.", + "type": "Float", + "defaultValue": 0.5, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_specularF0Factor" + } + }, + { + "name": "textureMap", + "displayName": "Texture", + "description": "Texture for defining surface reflectance.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_specularF0Map" + } + }, + { + "name": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture, or just default to the Factor value.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "textureMapUv", + "displayName": "UV", + "description": "Specular reflection map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_specularF0MapUvIndex" + } + }, + // Consider moving this to the "general" group to be consistent with StandardMultilayerPBR + { + "name": "enableMultiScatterCompensation", + "displayName": "Multiscattering Compensation", + "description": "Whether to enable multiple scattering compensation.", + "type": "Bool", + "connection": { + "type": "ShaderOption", + "name": "o_specularF0_enableMultiScatterCompensation" + } + } + ] }, { "name": "normal", "displayName": "Normal", - "description": "Properties related to configuring surface normal." + "description": "Properties related to configuring surface normal.", + "properties": [ + { + "name": "textureMap", + "displayName": "Texture", + "description": "Texture for defining surface normal direction.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_normalMap" + } + }, + { + "name": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture, or just rely on vertex normals.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "textureMapUv", + "displayName": "UV", + "description": "Normal map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_normalMapUvIndex" + } + }, + { + "name": "flipX", + "displayName": "Flip X Channel", + "description": "Flip tangent direction for this normal map.", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderInput", + "name": "m_flipNormalX" + } + }, + { + "name": "flipY", + "displayName": "Flip Y Channel", + "description": "Flip bitangent direction for this normal map.", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderInput", + "name": "m_flipNormalY" + } + }, + { + "name": "factor", + "displayName": "Factor", + "description": "Strength factor for scaling the values", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "softMax": 2.0, + "connection": { + "type": "ShaderInput", + "name": "m_normalFactor" + } + } + ] }, { "name": "detailLayerGroup", "displayName": "Detail Layer", - "description": "Properties for Fine Details Layer." + "description": "Properties for Fine Details Layer.", + "properties": [ + { + "name": "enableDetailLayer", + "displayName": "Enable Detail Layer", + "description": "Enable detail layer for fine details and scratches", + "type": "Bool", + "defaultValue": false + }, + { + "name": "blendDetailFactor", + "displayName": "Blend Factor", + "description": "Scales the overall impact of the detail layer.", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_detail_blendFactor" + } + }, + { + "name": "blendDetailMask", + "displayName": "Blend Mask", + "description": "Detailed blend mask for application of the detail maps.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_detail_blendMask_texture" + } + }, + { + "name": "enableDetailMaskTexture", + "displayName": " Use Texture", + "description": "Enable detail blend mask", + "type": "Bool", + "defaultValue": true + }, + { + "name": "blendDetailMaskUv", + "displayName": " Blend Mask UV", + "description": "Which UV set to use for sampling the detail blend mask", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_detail_blendMask_uvIndex" + } + }, + { + "name": "textureMapUv", + "displayName": "Detail Map UVs", + "description": "Which UV set to use for detail map sampling", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_detail_allMapsUvIndex" + } + }, + { + "name": "enableBaseColor", + "displayName": "Enable Base Color", + "description": "Enable detail blending for base color", + "type": "Bool", + "defaultValue": false + }, + { + "name": "baseColorDetailMap", + "displayName": " Texture", + "description": "Detailed Base Color Texture", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_detail_baseColor_texture" + } + }, + { + "name": "baseColorDetailBlend", + "displayName": " Blend Factor", + "description": "How much to blend the detail layer into the base color.", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_detail_baseColor_factor" + } + }, + { + "name": "enableNormals", + "displayName": "Enable Normal", + "description": "Enable detail normal map to be used for fine detail normal such as scratches and small dents", + "type": "Bool", + "defaultValue": false + }, + { + "name": "normalDetailStrength", + "displayName": " Factor", + "description": "Strength factor for scaling the Detail Normal", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "softMax": 2.0, + "connection": { + "type": "ShaderInput", + "name": "m_detail_normal_factor" + } + }, + { + "name": "normalDetailMap", + "displayName": " Texture", + "description": "Detailed Normal map", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_detail_normal_texture" + } + }, + { + "name": "normalDetailFlipX", + "displayName": " Flip X Channel", + "description": "Flip Detail tangent direction for this normal map.", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderInput", + "name": "m_detail_normal_flipX" + } + }, + { + "name": "normalDetailFlipY", + "displayName": " Flip Y Channel", + "description": "Flip Detail bitangent direction for this normal map.", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderInput", + "name": "m_detail_normal_flipY" + } + } + ] }, { "name": "detailUV", "displayName": "Detail Layer UV", - "description": "Properties for modifying detail layer UV." + "description": "Properties for modifying detail layer UV.", + "properties": [ + { + "name": "center", + "displayName": "Center", + "description": "Center point for scaling and rotation transformations.", + "type": "vector2", + "vectorLabels": [ "U", "V" ], + "defaultValue": [ 0.5, 0.5 ] + }, + { + "name": "tileU", + "displayName": "Tile U", + "description": "Scales texture coordinates in V.", + "type": "float", + "defaultValue": 1.0, + "step": 0.1 + }, + { + "name": "tileV", + "displayName": "Tile V", + "description": "Scales texture coordinates in V.", + "type": "float", + "defaultValue": 1.0, + "step": 0.1 + }, + { + "name": "offsetU", + "displayName": "Offset U", + "description": "Offsets texture coordinates in the U direction.", + "type": "float", + "defaultValue": 0.0, + "min": -1.0, + "max": 1.0 + }, + { + "name": "offsetV", + "displayName": "Offset V", + "description": "Offsets texture coordinates in the V direction.", + "type": "float", + "defaultValue": 0.0, + "min": -1.0, + "max": 1.0 + }, + { + "name": "rotateDegrees", + "displayName": "Rotate", + "description": "Rotates the texture coordinates (degrees).", + "type": "float", + "defaultValue": 0.0, + "min": -180.0, + "max": 180.0, + "step": 1.0 + }, + { + "name": "scale", + "displayName": "Scale", + "description": "Scales texture coordinates in both U and V.", + "type": "float", + "defaultValue": 1.0, + "step": 0.1 + } + ] }, { "name": "anisotropy", "displayName": "Anisotropic Material Response", - "description": "How much is this material response anisotropic." + "description": "How much is this material response anisotropic.", + "properties": [ + { + "name": "enableAnisotropy", + "displayName": "Enable Anisotropy", + "description": "Enable anisotropic surface response for non uniform reflection along the axis", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderOption", + "name": "o_enableAnisotropy" + } + }, + { + "name": "factor", + "displayName": "Anisotropy Factor", + "description": "Strength factor for the anisotropy: negative = along v, positive = along u", + "type": "Float", + "defaultValue": 0.0, + "min": -0.95, + "max": 0.95, + "connection": { + "type": "ShaderInput", + "name": "m_anisotropicFactor" + } + }, + { + "name": "anisotropyAngle", + "displayName": "Anisotropy Angle", + "description": "Anisotropy direction of major reflection axis: 0 = 0 degrees, 1.0 = 180 degrees", + "type": "Float", + "defaultValue": 0.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_anisotropicAngle" + } + } + ] }, { "name": "occlusion", "displayName": "Occlusion", - "description": "Properties for baked textures that represent geometric occlusion of light." + "description": "Properties for baked textures that represent geometric occlusion of light.", + "properties": [ + { + "name": "diffuseTextureMap", + "displayName": "Diffuse AO", + "description": "Texture for defining occlusion area for diffuse ambient lighting.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_diffuseOcclusionMap" + } + }, + { + "name": "diffuseUseTexture", + "displayName": " Use Texture", + "description": "Whether to use the Diffuse AO map.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "diffuseTextureMapUv", + "displayName": " UV", + "description": "Diffuse AO map UV set.", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_diffuseOcclusionMapUvIndex" + } + }, + { + "name": "diffuseFactor", + "displayName": " Factor", + "description": "Strength factor for scaling the values of Diffuse AO", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "softMax": 2.0, + "connection": { + "type": "ShaderInput", + "name": "m_diffuseOcclusionFactor" + } + }, + { + "name": "specularTextureMap", + "displayName": "Specular Cavity", + "description": "Texture for defining occlusion area for specular lighting.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_specularOcclusionMap" + } + }, + { + "name": "specularUseTexture", + "displayName": " Use Texture", + "description": "Whether to use the Specular Cavity map.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "specularTextureMapUv", + "displayName": " UV", + "description": "Specular Cavity map UV set.", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_specularOcclusionMapUvIndex" + } + }, + { + "name": "specularFactor", + "displayName": " Factor", + "description": "Strength factor for scaling the values of Specular Cavity", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "softMax": 2.0, + "connection": { + "type": "ShaderInput", + "name": "m_specularOcclusionFactor" + } + } + ] }, { "name": "emissive", "displayName": "Emissive", - "description": "Properties to add light emission, independent of other lights in the scene." + "description": "Properties to add light emission, independent of other lights in the scene.", + "properties": [ + { + "name": "enable", + "displayName": "Enable", + "description": "Enable the emissive group", + "type": "Bool", + "defaultValue": false + }, + { + "name": "unit", + "displayName": "Units", + "description": "The photometric units of the Intensity property.", + "type": "Enum", + "enumValues": ["Ev100"], + "defaultValue": "Ev100" + }, + { + "name": "color", + "displayName": "Color", + "description": "Color is displayed as sRGB but the values are stored as linear color.", + "type": "Color", + "defaultValue": [ 1.0, 1.0, 1.0 ], + "connection": { + "type": "ShaderInput", + "name": "m_emissiveColor" + } + }, + { + "name": "intensity", + "displayName": "Intensity", + "description": "The amount of energy emitted.", + "type": "Float", + "defaultValue": 4, + "min": -10, + "max": 20, + "softMin": -6, + "softMax": 16 + }, + { + "name": "textureMap", + "displayName": "Texture", + "description": "Texture for defining emissive area.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_emissiveMap" + } + }, + { + "name": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "textureMapUv", + "displayName": "UV", + "description": "Emissive map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_emissiveMapUvIndex" + } + } + ] }, { "name": "subsurfaceScattering", "displayName": "Subsurface Scattering", - "description": "Properties for configuring subsurface scattering effects." + "description": "Properties for configuring subsurface scattering effects.", + "properties": [ + { + "name": "enableSubsurfaceScattering", + "displayName": "Subsurface Scattering", + "description": "Enable subsurface scattering feature, this will disable metallic and parallax mapping property due to incompatibility", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderOption", + "name": "o_enableSubsurfaceScattering" + } + }, + { + "name": "subsurfaceScatterFactor", + "displayName": " Factor", + "description": "Strength factor for scaling percentage of subsurface scattering effect applied", + "type": "float", + "defaultValue": 1.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_subsurfaceScatteringFactor" + } + }, + { + "name": "influenceMap", + "displayName": " Influence Map", + "description": "Texture for controlling the strength of subsurface scattering", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_subsurfaceScatteringInfluenceMap" + } + }, + { + "name": "useInfluenceMap", + "displayName": " Use Influence Map", + "description": "Whether to use the influence map.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "influenceMapUv", + "displayName": " UV", + "description": "Influence map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_subsurfaceScatteringInfluenceMapUvIndex" + } + }, + { + "name": "scatterColor", + "displayName": " Scatter color", + "description": "Color of volume light traveled through", + "type": "Color", + "defaultValue": [ 1.0, 0.27, 0.13 ] + }, + { + "name": "scatterDistance", + "displayName": " Scatter distance", + "description": "How far light traveled inside the volume", + "type": "float", + "defaultValue": 8, + "min": 0.0, + "softMax": 20.0 + }, + { + "name": "quality", + "displayName": " Quality", + "description": "How much percent of sample will be used for each pixel, more samples improve quality and reduce artifacts, especially when the scatter distance is relatively large, but slow down computation time, 1.0 = full set 200 samples per pixel", + "type": "float", + "defaultValue": 0.4, + "min": 0.2, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_subsurfaceScatteringQuality" + } + }, + { + "name": "transmissionMode", + "displayName": "Transmission", + "description": "Algorithm used for calculating transmission", + "type": "Enum", + "enumValues": [ "None", "ThickObject", "ThinObject" ], + "defaultValue": "None", + "connection": { + "type": "ShaderOption", + "name": "o_transmission_mode" + } + }, + { + "name": "thickness", + "displayName": " Thickness", + "description": "Normalized global thickness, the maxima between this value (multiplied by thickness map if enabled) and thickness from shadow map (if applicable) will be used as final thickness of pixel", + "type": "float", + "defaultValue": 0.5, + "min": 0.0, + "max": 1.0 + }, + { + "name": "thicknessMap", + "displayName": " Thickness Map", + "description": "Texture for controlling per pixel thickness", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_transmissionThicknessMap" + } + }, + { + "name": "useThicknessMap", + "displayName": " Use Thickness Map", + "description": "Whether to use the thickness map", + "type": "Bool", + "defaultValue": true + }, + { + "name": "thicknessMapUv", + "displayName": " UV", + "description": "Thickness map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_transmissionThicknessMapUvIndex" + } + }, + { + "name": "transmissionTint", + "displayName": " Transmission Tint", + "description": "Color of the volume light traveling through", + "type": "Color", + "defaultValue": [ 1.0, 0.8, 0.6 ] + }, + { + "name": "transmissionPower", + "displayName": " Power", + "description": "How much transmitted light scatter radially ", + "type": "float", + "defaultValue": 6.0, + "min": 0.0, + "softMax": 20.0 + }, + { + "name": "transmissionDistortion", + "displayName": " Distortion", + "description": "How much light direction distorted towards surface normal", + "type": "float", + "defaultValue": 0.1, + "min": 0.0, + "max": 1.0 + }, + { + "name": "transmissionAttenuation", + "displayName": " Attenuation", + "description": "How fast transmitted light fade with thickness", + "type": "float", + "defaultValue": 4.0, + "min": 0.0, + "softMax": 20.0 + }, + { + "name": "transmissionScale", + "displayName": " Scale", + "description": "Strength of transmission", + "type": "float", + "defaultValue": 3.0, + "min": 0.0, + "softMax": 20.0 + } + ] }, { "name": "clearCoat", "displayName": "Clear Coat", - "description": "Properties for configuring gloss clear coat" - }, + "description": "Properties for configuring gloss clear coat", + "properties": [ + { + "name": "enable", + "displayName": "Enable", + "description": "Enable clear coat", + "type": "Bool", + "defaultValue": false + }, + { + "name": "factor", + "displayName": "Factor", + "description": "Strength factor for scaling the percentage of effect applied", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_clearCoatFactor" + } + }, + { + "name": "influenceMap", + "displayName": " Influence Map", + "description": "Strength factor texture", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_clearCoatInfluenceMap" + } + }, + { + "name": "useInfluenceMap", + "displayName": " Use Texture", + "description": "Whether to use the texture, or just default to the Factor value.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "influenceMapUv", + "displayName": " UV", + "description": "Strength factor map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_clearCoatInfluenceMapUvIndex" + } + }, + { + "name": "roughness", + "displayName": "Roughness", + "description": "Clear coat layer roughness", + "type": "Float", + "defaultValue": 0.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_clearCoatRoughness" + } + }, + { + "name": "roughnessMap", + "displayName": " Roughness Map", + "description": "Texture for defining surface roughness", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_clearCoatRoughnessMap" + } + }, + { + "name": "useRoughnessMap", + "displayName": " Use Texture", + "description": "Whether to use the texture, or just default to the roughness value.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "roughnessMapUv", + "displayName": " UV", + "description": "Roughness map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_clearCoatRoughnessMapUvIndex" + } + }, + { + "name": "normalStrength", + "displayName": "Normal Strength", + "description": "Scales the impact of the clear coat normal map", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 2.0, + "connection": { + "type": "ShaderInput", + "name": "m_clearCoatNormalStrength" + } + }, + { + "name": "normalMap", + "displayName": "Normal Map", + "description": "Normal map for clear coat layer, as top layer material clear coat doesn't affect by base layer normal map", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_clearCoatNormalMap" + } + }, + { + "name": "useNormalMap", + "displayName": " Use Texture", + "description": "Whether to use the normal map", + "type": "Bool", + "defaultValue": true + }, + { + "name": "normalMapUv", + "displayName": " UV", + "description": "Normal map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_clearCoatNormalMapUvIndex" + } + } + ] + }, { "name": "parallax", "displayName": "Displacement", - "description": "Properties for parallax effect produced by a height map." + "description": "Properties for parallax effect produced by a height map.", + "properties": [ + { + "name": "textureMap", + "displayName": "Height Map", + "description": "Displacement height map to create parallax effect.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_heightmap" + } + }, + { + "name": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the height map.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "textureMapUv", + "displayName": "UV", + "description": "Height map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_parallaxUvIndex" + } + }, + { + "name": "factor", + "displayName": "Height Map Scale", + "description": "The total height of the height map in local model units.", + "type": "Float", + "defaultValue": 0.05, + "min": 0.0, + "softMax": 0.1, + "connection": { + "type": "ShaderInput", + "name": "m_heightmapScale" + } + }, + { + "name": "offset", + "displayName": "Offset", + "description": "Adjusts the overall displacement amount in local model units.", + "type": "Float", + "defaultValue": 0.0, + "softMin": -0.1, + "softMax": 0.1, + "connection": { + "type": "ShaderInput", + "name": "m_heightmapOffset" + } + }, + { + "name": "algorithm", + "displayName": "Algorithm", + "description": "Select the algorithm to use for parallax mapping.", + "type": "Enum", + "enumValues": [ "Basic", "Steep", "POM", "Relief", "ContactRefinement" ], + "defaultValue": "POM", + "connection": { + "type": "ShaderOption", + "name": "o_parallax_algorithm" + } + }, + { + "name": "quality", + "displayName": "Quality", + "description": "Quality of parallax mapping.", + "type": "Enum", + "enumValues": [ "Low", "Medium", "High", "Ultra" ], + "defaultValue": "Low", + "connection": { + "type": "ShaderOption", + "name": "o_parallax_quality" + } + }, + { + "name": "pdo", + "displayName": "Pixel Depth Offset", + "description": "Enable PDO to offset the original pixel depths. This will affect any shaders using depth, for example, when receiving shadows.", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderOption", + "name": "o_parallax_enablePixelDepthOffset" + } + }, + { + "name": "showClipping", + "displayName": "Show Clipping", + "description": "Highlight areas where the height map is clipped by the mesh surface.", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderOption", + "name": "o_parallax_highlightClipping" + } + } + ] }, { "name": "opacity", "displayName": "Opacity", - "description": "Properties for configuring the materials transparency." + "description": "Properties for configuring the materials transparency.", + "properties": [ + { + "name": "mode", + "displayName": "Opacity Mode", + "description": "Indicates the general approach how transparency is to be applied.", + "type": "Enum", + "enumValues": [ "Opaque", "Cutout", "Blended", "TintedTransparent" ], + "defaultValue": "Opaque", + "connection": { + "type": "ShaderOption", + "name": "o_opacity_mode" + } + }, + { + "name": "alphaSource", + "displayName": "Alpha Source", + "description": "Indicates whether to get the opacity texture from the Base Color map (Packed) or from a separate greyscale texture (Split).", + "type": "Enum", + "enumValues": [ "Packed", "Split", "None" ], + "defaultValue": "Packed", + "connection": { + "type": "ShaderOption", + "name": "o_opacity_source" + } + }, + { + "name": "textureMap", + "displayName": "Texture", + "description": "Texture for defining surface opacity.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_opacityMap" + } + }, + { + "name": "textureMapUv", + "displayName": "UV", + "description": "Opacity map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_opacityMapUvIndex" + } + }, + { + "name": "factor", + "displayName": "Factor", + "description": "Factor for cutout threshold and blending", + "type": "Float", + "min": 0.0, + "max": 1.0, + "defaultValue": 0.5, + "connection": { + "type": "ShaderInput", + "name": "m_opacityFactor" + } + }, + { + "name": "doubleSided", + "displayName": "Double-sided", + "description": "Whether to render back-faces or just front-faces.", + "type": "Bool" + }, + { + "name": "alphaAffectsSpecular", + "displayName": "Alpha affects specular", + "description": "How much the alpha value should also affect specular reflection. This should be 0.0 for materials where light can transmit through their physical surface (like glass), but 1.0 when alpha determines the very presence of a surface (like hair or grass)", + "type": "float", + "min": 0.0, + "max": 1.0, + "defaultValue": 0.0, + "connection": { + "type": "ShaderInput", + "name": "m_opacityAffectsSpecularFactor" + } + } + ] }, { "name": "uv", "displayName": "UVs", - "description": "Properties for configuring UV transforms." + "description": "Properties for configuring UV transforms.", + "properties": [ + { + "name": "center", + "displayName": "Center", + "description": "Center point for scaling and rotation transformations.", + "type": "vector2", + "vectorLabels": [ "U", "V" ], + "defaultValue": [ 0.5, 0.5 ] + }, + { + "name": "tileU", + "displayName": "Tile U", + "description": "Scales texture coordinates in U.", + "type": "float", + "defaultValue": 1.0, + "step": 0.1 + }, + { + "name": "tileV", + "displayName": "Tile V", + "description": "Scales texture coordinates in V.", + "type": "float", + "defaultValue": 1.0, + "step": 0.1 + }, + { + "name": "offsetU", + "displayName": "Offset U", + "description": "Offsets texture coordinates in the U direction.", + "type": "float", + "defaultValue": 0.0, + "min": -1.0, + "max": 1.0 + }, + { + "name": "offsetV", + "displayName": "Offset V", + "description": "Offsets texture coordinates in the V direction.", + "type": "float", + "defaultValue": 0.0, + "min": -1.0, + "max": 1.0 + }, + { + "name": "rotateDegrees", + "displayName": "Rotate", + "description": "Rotates the texture coordinates (degrees).", + "type": "float", + "defaultValue": 0.0, + "min": -180.0, + "max": 180.0, + "step": 1.0 + }, + { + "name": "scale", + "displayName": "Scale", + "description": "Scales texture coordinates in both U and V.", + "type": "float", + "defaultValue": 1.0, + "step": 0.1 + } + ] }, { // Note: this property group is used in the DiffuseGlobalIllumination pass and not by the main forward shader "name": "irradiance", "displayName": "Irradiance", - "description": "Properties for configuring the irradiance used in global illumination." + "description": "Properties for configuring the irradiance used in global illumination.", + "properties": [ + { + "name": "color", + "displayName": "Color", + "description": "Color is displayed as sRGB but the values are stored as linear color.", + "type": "Color", + "defaultValue": [ 1.0, 1.0, 1.0 ] + }, + { + "name": "factor", + "displayName": "Factor", + "description": "Strength factor for scaling the irradiance color values. Zero (0.0) is black, white (1.0) is full color.", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 1.0 + } + ] }, { "name": "general", "displayName": "General Settings", - "description": "General settings." + "description": "General settings.", + "properties": [ + { + "name": "applySpecularAA", + "displayName": "Apply Specular AA", + "description": "Whether to apply specular anti-aliasing in the shader.", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderOption", + "name": "o_applySpecularAA" + } + }, + { + "name": "enableShadows", + "displayName": "Enable Shadows", + "description": "Whether to use the shadow maps.", + "type": "Bool", + "defaultValue": true, + "connection": { + "type": "ShaderOption", + "name": "o_enableShadows" + } + }, + { + "name": "enableDirectionalLights", + "displayName": "Enable Directional Lights", + "description": "Whether to use directional lights.", + "type": "Bool", + "defaultValue": true, + "connection": { + "type": "ShaderOption", + "name": "o_enableDirectionalLights" + } + }, + { + "name": "enablePunctualLights", + "displayName": "Enable Punctual Lights", + "description": "Whether to use punctual lights.", + "type": "Bool", + "defaultValue": true, + "connection": { + "type": "ShaderOption", + "name": "o_enablePunctualLights" + } + }, + { + "name": "enableAreaLights", + "displayName": "Enable Area Lights", + "description": "Whether to use area lights.", + "type": "Bool", + "defaultValue": true, + "connection": { + "type": "ShaderOption", + "name": "o_enableAreaLights" + } + }, + { + "name": "enableIBL", + "displayName": "Enable IBL", + "description": "Whether to use Image Based Lighting (IBL).", + "type": "Bool", + "defaultValue": true, + "connection": { + "type": "ShaderOption", + "name": "o_enableIBL" + } + }, + { + "name": "forwardPassIBLSpecular", + "displayName": "Forward Pass IBL Specular", + "description": "Whether to apply IBL specular in the forward pass.", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderOption", + "name": "o_materialUseForwardPassIBLSpecular" + } + } + ] } - ], - "properties": { - "general": [ - { - "name": "applySpecularAA", - "displayName": "Apply Specular AA", - "description": "Whether to apply specular anti-aliasing in the shader.", - "type": "Bool", - "defaultValue": false, - "connection": { - "type": "ShaderOption", - "name": "o_applySpecularAA" - } - }, - { - "name": "enableShadows", - "displayName": "Enable Shadows", - "description": "Whether to use the shadow maps.", - "type": "Bool", - "defaultValue": true, - "connection": { - "type": "ShaderOption", - "name": "o_enableShadows" - } - }, - { - "name": "enableDirectionalLights", - "displayName": "Enable Directional Lights", - "description": "Whether to use directional lights.", - "type": "Bool", - "defaultValue": true, - "connection": { - "type": "ShaderOption", - "name": "o_enableDirectionalLights" - } - }, - { - "name": "enablePunctualLights", - "displayName": "Enable Punctual Lights", - "description": "Whether to use punctual lights.", - "type": "Bool", - "defaultValue": true, - "connection": { - "type": "ShaderOption", - "name": "o_enablePunctualLights" - } - }, - { - "name": "enableAreaLights", - "displayName": "Enable Area Lights", - "description": "Whether to use area lights.", - "type": "Bool", - "defaultValue": true, - "connection": { - "type": "ShaderOption", - "name": "o_enableAreaLights" - } - }, - { - "name": "enableIBL", - "displayName": "Enable IBL", - "description": "Whether to use Image Based Lighting (IBL).", - "type": "Bool", - "defaultValue": true, - "connection": { - "type": "ShaderOption", - "name": "o_enableIBL" - } - }, - { - "name": "forwardPassIBLSpecular", - "displayName": "Forward Pass IBL Specular", - "description": "Whether to apply IBL specular in the forward pass.", - "type": "Bool", - "defaultValue": false, - "connection": { - "type": "ShaderOption", - "name": "o_materialUseForwardPassIBLSpecular" - } - } - ], - "baseColor": [ - { - "name": "color", - "displayName": "Color", - "description": "Color is displayed as sRGB but the values are stored as linear color.", - "type": "Color", - "defaultValue": [ 1.0, 1.0, 1.0 ], - "connection": { - "type": "ShaderInput", - "name": "m_baseColor" - } - }, - { - "name": "factor", - "displayName": "Factor", - "description": "Strength factor for scaling the base color values. Zero (0.0) is black, white (1.0) is full color.", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_baseColorFactor" - } - }, - { - "name": "textureMap", - "displayName": "Texture", - "description": "Base color texture map", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_baseColorMap" - } - }, - { - "name": "useTexture", - "displayName": "Use Texture", - "description": "Whether to use the texture.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "textureMapUv", - "displayName": "UV", - "description": "Base color map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_baseColorMapUvIndex" - } - }, - { - "name": "textureBlendMode", - "displayName": "Texture Blend Mode", - "description": "Selects the equation to use when combining Color, Factor, and Texture.", - "type": "Enum", - "enumValues": [ "Multiply", "LinearLight", "Lerp", "Overlay" ], - "defaultValue": "Multiply", - "connection": { - "type": "ShaderOption", - "name": "o_baseColorTextureBlendMode" - } - } - ], - "metallic": [ - { - "name": "factor", - "displayName": "Factor", - "description": "This value is linear, black is non-metal and white means raw metal.", - "type": "Float", - "defaultValue": 0.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_metallicFactor" - } - }, - { - "name": "textureMap", - "displayName": "Texture", - "description": "", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_metallicMap" - } - }, - { - "name": "useTexture", - "displayName": "Use Texture", - "description": "Whether to use the texture, or just default to the Factor value.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "textureMapUv", - "displayName": "UV", - "description": "Metallic map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_metallicMapUvIndex" - } - } - ], - "roughness": [ - { - "name": "textureMap", - "displayName": "Texture", - "description": "Texture for defining surface roughness.", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_roughnessMap" - } - }, - { - "name": "useTexture", - "displayName": "Use Texture", - "description": "Whether to use the texture, or just default to the Factor value.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "textureMapUv", - "displayName": "UV", - "description": "Roughness map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_roughnessMapUvIndex" - } - }, - { - // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. - "name": "lowerBound", - "displayName": "Lower Bound", - "description": "The roughness value that corresponds to black in the texture.", - "type": "Float", - "defaultValue": 0.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_roughnessLowerBound" - } - }, - { - // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. - "name": "upperBound", - "displayName": "Upper Bound", - "description": "The roughness value that corresponds to white in the texture.", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_roughnessUpperBound" - } - }, - { - // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. - "name": "factor", - "displayName": "Factor", - "description": "Controls the roughness value", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_roughnessFactor" - } - } - ], - "anisotropy": [ - { - "name": "enableAnisotropy", - "displayName": "Enable Anisotropy", - "description": "Enable anisotropic surface response for non uniform reflection along the axis", - "type": "Bool", - "defaultValue": false, - "connection": { - "type": "ShaderOption", - "name": "o_enableAnisotropy" - } - }, - { - "name": "factor", - "displayName": "Anisotropy Factor", - "description": "Strength factor for the anisotropy: negative = along v, positive = along u", - "type": "Float", - "defaultValue": 0.0, - "min": -0.95, - "max": 0.95, - "connection": { - "type": "ShaderInput", - "name": "m_anisotropicFactor" - } - }, - { - "name": "anisotropyAngle", - "displayName": "Anisotropy Angle", - "description": "Anisotropy direction of major reflection axis: 0 = 0 degrees, 1.0 = 180 degrees", - "type": "Float", - "defaultValue": 0.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_anisotropicAngle" - } - } - ], - "specularF0": [ - { - "name": "factor", - "displayName": "Factor", - "description": "The default IOR is 1.5, which gives you 0.04 (4% of light reflected at 0 degree angle for dielectric materials). F0 values lie in the range 0-0.08, so that is why the default F0 slider is set on 0.5.", - "type": "Float", - "defaultValue": 0.5, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_specularF0Factor" - } - }, - { - "name": "textureMap", - "displayName": "Texture", - "description": "Texture for defining surface reflectance.", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_specularF0Map" - } - }, - { - "name": "useTexture", - "displayName": "Use Texture", - "description": "Whether to use the texture, or just default to the Factor value.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "textureMapUv", - "displayName": "UV", - "description": "Specular reflection map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_specularF0MapUvIndex" - } - }, - // Consider moving this to the "general" group to be consistent with StandardMultilayerPBR - { - "name": "enableMultiScatterCompensation", - "displayName": "Multiscattering Compensation", - "description": "Whether to enable multiple scattering compensation.", - "type": "Bool", - "connection": { - "type": "ShaderOption", - "name": "o_specularF0_enableMultiScatterCompensation" - } - } - ], - "clearCoat": [ - { - "name": "enable", - "displayName": "Enable", - "description": "Enable clear coat", - "type": "Bool", - "defaultValue": false - }, - { - "name": "factor", - "displayName": "Factor", - "description": "Strength factor for scaling the percentage of effect applied", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_clearCoatFactor" - } - }, - { - "name": "influenceMap", - "displayName": " Influence Map", - "description": "Strength factor texture", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_clearCoatInfluenceMap" - } - }, - { - "name": "useInfluenceMap", - "displayName": " Use Texture", - "description": "Whether to use the texture, or just default to the Factor value.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "influenceMapUv", - "displayName": " UV", - "description": "Strength factor map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_clearCoatInfluenceMapUvIndex" - } - }, - { - "name": "roughness", - "displayName": "Roughness", - "description": "Clear coat layer roughness", - "type": "Float", - "defaultValue": 0.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_clearCoatRoughness" - } - }, - { - "name": "roughnessMap", - "displayName": " Roughness Map", - "description": "Texture for defining surface roughness", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_clearCoatRoughnessMap" - } - }, - { - "name": "useRoughnessMap", - "displayName": " Use Texture", - "description": "Whether to use the texture, or just default to the roughness value.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "roughnessMapUv", - "displayName": " UV", - "description": "Roughness map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_clearCoatRoughnessMapUvIndex" - } - }, - { - "name": "normalStrength", - "displayName": "Normal Strength", - "description": "Scales the impact of the clear coat normal map", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "max": 2.0, - "connection": { - "type": "ShaderInput", - "name": "m_clearCoatNormalStrength" - } - }, - { - "name": "normalMap", - "displayName": "Normal Map", - "description": "Normal map for clear coat layer, as top layer material clear coat doesn't affect by base layer normal map", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_clearCoatNormalMap" - } - }, - { - "name": "useNormalMap", - "displayName": " Use Texture", - "description": "Whether to use the normal map", - "type": "Bool", - "defaultValue": true - }, - { - "name": "normalMapUv", - "displayName": " UV", - "description": "Normal map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_clearCoatNormalMapUvIndex" - } - } - ], - "normal": [ - { - "name": "textureMap", - "displayName": "Texture", - "description": "Texture for defining surface normal direction.", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_normalMap" - } - }, - { - "name": "useTexture", - "displayName": "Use Texture", - "description": "Whether to use the texture, or just rely on vertex normals.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "textureMapUv", - "displayName": "UV", - "description": "Normal map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_normalMapUvIndex" - } - }, - { - "name": "flipX", - "displayName": "Flip X Channel", - "description": "Flip tangent direction for this normal map.", - "type": "Bool", - "defaultValue": false, - "connection": { - "type": "ShaderInput", - "name": "m_flipNormalX" - } - }, - { - "name": "flipY", - "displayName": "Flip Y Channel", - "description": "Flip bitangent direction for this normal map.", - "type": "Bool", - "defaultValue": false, - "connection": { - "type": "ShaderInput", - "name": "m_flipNormalY" - } - }, - { - "name": "factor", - "displayName": "Factor", - "description": "Strength factor for scaling the values", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "softMax": 2.0, - "connection": { - "type": "ShaderInput", - "name": "m_normalFactor" - } - } - ], - "opacity": [ - { - "name": "mode", - "displayName": "Opacity Mode", - "description": "Indicates the general approach how transparency is to be applied.", - "type": "Enum", - "enumValues": [ "Opaque", "Cutout", "Blended", "TintedTransparent" ], - "defaultValue": "Opaque", - "connection": { - "type": "ShaderOption", - "name": "o_opacity_mode" - } - }, - { - "name": "alphaSource", - "displayName": "Alpha Source", - "description": "Indicates whether to get the opacity texture from the Base Color map (Packed) or from a separate greyscale texture (Split).", - "type": "Enum", - "enumValues": [ "Packed", "Split", "None" ], - "defaultValue": "Packed", - "connection": { - "type": "ShaderOption", - "name": "o_opacity_source" - } - }, - { - "name": "textureMap", - "displayName": "Texture", - "description": "Texture for defining surface opacity.", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_opacityMap" - } - }, - { - "name": "textureMapUv", - "displayName": "UV", - "description": "Opacity map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_opacityMapUvIndex" - } - }, - { - "name": "factor", - "displayName": "Factor", - "description": "Factor for cutout threshold and blending", - "type": "Float", - "min": 0.0, - "max": 1.0, - "defaultValue": 0.5, - "connection": { - "type": "ShaderInput", - "name": "m_opacityFactor" - } - }, - { - "name": "doubleSided", - "displayName": "Double-sided", - "description": "Whether to render back-faces or just front-faces.", - "type": "Bool" - }, - { - "name": "alphaAffectsSpecular", - "displayName": "Alpha affects specular", - "description": "How much the alpha value should also affect specular reflection. This should be 0.0 for materials where light can transmit through their physical surface (like glass), but 1.0 when alpha determines the very presence of a surface (like hair or grass)", - "type": "float", - "min": 0.0, - "max": 1.0, - "defaultValue": 0.0, - "connection": { - "type": "ShaderInput", - "name": "m_opacityAffectsSpecularFactor" - } - } - ], - "uv": [ - { - "name": "center", - "displayName": "Center", - "description": "Center point for scaling and rotation transformations.", - "type": "vector2", - "vectorLabels": [ "U", "V" ], - "defaultValue": [ 0.5, 0.5 ] - }, - { - "name": "tileU", - "displayName": "Tile U", - "description": "Scales texture coordinates in U.", - "type": "float", - "defaultValue": 1.0, - "step": 0.1 - }, - { - "name": "tileV", - "displayName": "Tile V", - "description": "Scales texture coordinates in V.", - "type": "float", - "defaultValue": 1.0, - "step": 0.1 - }, - { - "name": "offsetU", - "displayName": "Offset U", - "description": "Offsets texture coordinates in the U direction.", - "type": "float", - "defaultValue": 0.0, - "min": -1.0, - "max": 1.0 - }, - { - "name": "offsetV", - "displayName": "Offset V", - "description": "Offsets texture coordinates in the V direction.", - "type": "float", - "defaultValue": 0.0, - "min": -1.0, - "max": 1.0 - }, - { - "name": "rotateDegrees", - "displayName": "Rotate", - "description": "Rotates the texture coordinates (degrees).", - "type": "float", - "defaultValue": 0.0, - "min": -180.0, - "max": 180.0, - "step": 1.0 - }, - { - "name": "scale", - "displayName": "Scale", - "description": "Scales texture coordinates in both U and V.", - "type": "float", - "defaultValue": 1.0, - "step": 0.1 - } - ], - "occlusion": [ - { - "name": "diffuseTextureMap", - "displayName": "Diffuse AO", - "description": "Texture for defining occlusion area for diffuse ambient lighting.", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_diffuseOcclusionMap" - } - }, - { - "name": "diffuseUseTexture", - "displayName": " Use Texture", - "description": "Whether to use the Diffuse AO map.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "diffuseTextureMapUv", - "displayName": " UV", - "description": "Diffuse AO map UV set.", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_diffuseOcclusionMapUvIndex" - } - }, - { - "name": "diffuseFactor", - "displayName": " Factor", - "description": "Strength factor for scaling the values of Diffuse AO", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "softMax": 2.0, - "connection": { - "type": "ShaderInput", - "name": "m_diffuseOcclusionFactor" - } - }, - { - "name": "specularTextureMap", - "displayName": "Specular Cavity", - "description": "Texture for defining occlusion area for specular lighting.", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_specularOcclusionMap" - } - }, - { - "name": "specularUseTexture", - "displayName": " Use Texture", - "description": "Whether to use the Specular Cavity map.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "specularTextureMapUv", - "displayName": " UV", - "description": "Specular Cavity map UV set.", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_specularOcclusionMapUvIndex" - } - }, - { - "name": "specularFactor", - "displayName": " Factor", - "description": "Strength factor for scaling the values of Specular Cavity", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "softMax": 2.0, - "connection": { - "type": "ShaderInput", - "name": "m_specularOcclusionFactor" - } - } - ], - "emissive": [ - { - "name": "enable", - "displayName": "Enable", - "description": "Enable the emissive group", - "type": "Bool", - "defaultValue": false - }, - { - "name": "unit", - "displayName": "Units", - "description": "The photometric units of the Intensity property.", - "type": "Enum", - "enumValues": ["Ev100"], - "defaultValue": "Ev100" - }, - { - "name": "color", - "displayName": "Color", - "description": "Color is displayed as sRGB but the values are stored as linear color.", - "type": "Color", - "defaultValue": [ 1.0, 1.0, 1.0 ], - "connection": { - "type": "ShaderInput", - "name": "m_emissiveColor" - } - }, - { - "name": "intensity", - "displayName": "Intensity", - "description": "The amount of energy emitted.", - "type": "Float", - "defaultValue": 4, - "min": -10, - "max": 20, - "softMin": -6, - "softMax": 16 - }, - { - "name": "textureMap", - "displayName": "Texture", - "description": "Texture for defining emissive area.", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_emissiveMap" - } - }, - { - "name": "useTexture", - "displayName": "Use Texture", - "description": "Whether to use the texture.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "textureMapUv", - "displayName": "UV", - "description": "Emissive map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_emissiveMapUvIndex" - } - } - ], - "parallax": [ - { - "name": "textureMap", - "displayName": "Height Map", - "description": "Displacement height map to create parallax effect.", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_heightmap" - } - }, - { - "name": "useTexture", - "displayName": "Use Texture", - "description": "Whether to use the height map.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "textureMapUv", - "displayName": "UV", - "description": "Height map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_parallaxUvIndex" - } - }, - { - "name": "factor", - "displayName": "Height Map Scale", - "description": "The total height of the height map in local model units.", - "type": "Float", - "defaultValue": 0.05, - "min": 0.0, - "softMax": 0.1, - "connection": { - "type": "ShaderInput", - "name": "m_heightmapScale" - } - }, - { - "name": "offset", - "displayName": "Offset", - "description": "Adjusts the overall displacement amount in local model units.", - "type": "Float", - "defaultValue": 0.0, - "softMin": -0.1, - "softMax": 0.1, - "connection": { - "type": "ShaderInput", - "name": "m_heightmapOffset" - } - }, - { - "name": "algorithm", - "displayName": "Algorithm", - "description": "Select the algorithm to use for parallax mapping.", - "type": "Enum", - "enumValues": [ "Basic", "Steep", "POM", "Relief", "ContactRefinement" ], - "defaultValue": "POM", - "connection": { - "type": "ShaderOption", - "name": "o_parallax_algorithm" - } - }, - { - "name": "quality", - "displayName": "Quality", - "description": "Quality of parallax mapping.", - "type": "Enum", - "enumValues": [ "Low", "Medium", "High", "Ultra" ], - "defaultValue": "Low", - "connection": { - "type": "ShaderOption", - "name": "o_parallax_quality" - } - }, - { - "name": "pdo", - "displayName": "Pixel Depth Offset", - "description": "Enable PDO to offset the original pixel depths. This will affect any shaders using depth, for example, when receiving shadows.", - "type": "Bool", - "defaultValue": false, - "connection": { - "type": "ShaderOption", - "name": "o_parallax_enablePixelDepthOffset" - } - }, - { - "name": "showClipping", - "displayName": "Show Clipping", - "description": "Highlight areas where the height map is clipped by the mesh surface.", - "type": "Bool", - "defaultValue": false, - "connection": { - "type": "ShaderOption", - "name": "o_parallax_highlightClipping" - } - } - ], - "subsurfaceScattering": [ - { - "name": "enableSubsurfaceScattering", - "displayName": "Subsurface Scattering", - "description": "Enable subsurface scattering feature, this will disable metallic and parallax mapping property due to incompatibility", - "type": "Bool", - "defaultValue": false, - "connection": { - "type": "ShaderOption", - "name": "o_enableSubsurfaceScattering" - } - }, - { - "name": "subsurfaceScatterFactor", - "displayName": " Factor", - "description": "Strength factor for scaling percentage of subsurface scattering effect applied", - "type": "float", - "defaultValue": 1.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_subsurfaceScatteringFactor" - } - }, - { - "name": "influenceMap", - "displayName": " Influence Map", - "description": "Texture for controlling the strength of subsurface scattering", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_subsurfaceScatteringInfluenceMap" - } - }, - { - "name": "useInfluenceMap", - "displayName": " Use Influence Map", - "description": "Whether to use the influence map.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "influenceMapUv", - "displayName": " UV", - "description": "Influence map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_subsurfaceScatteringInfluenceMapUvIndex" - } - }, - { - "name": "scatterColor", - "displayName": " Scatter color", - "description": "Color of volume light traveled through", - "type": "Color", - "defaultValue": [ 1.0, 0.27, 0.13 ] - }, - { - "name": "scatterDistance", - "displayName": " Scatter distance", - "description": "How far light traveled inside the volume", - "type": "float", - "defaultValue": 8, - "min": 0.0, - "softMax": 20.0 - }, - { - "name": "quality", - "displayName": " Quality", - "description": "How much percent of sample will be used for each pixel, more samples improve quality and reduce artifacts, especially when the scatter distance is relatively large, but slow down computation time, 1.0 = full set 200 samples per pixel", - "type": "float", - "defaultValue": 0.4, - "min": 0.2, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_subsurfaceScatteringQuality" - } - }, - { - "name": "transmissionMode", - "displayName": "Transmission", - "description": "Algorithm used for calculating transmission", - "type": "Enum", - "enumValues": [ "None", "ThickObject", "ThinObject" ], - "defaultValue": "None", - "connection": { - "type": "ShaderOption", - "name": "o_transmission_mode" - } - }, - { - "name": "thickness", - "displayName": " Thickness", - "description": "Normalized global thickness, the maxima between this value (multiplied by thickness map if enabled) and thickness from shadow map (if applicable) will be used as final thickness of pixel", - "type": "float", - "defaultValue": 0.5, - "min": 0.0, - "max": 1.0 - }, - { - "name": "thicknessMap", - "displayName": " Thickness Map", - "description": "Texture for controlling per pixel thickness", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_transmissionThicknessMap" - } - }, - { - "name": "useThicknessMap", - "displayName": " Use Thickness Map", - "description": "Whether to use the thickness map", - "type": "Bool", - "defaultValue": true - }, - { - "name": "thicknessMapUv", - "displayName": " UV", - "description": "Thickness map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_transmissionThicknessMapUvIndex" - } - }, - { - "name": "transmissionTint", - "displayName": " Transmission Tint", - "description": "Color of the volume light traveling through", - "type": "Color", - "defaultValue": [ 1.0, 0.8, 0.6 ] - }, - { - "name": "transmissionPower", - "displayName": " Power", - "description": "How much transmitted light scatter radially ", - "type": "float", - "defaultValue": 6.0, - "min": 0.0, - "softMax": 20.0 - }, - { - "name": "transmissionDistortion", - "displayName": " Distortion", - "description": "How much light direction distorted towards surface normal", - "type": "float", - "defaultValue": 0.1, - "min": 0.0, - "max": 1.0 - }, - { - "name": "transmissionAttenuation", - "displayName": " Attenuation", - "description": "How fast transmitted light fade with thickness", - "type": "float", - "defaultValue": 4.0, - "min": 0.0, - "softMax": 20.0 - }, - { - "name": "transmissionScale", - "displayName": " Scale", - "description": "Strength of transmission", - "type": "float", - "defaultValue": 3.0, - "min": 0.0, - "softMax": 20.0 - } - ], - "detailLayerGroup": [ - { - "name": "enableDetailLayer", - "displayName": "Enable Detail Layer", - "description": "Enable detail layer for fine details and scratches", - "type": "Bool", - "defaultValue": false - }, - { - "name": "blendDetailFactor", - "displayName": "Blend Factor", - "description": "Scales the overall impact of the detail layer.", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_detail_blendFactor" - } - }, - { - "name": "blendDetailMask", - "displayName": "Blend Mask", - "description": "Detailed blend mask for application of the detail maps.", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_detail_blendMask_texture" - } - }, - { - "name": "enableDetailMaskTexture", - "displayName": " Use Texture", - "description": "Enable detail blend mask", - "type": "Bool", - "defaultValue": true - }, - { - "name": "blendDetailMaskUv", - "displayName": " Blend Mask UV", - "description": "Which UV set to use for sampling the detail blend mask", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_detail_blendMask_uvIndex" - } - }, - { - "name": "textureMapUv", - "displayName": "Detail Map UVs", - "description": "Which UV set to use for detail map sampling", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_detail_allMapsUvIndex" - } - }, - { - "name": "enableBaseColor", - "displayName": "Enable Base Color", - "description": "Enable detail blending for base color", - "type": "Bool", - "defaultValue": false - }, - { - "name": "baseColorDetailMap", - "displayName": " Texture", - "description": "Detailed Base Color Texture", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_detail_baseColor_texture" - } - }, - { - "name": "baseColorDetailBlend", - "displayName": " Blend Factor", - "description": "How much to blend the detail layer into the base color.", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_detail_baseColor_factor" - } - }, - { - "name": "enableNormals", - "displayName": "Enable Normal", - "description": "Enable detail normal map to be used for fine detail normal such as scratches and small dents", - "type": "Bool", - "defaultValue": false - }, - { - "name": "normalDetailStrength", - "displayName": " Factor", - "description": "Strength factor for scaling the Detail Normal", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "softMax": 2.0, - "connection": { - "type": "ShaderInput", - "name": "m_detail_normal_factor" - } - }, - { - "name": "normalDetailMap", - "displayName": " Texture", - "description": "Detailed Normal map", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_detail_normal_texture" - } - }, - { - "name": "normalDetailFlipX", - "displayName": " Flip X Channel", - "description": "Flip Detail tangent direction for this normal map.", - "type": "Bool", - "defaultValue": false, - "connection": { - "type": "ShaderInput", - "name": "m_detail_normal_flipX" - } - }, - { - "name": "normalDetailFlipY", - "displayName": " Flip Y Channel", - "description": "Flip Detail bitangent direction for this normal map.", - "type": "Bool", - "defaultValue": false, - "connection": { - "type": "ShaderInput", - "name": "m_detail_normal_flipY" - } - } - ], - "detailUV": [ - { - "name": "center", - "displayName": "Center", - "description": "Center point for scaling and rotation transformations.", - "type": "vector2", - "vectorLabels": [ "U", "V" ], - "defaultValue": [ 0.5, 0.5 ] - }, - { - "name": "tileU", - "displayName": "Tile U", - "description": "Scales texture coordinates in V.", - "type": "float", - "defaultValue": 1.0, - "step": 0.1 - }, - { - "name": "tileV", - "displayName": "Tile V", - "description": "Scales texture coordinates in V.", - "type": "float", - "defaultValue": 1.0, - "step": 0.1 - }, - { - "name": "offsetU", - "displayName": "Offset U", - "description": "Offsets texture coordinates in the U direction.", - "type": "float", - "defaultValue": 0.0, - "min": -1.0, - "max": 1.0 - }, - { - "name": "offsetV", - "displayName": "Offset V", - "description": "Offsets texture coordinates in the V direction.", - "type": "float", - "defaultValue": 0.0, - "min": -1.0, - "max": 1.0 - }, - { - "name": "rotateDegrees", - "displayName": "Rotate", - "description": "Rotates the texture coordinates (degrees).", - "type": "float", - "defaultValue": 0.0, - "min": -180.0, - "max": 180.0, - "step": 1.0 - }, - { - "name": "scale", - "displayName": "Scale", - "description": "Scales texture coordinates in both U and V.", - "type": "float", - "defaultValue": 1.0, - "step": 0.1 - } - ], - "irradiance": [ - // Note: this property group is used in the DiffuseGlobalIllumination pass and not by the main forward shader - { - "name": "color", - "displayName": "Color", - "description": "Color is displayed as sRGB but the values are stored as linear color.", - "type": "Color", - "defaultValue": [ 1.0, 1.0, 1.0 ] - }, - { - "name": "factor", - "displayName": "Factor", - "description": "Strength factor for scaling the irradiance color values. Zero (0.0) is black, white (1.0) is full color.", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "max": 1.0 - } - ] - } + ] }, "shaders": [ { diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.materialtype b/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.materialtype index 0969cc36e8..b462c936e9 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.materialtype +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.materialtype @@ -2,970 +2,968 @@ "description": "Material Type tailored for rendering skin, with support for blended wrinkle maps that work with animated vertex blend shapes.", "propertyLayout": { "version": 3, - "groups": [ + "propertySets": [ { "name": "baseColor", "displayName": "Base Color", - "description": "Properties for configuring the surface reflected color for dielectrics or reflectance values for metals." + "description": "Properties for configuring the surface reflected color for dielectrics or reflectance values for metals.", + "properties": [ + { + "name": "color", + "displayName": "Color", + "description": "Color is displayed as sRGB but the values are stored as linear color.", + "type": "Color", + "defaultValue": [ 1.0, 1.0, 1.0 ], + "connection": { + "type": "ShaderInput", + "name": "m_baseColor" + } + }, + { + "name": "factor", + "displayName": "Factor", + "description": "Strength factor for scaling the base color values. Zero (0.0) is black, white (1.0) is full color.", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_baseColorFactor" + } + }, + { + "name": "textureMap", + "displayName": "Texture", + "description": "Base color texture map", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_baseColorMap" + } + }, + { + "name": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "textureMapUv", + "displayName": "UV", + "description": "Base color map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Unwrapped", + "connection": { + "type": "ShaderInput", + "name": "m_baseColorMapUvIndex" + } + }, + { + "name": "textureBlendMode", + "displayName": "Texture Blend Mode", + "description": "Selects the equation to use when combining Color, Factor, and Texture.", + "type": "Enum", + "enumValues": [ "Multiply", "LinearLight", "Lerp", "Overlay" ], + "defaultValue": "Multiply", + "connection": { + "type": "ShaderOption", + "name": "o_baseColorTextureBlendMode" + } + } + ] }, { "name": "roughness", "displayName": "Roughness", - "description": "Properties for configuring how rough the surface appears." + "description": "Properties for configuring how rough the surface appears.", + "properties": [ + { + "name": "textureMap", + "displayName": "Texture", + "description": "Texture for defining surface roughness.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_roughnessMap" + } + }, + { + "name": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture, or just default to the Factor value.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "textureMapUv", + "displayName": "UV", + "description": "Roughness map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Unwrapped", + "connection": { + "type": "ShaderInput", + "name": "m_roughnessMapUvIndex" + } + }, + { + // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. + "name": "lowerBound", + "displayName": "Lower Bound", + "description": "The roughness value that corresponds to black in the texture.", + "type": "Float", + "defaultValue": 0.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_roughnessLowerBound" + } + }, + { + // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. + "name": "upperBound", + "displayName": "Upper Bound", + "description": "The roughness value that corresponds to white in the texture.", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_roughnessUpperBound" + } + }, + { + // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. + "name": "factor", + "displayName": "Factor", + "description": "Controls the roughness value", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_roughnessFactor" + } + } + ] }, { "name": "specularF0", "displayName": "Specular Reflectance f0", - "description": "The constant f0 represents the specular reflectance at normal incidence (Fresnel 0 Angle). Used to adjust reflectance of non-metal surfaces." + "description": "The constant f0 represents the specular reflectance at normal incidence (Fresnel 0 Angle). Used to adjust reflectance of non-metal surfaces.", + "properties": [ + { + "name": "factor", + "displayName": "Factor", + "description": "The default IOR is 1.5, which gives you 0.04 (4% of light reflected at 0 degree angle for dielectric materials). F0 values lie in the range 0-0.08, so that is why the default F0 slider is set on 0.5.", + "type": "Float", + "defaultValue": 0.5, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_specularF0Factor" + } + }, + { + "name": "textureMap", + "displayName": "Texture", + "description": "Texture for defining surface reflectance.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_specularF0Map" + } + }, + { + "name": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture, or just default to the Factor value.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "textureMapUv", + "displayName": "UV", + "description": "Specular reflection map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Unwrapped", + "connection": { + "type": "ShaderInput", + "name": "m_specularF0MapUvIndex" + } + }, + // Consider moving this to the "general" group to be consistent with StandardMultilayerPBR + { + "name": "enableMultiScatterCompensation", + "displayName": "Multiscattering Compensation", + "description": "Whether to enable multiple scattering compensation.", + "type": "Bool", + "connection": { + "type": "ShaderOption", + "name": "o_specularF0_enableMultiScatterCompensation" + } + } + ] }, { "name": "normal", "displayName": "Normal", - "description": "Properties related to configuring surface normal." + "description": "Properties related to configuring surface normal.", + "properties": [ + { + "name": "textureMap", + "displayName": "Texture", + "description": "Texture for defining surface normal direction.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_normalMap" + } + }, + { + "name": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture, or just rely on vertex normals.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "textureMapUv", + "displayName": "UV", + "description": "Normal map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Unwrapped", + "connection": { + "type": "ShaderInput", + "name": "m_normalMapUvIndex" + } + }, + { + "name": "flipX", + "displayName": "Flip X Channel", + "description": "Flip tangent direction for this normal map.", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderInput", + "name": "m_flipNormalX" + } + }, + { + "name": "flipY", + "displayName": "Flip Y Channel", + "description": "Flip bitangent direction for this normal map.", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderInput", + "name": "m_flipNormalY" + } + }, + { + "name": "factor", + "displayName": "Factor", + "description": "Strength factor for scaling the values", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "softMax": 2.0, + "connection": { + "type": "ShaderInput", + "name": "m_normalFactor" + } + } + ] }, { "name": "detailLayerGroup", "displayName": "Detail Layer", - "description": "Properties for Fine Details Layer." + "description": "Properties for Fine Details Layer.", + "properties": [ + { + "name": "enableDetailLayer", + "displayName": "Enable Detail Layer", + "description": "Enable detail layer for fine details and scratches", + "type": "Bool", + "defaultValue": false + }, + { + "name": "blendDetailFactor", + "displayName": "Blend Factor", + "description": "Scales the overall impact of the detail layer.", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_detail_blendFactor" + } + }, + { + "name": "blendDetailMask", + "displayName": "Blend Mask", + "description": "Detailed blend mask for application of the detail maps.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_detail_blendMask_texture" + } + }, + { + "name": "enableDetailMaskTexture", + "displayName": " Use Texture", + "description": "Enable detail blend mask", + "type": "Bool", + "defaultValue": true + }, + { + "name": "blendDetailMaskUv", + "displayName": " Blend Mask UV", + "description": "Which UV set to use for sampling the detail blend mask", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Unwrapped", + "connection": { + "type": "ShaderInput", + "name": "m_detail_blendMask_uvIndex" + } + }, + { + "name": "textureMapUv", + "displayName": "Detail Map UVs", + "description": "Which UV set to use for detail map sampling", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Unwrapped", + "connection": { + "type": "ShaderInput", + "name": "m_detail_allMapsUvIndex" + } + }, + { + "name": "enableBaseColor", + "displayName": "Enable Base Color", + "description": "Enable detail blending for base color", + "type": "Bool", + "defaultValue": false + }, + { + "name": "baseColorDetailMap", + "displayName": " Texture", + "description": "Detailed Base Color Texture", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_detail_baseColor_texture" + } + }, + { + "name": "baseColorDetailBlend", + "displayName": " Blend Factor", + "description": "How much to blend the detail layer into the base color.", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_detail_baseColor_factor" + } + }, + { + "name": "enableNormals", + "displayName": "Enable Normal", + "description": "Enable detail normal map to be used for fine detail normal such as scratches and small dents", + "type": "Bool", + "defaultValue": false + }, + { + "name": "normalDetailStrength", + "displayName": " Factor", + "description": "Strength factor for scaling the Detail Normal", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "softMax": 2.0, + "connection": { + "type": "ShaderInput", + "name": "m_detail_normal_factor" + } + }, + { + "name": "normalDetailMap", + "displayName": " Texture", + "description": "Detailed Normal map", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_detail_normal_texture" + } + }, + { + "name": "normalDetailFlipX", + "displayName": " Flip X Channel", + "description": "Flip Detail tangent direction for this normal map.", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderInput", + "name": "m_detail_normal_flipX" + } + }, + { + "name": "normalDetailFlipY", + "displayName": " Flip Y Channel", + "description": "Flip Detail bitangent direction for this normal map.", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderInput", + "name": "m_detail_normal_flipY" + } + } + ] }, { "name": "detailUV", "displayName": "Detail Layer UV", - "description": "Properties for modifying detail layer UV." + "description": "Properties for modifying detail layer UV.", + "properties": [ + { + "name": "center", + "displayName": "Center", + "description": "Center point for scaling and rotation transformations.", + "type": "vector2", + "vectorLabels": [ "U", "V" ], + "defaultValue": [ 0.5, 0.5 ] + }, + { + "name": "tileU", + "displayName": "Tile U", + "description": "Scales texture coordinates in V.", + "type": "float", + "defaultValue": 1.0, + "step": 0.1 + }, + { + "name": "tileV", + "displayName": "Tile V", + "description": "Scales texture coordinates in V.", + "type": "float", + "defaultValue": 1.0, + "step": 0.1 + }, + { + "name": "offsetU", + "displayName": "Offset U", + "description": "Offsets texture coordinates in the U direction.", + "type": "float", + "defaultValue": 0.0, + "min": -1.0, + "max": 1.0 + }, + { + "name": "offsetV", + "displayName": "Offset V", + "description": "Offsets texture coordinates in the V direction.", + "type": "float", + "defaultValue": 0.0, + "min": -1.0, + "max": 1.0 + }, + { + "name": "rotateDegrees", + "displayName": "Rotate", + "description": "Rotates the texture coordinates (degrees).", + "type": "float", + "defaultValue": 0.0, + "min": -180.0, + "max": 180.0, + "step": 1.0 + }, + { + "name": "scale", + "displayName": "Scale", + "description": "Scales texture coordinates in both U and V.", + "type": "float", + "defaultValue": 1.0, + "step": 0.1 + } + ] }, { "name": "occlusion", "displayName": "Occlusion", - "description": "Properties for baked textures that represent geometric occlusion of light." + "description": "Properties for baked textures that represent geometric occlusion of light.", + "properties": [ + { + "name": "diffuseTextureMap", + "displayName": "Diffuse AO", + "description": "Texture for defining occlusion area for diffuse ambient lighting.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_diffuseOcclusionMap" + } + }, + { + "name": "diffuseUseTexture", + "displayName": " Use Texture", + "description": "Whether to use the Diffuse AO map.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "diffuseTextureMapUv", + "displayName": " UV", + "description": "Diffuse AO map UV set.", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_diffuseOcclusionMapUvIndex" + } + }, + { + "name": "diffuseFactor", + "displayName": " Factor", + "description": "Strength factor for scaling the values of Diffuse AO", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "softMax": 2.0, + "connection": { + "type": "ShaderInput", + "name": "m_diffuseOcclusionFactor" + } + }, + { + "name": "specularTextureMap", + "displayName": "Specular Cavity", + "description": "Texture for defining occlusion area for specular lighting.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_specularOcclusionMap" + } + }, + { + "name": "specularUseTexture", + "displayName": " Use Texture", + "description": "Whether to use the Specular Cavity map.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "specularTextureMapUv", + "displayName": " UV", + "description": "Specular Cavity map UV set.", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_specularOcclusionMapUvIndex" + } + }, + { + "name": "specularFactor", + "displayName": " Factor", + "description": "Strength factor for scaling the values of Specular Cavity", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "softMax": 2.0, + "connection": { + "type": "ShaderInput", + "name": "m_specularOcclusionFactor" + } + } + ] }, { "name": "subsurfaceScattering", "displayName": "Subsurface Scattering", - "description": "Properties for configuring subsurface scattering effects." + "description": "Properties for configuring subsurface scattering effects.", + "properties": [ + { + "name": "enableSubsurfaceScattering", + "displayName": "Subsurface Scattering", + "description": "Enable subsurface scattering feature, this will disable metallic and parallax mapping property due to incompatibility", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderOption", + "name": "o_enableSubsurfaceScattering" + } + }, + { + "name": "subsurfaceScatterFactor", + "displayName": " Factor", + "description": "Strength factor for scaling percentage of subsurface scattering effect applied", + "type": "float", + "defaultValue": 1.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_subsurfaceScatteringFactor" + } + }, + { + "name": "influenceMap", + "displayName": " Influence Map", + "description": "Texture for controlling the strength of subsurface scattering", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_subsurfaceScatteringInfluenceMap" + } + }, + { + "name": "useInfluenceMap", + "displayName": " Use Influence Map", + "description": "Whether to use the influence map.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "influenceMapUv", + "displayName": " UV", + "description": "Influence map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Unwrapped", + "connection": { + "type": "ShaderInput", + "name": "m_subsurfaceScatteringInfluenceMapUvIndex" + } + }, + { + "name": "scatterColor", + "displayName": " Scatter color", + "description": "Color of volume light traveled through", + "type": "Color", + "defaultValue": [ 1.0, 0.27, 0.13 ] + }, + { + "name": "scatterDistance", + "displayName": " Scatter distance", + "description": "How far light traveled inside the volume", + "type": "float", + "defaultValue": 8, + "min": 0.0, + "softMax": 20.0 + }, + { + "name": "quality", + "displayName": " Quality", + "description": "How much percent of sample will be used for each pixel, more samples improve quality and reduce artifacts, especially when the scatter distance is relatively large, but slow down computation time, 1.0 = full set 200 samples per pixel", + "type": "float", + "defaultValue": 0.4, + "min": 0.2, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_subsurfaceScatteringQuality" + } + }, + { + "name": "transmissionMode", + "displayName": "Transmission", + "description": "Algorithm used for calculating transmission", + "type": "Enum", + "enumValues": [ "None", "ThickObject", "ThinObject" ], + "defaultValue": "None", + "connection": { + "type": "ShaderOption", + "name": "o_transmission_mode" + } + }, + { + "name": "thickness", + "displayName": " Thickness", + "description": "Normalized global thickness, the maxima between this value (multiplied by thickness map if enabled) and thickness from shadow map (if applicable) will be used as final thickness of pixel", + "type": "float", + "defaultValue": 0.5, + "min": 0.0, + "max": 1.0 + }, + { + "name": "thicknessMap", + "displayName": " Thickness Map", + "description": "Texture for controlling per pixel thickness", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_transmissionThicknessMap" + } + }, + { + "name": "useThicknessMap", + "displayName": " Use Thickness Map", + "description": "Whether to use the thickness map", + "type": "Bool", + "defaultValue": true + }, + { + "name": "thicknessMapUv", + "displayName": " UV", + "description": "Thickness map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Unwrapped", + "connection": { + "type": "ShaderInput", + "name": "m_transmissionThicknessMapUvIndex" + } + }, + { + "name": "transmissionTint", + "displayName": " Transmission Tint", + "description": "Color of the volume light traveling through", + "type": "Color", + "defaultValue": [ 1.0, 0.8, 0.6 ] + }, + { + "name": "transmissionPower", + "displayName": " Power", + "description": "How much transmitted light scatter radially ", + "type": "float", + "defaultValue": 6.0, + "min": 0.0, + "softMax": 20.0 + }, + { + "name": "transmissionDistortion", + "displayName": " Distortion", + "description": "How much light direction distorted towards surface normal", + "type": "float", + "defaultValue": 0.1, + "min": 0.0, + "max": 1.0 + }, + { + "name": "transmissionAttenuation", + "displayName": " Attenuation", + "description": "How fast transmitted light fade with thickness", + "type": "float", + "defaultValue": 4.0, + "min": 0.0, + "softMax": 20.0 + }, + { + "name": "transmissionScale", + "displayName": " Scale", + "description": "Strength of transmission", + "type": "float", + "defaultValue": 3.0, + "min": 0.0, + "softMax": 20.0 + } + ] }, { "name": "wrinkleLayers", "displayName": "Wrinkle Layers", - "description": "Properties for wrinkle maps to support morph animation, using vertex color blend weights." + "description": "Properties for wrinkle maps to support morph animation, using vertex color blend weights.", + "properties": [ + { + "name": "enable", + "displayName": "Enable Wrinkle Layers", + "description": "Enable wrinkle layers for morph animations, using vertex color blend weights.", + "type": "Bool", + "defaultValue": false + }, + { + "name": "count", + "displayName": "Number Of Layers", + "description": "The number of wrinkle map layers to use. The blend values come from the 'COLOR0' vertex stream, where R/G/B/A correspond to wrinkle layers 1/2/3/4 respectively.", + "type": "UInt", + "defaultValue": 4, + "min": 1, + "max": 4 + }, + { + "name": "showBlendValues", + "displayName": "Show Blend Values", + "description": "Enable a debug mode that draws the blend values as red, green, blue, and white overlays.", + "type": "Bool", + "defaultValue": false + }, + { + "name": "enableBaseColor", + "displayName": "Enable Base Color Maps", + "description": "Enable support for blending the base color according to morph animations.", + "type": "Bool", + "defaultValue": false + }, + { + "name": "baseColorMap1", + "displayName": " Base Color 1", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_wrinkle_baseColor_texture1" + } + }, + { + "name": "baseColorMap2", + "displayName": " Base Color 2", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_wrinkle_baseColor_texture2" + } + }, + { + "name": "baseColorMap3", + "displayName": " Base Color 3", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_wrinkle_baseColor_texture3" + } + }, + { + "name": "baseColorMap4", + "displayName": " Base Color 4", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_wrinkle_baseColor_texture4" + } + }, + { + "name": "enableNormal", + "displayName": "Enable Normal Maps", + "description": "Enable support for blending the normal maps according to morph animations.", + "type": "Bool", + "defaultValue": false + }, + { + "name": "normalMap1", + "displayName": " Normals 1", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_wrinkle_normal_texture1" + } + }, + { + "name": "normalMap2", + "displayName": " Normals 2", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_wrinkle_normal_texture2" + } + }, + { + "name": "normalMap3", + "displayName": " Normals 3", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_wrinkle_normal_texture3" + } + }, + { + "name": "normalMap4", + "displayName": " Normals 4", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_wrinkle_normal_texture4" + } + } + ] }, { "name": "general", "displayName": "General Settings", - "description": "General settings." - } - ], - "properties": { - "general": [ - { - "name": "applySpecularAA", - "displayName": "Apply Specular AA", - "description": "Whether to apply specular anti-aliasing in the shader.", - "type": "Bool", - "defaultValue": false, - "connection": { - "type": "ShaderOption", - "name": "o_applySpecularAA" - } - }, - { - "name": "enableShadows", - "displayName": "Enable Shadows", - "description": "Whether to use the shadow maps.", - "type": "Bool", - "defaultValue": true, - "connection": { - "type": "ShaderOption", - "name": "o_enableShadows" - } - }, - { - "name": "enableDirectionalLights", - "displayName": "Enable Directional Lights", - "description": "Whether to use directional lights.", - "type": "Bool", - "defaultValue": true, - "connection": { - "type": "ShaderOption", - "name": "o_enableDirectionalLights" - } - }, - { - "name": "enablePunctualLights", - "displayName": "Enable Punctual Lights", - "description": "Whether to use punctual lights.", - "type": "Bool", - "defaultValue": true, - "connection": { - "type": "ShaderOption", - "name": "o_enablePunctualLights" - } - }, - { - "name": "enableAreaLights", - "displayName": "Enable Area Lights", - "description": "Whether to use area lights.", - "type": "Bool", - "defaultValue": true, - "connection": { - "type": "ShaderOption", - "name": "o_enableAreaLights" - } - }, - { - "name": "enableIBL", - "displayName": "Enable IBL", - "description": "Whether to use Image Based Lighting (IBL).", - "type": "Bool", - "defaultValue": true, - "connection": { - "type": "ShaderOption", - "name": "o_enableIBL" - } - } - ], - "baseColor": [ - { - "name": "color", - "displayName": "Color", - "description": "Color is displayed as sRGB but the values are stored as linear color.", - "type": "Color", - "defaultValue": [ 1.0, 1.0, 1.0 ], - "connection": { - "type": "ShaderInput", - "name": "m_baseColor" - } - }, - { - "name": "factor", - "displayName": "Factor", - "description": "Strength factor for scaling the base color values. Zero (0.0) is black, white (1.0) is full color.", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_baseColorFactor" - } - }, - { - "name": "textureMap", - "displayName": "Texture", - "description": "Base color texture map", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_baseColorMap" - } - }, - { - "name": "useTexture", - "displayName": "Use Texture", - "description": "Whether to use the texture.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "textureMapUv", - "displayName": "UV", - "description": "Base color map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Unwrapped", - "connection": { - "type": "ShaderInput", - "name": "m_baseColorMapUvIndex" - } - }, - { - "name": "textureBlendMode", - "displayName": "Texture Blend Mode", - "description": "Selects the equation to use when combining Color, Factor, and Texture.", - "type": "Enum", - "enumValues": [ "Multiply", "LinearLight", "Lerp", "Overlay" ], - "defaultValue": "Multiply", - "connection": { - "type": "ShaderOption", - "name": "o_baseColorTextureBlendMode" - } - } - ], - "roughness": [ - { - "name": "textureMap", - "displayName": "Texture", - "description": "Texture for defining surface roughness.", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_roughnessMap" - } - }, - { - "name": "useTexture", - "displayName": "Use Texture", - "description": "Whether to use the texture, or just default to the Factor value.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "textureMapUv", - "displayName": "UV", - "description": "Roughness map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Unwrapped", - "connection": { - "type": "ShaderInput", - "name": "m_roughnessMapUvIndex" - } - }, - { - // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. - "name": "lowerBound", - "displayName": "Lower Bound", - "description": "The roughness value that corresponds to black in the texture.", - "type": "Float", - "defaultValue": 0.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_roughnessLowerBound" - } - }, - { - // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. - "name": "upperBound", - "displayName": "Upper Bound", - "description": "The roughness value that corresponds to white in the texture.", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_roughnessUpperBound" - } - }, - { - // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. - "name": "factor", - "displayName": "Factor", - "description": "Controls the roughness value", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_roughnessFactor" - } - } - ], - "specularF0": [ - { - "name": "factor", - "displayName": "Factor", - "description": "The default IOR is 1.5, which gives you 0.04 (4% of light reflected at 0 degree angle for dielectric materials). F0 values lie in the range 0-0.08, so that is why the default F0 slider is set on 0.5.", - "type": "Float", - "defaultValue": 0.5, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_specularF0Factor" - } - }, - { - "name": "textureMap", - "displayName": "Texture", - "description": "Texture for defining surface reflectance.", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_specularF0Map" - } - }, - { - "name": "useTexture", - "displayName": "Use Texture", - "description": "Whether to use the texture, or just default to the Factor value.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "textureMapUv", - "displayName": "UV", - "description": "Specular reflection map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Unwrapped", - "connection": { - "type": "ShaderInput", - "name": "m_specularF0MapUvIndex" - } - }, - // Consider moving this to the "general" group to be consistent with StandardMultilayerPBR - { - "name": "enableMultiScatterCompensation", - "displayName": "Multiscattering Compensation", - "description": "Whether to enable multiple scattering compensation.", - "type": "Bool", - "connection": { - "type": "ShaderOption", - "name": "o_specularF0_enableMultiScatterCompensation" - } - } - ], - "normal": [ - { - "name": "textureMap", - "displayName": "Texture", - "description": "Texture for defining surface normal direction.", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_normalMap" - } - }, - { - "name": "useTexture", - "displayName": "Use Texture", - "description": "Whether to use the texture, or just rely on vertex normals.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "textureMapUv", - "displayName": "UV", - "description": "Normal map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Unwrapped", - "connection": { - "type": "ShaderInput", - "name": "m_normalMapUvIndex" - } - }, - { - "name": "flipX", - "displayName": "Flip X Channel", - "description": "Flip tangent direction for this normal map.", - "type": "Bool", - "defaultValue": false, - "connection": { - "type": "ShaderInput", - "name": "m_flipNormalX" - } - }, - { - "name": "flipY", - "displayName": "Flip Y Channel", - "description": "Flip bitangent direction for this normal map.", - "type": "Bool", - "defaultValue": false, - "connection": { - "type": "ShaderInput", - "name": "m_flipNormalY" - } - }, - { - "name": "factor", - "displayName": "Factor", - "description": "Strength factor for scaling the values", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "softMax": 2.0, - "connection": { - "type": "ShaderInput", - "name": "m_normalFactor" + "description": "General settings.", + "properties": [ + { + "name": "applySpecularAA", + "displayName": "Apply Specular AA", + "description": "Whether to apply specular anti-aliasing in the shader.", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderOption", + "name": "o_applySpecularAA" + } + }, + { + "name": "enableShadows", + "displayName": "Enable Shadows", + "description": "Whether to use the shadow maps.", + "type": "Bool", + "defaultValue": true, + "connection": { + "type": "ShaderOption", + "name": "o_enableShadows" + } + }, + { + "name": "enableDirectionalLights", + "displayName": "Enable Directional Lights", + "description": "Whether to use directional lights.", + "type": "Bool", + "defaultValue": true, + "connection": { + "type": "ShaderOption", + "name": "o_enableDirectionalLights" + } + }, + { + "name": "enablePunctualLights", + "displayName": "Enable Punctual Lights", + "description": "Whether to use punctual lights.", + "type": "Bool", + "defaultValue": true, + "connection": { + "type": "ShaderOption", + "name": "o_enablePunctualLights" + } + }, + { + "name": "enableAreaLights", + "displayName": "Enable Area Lights", + "description": "Whether to use area lights.", + "type": "Bool", + "defaultValue": true, + "connection": { + "type": "ShaderOption", + "name": "o_enableAreaLights" + } + }, + { + "name": "enableIBL", + "displayName": "Enable IBL", + "description": "Whether to use Image Based Lighting (IBL).", + "type": "Bool", + "defaultValue": true, + "connection": { + "type": "ShaderOption", + "name": "o_enableIBL" + } } - } - ], - "occlusion": [ - { - "name": "diffuseTextureMap", - "displayName": "Diffuse AO", - "description": "Texture for defining occlusion area for diffuse ambient lighting.", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_diffuseOcclusionMap" - } - }, - { - "name": "diffuseUseTexture", - "displayName": " Use Texture", - "description": "Whether to use the Diffuse AO map.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "diffuseTextureMapUv", - "displayName": " UV", - "description": "Diffuse AO map UV set.", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_diffuseOcclusionMapUvIndex" - } - }, - { - "name": "diffuseFactor", - "displayName": " Factor", - "description": "Strength factor for scaling the values of Diffuse AO", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "softMax": 2.0, - "connection": { - "type": "ShaderInput", - "name": "m_diffuseOcclusionFactor" - } - }, - { - "name": "specularTextureMap", - "displayName": "Specular Cavity", - "description": "Texture for defining occlusion area for specular lighting.", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_specularOcclusionMap" - } - }, - { - "name": "specularUseTexture", - "displayName": " Use Texture", - "description": "Whether to use the Specular Cavity map.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "specularTextureMapUv", - "displayName": " UV", - "description": "Specular Cavity map UV set.", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_specularOcclusionMapUvIndex" - } - }, - { - "name": "specularFactor", - "displayName": " Factor", - "description": "Strength factor for scaling the values of Specular Cavity", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "softMax": 2.0, - "connection": { - "type": "ShaderInput", - "name": "m_specularOcclusionFactor" - } - } - ], - "subsurfaceScattering": [ - { - "name": "enableSubsurfaceScattering", - "displayName": "Subsurface Scattering", - "description": "Enable subsurface scattering feature, this will disable metallic and parallax mapping property due to incompatibility", - "type": "Bool", - "defaultValue": false, - "connection": { - "type": "ShaderOption", - "name": "o_enableSubsurfaceScattering" - } - }, - { - "name": "subsurfaceScatterFactor", - "displayName": " Factor", - "description": "Strength factor for scaling percentage of subsurface scattering effect applied", - "type": "float", - "defaultValue": 1.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_subsurfaceScatteringFactor" - } - }, - { - "name": "influenceMap", - "displayName": " Influence Map", - "description": "Texture for controlling the strength of subsurface scattering", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_subsurfaceScatteringInfluenceMap" - } - }, - { - "name": "useInfluenceMap", - "displayName": " Use Influence Map", - "description": "Whether to use the influence map.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "influenceMapUv", - "displayName": " UV", - "description": "Influence map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Unwrapped", - "connection": { - "type": "ShaderInput", - "name": "m_subsurfaceScatteringInfluenceMapUvIndex" - } - }, - { - "name": "scatterColor", - "displayName": " Scatter color", - "description": "Color of volume light traveled through", - "type": "Color", - "defaultValue": [ 1.0, 0.27, 0.13 ] - }, - { - "name": "scatterDistance", - "displayName": " Scatter distance", - "description": "How far light traveled inside the volume", - "type": "float", - "defaultValue": 8, - "min": 0.0, - "softMax": 20.0 - }, - { - "name": "quality", - "displayName": " Quality", - "description": "How much percent of sample will be used for each pixel, more samples improve quality and reduce artifacts, especially when the scatter distance is relatively large, but slow down computation time, 1.0 = full set 200 samples per pixel", - "type": "float", - "defaultValue": 0.4, - "min": 0.2, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_subsurfaceScatteringQuality" - } - }, - { - "name": "transmissionMode", - "displayName": "Transmission", - "description": "Algorithm used for calculating transmission", - "type": "Enum", - "enumValues": [ "None", "ThickObject", "ThinObject" ], - "defaultValue": "None", - "connection": { - "type": "ShaderOption", - "name": "o_transmission_mode" - } - }, - { - "name": "thickness", - "displayName": " Thickness", - "description": "Normalized global thickness, the maxima between this value (multiplied by thickness map if enabled) and thickness from shadow map (if applicable) will be used as final thickness of pixel", - "type": "float", - "defaultValue": 0.5, - "min": 0.0, - "max": 1.0 - }, - { - "name": "thicknessMap", - "displayName": " Thickness Map", - "description": "Texture for controlling per pixel thickness", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_transmissionThicknessMap" - } - }, - { - "name": "useThicknessMap", - "displayName": " Use Thickness Map", - "description": "Whether to use the thickness map", - "type": "Bool", - "defaultValue": true - }, - { - "name": "thicknessMapUv", - "displayName": " UV", - "description": "Thickness map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Unwrapped", - "connection": { - "type": "ShaderInput", - "name": "m_transmissionThicknessMapUvIndex" - } - }, - { - "name": "transmissionTint", - "displayName": " Transmission Tint", - "description": "Color of the volume light traveling through", - "type": "Color", - "defaultValue": [ 1.0, 0.8, 0.6 ] - }, - { - "name": "transmissionPower", - "displayName": " Power", - "description": "How much transmitted light scatter radially ", - "type": "float", - "defaultValue": 6.0, - "min": 0.0, - "softMax": 20.0 - }, - { - "name": "transmissionDistortion", - "displayName": " Distortion", - "description": "How much light direction distorted towards surface normal", - "type": "float", - "defaultValue": 0.1, - "min": 0.0, - "max": 1.0 - }, - { - "name": "transmissionAttenuation", - "displayName": " Attenuation", - "description": "How fast transmitted light fade with thickness", - "type": "float", - "defaultValue": 4.0, - "min": 0.0, - "softMax": 20.0 - }, - { - "name": "transmissionScale", - "displayName": " Scale", - "description": "Strength of transmission", - "type": "float", - "defaultValue": 3.0, - "min": 0.0, - "softMax": 20.0 - } - ], - "wrinkleLayers": [ - { - "name": "enable", - "displayName": "Enable Wrinkle Layers", - "description": "Enable wrinkle layers for morph animations, using vertex color blend weights.", - "type": "Bool", - "defaultValue": false - }, - { - "name": "count", - "displayName": "Number Of Layers", - "description": "The number of wrinkle map layers to use. The blend values come from the 'COLOR0' vertex stream, where R/G/B/A correspond to wrinkle layers 1/2/3/4 respectively.", - "type": "UInt", - "defaultValue": 4, - "min": 1, - "max": 4 - }, - { - "name": "showBlendValues", - "displayName": "Show Blend Values", - "description": "Enable a debug mode that draws the blend values as red, green, blue, and white overlays.", - "type": "Bool", - "defaultValue": false - }, - { - "name": "enableBaseColor", - "displayName": "Enable Base Color Maps", - "description": "Enable support for blending the base color according to morph animations.", - "type": "Bool", - "defaultValue": false - }, - { - "name": "baseColorMap1", - "displayName": " Base Color 1", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_wrinkle_baseColor_texture1" - } - }, - { - "name": "baseColorMap2", - "displayName": " Base Color 2", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_wrinkle_baseColor_texture2" - } - }, - { - "name": "baseColorMap3", - "displayName": " Base Color 3", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_wrinkle_baseColor_texture3" - } - }, - { - "name": "baseColorMap4", - "displayName": " Base Color 4", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_wrinkle_baseColor_texture4" - } - }, - { - "name": "enableNormal", - "displayName": "Enable Normal Maps", - "description": "Enable support for blending the normal maps according to morph animations.", - "type": "Bool", - "defaultValue": false - }, - { - "name": "normalMap1", - "displayName": " Normals 1", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_wrinkle_normal_texture1" - } - }, - { - "name": "normalMap2", - "displayName": " Normals 2", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_wrinkle_normal_texture2" - } - }, - { - "name": "normalMap3", - "displayName": " Normals 3", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_wrinkle_normal_texture3" - } - }, - { - "name": "normalMap4", - "displayName": " Normals 4", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_wrinkle_normal_texture4" - } - } - ], - "detailLayerGroup": [ - { - "name": "enableDetailLayer", - "displayName": "Enable Detail Layer", - "description": "Enable detail layer for fine details and scratches", - "type": "Bool", - "defaultValue": false - }, - { - "name": "blendDetailFactor", - "displayName": "Blend Factor", - "description": "Scales the overall impact of the detail layer.", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_detail_blendFactor" - } - }, - { - "name": "blendDetailMask", - "displayName": "Blend Mask", - "description": "Detailed blend mask for application of the detail maps.", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_detail_blendMask_texture" - } - }, - { - "name": "enableDetailMaskTexture", - "displayName": " Use Texture", - "description": "Enable detail blend mask", - "type": "Bool", - "defaultValue": true - }, - { - "name": "blendDetailMaskUv", - "displayName": " Blend Mask UV", - "description": "Which UV set to use for sampling the detail blend mask", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Unwrapped", - "connection": { - "type": "ShaderInput", - "name": "m_detail_blendMask_uvIndex" - } - }, - { - "name": "textureMapUv", - "displayName": "Detail Map UVs", - "description": "Which UV set to use for detail map sampling", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Unwrapped", - "connection": { - "type": "ShaderInput", - "name": "m_detail_allMapsUvIndex" - } - }, - { - "name": "enableBaseColor", - "displayName": "Enable Base Color", - "description": "Enable detail blending for base color", - "type": "Bool", - "defaultValue": false - }, - { - "name": "baseColorDetailMap", - "displayName": " Texture", - "description": "Detailed Base Color Texture", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_detail_baseColor_texture" - } - }, - { - "name": "baseColorDetailBlend", - "displayName": " Blend Factor", - "description": "How much to blend the detail layer into the base color.", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_detail_baseColor_factor" - } - }, - { - "name": "enableNormals", - "displayName": "Enable Normal", - "description": "Enable detail normal map to be used for fine detail normal such as scratches and small dents", - "type": "Bool", - "defaultValue": false - }, - { - "name": "normalDetailStrength", - "displayName": " Factor", - "description": "Strength factor for scaling the Detail Normal", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "softMax": 2.0, - "connection": { - "type": "ShaderInput", - "name": "m_detail_normal_factor" - } - }, - { - "name": "normalDetailMap", - "displayName": " Texture", - "description": "Detailed Normal map", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_detail_normal_texture" - } - }, - { - "name": "normalDetailFlipX", - "displayName": " Flip X Channel", - "description": "Flip Detail tangent direction for this normal map.", - "type": "Bool", - "defaultValue": false, - "connection": { - "type": "ShaderInput", - "name": "m_detail_normal_flipX" - } - }, - { - "name": "normalDetailFlipY", - "displayName": " Flip Y Channel", - "description": "Flip Detail bitangent direction for this normal map.", - "type": "Bool", - "defaultValue": false, - "connection": { - "type": "ShaderInput", - "name": "m_detail_normal_flipY" - } - } - ], - "detailUV": [ - { - "name": "center", - "displayName": "Center", - "description": "Center point for scaling and rotation transformations.", - "type": "vector2", - "vectorLabels": [ "U", "V" ], - "defaultValue": [ 0.5, 0.5 ] - }, - { - "name": "tileU", - "displayName": "Tile U", - "description": "Scales texture coordinates in V.", - "type": "float", - "defaultValue": 1.0, - "step": 0.1 - }, - { - "name": "tileV", - "displayName": "Tile V", - "description": "Scales texture coordinates in V.", - "type": "float", - "defaultValue": 1.0, - "step": 0.1 - }, - { - "name": "offsetU", - "displayName": "Offset U", - "description": "Offsets texture coordinates in the U direction.", - "type": "float", - "defaultValue": 0.0, - "min": -1.0, - "max": 1.0 - }, - { - "name": "offsetV", - "displayName": "Offset V", - "description": "Offsets texture coordinates in the V direction.", - "type": "float", - "defaultValue": 0.0, - "min": -1.0, - "max": 1.0 - }, - { - "name": "rotateDegrees", - "displayName": "Rotate", - "description": "Rotates the texture coordinates (degrees).", - "type": "float", - "defaultValue": 0.0, - "min": -180.0, - "max": 180.0, - "step": 1.0 - }, - { - "name": "scale", - "displayName": "Scale", - "description": "Scales texture coordinates in both U and V.", - "type": "float", - "defaultValue": 1.0, - "step": 0.1 - } - ] - } + ] + } + ] }, "shaders": [ { @@ -1095,4 +1093,4 @@ "UV0": "Tiled", "UV1": "Unwrapped" } -} +} \ No newline at end of file diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR.materialtype b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR.materialtype index 6eb82b85ae..d6a5dad8cf 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR.materialtype +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR.materialtype @@ -2,1013 +2,1010 @@ "description": "Material Type with properties used to define Standard PBR, a metallic-roughness Physically-Based Rendering (PBR) material shading model.", "propertyLayout": { "version": 3, - "groups": [ + "propertySets": [ { "name": "baseColor", "displayName": "Base Color", - "description": "Properties for configuring the surface reflected color for dielectrics or reflectance values for metals." + "description": "Properties for configuring the surface reflected color for dielectrics or reflectance values for metals.", + "properties": [ + { + "name": "color", + "displayName": "Color", + "description": "Color is displayed as sRGB but the values are stored as linear color.", + "type": "Color", + "defaultValue": [ 1.0, 1.0, 1.0 ], + "connection": { + "type": "ShaderInput", + "name": "m_baseColor" + } + }, + { + "name": "factor", + "displayName": "Factor", + "description": "Strength factor for scaling the base color values. Zero (0.0) is black, white (1.0) is full color.", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_baseColorFactor" + } + }, + { + "name": "textureMap", + "displayName": "Texture", + "description": "Base color texture map", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_baseColorMap" + } + }, + { + "name": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "textureMapUv", + "displayName": "UV", + "description": "Base color map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_baseColorMapUvIndex" + } + }, + { + "name": "textureBlendMode", + "displayName": "Texture Blend Mode", + "description": "Selects the equation to use when combining Color, Factor, and Texture.", + "type": "Enum", + "enumValues": [ "Multiply", "LinearLight", "Lerp", "Overlay" ], + "defaultValue": "Multiply", + "connection": { + "type": "ShaderOption", + "name": "o_baseColorTextureBlendMode" + } + } + ] }, { "name": "metallic", "displayName": "Metallic", - "description": "Properties for configuring whether the surface is metallic or not." + "description": "Properties for configuring whether the surface is metallic or not.", + "properties": [ + { + "name": "factor", + "displayName": "Factor", + "description": "This value is linear, black is non-metal and white means raw metal.", + "type": "Float", + "defaultValue": 0.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_metallicFactor" + } + }, + { + "name": "textureMap", + "displayName": "Texture", + "description": "", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_metallicMap" + } + }, + { + "name": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture, or just default to the Factor value.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "textureMapUv", + "displayName": "UV", + "description": "Metallic map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_metallicMapUvIndex" + } + } + ] }, { "name": "roughness", "displayName": "Roughness", - "description": "Properties for configuring how rough the surface appears." + "description": "Properties for configuring how rough the surface appears.", + "properties": [ + { + "name": "textureMap", + "displayName": "Texture", + "description": "Texture for defining surface roughness.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_roughnessMap" + } + }, + { + "name": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture, or just default to the Factor value.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "textureMapUv", + "displayName": "UV", + "description": "Roughness map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_roughnessMapUvIndex" + } + }, + { + // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. + "name": "lowerBound", + "displayName": "Lower Bound", + "description": "The roughness value that corresponds to black in the texture.", + "type": "Float", + "defaultValue": 0.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_roughnessLowerBound" + } + }, + { + // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. + "name": "upperBound", + "displayName": "Upper Bound", + "description": "The roughness value that corresponds to white in the texture.", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_roughnessUpperBound" + } + }, + { + // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. + "name": "factor", + "displayName": "Factor", + "description": "Controls the roughness value", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_roughnessFactor" + } + } + ] }, { "name": "specularF0", "displayName": "Specular Reflectance f0", - "description": "The constant f0 represents the specular reflectance at normal incidence (Fresnel 0 Angle). Used to adjust reflectance of non-metal surfaces." + "description": "The constant f0 represents the specular reflectance at normal incidence (Fresnel 0 Angle). Used to adjust reflectance of non-metal surfaces.", + "properties": [ + { + "name": "factor", + "displayName": "Factor", + "description": "The default IOR is 1.5, which gives you 0.04 (4% of light reflected at 0 degree angle for dielectric materials). F0 values lie in the range 0-0.08, so that is why the default F0 slider is set on 0.5.", + "type": "Float", + "defaultValue": 0.5, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_specularF0Factor" + } + }, + { + "name": "textureMap", + "displayName": "Texture", + "description": "Texture for defining surface reflectance.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_specularF0Map" + } + }, + { + "name": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture, or just default to the Factor value.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "textureMapUv", + "displayName": "UV", + "description": "Specular reflection map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_specularF0MapUvIndex" + } + }, + // Consider moving this to the "general" group to be consistent with StandardMultilayerPBR + { + "name": "enableMultiScatterCompensation", + "displayName": "Multiscattering Compensation", + "description": "Whether to enable multiple scattering compensation.", + "type": "Bool", + "connection": { + "type": "ShaderOption", + "name": "o_specularF0_enableMultiScatterCompensation" + } + } + ] }, { "name": "normal", "displayName": "Normal", - "description": "Properties related to configuring surface normal." + "description": "Properties related to configuring surface normal.", + "properties": [ + { + "name": "textureMap", + "displayName": "Texture", + "description": "Texture for defining surface normal direction.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_normalMap" + } + }, + { + "name": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture, or just rely on vertex normals.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "textureMapUv", + "displayName": "UV", + "description": "Normal map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_normalMapUvIndex" + } + }, + { + "name": "flipX", + "displayName": "Flip X Channel", + "description": "Flip tangent direction for this normal map.", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderInput", + "name": "m_flipNormalX" + } + }, + { + "name": "flipY", + "displayName": "Flip Y Channel", + "description": "Flip bitangent direction for this normal map.", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderInput", + "name": "m_flipNormalY" + } + }, + { + "name": "factor", + "displayName": "Factor", + "description": "Strength factor for scaling the values", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "softMax": 2.0, + "connection": { + "type": "ShaderInput", + "name": "m_normalFactor" + } + } + ] }, { "name": "occlusion", "displayName": "Occlusion", - "description": "Properties for baked textures that represent geometric occlusion of light." + "description": "Properties for baked textures that represent geometric occlusion of light.", + "properties": [ + { + "name": "diffuseTextureMap", + "displayName": "Diffuse AO", + "description": "Texture for defining occlusion area for diffuse ambient lighting.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_diffuseOcclusionMap" + } + }, + { + "name": "diffuseUseTexture", + "displayName": " Use Texture", + "description": "Whether to use the Diffuse AO map.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "diffuseTextureMapUv", + "displayName": " UV", + "description": "Diffuse AO map UV set.", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_diffuseOcclusionMapUvIndex" + } + }, + { + "name": "diffuseFactor", + "displayName": " Factor", + "description": "Strength factor for scaling the values of Diffuse AO", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "softMax": 2.0, + "connection": { + "type": "ShaderInput", + "name": "m_diffuseOcclusionFactor" + } + }, + { + "name": "specularTextureMap", + "displayName": "Specular Cavity", + "description": "Texture for defining occlusion area for specular lighting.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_specularOcclusionMap" + } + }, + { + "name": "specularUseTexture", + "displayName": " Use Texture", + "description": "Whether to use the Specular Cavity map.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "specularTextureMapUv", + "displayName": " UV", + "description": "Specular Cavity map UV set.", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_specularOcclusionMapUvIndex" + } + }, + { + "name": "specularFactor", + "displayName": " Factor", + "description": "Strength factor for scaling the values of Specular Cavity", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "softMax": 2.0, + "connection": { + "type": "ShaderInput", + "name": "m_specularOcclusionFactor" + } + } + ] }, { "name": "emissive", "displayName": "Emissive", - "description": "Properties to add light emission, independent of other lights in the scene." + "description": "Properties to add light emission, independent of other lights in the scene.", + "properties": [ + { + "name": "enable", + "displayName": "Enable", + "description": "Enable the emissive group", + "type": "Bool", + "defaultValue": false + }, + { + "name": "unit", + "displayName": "Units", + "description": "The photometric units of the Intensity property.", + "type": "Enum", + "enumValues": ["Ev100"], + "defaultValue": "Ev100" + }, + { + "name": "color", + "displayName": "Color", + "description": "Color is displayed as sRGB but the values are stored as linear color.", + "type": "Color", + "defaultValue": [ 1.0, 1.0, 1.0 ], + "connection": { + "type": "ShaderInput", + "name": "m_emissiveColor" + } + }, + { + "name": "intensity", + "displayName": "Intensity", + "description": "The amount of energy emitted.", + "type": "Float", + "defaultValue": 4, + "min": -10, + "max": 20, + "softMin": -6, + "softMax": 16 + }, + { + "name": "textureMap", + "displayName": "Texture", + "description": "Texture for defining emissive area.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_emissiveMap" + } + }, + { + "name": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "textureMapUv", + "displayName": "UV", + "description": "Emissive map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_emissiveMapUvIndex" + } + } + ] }, { "name": "clearCoat", "displayName": "Clear Coat", - "description": "Properties for configuring gloss clear coat" - }, + "description": "Properties for configuring gloss clear coat", + "properties": [ + { + "name": "enable", + "displayName": "Enable", + "description": "Enable clear coat", + "type": "Bool", + "defaultValue": false + }, + { + "name": "factor", + "displayName": "Factor", + "description": "Strength factor for scaling the percentage of effect applied", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_clearCoatFactor" + } + }, + { + "name": "influenceMap", + "displayName": " Influence Map", + "description": "Strength factor texture", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_clearCoatInfluenceMap" + } + }, + { + "name": "useInfluenceMap", + "displayName": " Use Texture", + "description": "Whether to use the texture, or just default to the Factor value.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "influenceMapUv", + "displayName": " UV", + "description": "Strength factor map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_clearCoatInfluenceMapUvIndex" + } + }, + { + "name": "roughness", + "displayName": "Roughness", + "description": "Clear coat layer roughness", + "type": "Float", + "defaultValue": 0.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_clearCoatRoughness" + } + }, + { + "name": "roughnessMap", + "displayName": " Roughness Map", + "description": "Texture for defining surface roughness", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_clearCoatRoughnessMap" + } + }, + { + "name": "useRoughnessMap", + "displayName": " Use Texture", + "description": "Whether to use the texture, or just default to the roughness value.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "roughnessMapUv", + "displayName": " UV", + "description": "Roughness map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_clearCoatRoughnessMapUvIndex" + } + }, + { + "name": "normalStrength", + "displayName": "Normal Strength", + "description": "Scales the impact of the clear coat normal map", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 2.0, + "connection": { + "type": "ShaderInput", + "name": "m_clearCoatNormalStrength" + } + }, + { + "name": "normalMap", + "displayName": "Normal Map", + "description": "Normal map for clear coat layer, as top layer material clear coat doesn't affect by base layer normal map", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_clearCoatNormalMap" + } + }, + { + "name": "useNormalMap", + "displayName": " Use Texture", + "description": "Whether to use the normal map", + "type": "Bool", + "defaultValue": true + }, + { + "name": "normalMapUv", + "displayName": " UV", + "description": "Normal map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_clearCoatNormalMapUvIndex" + } + } + ] + }, { "name": "parallax", "displayName": "Displacement", - "description": "Properties for parallax effect produced by a height map." + "description": "Properties for parallax effect produced by a height map.", + "properties": [ + { + "name": "textureMap", + "displayName": "Height Map", + "description": "Displacement height map to create parallax effect.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_heightmap" + } + }, + { + "name": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the height map.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "textureMapUv", + "displayName": "UV", + "description": "Height map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_parallaxUvIndex" + } + }, + { + "name": "factor", + "displayName": "Height Map Scale", + "description": "The total height of the height map in local model units.", + "type": "Float", + "defaultValue": 0.05, + "min": 0.0, + "softMax": 0.1, + "connection": { + "type": "ShaderInput", + "name": "m_heightmapScale" + } + }, + { + "name": "offset", + "displayName": "Offset", + "description": "Adjusts the overall displacement amount in local model units.", + "type": "Float", + "defaultValue": 0.0, + "softMin": -0.1, + "softMax": 0.1, + "connection": { + "type": "ShaderInput", + "name": "m_heightmapOffset" + } + }, + { + "name": "algorithm", + "displayName": "Algorithm", + "description": "Select the algorithm to use for parallax mapping.", + "type": "Enum", + "enumValues": [ "Basic", "Steep", "POM", "Relief", "ContactRefinement" ], + "defaultValue": "POM", + "connection": { + "type": "ShaderOption", + "name": "o_parallax_algorithm" + } + }, + { + "name": "quality", + "displayName": "Quality", + "description": "Quality of parallax mapping.", + "type": "Enum", + "enumValues": [ "Low", "Medium", "High", "Ultra" ], + "defaultValue": "Low", + "connection": { + "type": "ShaderOption", + "name": "o_parallax_quality" + } + }, + { + "name": "pdo", + "displayName": "Pixel Depth Offset", + "description": "Enable PDO to offset the original pixel depths. This will affect any shaders using depth, for example, when receiving shadows.", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderOption", + "name": "o_parallax_enablePixelDepthOffset" + } + }, + { + "name": "showClipping", + "displayName": "Show Clipping", + "description": "Highlight areas where the height map is clipped by the mesh surface.", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderOption", + "name": "o_parallax_highlightClipping" + } + } + ] }, { "name": "opacity", "displayName": "Opacity", - "description": "Properties for configuring the materials transparency." + "description": "Properties for configuring the materials transparency.", + "properties": [ + { + "name": "mode", + "displayName": "Opacity Mode", + "description": "Indicates the general approach how transparency is to be applied.", + "type": "Enum", + "enumValues": [ "Opaque", "Cutout", "Blended", "TintedTransparent" ], + "defaultValue": "Opaque", + "connection": { + "type": "ShaderOption", + "name": "o_opacity_mode" + } + }, + { + "name": "alphaSource", + "displayName": "Alpha Source", + "description": "Indicates whether to get the opacity texture from the Base Color map (Packed) or from a separate greyscale texture (Split).", + "type": "Enum", + "enumValues": [ "Packed", "Split", "None" ], + "defaultValue": "Packed", + "connection": { + "type": "ShaderOption", + "name": "o_opacity_source" + } + }, + { + "name": "textureMap", + "displayName": "Texture", + "description": "Texture for defining surface opacity.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_opacityMap" + } + }, + { + "name": "textureMapUv", + "displayName": "UV", + "description": "Opacity map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_opacityMapUvIndex" + } + }, + { + "name": "factor", + "displayName": "Factor", + "description": "Factor for cutout threshold and blending", + "type": "Float", + "min": 0.0, + "max": 1.0, + "defaultValue": 0.5, + "connection": { + "type": "ShaderInput", + "name": "m_opacityFactor" + } + }, + { + "name": "doubleSided", + "displayName": "Double-sided", + "description": "Whether to render back-faces or just front-faces.", + "type": "Bool" + }, + { + "name": "alphaAffectsSpecular", + "displayName": "Alpha affects specular", + "description": "How much the alpha value should also affect specular reflection. This should be 0.0 for materials where light can transmit through their physical surface (like glass), but 1.0 when alpha determines the very presence of a surface (like hair or grass)", + "type": "float", + "min": 0.0, + "max": 1.0, + "defaultValue": 0.0, + "connection": { + "type": "ShaderInput", + "name": "m_opacityAffectsSpecularFactor" + } + } + ] }, { "name": "uv", "displayName": "UVs", - "description": "Properties for configuring UV transforms." + "description": "Properties for configuring UV transforms.", + "properties": [ + { + "name": "center", + "displayName": "Center", + "description": "Center point for scaling and rotation transformations.", + "type": "vector2", + "vectorLabels": [ "U", "V" ], + "defaultValue": [ 0.5, 0.5 ] + }, + { + "name": "tileU", + "displayName": "Tile U", + "description": "Scales texture coordinates in U.", + "type": "float", + "defaultValue": 1.0, + "step": 0.1 + }, + { + "name": "tileV", + "displayName": "Tile V", + "description": "Scales texture coordinates in V.", + "type": "float", + "defaultValue": 1.0, + "step": 0.1 + }, + { + "name": "offsetU", + "displayName": "Offset U", + "description": "Offsets texture coordinates in the U direction.", + "type": "float", + "defaultValue": 0.0, + "min": -1.0, + "max": 1.0 + }, + { + "name": "offsetV", + "displayName": "Offset V", + "description": "Offsets texture coordinates in the V direction.", + "type": "float", + "defaultValue": 0.0, + "min": -1.0, + "max": 1.0 + }, + { + "name": "rotateDegrees", + "displayName": "Rotate", + "description": "Rotates the texture coordinates (degrees).", + "type": "float", + "defaultValue": 0.0, + "min": -180.0, + "max": 180.0, + "step": 1.0 + }, + { + "name": "scale", + "displayName": "Scale", + "description": "Scales texture coordinates in both U and V.", + "type": "float", + "defaultValue": 1.0, + "step": 0.1 + } + ] }, { // Note: this property group is used in the DiffuseGlobalIllumination pass, it is not read by the StandardPBR shader "name": "irradiance", "displayName": "Irradiance", - "description": "Properties for configuring the irradiance used in global illumination." + "description": "Properties for configuring the irradiance used in global illumination.", + "properties": [ + { + "name": "color", + "displayName": "Color", + "description": "Color is displayed as sRGB but the values are stored as linear color.", + "type": "Color", + "defaultValue": [ 1.0, 1.0, 1.0 ] + }, + { + "name": "factor", + "displayName": "Factor", + "description": "Strength factor for scaling the irradiance color values. Zero (0.0) is black, white (1.0) is full color.", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 1.0 + } + ] }, { "name": "general", "displayName": "General Settings", - "description": "General settings." - } - ], - "properties": { - "general": [ - { - "name": "applySpecularAA", - "displayName": "Apply Specular AA", - "description": "Whether to apply specular anti-aliasing in the shader.", - "type": "Bool", - "defaultValue": false, - "connection": { - "type": "ShaderOption", - "name": "o_applySpecularAA" - } - }, - { - "name": "enableShadows", - "displayName": "Enable Shadows", - "description": "Whether to use the shadow maps.", - "type": "Bool", - "defaultValue": true, - "connection": { - "type": "ShaderOption", - "name": "o_enableShadows" - } - }, - { - "name": "enableDirectionalLights", - "displayName": "Enable Directional Lights", - "description": "Whether to use directional lights.", - "type": "Bool", - "defaultValue": true, - "connection": { - "type": "ShaderOption", - "name": "o_enableDirectionalLights" - } - }, - { - "name": "enablePunctualLights", - "displayName": "Enable Punctual Lights", - "description": "Whether to use punctual lights.", - "type": "Bool", - "defaultValue": true, - "connection": { - "type": "ShaderOption", - "name": "o_enablePunctualLights" - } - }, - { - "name": "enableAreaLights", - "displayName": "Enable Area Lights", - "description": "Whether to use area lights.", - "type": "Bool", - "defaultValue": true, - "connection": { - "type": "ShaderOption", - "name": "o_enableAreaLights" - } - }, - { - "name": "enableIBL", - "displayName": "Enable IBL", - "description": "Whether to use Image Based Lighting (IBL).", - "type": "Bool", - "defaultValue": true, - "connection": { - "type": "ShaderOption", - "name": "o_enableIBL" - } - }, - { - "name": "forwardPassIBLSpecular", - "displayName": "Forward Pass IBL Specular", - "description": "Whether to apply IBL specular in the forward pass.", - "type": "Bool", - "defaultValue": false, - "connection": { - "type": "ShaderOption", - "name": "o_materialUseForwardPassIBLSpecular" - } - } - ], - "baseColor": [ - { - "name": "color", - "displayName": "Color", - "description": "Color is displayed as sRGB but the values are stored as linear color.", - "type": "Color", - "defaultValue": [ 1.0, 1.0, 1.0 ], - "connection": { - "type": "ShaderInput", - "name": "m_baseColor" - } - }, - { - "name": "factor", - "displayName": "Factor", - "description": "Strength factor for scaling the base color values. Zero (0.0) is black, white (1.0) is full color.", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_baseColorFactor" - } - }, - { - "name": "textureMap", - "displayName": "Texture", - "description": "Base color texture map", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_baseColorMap" - } - }, - { - "name": "useTexture", - "displayName": "Use Texture", - "description": "Whether to use the texture.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "textureMapUv", - "displayName": "UV", - "description": "Base color map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_baseColorMapUvIndex" - } - }, - { - "name": "textureBlendMode", - "displayName": "Texture Blend Mode", - "description": "Selects the equation to use when combining Color, Factor, and Texture.", - "type": "Enum", - "enumValues": [ "Multiply", "LinearLight", "Lerp", "Overlay" ], - "defaultValue": "Multiply", - "connection": { - "type": "ShaderOption", - "name": "o_baseColorTextureBlendMode" - } - } - ], - "metallic": [ - { - "name": "factor", - "displayName": "Factor", - "description": "This value is linear, black is non-metal and white means raw metal.", - "type": "Float", - "defaultValue": 0.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_metallicFactor" - } - }, - { - "name": "textureMap", - "displayName": "Texture", - "description": "", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_metallicMap" - } - }, - { - "name": "useTexture", - "displayName": "Use Texture", - "description": "Whether to use the texture, or just default to the Factor value.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "textureMapUv", - "displayName": "UV", - "description": "Metallic map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_metallicMapUvIndex" - } - } - ], - "roughness": [ - { - "name": "textureMap", - "displayName": "Texture", - "description": "Texture for defining surface roughness.", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_roughnessMap" - } - }, - { - "name": "useTexture", - "displayName": "Use Texture", - "description": "Whether to use the texture, or just default to the Factor value.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "textureMapUv", - "displayName": "UV", - "description": "Roughness map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_roughnessMapUvIndex" - } - }, - { - // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. - "name": "lowerBound", - "displayName": "Lower Bound", - "description": "The roughness value that corresponds to black in the texture.", - "type": "Float", - "defaultValue": 0.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_roughnessLowerBound" - } - }, - { - // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. - "name": "upperBound", - "displayName": "Upper Bound", - "description": "The roughness value that corresponds to white in the texture.", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_roughnessUpperBound" - } - }, - { - // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. - "name": "factor", - "displayName": "Factor", - "description": "Controls the roughness value", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_roughnessFactor" - } - } - ], - "specularF0": [ - { - "name": "factor", - "displayName": "Factor", - "description": "The default IOR is 1.5, which gives you 0.04 (4% of light reflected at 0 degree angle for dielectric materials). F0 values lie in the range 0-0.08, so that is why the default F0 slider is set on 0.5.", - "type": "Float", - "defaultValue": 0.5, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_specularF0Factor" - } - }, - { - "name": "textureMap", - "displayName": "Texture", - "description": "Texture for defining surface reflectance.", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_specularF0Map" - } - }, - { - "name": "useTexture", - "displayName": "Use Texture", - "description": "Whether to use the texture, or just default to the Factor value.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "textureMapUv", - "displayName": "UV", - "description": "Specular reflection map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_specularF0MapUvIndex" - } - }, - // Consider moving this to the "general" group to be consistent with StandardMultilayerPBR - { - "name": "enableMultiScatterCompensation", - "displayName": "Multiscattering Compensation", - "description": "Whether to enable multiple scattering compensation.", - "type": "Bool", - "connection": { - "type": "ShaderOption", - "name": "o_specularF0_enableMultiScatterCompensation" - } - } - ], - "clearCoat": [ - { - "name": "enable", - "displayName": "Enable", - "description": "Enable clear coat", - "type": "Bool", - "defaultValue": false - }, - { - "name": "factor", - "displayName": "Factor", - "description": "Strength factor for scaling the percentage of effect applied", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_clearCoatFactor" + "description": "General settings.", + "properties": [ + { + "name": "applySpecularAA", + "displayName": "Apply Specular AA", + "description": "Whether to apply specular anti-aliasing in the shader.", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderOption", + "name": "o_applySpecularAA" + } + }, + { + "name": "enableShadows", + "displayName": "Enable Shadows", + "description": "Whether to use the shadow maps.", + "type": "Bool", + "defaultValue": true, + "connection": { + "type": "ShaderOption", + "name": "o_enableShadows" + } + }, + { + "name": "enableDirectionalLights", + "displayName": "Enable Directional Lights", + "description": "Whether to use directional lights.", + "type": "Bool", + "defaultValue": true, + "connection": { + "type": "ShaderOption", + "name": "o_enableDirectionalLights" + } + }, + { + "name": "enablePunctualLights", + "displayName": "Enable Punctual Lights", + "description": "Whether to use punctual lights.", + "type": "Bool", + "defaultValue": true, + "connection": { + "type": "ShaderOption", + "name": "o_enablePunctualLights" + } + }, + { + "name": "enableAreaLights", + "displayName": "Enable Area Lights", + "description": "Whether to use area lights.", + "type": "Bool", + "defaultValue": true, + "connection": { + "type": "ShaderOption", + "name": "o_enableAreaLights" + } + }, + { + "name": "enableIBL", + "displayName": "Enable IBL", + "description": "Whether to use Image Based Lighting (IBL).", + "type": "Bool", + "defaultValue": true, + "connection": { + "type": "ShaderOption", + "name": "o_enableIBL" + } + }, + { + "name": "forwardPassIBLSpecular", + "displayName": "Forward Pass IBL Specular", + "description": "Whether to apply IBL specular in the forward pass.", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderOption", + "name": "o_materialUseForwardPassIBLSpecular" + } } - }, - { - "name": "influenceMap", - "displayName": " Influence Map", - "description": "Strength factor texture", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_clearCoatInfluenceMap" - } - }, - { - "name": "useInfluenceMap", - "displayName": " Use Texture", - "description": "Whether to use the texture, or just default to the Factor value.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "influenceMapUv", - "displayName": " UV", - "description": "Strength factor map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_clearCoatInfluenceMapUvIndex" - } - }, - { - "name": "roughness", - "displayName": "Roughness", - "description": "Clear coat layer roughness", - "type": "Float", - "defaultValue": 0.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_clearCoatRoughness" - } - }, - { - "name": "roughnessMap", - "displayName": " Roughness Map", - "description": "Texture for defining surface roughness", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_clearCoatRoughnessMap" - } - }, - { - "name": "useRoughnessMap", - "displayName": " Use Texture", - "description": "Whether to use the texture, or just default to the roughness value.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "roughnessMapUv", - "displayName": " UV", - "description": "Roughness map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_clearCoatRoughnessMapUvIndex" - } - }, - { - "name": "normalStrength", - "displayName": "Normal Strength", - "description": "Scales the impact of the clear coat normal map", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "max": 2.0, - "connection": { - "type": "ShaderInput", - "name": "m_clearCoatNormalStrength" - } - }, - { - "name": "normalMap", - "displayName": "Normal Map", - "description": "Normal map for clear coat layer, as top layer material clear coat doesn't affect by base layer normal map", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_clearCoatNormalMap" - } - }, - { - "name": "useNormalMap", - "displayName": " Use Texture", - "description": "Whether to use the normal map", - "type": "Bool", - "defaultValue": true - }, - { - "name": "normalMapUv", - "displayName": " UV", - "description": "Normal map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_clearCoatNormalMapUvIndex" - } - } - ], - "normal": [ - { - "name": "textureMap", - "displayName": "Texture", - "description": "Texture for defining surface normal direction.", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_normalMap" - } - }, - { - "name": "useTexture", - "displayName": "Use Texture", - "description": "Whether to use the texture, or just rely on vertex normals.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "textureMapUv", - "displayName": "UV", - "description": "Normal map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_normalMapUvIndex" - } - }, - { - "name": "flipX", - "displayName": "Flip X Channel", - "description": "Flip tangent direction for this normal map.", - "type": "Bool", - "defaultValue": false, - "connection": { - "type": "ShaderInput", - "name": "m_flipNormalX" - } - }, - { - "name": "flipY", - "displayName": "Flip Y Channel", - "description": "Flip bitangent direction for this normal map.", - "type": "Bool", - "defaultValue": false, - "connection": { - "type": "ShaderInput", - "name": "m_flipNormalY" - } - }, - { - "name": "factor", - "displayName": "Factor", - "description": "Strength factor for scaling the values", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "softMax": 2.0, - "connection": { - "type": "ShaderInput", - "name": "m_normalFactor" - } - } - ], - "opacity": [ - { - "name": "mode", - "displayName": "Opacity Mode", - "description": "Indicates the general approach how transparency is to be applied.", - "type": "Enum", - "enumValues": [ "Opaque", "Cutout", "Blended", "TintedTransparent" ], - "defaultValue": "Opaque", - "connection": { - "type": "ShaderOption", - "name": "o_opacity_mode" - } - }, - { - "name": "alphaSource", - "displayName": "Alpha Source", - "description": "Indicates whether to get the opacity texture from the Base Color map (Packed) or from a separate greyscale texture (Split).", - "type": "Enum", - "enumValues": [ "Packed", "Split", "None" ], - "defaultValue": "Packed", - "connection": { - "type": "ShaderOption", - "name": "o_opacity_source" - } - }, - { - "name": "textureMap", - "displayName": "Texture", - "description": "Texture for defining surface opacity.", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_opacityMap" - } - }, - { - "name": "textureMapUv", - "displayName": "UV", - "description": "Opacity map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_opacityMapUvIndex" - } - }, - { - "name": "factor", - "displayName": "Factor", - "description": "Factor for cutout threshold and blending", - "type": "Float", - "min": 0.0, - "max": 1.0, - "defaultValue": 0.5, - "connection": { - "type": "ShaderInput", - "name": "m_opacityFactor" - } - }, - { - "name": "doubleSided", - "displayName": "Double-sided", - "description": "Whether to render back-faces or just front-faces.", - "type": "Bool" - }, - { - "name": "alphaAffectsSpecular", - "displayName": "Alpha affects specular", - "description": "How much the alpha value should also affect specular reflection. This should be 0.0 for materials where light can transmit through their physical surface (like glass), but 1.0 when alpha determines the very presence of a surface (like hair or grass)", - "type": "float", - "min": 0.0, - "max": 1.0, - "defaultValue": 0.0, - "connection": { - "type": "ShaderInput", - "name": "m_opacityAffectsSpecularFactor" - } - } - ], - "uv": [ - { - "name": "center", - "displayName": "Center", - "description": "Center point for scaling and rotation transformations.", - "type": "vector2", - "vectorLabels": [ "U", "V" ], - "defaultValue": [ 0.5, 0.5 ] - }, - { - "name": "tileU", - "displayName": "Tile U", - "description": "Scales texture coordinates in U.", - "type": "float", - "defaultValue": 1.0, - "step": 0.1 - }, - { - "name": "tileV", - "displayName": "Tile V", - "description": "Scales texture coordinates in V.", - "type": "float", - "defaultValue": 1.0, - "step": 0.1 - }, - { - "name": "offsetU", - "displayName": "Offset U", - "description": "Offsets texture coordinates in the U direction.", - "type": "float", - "defaultValue": 0.0, - "min": -1.0, - "max": 1.0 - }, - { - "name": "offsetV", - "displayName": "Offset V", - "description": "Offsets texture coordinates in the V direction.", - "type": "float", - "defaultValue": 0.0, - "min": -1.0, - "max": 1.0 - }, - { - "name": "rotateDegrees", - "displayName": "Rotate", - "description": "Rotates the texture coordinates (degrees).", - "type": "float", - "defaultValue": 0.0, - "min": -180.0, - "max": 180.0, - "step": 1.0 - }, - { - "name": "scale", - "displayName": "Scale", - "description": "Scales texture coordinates in both U and V.", - "type": "float", - "defaultValue": 1.0, - "step": 0.1 - } - ], - "occlusion": [ - { - "name": "diffuseTextureMap", - "displayName": "Diffuse AO", - "description": "Texture for defining occlusion area for diffuse ambient lighting.", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_diffuseOcclusionMap" - } - }, - { - "name": "diffuseUseTexture", - "displayName": " Use Texture", - "description": "Whether to use the Diffuse AO map.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "diffuseTextureMapUv", - "displayName": " UV", - "description": "Diffuse AO map UV set.", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_diffuseOcclusionMapUvIndex" - } - }, - { - "name": "diffuseFactor", - "displayName": " Factor", - "description": "Strength factor for scaling the values of Diffuse AO", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "softMax": 2.0, - "connection": { - "type": "ShaderInput", - "name": "m_diffuseOcclusionFactor" - } - }, - { - "name": "specularTextureMap", - "displayName": "Specular Cavity", - "description": "Texture for defining occlusion area for specular lighting.", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_specularOcclusionMap" - } - }, - { - "name": "specularUseTexture", - "displayName": " Use Texture", - "description": "Whether to use the Specular Cavity map.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "specularTextureMapUv", - "displayName": " UV", - "description": "Specular Cavity map UV set.", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_specularOcclusionMapUvIndex" - } - }, - { - "name": "specularFactor", - "displayName": " Factor", - "description": "Strength factor for scaling the values of Specular Cavity", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "softMax": 2.0, - "connection": { - "type": "ShaderInput", - "name": "m_specularOcclusionFactor" - } - } - ], - "emissive": [ - { - "name": "enable", - "displayName": "Enable", - "description": "Enable the emissive group", - "type": "Bool", - "defaultValue": false - }, - { - "name": "unit", - "displayName": "Units", - "description": "The photometric units of the Intensity property.", - "type": "Enum", - "enumValues": ["Ev100"], - "defaultValue": "Ev100" - }, - { - "name": "color", - "displayName": "Color", - "description": "Color is displayed as sRGB but the values are stored as linear color.", - "type": "Color", - "defaultValue": [ 1.0, 1.0, 1.0 ], - "connection": { - "type": "ShaderInput", - "name": "m_emissiveColor" - } - }, - { - "name": "intensity", - "displayName": "Intensity", - "description": "The amount of energy emitted.", - "type": "Float", - "defaultValue": 4, - "min": -10, - "max": 20, - "softMin": -6, - "softMax": 16 - }, - { - "name": "textureMap", - "displayName": "Texture", - "description": "Texture for defining emissive area.", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_emissiveMap" - } - }, - { - "name": "useTexture", - "displayName": "Use Texture", - "description": "Whether to use the texture.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "textureMapUv", - "displayName": "UV", - "description": "Emissive map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_emissiveMapUvIndex" - } - } - ], - "parallax": [ - { - "name": "textureMap", - "displayName": "Height Map", - "description": "Displacement height map to create parallax effect.", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_heightmap" - } - }, - { - "name": "useTexture", - "displayName": "Use Texture", - "description": "Whether to use the height map.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "textureMapUv", - "displayName": "UV", - "description": "Height map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_parallaxUvIndex" - } - }, - { - "name": "factor", - "displayName": "Height Map Scale", - "description": "The total height of the height map in local model units.", - "type": "Float", - "defaultValue": 0.05, - "min": 0.0, - "softMax": 0.1, - "connection": { - "type": "ShaderInput", - "name": "m_heightmapScale" - } - }, - { - "name": "offset", - "displayName": "Offset", - "description": "Adjusts the overall displacement amount in local model units.", - "type": "Float", - "defaultValue": 0.0, - "softMin": -0.1, - "softMax": 0.1, - "connection": { - "type": "ShaderInput", - "name": "m_heightmapOffset" - } - }, - { - "name": "algorithm", - "displayName": "Algorithm", - "description": "Select the algorithm to use for parallax mapping.", - "type": "Enum", - "enumValues": [ "Basic", "Steep", "POM", "Relief", "ContactRefinement" ], - "defaultValue": "POM", - "connection": { - "type": "ShaderOption", - "name": "o_parallax_algorithm" - } - }, - { - "name": "quality", - "displayName": "Quality", - "description": "Quality of parallax mapping.", - "type": "Enum", - "enumValues": [ "Low", "Medium", "High", "Ultra" ], - "defaultValue": "Low", - "connection": { - "type": "ShaderOption", - "name": "o_parallax_quality" - } - }, - { - "name": "pdo", - "displayName": "Pixel Depth Offset", - "description": "Enable PDO to offset the original pixel depths. This will affect any shaders using depth, for example, when receiving shadows.", - "type": "Bool", - "defaultValue": false, - "connection": { - "type": "ShaderOption", - "name": "o_parallax_enablePixelDepthOffset" - } - }, - { - "name": "showClipping", - "displayName": "Show Clipping", - "description": "Highlight areas where the height map is clipped by the mesh surface.", - "type": "Bool", - "defaultValue": false, - "connection": { - "type": "ShaderOption", - "name": "o_parallax_highlightClipping" - } - } - ], - "irradiance": [ - // Note: this property group is used in the DiffuseGlobalIllumination pass and not by the main forward shader - { - "name": "color", - "displayName": "Color", - "description": "Color is displayed as sRGB but the values are stored as linear color.", - "type": "Color", - "defaultValue": [ 1.0, 1.0, 1.0 ] - }, - { - "name": "factor", - "displayName": "Factor", - "description": "Strength factor for scaling the irradiance color values. Zero (0.0) is black, white (1.0) is full color.", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "max": 1.0 - } - ] - } + ] + } + ] }, "shaders": [ { @@ -1194,4 +1191,4 @@ "UV0": "Tiled", "UV1": "Unwrapped" } -} +} \ No newline at end of file diff --git a/Gems/Atom/TestData/TestData/Materials/Types/AutoBrick.materialtype b/Gems/Atom/TestData/TestData/Materials/Types/AutoBrick.materialtype index 00f11663f7..0d4d24d782 100644 --- a/Gems/Atom/TestData/TestData/Materials/Types/AutoBrick.materialtype +++ b/Gems/Atom/TestData/TestData/Materials/Types/AutoBrick.materialtype @@ -2,176 +2,174 @@ "description": "This is an example of a custom material type using Atom's PBR shading model: procedurally generated brick or tile.", "propertyLayout": { "version": 3, - "groups": [ + "propertySets": [ { "name": "shape", "displayName": "Shape", - "description": "Properties for configuring size, shape, and position of the bricks." + "description": "Properties for configuring size, shape, and position of the bricks.", + "properties": [ + { + "name": "brickWidth", + "displayName": "Brick Width", + "description": "The width of each brick.", + "type": "Float", + "defaultValue": 0.1, + "min": 0.0, + "softMax": 0.2, + "step": 0.001, + "connection": { + "type": "ShaderInput", + "name": "m_brickWidth" + } + }, + { + "name": "brickHeight", + "displayName": "Brick Height", + "description": "The height of each brick.", + "type": "Float", + "defaultValue": 0.05, + "min": 0.0, + "softMax": 0.2, + "step": 0.001, + "connection": { + "type": "ShaderInput", + "name": "m_brickHeight" + } + }, + { + "name": "brickOffset", + "displayName": "Offset", + "description": "The offset of each stack of bricks as a percentage of brick width.", + "type": "Float", + "defaultValue": 0.5, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_brickOffset" + } + }, + { + "name": "lineWidth", + "displayName": "Line Width", + "description": "The width of the grout lines.", + "type": "Float", + "defaultValue": 0.01, + "min": 0.0, + "softMax": 0.02, + "step": 0.0001, + "connection": { + "type": "ShaderInput", + "name": "m_lineWidth" + } + }, + { + "name": "lineDepth", + "displayName": "Line Depth", + "description": "The depth of the grout lines.", + "type": "Float", + "defaultValue": 0.01, + "min": 0.0, + "softMax": 0.02, + "connection": { + "type": "ShaderInput", + "name": "m_lineDepth" + } + } + ] }, { "name": "appearance", "displayName": "Appearance", - "description": "Properties for configuring the appearance of the bricks and grout lines." - } - ], - "properties": { - "shape": [ - { - "name": "brickWidth", - "displayName": "Brick Width", - "description": "The width of each brick.", - "type": "Float", - "defaultValue": 0.1, - "min": 0.0, - "softMax": 0.2, - "step": 0.001, - "connection": { - "type": "ShaderInput", - "name": "m_brickWidth" - } - }, - { - "name": "brickHeight", - "displayName": "Brick Height", - "description": "The height of each brick.", - "type": "Float", - "defaultValue": 0.05, - "min": 0.0, - "softMax": 0.2, - "step": 0.001, - "connection": { - "type": "ShaderInput", - "name": "m_brickHeight" - } - }, - { - "name": "brickOffset", - "displayName": "Offset", - "description": "The offset of each stack of bricks as a percentage of brick width.", - "type": "Float", - "defaultValue": 0.5, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_brickOffset" - } - }, - { - "name": "lineWidth", - "displayName": "Line Width", - "description": "The width of the grout lines.", - "type": "Float", - "defaultValue": 0.01, - "min": 0.0, - "softMax": 0.02, - "step": 0.0001, - "connection": { - "type": "ShaderInput", - "name": "m_lineWidth" - } - }, - { - "name": "lineDepth", - "displayName": "Line Depth", - "description": "The depth of the grout lines.", - "type": "Float", - "defaultValue": 0.01, - "min": 0.0, - "softMax": 0.02, - "connection": { - "type": "ShaderInput", - "name": "m_lineDepth" - } - } - ], - "appearance": [ - { - "name": "noiseTexture", - "type": "Image", - "defaultValue": "TestData/Textures/noise512.png", - "visibility": "Hidden", - "connection": { - "type": "ShaderInput", - "name": "m_noise" - } - }, - { - "name": "brickColor", - "displayName": "Brick Color", - "description": "The color of the bricks.", - "type": "Color", - "defaultValue": [1.0,1.0,1.0], - "connection": { - "type": "ShaderInput", - "name": "m_brickColor" + "description": "Properties for configuring the appearance of the bricks and grout lines.", + "properties": [ + { + "name": "noiseTexture", + "type": "Image", + "defaultValue": "TestData/Textures/noise512.png", + "visibility": "Hidden", + "connection": { + "type": "ShaderInput", + "name": "m_noise" + } + }, + { + "name": "brickColor", + "displayName": "Brick Color", + "description": "The color of the bricks.", + "type": "Color", + "defaultValue": [1.0,1.0,1.0], + "connection": { + "type": "ShaderInput", + "name": "m_brickColor" + } + }, + { + "name": "brickColorNoise", + "displayName": "Brick Color Noise", + "description": "Scale the variation of brick color.", + "type": "Float", + "defaultValue": 0.25, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_brickNoiseFactor" + } + }, + { + "name": "lineColor", + "displayName": "Line Color", + "description": "The color of the grout lines.", + "type": "Color", + "defaultValue": [0.5,0.5,0.5], + "connection": { + "type": "ShaderInput", + "name": "m_lineColor" + } + }, + { + "name": "lineColorNoise", + "displayName": "Line Color Noise", + "description": "Scale the variation of grout line color.", + "type": "Float", + "defaultValue": 0.25, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_lineNoiseFactor" + } + }, + { + "name": "brickColorBleed", + "displayName": "Brick Color Bleed", + "description": "Distance into the grout line that the brick color will continue.", + "type": "Float", + "defaultValue": 0.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_brickColorBleed" + } + }, + { + "name": "ao", + "displayName": "Ambient Occlusion", + "description": "The strength of baked ambient occlusion in the grout lines.", + "type": "Float", + "defaultValue": 0.5, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_aoFactor" + } } - }, - { - "name": "brickColorNoise", - "displayName": "Brick Color Noise", - "description": "Scale the variation of brick color.", - "type": "Float", - "defaultValue": 0.25, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_brickNoiseFactor" - } - }, - { - "name": "lineColor", - "displayName": "Line Color", - "description": "The color of the grout lines.", - "type": "Color", - "defaultValue": [0.5,0.5,0.5], - "connection": { - "type": "ShaderInput", - "name": "m_lineColor" - } - }, - { - "name": "lineColorNoise", - "displayName": "Line Color Noise", - "description": "Scale the variation of grout line color.", - "type": "Float", - "defaultValue": 0.25, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_lineNoiseFactor" - } - }, - { - "name": "brickColorBleed", - "displayName": "Brick Color Bleed", - "description": "Distance into the grout line that the brick color will continue.", - "type": "Float", - "defaultValue": 0.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_brickColorBleed" - } - }, - { - "name": "ao", - "displayName": "Ambient Occlusion", - "description": "The strength of baked ambient occlusion in the grout lines.", - "type": "Float", - "defaultValue": 0.5, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_aoFactor" - } - } - ] - } + ] + } + ] }, "shaders": [ { @@ -187,8 +185,5 @@ { "file": "Shaders/Depth/DepthPass.shader" } - ], - "functors": [ ] -} - +} \ No newline at end of file From b1c746968752a02a621220edf81c902cb3161ebd Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Fri, 1 Oct 2021 17:11:54 -0700 Subject: [PATCH 06/20] Renamed m_groups and m_properties to have "Old" in the name for clarity. Also fixed a potential uninitialized data bug in Conve. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../ConvertEmissiveUnitFunctorSourceData.h | 4 ++-- .../RPI.Edit/Material/MaterialTypeSourceData.h | 4 ++-- .../Material/MaterialTypeSourceData.cpp | 18 +++++++++--------- .../Material/MaterialTypeSourceDataTests.cpp | 8 ++++---- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/Material/ConvertEmissiveUnitFunctorSourceData.h b/Gems/Atom/Feature/Common/Code/Source/Material/ConvertEmissiveUnitFunctorSourceData.h index 23219ce940..091351087f 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Material/ConvertEmissiveUnitFunctorSourceData.h +++ b/Gems/Atom/Feature/Common/Code/Source/Material/ConvertEmissiveUnitFunctorSourceData.h @@ -44,8 +44,8 @@ namespace AZ AZStd::string m_shaderInputName; // The indices of photometric units in the dropdown list - uint32_t m_ev100Index; - uint32_t m_nitIndex; + uint32_t m_ev100Index = 0; + uint32_t m_nitIndex = 1; // Minimum and Maximum value for different photometric units AZ::Vector2 m_ev100MinMax; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialTypeSourceData.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialTypeSourceData.h index 1d918702ff..ec12384286 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialTypeSourceData.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialTypeSourceData.h @@ -170,11 +170,11 @@ namespace AZ //! [Deprecated] Use m_propertySets instead //! List of groups that will contain the available properties - AZStd::vector m_groups; + AZStd::vector m_groupsOld; //! [Deprecated] Use m_propertySets instead //! Collection of all available user-facing properties - AZStd::map> m_properties; + AZStd::map> m_propertiesOld; AZStd::vector> m_propertySets; }; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp index 816e9f4f8d..bddbf726e2 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp @@ -83,8 +83,8 @@ namespace AZ serializeContext->Class() ->Version(1) ->Field("version", &PropertyLayout::m_version) - ->Field("groups", &PropertyLayout::m_groups) //< Old, preserved for backward compatibility, replaced by propertySets - ->Field("properties", &PropertyLayout::m_properties) //< Old, preserved for backward compatibility, replaced by propertySets + ->Field("groups", &PropertyLayout::m_groupsOld) //< Deprecated, preserved for backward compatibility, replaced by propertySets + ->Field("properties", &PropertyLayout::m_propertiesOld) //< Deprecated, preserved for backward compatibility, replaced by propertySets ->Field("propertySets", &PropertyLayout::m_propertySets) ; @@ -397,8 +397,8 @@ namespace AZ { for (const auto& group : GetOldFormatGroupDefinitionsInDisplayOrder()) { - auto propertyListItr = m_propertyLayout.m_properties.find(group.m_name); - if (propertyListItr != m_propertyLayout.m_properties.end()) + auto propertyListItr = m_propertyLayout.m_propertiesOld.find(group.m_name); + if (propertyListItr != m_propertyLayout.m_propertiesOld.end()) { const auto& propertyList = propertyListItr->second; for (auto& propertyDefinition : propertyList) @@ -421,8 +421,8 @@ namespace AZ } } - m_propertyLayout.m_groups.clear(); - m_propertyLayout.m_properties.clear(); + m_propertyLayout.m_groupsOld.clear(); + m_propertyLayout.m_propertiesOld.clear(); return true; } @@ -451,11 +451,11 @@ namespace AZ AZStd::vector MaterialTypeSourceData::GetOldFormatGroupDefinitionsInDisplayOrder() const { AZStd::vector groupDefinitions; - groupDefinitions.reserve(m_propertyLayout.m_properties.size()); + groupDefinitions.reserve(m_propertyLayout.m_propertiesOld.size()); // Some groups are defined explicitly in the .materialtype file's "groups" section. This is the primary way groups are sorted in the UI. AZStd::unordered_set foundGroups; - for (const auto& groupDefinition : m_propertyLayout.m_groups) + for (const auto& groupDefinition : m_propertyLayout.m_groupsOld) { if (foundGroups.insert(groupDefinition.m_name).second) { @@ -468,7 +468,7 @@ namespace AZ } // Some groups are defined implicitly, in the "properties" section where a group name is used but not explicitly defined in the "groups" section. - for (const auto& propertyListPair : m_propertyLayout.m_properties) + for (const auto& propertyListPair : m_propertyLayout.m_propertiesOld) { const AZStd::string& groupName = propertyListPair.first; if (foundGroups.insert(groupName).second) diff --git a/Gems/Atom/RPI/Code/Tests/Material/MaterialTypeSourceDataTests.cpp b/Gems/Atom/RPI/Code/Tests/Material/MaterialTypeSourceDataTests.cpp index 00523abbd8..e5394106fd 100644 --- a/Gems/Atom/RPI/Code/Tests/Material/MaterialTypeSourceDataTests.cpp +++ b/Gems/Atom/RPI/Code/Tests/Material/MaterialTypeSourceDataTests.cpp @@ -1781,15 +1781,15 @@ namespace UnitTest JsonTestResult loadResult = LoadTestDataFromJson(material, inputJson); // Before conversion to the new format, the data is in the old place - EXPECT_EQ(material.GetPropertyLayout().m_groups.size(), 2); - EXPECT_EQ(material.GetPropertyLayout().m_properties.size(), 2); + EXPECT_EQ(material.GetPropertyLayout().m_groupsOld.size(), 2); + EXPECT_EQ(material.GetPropertyLayout().m_propertiesOld.size(), 2); EXPECT_EQ(material.GetPropertyLayout().m_propertySets.size(), 0); material.ConvertToNewDataFormat(); // After conversion to the new format, the data is in the new place - EXPECT_EQ(material.GetPropertyLayout().m_groups.size(), 0); - EXPECT_EQ(material.GetPropertyLayout().m_properties.size(), 0); + EXPECT_EQ(material.GetPropertyLayout().m_groupsOld.size(), 0); + EXPECT_EQ(material.GetPropertyLayout().m_propertiesOld.size(), 0); EXPECT_EQ(material.GetPropertyLayout().m_propertySets.size(), 2); EXPECT_EQ(material.m_description, "This is a general description about the material"); From 4312c636afb458cb630a23100186150a6324240a Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Wed, 26 Jan 2022 12:19:49 -0800 Subject: [PATCH 07/20] Got the RPI unit tests building and working again after merge. There were some incorrectly resolved conflicts that I had to re-resolve, especially in MaterialTypeSourceData::CreateMaterialTypeAsset. I removed support for property rename version updates in MaterialTypeSourceData (i.e. ApplyPropertyRenames) because MaterialSourceData serialization no longer loads material property definitions from the .materialtype file, per a recent change on the development branch. The unit tests were broken and it wasn't worth updating them since we don't need this functionality anymore. Material property renames and other version updates are now exclusively applied by the MaterialAsset class. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../Material/MaterialTypeSourceData.cpp | 327 +----------------- .../Material/MaterialSourceDataTests.cpp | 45 +-- .../Material/MaterialTypeSourceDataTests.cpp | 152 +------- 3 files changed, 38 insertions(+), 486 deletions(-) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp index 9e72e13b34..2504981273 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp @@ -132,32 +132,6 @@ namespace AZ const float MaterialTypeSourceData::PropertyDefinition::DefaultMax = std::numeric_limits::max(); const float MaterialTypeSourceData::PropertyDefinition::DefaultStep = 0.1f; - bool MaterialTypeSourceData::ApplyPropertyRenames(MaterialPropertyId& propertyId) const - { - bool renamed = false; - - for (const VersionUpdateDefinition& versionUpdate : m_versionUpdates) - { - for (const VersionUpdatesRenameOperationDefinition& action : versionUpdate.m_actions) - { - if (action.m_operation == "rename") - { - if (action.m_renameFrom == propertyId.GetStringView()) - { - propertyId = MaterialPropertyId::Parse(action.m_renameTo); - renamed = true; - } - } - else - { - AZ_Warning("Material source data", false, "Unsupported material version update operation '%s'", action.m_operation.c_str()); - } - } - } - - return renamed; - } - /*static*/ MaterialTypeSourceData::PropertySet* MaterialTypeSourceData::PropertySet::AddPropertySet(AZStd::string_view name, AZStd::vector>& toPropertySetList) { auto iter = AZStd::find_if(toPropertySetList.begin(), toPropertySetList.end(), [name](const AZStd::unique_ptr& existingPropertySet) @@ -528,49 +502,6 @@ namespace AZ return groupDefinitions; } - // TODO: It looks like this function doesn't operate on MaterialTypeSourceData data, it belongs in MaterialUtils - bool MaterialTypeSourceData::ConvertPropertyValueToSourceDataFormat(const PropertyDefinition& propertyDefinition, MaterialPropertyValue& propertyValue) const - { - if (propertyDefinition.m_dataType == AZ::RPI::MaterialPropertyDataType::Enum && propertyValue.Is()) - { - const uint32_t index = propertyValue.GetValue(); - if (index >= propertyDefinition.m_enumValues.size()) - { - AZ_Error("Material source data", false, "Invalid value for material enum property: '%s'.", propertyDefinition.m_name.c_str()); - return false; - } - - propertyValue = propertyDefinition.m_enumValues[index]; - return true; - } - - // Image asset references must be converted from asset IDs to a relative source file path - if (propertyDefinition.m_dataType == AZ::RPI::MaterialPropertyDataType::Image && propertyValue.Is>()) - { - const Data::Asset& imageAsset = propertyValue.GetValue>(); - - Data::AssetInfo imageAssetInfo; - if (imageAsset.GetId().IsValid()) - { - bool result = false; - AZStd::string rootFilePath; - const AZStd::string platformName = ""; // Empty for default - AzToolsFramework::AssetSystemRequestBus::BroadcastResult(result, &AzToolsFramework::AssetSystem::AssetSystemRequest::GetAssetInfoById, - imageAsset.GetId(), imageAsset.GetType(), platformName, imageAssetInfo, rootFilePath); - if (!result) - { - AZ_Error("Material source data", false, "Image asset could not be found for property: '%s'.", propertyDefinition.m_name.c_str()); - return false; - } - } - - propertyValue = imageAssetInfo.m_relativePath; - return true; - } - - return true; - } - bool MaterialTypeSourceData::BuildPropertyList( const AZStd::string& materialTypeSourceFilePath, MaterialTypeAssetCreator& materialTypeAssetCreator, @@ -651,15 +582,20 @@ namespace AZ { case MaterialPropertyDataType::Image: { - Outcome> imageAssetResult = MaterialUtils::GetImageAssetReference(materialTypeSourceFilePath, property->m_value.GetValue()); + Data::Asset imageAsset; - if (imageAssetResult.IsSuccess()) + MaterialUtils::GetImageAssetResult result = MaterialUtils::GetImageAssetReference( + imageAsset, materialTypeSourceFilePath, property->m_value.GetValue()); + + if (result == MaterialUtils::GetImageAssetResult::Missing) { - materialTypeAssetCreator.SetPropertyValue(propertyId, imageAssetResult.GetValue()); + materialTypeAssetCreator.ReportError( + "Material property '%s': Could not find the image '%s'", propertyId.GetCStr(), + property->m_value.GetValue().data()); } else { - materialTypeAssetCreator.ReportError("Material property '%s': Could not find the image '%s'", propertyId.GetCStr(), property->m_value.GetValue().data()); + materialTypeAssetCreator.SetPropertyValue(propertyId, imageAsset); } } break; @@ -743,145 +679,6 @@ namespace AZ } - Outcome> MaterialTypeSourceData::CreateMaterialTypeAsset(Data::AssetId assetId, AZStd::string_view materialTypeSourceFilePath, bool elevateWarnings) const - { - MaterialTypeAssetCreator materialTypeAssetCreator; - materialTypeAssetCreator.SetElevateWarnings(elevateWarnings); - materialTypeAssetCreator.Begin(assetId); - - // Used to gather all the UV streams used in this material type from its shaders in alphabetical order. - auto semanticComp = [](const RHI::ShaderSemantic& lhs, const RHI::ShaderSemantic& rhs) -> bool - { - return lhs.ToString() < rhs.ToString(); - }; - AZStd::set uvsInThisMaterialType(semanticComp); - - for (const ShaderVariantReferenceData& shaderRef : m_shaderCollection) - { - const auto& shaderFile = shaderRef.m_shaderFilePath; - auto shaderAssetResult = AssetUtils::LoadAsset(materialTypeSourceFilePath, shaderFile, 0); - - if (shaderAssetResult) - { - auto shaderAsset = shaderAssetResult.GetValue(); - auto optionsLayout = shaderAsset->GetShaderOptionGroupLayout(); - ShaderOptionGroup options{ optionsLayout }; - for (auto& iter : shaderRef.m_shaderOptionValues) - { - if (!options.SetValue(iter.first, iter.second)) - { - return Failure(); - } - } - - materialTypeAssetCreator.AddShader( - shaderAsset, options.GetShaderVariantId(), - shaderRef.m_shaderTag.IsEmpty() ? Uuid::CreateRandom().ToString() : shaderRef.m_shaderTag); - - // Gather UV names - const ShaderInputContract& shaderInputContract = shaderAsset->GetInputContract(); - for (const ShaderInputContract::StreamChannelInfo& channel : shaderInputContract.m_streamChannels) - { - const RHI::ShaderSemantic& semantic = channel.m_semantic; - - if (semantic.m_name.GetStringView().starts_with(RHI::ShaderSemantic::UvStreamSemantic)) - { - uvsInThisMaterialType.insert(semantic); - } - } - } - else - { - materialTypeAssetCreator.ReportError("Shader '%s' not found", shaderFile.data()); - return Failure(); - } - } - - for (const AZStd::unique_ptr& propertySet : m_propertyLayout.m_propertySets) - { - AZStd::vector propertyNameContext; - propertyNameContext.push_back(propertySet->m_name); - materialTypeAssetCreator.BeginMaterialProperty(propertyId.GetFullName(), property.m_dataType); - - if (!success) - { - return Failure(); - Data::Asset imageAsset; - - MaterialUtils::GetImageAssetResult result = MaterialUtils::GetImageAssetReference( - Outcome> imageAssetResult = MaterialUtils::GetImageAssetReference(materialTypeSourceFilePath, property.m_value.GetValue()); - if (imageAssetResult.IsSuccess()) - materialTypeAssetCreator.SetPropertyValue(propertyId.GetFullName(), imageAssetResult.GetValue()); - "Material property '%s': Could not find the image '%s'", propertyId.GetCStr(), - property.m_value.GetValue().data()); - materialTypeAssetCreator.ReportError("Material property '%s': Could not find the image '%s'", propertyId.GetFullName().GetCStr(), property.m_value.GetValue().data()); - MaterialPropertyIndex propertyIndex = materialTypeAssetCreator.GetMaterialPropertiesLayout()->FindPropertyIndex(propertyId.GetFullName()); - materialTypeAssetCreator.SetPropertyValue(propertyId.GetFullName(), enumValue); - materialTypeAssetCreator.SetPropertyValue(propertyId.GetFullName(), property.m_value); - } - } - - // We cannot create the MaterialFunctor until after all the properties are added because - // CreateFunctor() may need to look up properties in the MaterialPropertiesLayout - for (auto& functorData : m_materialFunctorSourceData) - { - MaterialFunctorSourceData::FunctorResult result = functorData->CreateFunctor( - MaterialFunctorSourceData::RuntimeContext( - materialTypeSourceFilePath, - materialTypeAssetCreator.GetMaterialPropertiesLayout(), - materialTypeAssetCreator.GetMaterialShaderResourceGroupLayout(), - materialTypeAssetCreator.GetShaderCollection() - ) - ); - - if (result.IsSuccess()) - { - Ptr& functor = result.GetValue(); - if (functor != nullptr) - { - materialTypeAssetCreator.AddMaterialFunctor(functor); - - for (const AZ::Name& optionName : functorData->GetActualSourceData()->GetShaderOptionDependencies()) - { - materialTypeAssetCreator.ClaimShaderOptionOwnership(optionName); - } - } - } - else - { - materialTypeAssetCreator.ReportError("Failed to create MaterialFunctor"); - return Failure(); - } - } - - // Only add the UV mapping related to this material type. - for (const auto& uvInput : uvsInThisMaterialType) - { - // We may have cases where the uv map is empty or inconsistent (exported from other projects), - // So we use semantic if mapping is not found. - auto iter = m_uvNameMap.find(uvInput.ToString()); - if (iter != m_uvNameMap.end()) - { - materialTypeAssetCreator.AddUvName(uvInput, Name(iter->second)); - } - else - { - materialTypeAssetCreator.AddUvName(uvInput, Name(uvInput.ToString())); - } - } - - Data::Asset materialTypeAsset; - if (materialTypeAssetCreator.End(materialTypeAsset)) - { - return Success(AZStd::move(materialTypeAsset)); - } - else - { - return Failure(); - } - } - - Outcome> MaterialTypeSourceData::CreateMaterialTypeAsset(Data::AssetId assetId, AZStd::string_view materialTypeSourceFilePath, bool elevateWarnings) const { MaterialTypeAssetCreator materialTypeAssetCreator; @@ -970,108 +767,16 @@ namespace AZ return Failure(); } } - - for (auto& groupIter : m_propertyLayout.m_properties) + + for (const AZStd::unique_ptr& propertySet : m_propertyLayout.m_propertySets) { - const AZStd::string& groupName = groupIter.first; + AZStd::vector propertyNameContext; + propertyNameContext.push_back(propertySet->m_name); + bool success = BuildPropertyList(materialTypeSourceFilePath, materialTypeAssetCreator, propertyNameContext, propertySet.get()); - for (const PropertyDefinition& property : groupIter.second) + if (!success) { - // Register the property... - - MaterialPropertyId propertyId{ groupName, property.m_name }; - - if (!propertyId.IsValid()) - { - materialTypeAssetCreator.ReportWarning("Cannot create material property with invalid ID '%s'.", propertyId.GetCStr()); - continue; - } - - materialTypeAssetCreator.BeginMaterialProperty(propertyId, property.m_dataType); - - if (property.m_dataType == MaterialPropertyDataType::Enum) - { - materialTypeAssetCreator.SetMaterialPropertyEnumNames(property.m_enumValues); - } - - for (auto& output : property.m_outputConnections) - { - switch (output.m_type) - { - case MaterialPropertyOutputType::ShaderInput: - materialTypeAssetCreator.ConnectMaterialPropertyToShaderInput(Name{ output.m_fieldName.data() }); - break; - case MaterialPropertyOutputType::ShaderOption: - if (output.m_shaderIndex >= 0) - { - materialTypeAssetCreator.ConnectMaterialPropertyToShaderOption(Name{ output.m_fieldName.data() }, output.m_shaderIndex); - } - else - { - materialTypeAssetCreator.ConnectMaterialPropertyToShaderOptions(Name{ output.m_fieldName.data() }); - } - break; - case MaterialPropertyOutputType::Invalid: - // Don't add any output mappings, this is the case when material functors are expected to process the property - break; - default: - AZ_Assert(false, "Unsupported MaterialPropertyOutputType"); - return Failure(); - } - } - - materialTypeAssetCreator.EndMaterialProperty(); - - // Parse and set the property's value... - if (!property.m_value.IsValid()) - { - AZ_Warning("Material source data", false, "Source data for material property value is invalid."); - } - else - { - switch (property.m_dataType) - { - case MaterialPropertyDataType::Image: - { - Data::Asset imageAsset; - - MaterialUtils::GetImageAssetResult result = MaterialUtils::GetImageAssetReference( - imageAsset, materialTypeSourceFilePath, property.m_value.GetValue()); - - if (result == MaterialUtils::GetImageAssetResult::Missing) - { - materialTypeAssetCreator.ReportError( - "Material property '%s': Could not find the image '%s'", propertyId.GetCStr(), - property.m_value.GetValue().data()); - } - else - { - materialTypeAssetCreator.SetPropertyValue(propertyId, imageAsset); - } - } - break; - case MaterialPropertyDataType::Enum: - { - MaterialPropertyIndex propertyIndex = materialTypeAssetCreator.GetMaterialPropertiesLayout()->FindPropertyIndex(propertyId); - const MaterialPropertyDescriptor* propertyDescriptor = materialTypeAssetCreator.GetMaterialPropertiesLayout()->GetPropertyDescriptor(propertyIndex); - - AZ::Name enumName = AZ::Name(property.m_value.GetValue()); - uint32_t enumValue = propertyDescriptor ? propertyDescriptor->GetEnumValue(enumName) : MaterialPropertyDescriptor::InvalidEnumValue; - if (enumValue == MaterialPropertyDescriptor::InvalidEnumValue) - { - materialTypeAssetCreator.ReportError("Enum value '%s' couldn't be found in the 'enumValues' list", enumName.GetCStr()); - } - else - { - materialTypeAssetCreator.SetPropertyValue(propertyId, enumValue); - } - } - break; - default: - materialTypeAssetCreator.SetPropertyValue(propertyId, property.m_value); - break; - } - } + return Failure(); } } diff --git a/Gems/Atom/RPI/Code/Tests/Material/MaterialSourceDataTests.cpp b/Gems/Atom/RPI/Code/Tests/Material/MaterialSourceDataTests.cpp index 808e312b71..1a3b46ac86 100644 --- a/Gems/Atom/RPI/Code/Tests/Material/MaterialSourceDataTests.cpp +++ b/Gems/Atom/RPI/Code/Tests/Material/MaterialSourceDataTests.cpp @@ -93,20 +93,23 @@ namespace UnitTest { "version": 10, "propertyLayout": { - "properties": { - "general": [ - {"name": "MyBool", "type": "bool"}, - {"name": "MyInt", "type": "Int"}, - {"name": "MyUInt", "type": "UInt"}, - {"name": "MyFloat", "type": "Float"}, - {"name": "MyFloat2", "type": "Vector2"}, - {"name": "MyFloat3", "type": "Vector3"}, - {"name": "MyFloat4", "type": "Vector4"}, - {"name": "MyColor", "type": "Color"}, - {"name": "MyImage", "type": "Image"}, - {"name": "MyEnum", "type": "Enum", "enumValues": ["Enum0", "Enum1", "Enum2"], "defaultValue": "Enum0"} - ] - } + "propertySets": [ + { + "name": "general", + "properties": [ + {"name": "MyBool", "type": "bool"}, + {"name": "MyInt", "type": "Int"}, + {"name": "MyUInt", "type": "UInt"}, + {"name": "MyFloat", "type": "Float"}, + {"name": "MyFloat2", "type": "Vector2"}, + {"name": "MyFloat3", "type": "Vector3"}, + {"name": "MyFloat4", "type": "Vector4"}, + {"name": "MyColor", "type": "Color"}, + {"name": "MyImage", "type": "Image"}, + {"name": "MyEnum", "type": "Enum", "enumValues": ["Enum0", "Enum1", "Enum2"], "defaultValue": "Enum0"} + ] + } + ] }, "shaders": [ { @@ -580,18 +583,12 @@ namespace UnitTest errorMessageFinder.Reset(); errorMessageFinder.AddExpectedErrorMessage("Could not find asset [DoesNotExist.materialtype]"); - "properties": { - [ - { - "general": [ - "properties": [ - ] result = material.CreateMaterialAsset(AZ::Uuid::CreateRandom(), "test.material", AZ::RPI::MaterialAssetProcessingMode::PreBake, elevateWarnings); EXPECT_FALSE(result.IsSuccess()); errorMessageFinder.CheckExpectedErrorsFound(); errorMessageFinder.Reset(); - EXPECT_TRUE(loadResult.ContainsMessage("[simpleMaterialType.materialtype]/propertyLayout/properties", "Successfully read")); + errorMessageFinder.AddExpectedErrorMessage("Could not find asset [DoesNotExist.materialtype]"); errorMessageFinder.AddIgnoredErrorMessage("Failed to create material type asset ID", true); result = material.CreateMaterialAssetFromSourceData(AZ::Uuid::CreateRandom(), "test.material", elevateWarnings); EXPECT_FALSE(result.IsSuccess()); @@ -600,12 +597,6 @@ namespace UnitTest TEST_F(MaterialSourceDataTests, CreateMaterialAsset_MaterialPropertyNotFound) { - "properties": { - [ - { - "general": [ - "properties": [ - ] MaterialSourceData material; material.m_materialType = "@exefolder@/Temp/test.materialtype"; AddPropertyGroup(material, "general"); diff --git a/Gems/Atom/RPI/Code/Tests/Material/MaterialTypeSourceDataTests.cpp b/Gems/Atom/RPI/Code/Tests/Material/MaterialTypeSourceDataTests.cpp index 8e65b41e6c..f07e1da6c2 100644 --- a/Gems/Atom/RPI/Code/Tests/Material/MaterialTypeSourceDataTests.cpp +++ b/Gems/Atom/RPI/Code/Tests/Material/MaterialTypeSourceDataTests.cpp @@ -1911,157 +1911,13 @@ namespace UnitTest } - TEST_F(MaterialTypeSourceDataTests, FindPropertyUsingOldName) - { - const AZStd::string inputJson = R"( - { - "version": 10, - "versionUpdates": [ - { - "toVersion": 2, - "actions": [ - { "op": "rename", "from": "general.fooA", "to": "general.fooB" } - ] - }, - { - "toVersion": 4, - "actions": [ - { "op": "rename", "from": "general.barA", "to": "general.barB" } - ] - }, - { - "toVersion": 6, - "actions": [ - { "op": "rename", "from": "general.fooB", "to": "general.fooC" }, - { "op": "rename", "from": "general.barB", "to": "general.barC" } - ] - }, - { - "toVersion": 7, - "actions": [ - { "op": "rename", "from": "general.bazA", "to": "otherGroup.bazB" }, - { "op": "rename", "from": "onlyOneProperty.bopA", "to": "otherGroup.bopB" } // This tests a group 'onlyOneProperty' that no longer exists in the material type - ] - } - ], - "propertyLayout": { - "properties": { - "general": [ - { - "name": "fooC", - "type": "Bool" - }, - { - "name": "barC", - "type": "Float" - } - ], - "otherGroup": [ - { - "name": "dontMindMe", - "type": "Bool" - }, - { - "name": "bazB", - "type": "Float" - }, - { - "name": "bopB", - "type": "Float" - } - ] - } - } - } - )"; - - MaterialTypeSourceData materialType; - JsonTestResult loadResult = LoadTestDataFromJson(materialType, inputJson); - - EXPECT_EQ(materialType.m_version, 10); - - // First find the properties using their correct current names - const MaterialTypeSourceData::PropertyDefinition* foo = materialType.FindProperty("general", "fooC"); - const MaterialTypeSourceData::PropertyDefinition* bar = materialType.FindProperty("general", "barC"); - const MaterialTypeSourceData::PropertyDefinition* baz = materialType.FindProperty("otherGroup", "bazB"); - const MaterialTypeSourceData::PropertyDefinition* bop = materialType.FindProperty("otherGroup", "bopB"); - - EXPECT_TRUE(foo); - EXPECT_TRUE(bar); - EXPECT_TRUE(baz); - EXPECT_TRUE(bop); - EXPECT_EQ(foo->m_name, "fooC"); - EXPECT_EQ(bar->m_name, "barC"); - EXPECT_EQ(baz->m_name, "bazB"); - EXPECT_EQ(bop->m_name, "bopB"); - - // Now try doing the property lookup using old versions of the name and make sure the same property can be found - - EXPECT_EQ(foo, materialType.FindProperty("general", "fooA")); - EXPECT_EQ(foo, materialType.FindProperty("general", "fooB")); - EXPECT_EQ(bar, materialType.FindProperty("general", "barA")); - EXPECT_EQ(bar, materialType.FindProperty("general", "barB")); - EXPECT_EQ(baz, materialType.FindProperty("general", "bazA")); - EXPECT_EQ(bop, materialType.FindProperty("onlyOneProperty", "bopA")); - - EXPECT_EQ(nullptr, materialType.FindProperty("general", "fooX")); - EXPECT_EQ(nullptr, materialType.FindProperty("general", "barX")); - EXPECT_EQ(nullptr, materialType.FindProperty("general", "bazX")); - EXPECT_EQ(nullptr, materialType.FindProperty("general", "bazB")); - EXPECT_EQ(nullptr, materialType.FindProperty("otherGroup", "bazA")); - EXPECT_EQ(nullptr, materialType.FindProperty("onlyOneProperty", "bopB")); - EXPECT_EQ(nullptr, materialType.FindProperty("otherGroup", "bopA")); - } - - TEST_F(MaterialTypeSourceDataTests, FindPropertyUsingOldName_Error_UnsupportedVersionUpdate) - { - const AZStd::string inputJson = R"( - { - "version": 10, - "versionUpdates": [ - { - "toVersion": 2, - "actions": [ - { "op": "notRename", "from": "general.fooA", "to": "general.fooB" } - ] - } - ], - "propertyLayout": { - "properties": { - "general": [ - { - "name": "fooB", - "type": "Bool" - } - ] - } - } - } - )"; - - MaterialTypeSourceData materialType; - JsonTestResult loadResult = LoadTestDataFromJson(materialType, inputJson); - - ErrorMessageFinder errorMessageFinder; - errorMessageFinder.AddExpectedErrorMessage("Unsupported material version update operation 'notRename'"); - - - const MaterialTypeSourceData::PropertyDefinition* foo = materialType.FindProperty("general", "fooA"); - - EXPECT_EQ(nullptr, foo); - - errorMessageFinder.CheckExpectedErrorsFound(); - } - TEST_F(MaterialTypeSourceDataTests, CreateMaterialTypeAsset_Error_UnsupportedVersionUpdate) { MaterialTypeSourceData sourceData; - - MaterialTypeSourceData::PropertyDefinition propertySource; - propertySource.m_name = "a"; - propertySource.m_dataType = MaterialPropertyDataType::Int; - propertySource.m_value = 0; - sourceData.m_propertyLayout.m_properties["general"].push_back(propertySource); + + MaterialTypeSourceData::PropertyDefinition* propertySource = sourceData.AddPropertySet("general")->AddProperty("a"); + propertySource->m_dataType = MaterialPropertyDataType::Int; + propertySource->m_value = 0; sourceData.m_version = 2; From 9b8bebbd70d96282ca06fbf0b8e64e0afee2a4e0 Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Wed, 26 Jan 2022 12:21:43 -0800 Subject: [PATCH 08/20] Bumped the MaterialBuilder version number. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../RPI/Code/Source/RPI.Builders/Material/MaterialBuilder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Builders/Material/MaterialBuilder.cpp b/Gems/Atom/RPI/Code/Source/RPI.Builders/Material/MaterialBuilder.cpp index cadb182d03..d55f202c03 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Builders/Material/MaterialBuilder.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Builders/Material/MaterialBuilder.cpp @@ -52,7 +52,7 @@ namespace AZ { AssetBuilderSDK::AssetBuilderDesc materialBuilderDescriptor; materialBuilderDescriptor.m_name = JobKey; - materialBuilderDescriptor.m_version = 116; // more material dependency improvements + materialBuilderDescriptor.m_version = 117; // new material type file format materialBuilderDescriptor.m_patterns.push_back(AssetBuilderSDK::AssetBuilderPattern("*.material", AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard)); materialBuilderDescriptor.m_patterns.push_back(AssetBuilderSDK::AssetBuilderPattern("*.materialtype", AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard)); materialBuilderDescriptor.m_busId = azrtti_typeid(); From aeb43c4012fd23ebf9cbe1a4758250c86d15a8f9 Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Wed, 26 Jan 2022 13:04:28 -0800 Subject: [PATCH 09/20] Fixed up a few small things to get Material Editor working again. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../Materials/Special/ShadowCatcher.materialtype | 1 - .../RPI.Edit/Material/MaterialTypeSourceData.h | 11 ++++------- .../Code/Source/Document/MaterialDocument.cpp | 14 +++++++------- .../Material/EditorMaterialComponentUtil.cpp | 6 +++--- 4 files changed, 14 insertions(+), 18 deletions(-) diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Special/ShadowCatcher.materialtype b/Gems/Atom/Feature/Common/Assets/Materials/Special/ShadowCatcher.materialtype index 937abe656d..973f8b2147 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Special/ShadowCatcher.materialtype +++ b/Gems/Atom/Feature/Common/Assets/Materials/Special/ShadowCatcher.materialtype @@ -2,7 +2,6 @@ "description": "Base material for the reflection probe visualization model.", "version": 1, "propertyLayout": { - "version": 1, "propertySets": [ { "name": "settings", diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialTypeSourceData.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialTypeSourceData.h index 4fae3f710e..b5e7eecd0d 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialTypeSourceData.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialTypeSourceData.h @@ -76,6 +76,7 @@ namespace AZ static const float DefaultMax; static const float DefaultStep; + // TODO: Consider making this private and readonly because it is used as the key for lookups and collision validation. AZStd::string m_name; //!< The name of the property within the property group. The full property ID will be groupName.propertyName. MaterialPropertyVisibility m_visibility = MaterialPropertyVisibility::Default; @@ -213,9 +214,9 @@ namespace AZ AZStd::string m_description; //< TODO: Make this private //! Version 1 is the default and should not contain any version update. - uint32_t m_version = 1; + uint32_t m_version = 1; //< TODO: Make this private - VersionUpdates m_versionUpdates; + VersionUpdates m_versionUpdates; //< TODO: Make this private //! A list of shader variants that are always used at runtime; they cannot be turned off AZStd::vector m_shaderCollection; //< TODO: Make this private @@ -283,11 +284,7 @@ namespace AZ MaterialTypeAssetCreator& materialTypeAssetCreator, AZStd::vector& propertyNameContext, const MaterialTypeSourceData::PropertySet* propertySet) const; - - //! Possibly renames @propertyId based on the material version update steps. - //! @return true if the property was renamed - bool ApplyPropertyRenames(MaterialPropertyId& propertyId) const; - + //! Construct a complete list of group definitions, including implicit groups, arranged in the same order as the source data. //! Groups with the same name will be consolidated into a single entry. //! Operates on the old format PropertyLayout::m_groups, used for conversion to the new format. diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp index 8d6eaf0633..c9ae970215 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp @@ -585,11 +585,11 @@ namespace MaterialEditor bool result = true; // populate sourceData with properties that meet the filter - m_materialTypeSourceData.EnumerateProperties([this, &sourceData, &propertyFilter, &result](const AZStd::string& propertyIdContext, const auto& propertyDefinition) { + m_materialTypeSourceData.EnumerateProperties([&](const AZStd::string& propertyIdContext, const auto& propertyDefinition) { - const AZStd::string propertyId = propertyIdContext + propertyDefinition->m_name; + Name propertyId{propertyIdContext + propertyDefinition->m_name}; - const auto it = m_properties.find(Name{propertyId}); + const auto it = m_properties.find(propertyId); if (it != m_properties.end() && propertyFilter(it->second)) { MaterialPropertyValue propertyValue = AtomToolsFramework::ConvertToRuntimeType(it->second.GetValue()); @@ -603,7 +603,7 @@ namespace MaterialEditor } // TODO: Support populating the Material Editor with nested property sets, not just the top level. - const AZStd::string groupName = propertyId.substr(0, propertyId.size() - propertyDefinition->m_name.size() - 1); + const AZStd::string groupName = propertyId.GetStringView().substr(0, propertyId.GetStringView().size() - propertyDefinition->m_name.size() - 1); sourceData.m_properties[groupName][propertyDefinition->m_name].m_value = propertyValue; } } @@ -897,12 +897,12 @@ namespace MaterialEditor return false; } } - + bool enumerateResult = m_materialTypeSourceData.EnumeratePropertySets( - [this, &materialTypeSourceFilePath](const AZStd::string&, const MaterialTypeSourceData::PropertySet* propertySet) + [this](const AZStd::string&, const MaterialTypeSourceData::PropertySet* propertySet) { const MaterialFunctorSourceData::EditorContext editorContext = MaterialFunctorSourceData::EditorContext( - materialTypeSourceFilePath, m_materialAsset->GetMaterialPropertiesLayout()); + m_materialSourceData.m_materialType, m_materialAsset->GetMaterialPropertiesLayout()); for (Ptr functorData : propertySet->GetFunctors()) { diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp index 96cf02c6f9..d6342a2507 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp @@ -122,7 +122,7 @@ namespace AZ 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()]; @@ -135,7 +135,7 @@ namespace AZ propertyValue = AZ::RPI::MaterialPropertyValue::FromAny(propertyOverrideItr->second); } - if (!AtomToolsFramework::ConvertToExportFormat(path, propertyId, propertyDefinition, propertyValue)) + if (!AtomToolsFramework::ConvertToExportFormat(path, propertyId, *propertyDefinition, propertyValue)) { AZ_Error("AZ::Render::EditorMaterialComponentUtil", false, "Failed to export: %s", path.c_str()); result = false; @@ -151,7 +151,7 @@ namespace AZ // 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; }); From 048b068c8991501a476f06578a9a37bcff107f1c Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Thu, 30 Sep 2021 01:08:54 -0700 Subject: [PATCH 10/20] Updated StringFunc::Tokenize to support returning a list of string_view instead of string, which should be more efficient. string is still supported as well, but users should prefer the string_view version. Testing: Updated unit tests. Reprocessed Atom material assets. Ran AtomSampleViewer material screenshot test. Opened, edited, saved materail in the Material Editor. Opened a level, edited material property overrides, saved and reloaded. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../AzCore/AzCore/StringFunc/StringFunc.cpp | 24 ++++++++++---- .../AzCore/AzCore/StringFunc/StringFunc.h | 12 ++++--- Code/Framework/AzCore/Tests/StringFunc.cpp | 31 +++++++++++++++---- 3 files changed, 51 insertions(+), 16 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/StringFunc/StringFunc.cpp b/Code/Framework/AzCore/AzCore/StringFunc/StringFunc.cpp index 8405424f7d..61a9096d5e 100644 --- a/Code/Framework/AzCore/AzCore/StringFunc/StringFunc.cpp +++ b/Code/Framework/AzCore/AzCore/StringFunc/StringFunc.cpp @@ -757,13 +757,18 @@ namespace AZ::StringFunc } return value; } - - void Tokenize(AZStd::string_view in, AZStd::vector& tokens, const char delimiter, bool keepEmptyStrings, bool keepSpaceStrings) + + template + void Tokenize(AZStd::string_view in, AZStd::vector& tokens, const char delimiter, bool keepEmptyStrings, bool keepSpaceStrings) { return Tokenize(in, tokens, { &delimiter, 1 }, keepEmptyStrings, keepSpaceStrings); } - void Tokenize(AZStd::string_view in, AZStd::vector& tokens, AZStd::string_view delimiters, bool keepEmptyStrings, bool keepSpaceStrings) + template void Tokenize(AZStd::string_view in, AZStd::vector& tokens, const char delimiter, bool keepEmptyStrings, bool keepSpaceStrings); + template void Tokenize(AZStd::string_view in, AZStd::vector& tokens, const char delimiter, bool keepEmptyStrings, bool keepSpaceStrings); + + template + void Tokenize(AZStd::string_view in, AZStd::vector& tokens, AZStd::string_view delimiters, bool keepEmptyStrings, bool keepSpaceStrings) { auto insertVisitor = [&tokens](AZStd::string_view token) { @@ -771,6 +776,9 @@ namespace AZ::StringFunc }; return TokenizeVisitor(in, insertVisitor, delimiters, keepEmptyStrings, keepSpaceStrings); } + + template void Tokenize(AZStd::string_view in, AZStd::vector& tokens, AZStd::string_view delimiters, bool keepEmptyStrings, bool keepSpaceStrings); + template void Tokenize(AZStd::string_view in, AZStd::vector& tokens, AZStd::string_view delimiters, bool keepEmptyStrings, bool keepSpaceStrings); void TokenizeVisitor(AZStd::string_view in, const TokenVisitor& tokenVisitor, const char delimiter, bool keepEmptyStrings, bool keepSpaceStrings) { @@ -918,8 +926,9 @@ namespace AZ::StringFunc return found; } - - void Tokenize(AZStd::string_view input, AZStd::vector& tokens, const AZStd::vector& delimiters, bool keepEmptyStrings /*= false*/, bool keepSpaceStrings /*= false*/) + + template + void Tokenize(AZStd::string_view input, AZStd::vector& tokens, const AZStd::vector& delimiters, bool keepEmptyStrings /*= false*/, bool keepSpaceStrings /*= false*/) { if (input.empty()) { @@ -939,7 +948,7 @@ namespace AZ::StringFunc } // Take the substring, not including the separator, and increment our offset - AZStd::string nextSubstring = input.substr(offset, nextOffset - offset); + AZStd::string_view nextSubstring = input.substr(offset, nextOffset - offset); if (keepEmptyStrings || keepSpaceStrings || !nextSubstring.empty()) { tokens.push_back(nextSubstring); @@ -948,6 +957,9 @@ namespace AZ::StringFunc offset = nextOffset + delimiters[nextMatch].size(); } } + + template void Tokenize(AZStd::string_view input, AZStd::vector& tokens, const AZStd::vector& delimiters, bool keepEmptyStrings /*= false*/, bool keepSpaceStrings /*= false*/); + template void Tokenize(AZStd::string_view input, AZStd::vector& tokens, const AZStd::vector& delimiters, bool keepEmptyStrings /*= false*/, bool keepSpaceStrings /*= false*/); int ToInt(const char* in) { diff --git a/Code/Framework/AzCore/AzCore/StringFunc/StringFunc.h b/Code/Framework/AzCore/AzCore/StringFunc/StringFunc.h index 55236a0fff..db26b364aa 100644 --- a/Code/Framework/AzCore/AzCore/StringFunc/StringFunc.h +++ b/Code/Framework/AzCore/AzCore/StringFunc/StringFunc.h @@ -258,17 +258,21 @@ namespace AZ bool Strip(AZStd::string& inout, const char* stripCharacters = " ", bool bCaseSensitive = false, bool bStripBeginning = false, bool bStripEnding = false); //! Tokenize - /*! Tokenize a c-string, into a vector of AZStd::string(s) optionally keeping empty string + /*! Tokenize a c-string, into a vector of strings optionally keeping empty string *! and optionally keeping space only strings + *! (The string type may be AZStd::string or AZStd::string_view. New code should use AZStd::string_view for better performance. AZStd::string version is preserved for compatibility.) Example: Tokenize the words of a sentence. StringFunc::Tokenize("Hello World", d, ' '); s[0] == "Hello", s[1] == "World" Example: Tokenize a comma and end line delimited string StringFunc::Tokenize("Hello,World\nHello,World", d, ' '); s[0] == "Hello", s[1] == "World" s[2] == "Hello", s[3] == "World" */ - void Tokenize(AZStd::string_view in, AZStd::vector& tokens, const char delimiter, bool keepEmptyStrings = false, bool keepSpaceStrings = false); - void Tokenize(AZStd::string_view in, AZStd::vector& tokens, AZStd::string_view delimiters = "\\//, \t\n", bool keepEmptyStrings = false, bool keepSpaceStrings = false); - void Tokenize(AZStd::string_view in, AZStd::vector& tokens, const AZStd::vector& delimiters, bool keepEmptyStrings = false, bool keepSpaceStrings = false); + template + void Tokenize(AZStd::string_view in, AZStd::vector& tokens, const char delimiter, bool keepEmptyStrings = false, bool keepSpaceStrings = false); + template + void Tokenize(AZStd::string_view in, AZStd::vector& tokens, AZStd::string_view delimiters = "\\//, \t\n", bool keepEmptyStrings = false, bool keepSpaceStrings = false); + template + void Tokenize(AZStd::string_view in, AZStd::vector& tokens, const AZStd::vector& delimiters, bool keepEmptyStrings = false, bool keepSpaceStrings = false); //! TokenizeVisitor /*! Tokenize a string_view and invoke a handler for each token found. diff --git a/Code/Framework/AzCore/Tests/StringFunc.cpp b/Code/Framework/AzCore/Tests/StringFunc.cpp index dc4bc40e5b..fd6fe7839d 100644 --- a/Code/Framework/AzCore/Tests/StringFunc.cpp +++ b/Code/Framework/AzCore/Tests/StringFunc.cpp @@ -199,7 +199,7 @@ namespace AZ TEST_F(StringFuncTest, Tokenize_SingleDelimeter_Empty) { AZStd::string input = ""; - AZStd::vector tokens; + AZStd::vector tokens; AZ::StringFunc::Tokenize(input.c_str(), tokens, ' '); ASSERT_EQ(tokens.size(), 0); } @@ -207,7 +207,7 @@ namespace AZ TEST_F(StringFuncTest, Tokenize_SingleDelimeter) { AZStd::string input = "a b,c"; - AZStd::vector tokens; + AZStd::vector tokens; AZ::StringFunc::Tokenize(input.c_str(), tokens, ' '); ASSERT_EQ(tokens.size(), 2); @@ -218,7 +218,7 @@ namespace AZ TEST_F(StringFuncTest, Tokenize_MultiDelimeter_Empty) { AZStd::string input = ""; - AZStd::vector tokens; + AZStd::vector tokens; AZ::StringFunc::Tokenize(input.c_str(), tokens, " ,"); ASSERT_EQ(tokens.size(), 0); } @@ -226,7 +226,7 @@ namespace AZ TEST_F(StringFuncTest, Tokenize_MultiDelimeters) { AZStd::string input = " -a +b +c -d-e"; - AZStd::vector tokens; + AZStd::vector tokens; AZ::StringFunc::Tokenize(input.c_str(), tokens, "-+"); ASSERT_EQ(tokens.size(), 5); @@ -240,7 +240,7 @@ namespace AZ TEST_F(StringFuncTest, Tokenize_SubstringDelimeters_Empty) { AZStd::string input = ""; - AZStd::vector tokens; + AZStd::vector tokens; AZStd::vector delimeters = {" -", " +"}; AZ::StringFunc::Tokenize(input.c_str(), tokens, delimeters); ASSERT_EQ(tokens.size(), 0); @@ -249,7 +249,7 @@ namespace AZ TEST_F(StringFuncTest, Tokenize_SubstringDelimeters) { AZStd::string input = " -a +b +c -d-e"; - AZStd::vector tokens; + AZStd::vector tokens; AZStd::vector delimeters = { " -", " +" }; AZ::StringFunc::Tokenize(input.c_str(), tokens, delimeters); @@ -259,6 +259,25 @@ namespace AZ ASSERT_TRUE(tokens[2] == "c"); ASSERT_TRUE(tokens[3] == "d-e"); // Test for something like a guid, which contain typical separator characters } + + TEST_F(StringFuncTest, Tokenize_MultiDelimeters_String) + { + // Test with AZStd::string for backward compatibility. The functions + // use to only work with AZStd::string, and now they are templatized + // to support both AZStd::string and AZStd::string_view (the latter + // being perferred for performance). + + AZStd::string input = " -a +b +c -d-e"; + AZStd::vector tokens; + AZ::StringFunc::Tokenize(input.c_str(), tokens, "-+"); + + ASSERT_EQ(tokens.size(), 5); + ASSERT_TRUE(tokens[0] == "a "); + ASSERT_TRUE(tokens[1] == "b "); + ASSERT_TRUE(tokens[2] == "c "); + ASSERT_TRUE(tokens[3] == "d"); + ASSERT_TRUE(tokens[4] == "e"); + } TEST_F(StringFuncTest, TokenizeVisitor_EmptyString_DoesNotInvokeVisitor) { From 68e4970a2d5e71b4ce038aeeefb481f5257051da Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Wed, 26 Jan 2022 16:47:10 -0800 Subject: [PATCH 11/20] Reverted the new Tokenize function I added, and used TokenizeVisitor instead. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../AzCore/AzCore/StringFunc/StringFunc.cpp | 24 ++++---------- .../AzCore/AzCore/StringFunc/StringFunc.h | 12 +++---- Code/Framework/AzCore/Tests/StringFunc.cpp | 33 ++++--------------- .../Material/MaterialTypeSourceData.cpp | 8 ++++- 4 files changed, 24 insertions(+), 53 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/StringFunc/StringFunc.cpp b/Code/Framework/AzCore/AzCore/StringFunc/StringFunc.cpp index 61a9096d5e..e4d132afef 100644 --- a/Code/Framework/AzCore/AzCore/StringFunc/StringFunc.cpp +++ b/Code/Framework/AzCore/AzCore/StringFunc/StringFunc.cpp @@ -758,17 +758,12 @@ namespace AZ::StringFunc return value; } - template - void Tokenize(AZStd::string_view in, AZStd::vector& tokens, const char delimiter, bool keepEmptyStrings, bool keepSpaceStrings) + void Tokenize(AZStd::string_view in, AZStd::vector& tokens, const char delimiter, bool keepEmptyStrings, bool keepSpaceStrings) { return Tokenize(in, tokens, { &delimiter, 1 }, keepEmptyStrings, keepSpaceStrings); } - - template void Tokenize(AZStd::string_view in, AZStd::vector& tokens, const char delimiter, bool keepEmptyStrings, bool keepSpaceStrings); - template void Tokenize(AZStd::string_view in, AZStd::vector& tokens, const char delimiter, bool keepEmptyStrings, bool keepSpaceStrings); - - template - void Tokenize(AZStd::string_view in, AZStd::vector& tokens, AZStd::string_view delimiters, bool keepEmptyStrings, bool keepSpaceStrings) + + void Tokenize(AZStd::string_view in, AZStd::vector& tokens, AZStd::string_view delimiters, bool keepEmptyStrings, bool keepSpaceStrings) { auto insertVisitor = [&tokens](AZStd::string_view token) { @@ -776,10 +771,7 @@ namespace AZ::StringFunc }; return TokenizeVisitor(in, insertVisitor, delimiters, keepEmptyStrings, keepSpaceStrings); } - - template void Tokenize(AZStd::string_view in, AZStd::vector& tokens, AZStd::string_view delimiters, bool keepEmptyStrings, bool keepSpaceStrings); - template void Tokenize(AZStd::string_view in, AZStd::vector& tokens, AZStd::string_view delimiters, bool keepEmptyStrings, bool keepSpaceStrings); - + void TokenizeVisitor(AZStd::string_view in, const TokenVisitor& tokenVisitor, const char delimiter, bool keepEmptyStrings, bool keepSpaceStrings) { return TokenizeVisitor(in, tokenVisitor, { &delimiter, 1 }, keepEmptyStrings, keepSpaceStrings); @@ -927,8 +919,7 @@ namespace AZ::StringFunc return found; } - template - void Tokenize(AZStd::string_view input, AZStd::vector& tokens, const AZStd::vector& delimiters, bool keepEmptyStrings /*= false*/, bool keepSpaceStrings /*= false*/) + void Tokenize(AZStd::string_view input, AZStd::vector& tokens, const AZStd::vector& delimiters, bool keepEmptyStrings /*= false*/, bool keepSpaceStrings /*= false*/) { if (input.empty()) { @@ -948,7 +939,7 @@ namespace AZ::StringFunc } // Take the substring, not including the separator, and increment our offset - AZStd::string_view nextSubstring = input.substr(offset, nextOffset - offset); + AZStd::string nextSubstring = input.substr(offset, nextOffset - offset); if (keepEmptyStrings || keepSpaceStrings || !nextSubstring.empty()) { tokens.push_back(nextSubstring); @@ -958,9 +949,6 @@ namespace AZ::StringFunc } } - template void Tokenize(AZStd::string_view input, AZStd::vector& tokens, const AZStd::vector& delimiters, bool keepEmptyStrings /*= false*/, bool keepSpaceStrings /*= false*/); - template void Tokenize(AZStd::string_view input, AZStd::vector& tokens, const AZStd::vector& delimiters, bool keepEmptyStrings /*= false*/, bool keepSpaceStrings /*= false*/); - int ToInt(const char* in) { if (!in) diff --git a/Code/Framework/AzCore/AzCore/StringFunc/StringFunc.h b/Code/Framework/AzCore/AzCore/StringFunc/StringFunc.h index db26b364aa..55236a0fff 100644 --- a/Code/Framework/AzCore/AzCore/StringFunc/StringFunc.h +++ b/Code/Framework/AzCore/AzCore/StringFunc/StringFunc.h @@ -258,21 +258,17 @@ namespace AZ bool Strip(AZStd::string& inout, const char* stripCharacters = " ", bool bCaseSensitive = false, bool bStripBeginning = false, bool bStripEnding = false); //! Tokenize - /*! Tokenize a c-string, into a vector of strings optionally keeping empty string + /*! Tokenize a c-string, into a vector of AZStd::string(s) optionally keeping empty string *! and optionally keeping space only strings - *! (The string type may be AZStd::string or AZStd::string_view. New code should use AZStd::string_view for better performance. AZStd::string version is preserved for compatibility.) Example: Tokenize the words of a sentence. StringFunc::Tokenize("Hello World", d, ' '); s[0] == "Hello", s[1] == "World" Example: Tokenize a comma and end line delimited string StringFunc::Tokenize("Hello,World\nHello,World", d, ' '); s[0] == "Hello", s[1] == "World" s[2] == "Hello", s[3] == "World" */ - template - void Tokenize(AZStd::string_view in, AZStd::vector& tokens, const char delimiter, bool keepEmptyStrings = false, bool keepSpaceStrings = false); - template - void Tokenize(AZStd::string_view in, AZStd::vector& tokens, AZStd::string_view delimiters = "\\//, \t\n", bool keepEmptyStrings = false, bool keepSpaceStrings = false); - template - void Tokenize(AZStd::string_view in, AZStd::vector& tokens, const AZStd::vector& delimiters, bool keepEmptyStrings = false, bool keepSpaceStrings = false); + void Tokenize(AZStd::string_view in, AZStd::vector& tokens, const char delimiter, bool keepEmptyStrings = false, bool keepSpaceStrings = false); + void Tokenize(AZStd::string_view in, AZStd::vector& tokens, AZStd::string_view delimiters = "\\//, \t\n", bool keepEmptyStrings = false, bool keepSpaceStrings = false); + void Tokenize(AZStd::string_view in, AZStd::vector& tokens, const AZStd::vector& delimiters, bool keepEmptyStrings = false, bool keepSpaceStrings = false); //! TokenizeVisitor /*! Tokenize a string_view and invoke a handler for each token found. diff --git a/Code/Framework/AzCore/Tests/StringFunc.cpp b/Code/Framework/AzCore/Tests/StringFunc.cpp index fd6fe7839d..760cadb2c6 100644 --- a/Code/Framework/AzCore/Tests/StringFunc.cpp +++ b/Code/Framework/AzCore/Tests/StringFunc.cpp @@ -199,15 +199,15 @@ namespace AZ TEST_F(StringFuncTest, Tokenize_SingleDelimeter_Empty) { AZStd::string input = ""; - AZStd::vector tokens; + AZStd::vector tokens; AZ::StringFunc::Tokenize(input.c_str(), tokens, ' '); ASSERT_EQ(tokens.size(), 0); - } + } TEST_F(StringFuncTest, Tokenize_SingleDelimeter) { AZStd::string input = "a b,c"; - AZStd::vector tokens; + AZStd::vector tokens; AZ::StringFunc::Tokenize(input.c_str(), tokens, ' '); ASSERT_EQ(tokens.size(), 2); @@ -218,7 +218,7 @@ namespace AZ TEST_F(StringFuncTest, Tokenize_MultiDelimeter_Empty) { AZStd::string input = ""; - AZStd::vector tokens; + AZStd::vector tokens; AZ::StringFunc::Tokenize(input.c_str(), tokens, " ,"); ASSERT_EQ(tokens.size(), 0); } @@ -226,7 +226,7 @@ namespace AZ TEST_F(StringFuncTest, Tokenize_MultiDelimeters) { AZStd::string input = " -a +b +c -d-e"; - AZStd::vector tokens; + AZStd::vector tokens; AZ::StringFunc::Tokenize(input.c_str(), tokens, "-+"); ASSERT_EQ(tokens.size(), 5); @@ -240,7 +240,7 @@ namespace AZ TEST_F(StringFuncTest, Tokenize_SubstringDelimeters_Empty) { AZStd::string input = ""; - AZStd::vector tokens; + AZStd::vector tokens; AZStd::vector delimeters = {" -", " +"}; AZ::StringFunc::Tokenize(input.c_str(), tokens, delimeters); ASSERT_EQ(tokens.size(), 0); @@ -249,7 +249,7 @@ namespace AZ TEST_F(StringFuncTest, Tokenize_SubstringDelimeters) { AZStd::string input = " -a +b +c -d-e"; - AZStd::vector tokens; + AZStd::vector tokens; AZStd::vector delimeters = { " -", " +" }; AZ::StringFunc::Tokenize(input.c_str(), tokens, delimeters); @@ -260,25 +260,6 @@ namespace AZ ASSERT_TRUE(tokens[3] == "d-e"); // Test for something like a guid, which contain typical separator characters } - TEST_F(StringFuncTest, Tokenize_MultiDelimeters_String) - { - // Test with AZStd::string for backward compatibility. The functions - // use to only work with AZStd::string, and now they are templatized - // to support both AZStd::string and AZStd::string_view (the latter - // being perferred for performance). - - AZStd::string input = " -a +b +c -d-e"; - AZStd::vector tokens; - AZ::StringFunc::Tokenize(input.c_str(), tokens, "-+"); - - ASSERT_EQ(tokens.size(), 5); - ASSERT_TRUE(tokens[0] == "a "); - ASSERT_TRUE(tokens[1] == "b "); - ASSERT_TRUE(tokens[2] == "c "); - ASSERT_TRUE(tokens[3] == "d"); - ASSERT_TRUE(tokens[4] == "e"); - } - TEST_F(StringFuncTest, TokenizeVisitor_EmptyString_DoesNotInvokeVisitor) { int visitedCount{}; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp index 2504981273..bf24b98ac8 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp @@ -327,7 +327,13 @@ namespace AZ AZStd::vector MaterialTypeSourceData::TokenizeId(AZStd::string_view id) { AZStd::vector tokens; - AzFramework::StringFunc::Tokenize(id, tokens, "./", true, true); + + AzFramework::StringFunc::TokenizeVisitor(id, [&tokens](AZStd::string_view t) + { + tokens.push_back(t); + }, + "./", true, true); + return tokens; } From ed21e97dcd07f8543e707e0c028e3f1d26542bdd Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Wed, 26 Jan 2022 16:55:45 -0800 Subject: [PATCH 12/20] Fixed StringFunc whitespace differences. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- Code/Framework/AzCore/AzCore/StringFunc/StringFunc.cpp | 10 +++++----- Code/Framework/AzCore/Tests/StringFunc.cpp | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/StringFunc/StringFunc.cpp b/Code/Framework/AzCore/AzCore/StringFunc/StringFunc.cpp index e4d132afef..8405424f7d 100644 --- a/Code/Framework/AzCore/AzCore/StringFunc/StringFunc.cpp +++ b/Code/Framework/AzCore/AzCore/StringFunc/StringFunc.cpp @@ -757,12 +757,12 @@ namespace AZ::StringFunc } return value; } - + void Tokenize(AZStd::string_view in, AZStd::vector& tokens, const char delimiter, bool keepEmptyStrings, bool keepSpaceStrings) { return Tokenize(in, tokens, { &delimiter, 1 }, keepEmptyStrings, keepSpaceStrings); } - + void Tokenize(AZStd::string_view in, AZStd::vector& tokens, AZStd::string_view delimiters, bool keepEmptyStrings, bool keepSpaceStrings) { auto insertVisitor = [&tokens](AZStd::string_view token) @@ -771,7 +771,7 @@ namespace AZ::StringFunc }; return TokenizeVisitor(in, insertVisitor, delimiters, keepEmptyStrings, keepSpaceStrings); } - + void TokenizeVisitor(AZStd::string_view in, const TokenVisitor& tokenVisitor, const char delimiter, bool keepEmptyStrings, bool keepSpaceStrings) { return TokenizeVisitor(in, tokenVisitor, { &delimiter, 1 }, keepEmptyStrings, keepSpaceStrings); @@ -918,7 +918,7 @@ namespace AZ::StringFunc return found; } - + void Tokenize(AZStd::string_view input, AZStd::vector& tokens, const AZStd::vector& delimiters, bool keepEmptyStrings /*= false*/, bool keepSpaceStrings /*= false*/) { if (input.empty()) @@ -948,7 +948,7 @@ namespace AZ::StringFunc offset = nextOffset + delimiters[nextMatch].size(); } } - + int ToInt(const char* in) { if (!in) diff --git a/Code/Framework/AzCore/Tests/StringFunc.cpp b/Code/Framework/AzCore/Tests/StringFunc.cpp index 760cadb2c6..dc4bc40e5b 100644 --- a/Code/Framework/AzCore/Tests/StringFunc.cpp +++ b/Code/Framework/AzCore/Tests/StringFunc.cpp @@ -202,7 +202,7 @@ namespace AZ AZStd::vector tokens; AZ::StringFunc::Tokenize(input.c_str(), tokens, ' '); ASSERT_EQ(tokens.size(), 0); - } + } TEST_F(StringFuncTest, Tokenize_SingleDelimeter) { @@ -259,7 +259,7 @@ namespace AZ ASSERT_TRUE(tokens[2] == "c"); ASSERT_TRUE(tokens[3] == "d-e"); // Test for something like a guid, which contain typical separator characters } - + TEST_F(StringFuncTest, TokenizeVisitor_EmptyString_DoesNotInvokeVisitor) { int visitedCount{}; From e0cee13747befb882d405b6ce61d68d153331348 Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Wed, 26 Jan 2022 18:10:02 -0800 Subject: [PATCH 13/20] Code cleanup. Made PropertyDefinition::m_name private. Moved code around for a cleaner diff in MaterialTypeSourceData.h. Added API comments. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../Material/MaterialTypeSourceData.h | 156 +++++++++++------- .../Material/MaterialTypeSourceData.cpp | 15 +- .../MaterialPropertySerializerTests.cpp | 16 +- .../Material/MaterialTypeSourceDataTests.cpp | 20 +-- 4 files changed, 118 insertions(+), 89 deletions(-) diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialTypeSourceData.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialTypeSourceData.h index b5e7eecd0d..0daa0a4c24 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialTypeSourceData.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialTypeSourceData.h @@ -23,8 +23,10 @@ namespace AZ { class MaterialTypeAsset; class MaterialFunctorSourceDataHolder; + class JsonMaterialPropertySerializer; //! This is a simple data structure for serializing in/out material type source files. + //! Note that there may be a mixture of public and private members, as we are gradually introducing a proper API. class MaterialTypeSourceData final { public: @@ -69,15 +71,22 @@ namespace AZ struct PropertyDefinition { + friend class JsonMaterialPropertySerializer; + AZ_CLASS_ALLOCATOR(PropertyDefinition, SystemAllocator, 0); AZ_TYPE_INFO(AZ::RPI::MaterialTypeSourceData::PropertyDefinition, "{E0DB3C0D-75DB-4ADB-9E79-30DA63FA18B7}"); static const float DefaultMin; static const float DefaultMax; static const float DefaultStep; + + PropertyDefinition() = default; - // TODO: Consider making this private and readonly because it is used as the key for lookups and collision validation. - AZStd::string m_name; //!< The name of the property within the property group. The full property ID will be groupName.propertyName. + explicit PropertyDefinition(AZStd::string_view name) : m_name(name) + { + } + + const AZStd::string& GetName() const { return m_name; } MaterialPropertyVisibility m_visibility = MaterialPropertyVisibility::Default; @@ -99,6 +108,51 @@ namespace AZ MaterialPropertyValue m_softMin; MaterialPropertyValue m_softMax; MaterialPropertyValue m_step; + + private: + + // We are gradually moving toward having a more proper API for MaterialTypeSourceData code, but we still some public members + // like above. However, it's important for m_name to be private because it is used as the key for lookups, collision validation, etc. + AZStd::string m_name; //!< The name of the property within the property group. The full property ID will be groupName.propertyName. + }; + + using PropertyList = AZStd::vector>; + + struct PropertySet + { + friend class MaterialTypeSourceData; + + AZ_CLASS_ALLOCATOR(PropertySet, SystemAllocator, 0); + AZ_TYPE_INFO(AZ::RPI::MaterialTypeSourceData::PropertySet, "{BA3AA0E4-C74D-4FD0-ADB2-00B060F06314}"); + + public: + + PropertySet() = default; + AZ_DISABLE_COPY(PropertySet) + + const AZStd::string& GetName() const { return m_name; } + const AZStd::string& GetDisplayName() const { return m_displayName; } + const AZStd::string& GetDescription() const { return m_description; } + const PropertyList& GetProperties() const { return m_properties; } + const AZStd::vector>& GetPropertySets() const { return m_propertySets; } + const AZStd::vector>& GetFunctors() const { return m_materialFunctorSourceData; } + + void SetDisplayName(AZStd::string_view displayName) { m_displayName = displayName; } + void SetDescription(AZStd::string_view description) { m_description = description; } + + PropertyDefinition* AddProperty(AZStd::string_view name); + PropertySet* AddPropertySet(AZStd::string_view name); + + private: + + static PropertySet* AddPropertySet(AZStd::string_view name, AZStd::vector>& toPropertySetList); + + AZStd::string m_name; + AZStd::string m_displayName; + AZStd::string m_description; + PropertyList m_properties; + AZStd::vector> m_propertySets; + AZStd::vector> m_materialFunctorSourceData; }; struct ShaderVariantReferenceData @@ -144,47 +198,6 @@ namespace AZ using VersionUpdates = AZStd::vector; - using PropertyList = AZStd::vector>; - - struct PropertySet - { - friend class MaterialTypeSourceData; - - AZ_CLASS_ALLOCATOR(PropertySet, SystemAllocator, 0); - AZ_TYPE_INFO(AZ::RPI::MaterialTypeSourceData::PropertySet, "{BA3AA0E4-C74D-4FD0-ADB2-00B060F06314}"); - - public: - - PropertySet() = default; - AZ_DISABLE_COPY(PropertySet) - - const AZStd::string& GetName() const { return m_name; } - const AZStd::string& GetDisplayName() const { return m_displayName; } - const AZStd::string& GetDescription() const { return m_description; } - const PropertyList& GetProperties() const { return m_properties; } - const AZStd::vector>& GetPropertySets() const { return m_propertySets; } - const AZStd::vector>& GetFunctors() const { return m_materialFunctorSourceData; } - - void SetDisplayName(AZStd::string_view displayName) { m_displayName = displayName; } - void SetDescription(AZStd::string_view description) { m_description = description; } - - PropertyDefinition* AddProperty(AZStd::string_view name); - PropertySet* AddPropertySet(AZStd::string_view name); - - private: - - static PropertySet* AddPropertySet(AZStd::string_view name, AZStd::vector>& toPropertySetList); - - AZStd::string m_name; - AZStd::string m_displayName; - AZStd::string m_description; - PropertyList m_properties; - AZStd::vector> m_propertySets; - AZStd::vector> m_materialFunctorSourceData; - }; - - using VersionUpdates = AZStd::vector; - struct PropertyLayout { AZ_TYPE_INFO(AZ::RPI::MaterialTypeSourceData::PropertyLayout, "{AE53CF3F-5C3B-44F5-B2FB-306F0EB06393}"); @@ -206,52 +219,69 @@ namespace AZ AZStd::vector> m_propertySets; }; - PropertySet* AddPropertySet(AZStd::string_view propertySetId); - PropertyDefinition* AddProperty(AZStd::string_view propertyId); - - const PropertyLayout& GetPropertyLayout() const { return m_propertyLayout; } - - AZStd::string m_description; //< TODO: Make this private + AZStd::string m_description; //! Version 1 is the default and should not contain any version update. - uint32_t m_version = 1; //< TODO: Make this private - - VersionUpdates m_versionUpdates; //< TODO: Make this private + uint32_t m_version = 1; + + VersionUpdates m_versionUpdates; //! A list of shader variants that are always used at runtime; they cannot be turned off - AZStd::vector m_shaderCollection; //< TODO: Make this private + AZStd::vector m_shaderCollection; //! Material functors provide custom logic and calculations to configure shaders, render states, and more. See MaterialFunctor.h for details. - AZStd::vector> m_materialFunctorSourceData; //< TODO: Make this private + AZStd::vector> m_materialFunctorSourceData; //! Override names for UV input in the shaders of this material type. //! Using ordered map to sort names on loading. using UvNameMap = AZStd::map; - UvNameMap m_uvNameMap; //< TODO: Make this private + UvNameMap m_uvNameMap; //! Copy over UV custom names to the properties enum values. void ResolveUvEnums(); - - const PropertySet* FindPropertySet(AZStd::string_view propertySetId) const; + //! Add a new PropertySet for containing properties or other PropertySets. + //! @param propertySetId The ID of the new property set. To add as a nested PropertySet, use a full path ID like "levelA.levelB.levelC"; in this case a property set "levelA.levelB" must already exist. + //! @return a pointer to the new PropertySet or null if there was a problem (an AZ_Error will be reported). + PropertySet* AddPropertySet(AZStd::string_view propertySetId); + + //! Add a new property to a PropertySet. + //! @param propertyId The ID of the new property, like "layerBlend.factor" or "layer2.roughness.texture". The indicated property set must already exist. + //! @return a pointer to the new PropertyDefinition or null if there was a problem (an AZ_Error will be reported). + PropertyDefinition* AddProperty(AZStd::string_view propertyId); + + //! Return the PropertyLayout containing the tree of property sets and property definitions. + const PropertyLayout& GetPropertyLayout() const { return m_propertyLayout; } + + //! Find the PropertySet with the given ID. + //! @param propertySetId The full ID of a property set to find, like "levelA.levelB.levelC". + //! @return the found PropertySet or null if it doesn't exist. + const PropertySet* FindPropertySet(AZStd::string_view propertySetId) const; + + //! Find the definition for a property with the given ID. + //! @param propertyId The full ID of a property to find, like "baseColor.texture". + //! @return the found PropertyDefinition or null if it doesn't exist. const PropertyDefinition* FindProperty(AZStd::string_view propertyId) const; - //! Tokenizes an ID string like "itemA.itemB.itemC" into a vector like ["itemA", "itemB", "itemC"] + //! Tokenizes an ID string like "itemA.itemB.itemC" into a vector like ["itemA", "itemB", "itemC"]. static AZStd::vector TokenizeId(AZStd::string_view id); - //! Splits an ID string like "itemA.itemB.itemC" into a vector like ["itemA.itemB", "itemC"] + //! Splits an ID string like "itemA.itemB.itemC" into a vector like ["itemA.itemB", "itemC"]. static AZStd::vector SplitId(AZStd::string_view id); - //! Call back function type used with the enumeration functions + //! Call back function type used with the enumeration functions. + //! Return false to terminate the traversal. using EnumeratePropertySetsCallback = AZStd::function; + //! Recursively traverses all of the property sets contained in the material type, executing a callback function for each. //! @return false if the enumeration was terminated early by the callback returning false. bool EnumeratePropertySets(const EnumeratePropertySetsCallback& callback) const; - //! Call back function type used with the numeration functions + //! Call back function type used with the numeration functions. + //! Return false to terminate the traversal. using EnumeratePropertiesCallback = AZStd::function> CreateMaterialTypeAsset(Data::AssetId assetId, AZStd::string_view materialTypeSourceFilePath = "", bool elevateWarnings = true) const; + //! If the data was loaded from an old format file (i.e. where "groups" and "properties" were separate sections), + //! this converts to the new format where properties are listed inside property sets. bool ConvertToNewDataFormat(); private: diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp index bf24b98ac8..046dee9507 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp @@ -160,7 +160,7 @@ namespace AZ { auto propertyIter = AZStd::find_if(m_properties.begin(), m_properties.end(), [name](const AZStd::unique_ptr& existingProperty) { - return existingProperty->m_name == name; + return existingProperty->GetName() == name; }); if (propertyIter != m_properties.end()) @@ -186,8 +186,7 @@ namespace AZ return nullptr; } - m_properties.emplace_back(AZStd::make_unique()); - m_properties.back()->m_name = name; + m_properties.emplace_back(AZStd::make_unique(name)); return m_properties.back().get(); } @@ -195,7 +194,7 @@ namespace AZ { auto iter = AZStd::find_if(m_properties.begin(), m_properties.end(), [name](const AZStd::unique_ptr& existingProperty) { - return existingProperty->m_name == name; + return existingProperty->GetName() == name; }); if (iter != m_properties.end()) @@ -298,7 +297,7 @@ namespace AZ { for (AZStd::unique_ptr& property : propertySet->m_properties) { - if (property->m_name == subPath[0]) + if (property->GetName() == subPath[0]) { return property.get(); } @@ -440,7 +439,7 @@ namespace AZ propertySet = m_propertyLayout.m_propertySets.back().get(); } - PropertyDefinition* newProperty = propertySet->AddProperty(propertyDefinition.m_name); + PropertyDefinition* newProperty = propertySet->AddProperty(propertyDefinition.GetName()); *newProperty = propertyDefinition; } @@ -518,7 +517,7 @@ namespace AZ { // Register the property... - MaterialPropertyId propertyId{propertyNameContext, property->m_name}; + MaterialPropertyId propertyId{propertyNameContext, property->GetName()}; if (!propertyId.IsValid()) { @@ -529,7 +528,7 @@ namespace AZ auto propertySetIter = AZStd::find_if(propertySet->GetPropertySets().begin(), propertySet->GetPropertySets().end(), [&property](const AZStd::unique_ptr& existingPropertySet) { - return existingPropertySet->GetName() == property->m_name; + return existingPropertySet->GetName() == property->GetName(); }); if (propertySetIter != propertySet->GetPropertySets().end()) diff --git a/Gems/Atom/RPI/Code/Tests/Material/MaterialPropertySerializerTests.cpp b/Gems/Atom/RPI/Code/Tests/Material/MaterialPropertySerializerTests.cpp index 9afc05a237..904860d4fc 100644 --- a/Gems/Atom/RPI/Code/Tests/Material/MaterialPropertySerializerTests.cpp +++ b/Gems/Atom/RPI/Code/Tests/Material/MaterialPropertySerializerTests.cpp @@ -45,8 +45,7 @@ namespace JsonSerializationTests AZStd::shared_ptr CreatePartialDefaultInstance() override { - auto result = AZStd::make_shared(); - result->m_name = "testProperty"; + auto result = AZStd::make_shared("testProperty"); result->m_dataType = AZ::RPI::MaterialPropertyDataType::Float; result->m_step = 1.0f; result->m_value = 0.0f; @@ -65,8 +64,7 @@ namespace JsonSerializationTests AZStd::shared_ptr CreateFullySetInstance() override { - auto result = AZStd::make_shared(); - result->m_name = "testProperty"; + auto result = AZStd::make_shared("testProperty"); result->m_description = "description"; result->m_displayName = "display_name"; result->m_dataType = AZ::RPI::MaterialPropertyDataType::Float; @@ -135,7 +133,7 @@ namespace JsonSerializationTests const AZ::RPI::MaterialTypeSourceData::PropertyDefinition& lhs, const AZ::RPI::MaterialTypeSourceData::PropertyDefinition& rhs) override { - if (lhs.m_name != rhs.m_name) { return false; } + if (lhs.GetName() != rhs.GetName()) { return false; } if (lhs.m_description != rhs.m_description) { return false; } if (lhs.m_displayName != rhs.m_displayName) { return false; } if (lhs.m_dataType != rhs.m_dataType) { return false; } @@ -216,7 +214,7 @@ namespace UnitTest EXPECT_EQ(AZ::JsonSerializationResult::Processing::Completed, loadResult.m_jsonResultCode.GetProcessing()); EXPECT_EQ(AZ::JsonSerializationResult::Outcomes::PartialDefaults, loadResult.m_jsonResultCode.GetOutcome()); - EXPECT_EQ("testProperty", propertyData.m_name); + EXPECT_EQ("testProperty", propertyData.GetName()); EXPECT_EQ("Test Property", propertyData.m_displayName); EXPECT_EQ("This is a property description", propertyData.m_description); EXPECT_EQ(MaterialPropertyDataType::Float, propertyData.m_dataType); @@ -851,7 +849,7 @@ namespace UnitTest EXPECT_EQ(AZ::JsonSerializationResult::Tasks::ReadField, loadResult.m_jsonResultCode.GetTask()); EXPECT_EQ(AZ::JsonSerializationResult::Processing::Completed, loadResult.m_jsonResultCode.GetProcessing()); - EXPECT_EQ("testProperty", propertyData.m_name); + EXPECT_EQ("testProperty", propertyData.GetName()); EXPECT_EQ(1, propertyData.m_outputConnections.size()); EXPECT_EQ(MaterialPropertyOutputType::ShaderOption, propertyData.m_outputConnections[0].m_type); @@ -934,7 +932,7 @@ namespace UnitTest EXPECT_EQ(AZ::JsonSerializationResult::Tasks::ReadField, loadResult.m_jsonResultCode.GetTask()); EXPECT_EQ(AZ::JsonSerializationResult::Processing::Completed, loadResult.m_jsonResultCode.GetProcessing()); - EXPECT_EQ(propertyData.m_name, "testProperty"); + EXPECT_EQ(propertyData.GetName(), "testProperty"); EXPECT_EQ(propertyData.m_dataType, MaterialPropertyDataType::Float); EXPECT_EQ(propertyData.m_outputConnections.size(), 0); @@ -964,7 +962,7 @@ namespace UnitTest EXPECT_EQ(AZ::JsonSerializationResult::Tasks::ReadField, loadResult.m_jsonResultCode.GetTask()); EXPECT_EQ(AZ::JsonSerializationResult::Processing::Completed, loadResult.m_jsonResultCode.GetProcessing()); - EXPECT_EQ(propertyData.m_name, "testProperty"); + EXPECT_EQ(propertyData.GetName(), "testProperty"); EXPECT_EQ(propertyData.m_dataType, MaterialPropertyDataType::Float); EXPECT_EQ(propertyData.m_outputConnections.size(), 1); EXPECT_EQ(propertyData.m_outputConnections[0].m_fieldName, "o_foo"); diff --git a/Gems/Atom/RPI/Code/Tests/Material/MaterialTypeSourceDataTests.cpp b/Gems/Atom/RPI/Code/Tests/Material/MaterialTypeSourceDataTests.cpp index f07e1da6c2..2ecf2369f9 100644 --- a/Gems/Atom/RPI/Code/Tests/Material/MaterialTypeSourceDataTests.cpp +++ b/Gems/Atom/RPI/Code/Tests/Material/MaterialTypeSourceDataTests.cpp @@ -1645,12 +1645,12 @@ namespace UnitTest EXPECT_NE(material.FindProperty("groupC.groupD.foo"), nullptr); EXPECT_NE(material.FindProperty("groupC.groupE.bar"), nullptr); - EXPECT_EQ(material.FindProperty("groupA.foo")->m_name, "foo"); - EXPECT_EQ(material.FindProperty("groupA.bar")->m_name, "bar"); - EXPECT_EQ(material.FindProperty("groupB.foo")->m_name, "foo"); - EXPECT_EQ(material.FindProperty("groupB.bar")->m_name, "bar"); - EXPECT_EQ(material.FindProperty("groupC.groupD.foo")->m_name, "foo"); - EXPECT_EQ(material.FindProperty("groupC.groupE.bar")->m_name, "bar"); + EXPECT_EQ(material.FindProperty("groupA.foo")->GetName(), "foo"); + EXPECT_EQ(material.FindProperty("groupA.bar")->GetName(), "bar"); + EXPECT_EQ(material.FindProperty("groupB.foo")->GetName(), "foo"); + EXPECT_EQ(material.FindProperty("groupB.bar")->GetName(), "bar"); + EXPECT_EQ(material.FindProperty("groupC.groupD.foo")->GetName(), "foo"); + EXPECT_EQ(material.FindProperty("groupC.groupE.bar")->GetName(), "bar"); EXPECT_EQ(material.FindProperty("groupA.foo")->m_dataType, MaterialPropertyDataType::Bool); EXPECT_EQ(material.FindProperty("groupA.bar")->m_dataType, MaterialPropertyDataType::Image); EXPECT_EQ(material.FindProperty("groupB.foo")->m_dataType, MaterialPropertyDataType::Float); @@ -1823,10 +1823,10 @@ namespace UnitTest EXPECT_TRUE(material.FindProperty("groupB.foo") != nullptr); EXPECT_TRUE(material.FindProperty("groupB.bar") != nullptr); - EXPECT_EQ(material.FindProperty("groupA.foo")->m_name, "foo"); - EXPECT_EQ(material.FindProperty("groupA.bar")->m_name, "bar"); - EXPECT_EQ(material.FindProperty("groupB.foo")->m_name, "foo"); - EXPECT_EQ(material.FindProperty("groupB.bar")->m_name, "bar"); + EXPECT_EQ(material.FindProperty("groupA.foo")->GetName(), "foo"); + EXPECT_EQ(material.FindProperty("groupA.bar")->GetName(), "bar"); + EXPECT_EQ(material.FindProperty("groupB.foo")->GetName(), "foo"); + EXPECT_EQ(material.FindProperty("groupB.bar")->GetName(), "bar"); EXPECT_EQ(material.FindProperty("groupA.foo")->m_dataType, MaterialPropertyDataType::Bool); EXPECT_EQ(material.FindProperty("groupA.bar")->m_dataType, MaterialPropertyDataType::Image); EXPECT_EQ(material.FindProperty("groupB.foo")->m_dataType, MaterialPropertyDataType::Float); From a4346de65845b26fc827f3e5aea036c27f872f03 Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Wed, 26 Jan 2022 23:54:25 -0800 Subject: [PATCH 14/20] Code cleanup. New comments. Added some non-const find functions to MaterialTypeSourceData. Fixed places where I forgot to change m_name to GetName(). Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../Material/MaterialTypeSourceData.h | 16 ++++++++-- .../Material/MaterialTypeSourceData.cpp | 30 ++++++++++++++++--- .../Code/Tests/Common/ErrorMessageFinder.cpp | 2 +- .../Code/Source/Util/MaterialPropertyUtil.cpp | 2 +- .../Code/Source/Document/MaterialDocument.cpp | 12 ++++---- .../MaterialInspector/MaterialInspector.cpp | 2 +- .../EditorMaterialComponentInspector.cpp | 3 +- .../Material/EditorMaterialComponentUtil.cpp | 7 ++--- 8 files changed, 54 insertions(+), 20 deletions(-) diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialTypeSourceData.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialTypeSourceData.h index 0daa0a4c24..6c439195f1 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialTypeSourceData.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialTypeSourceData.h @@ -140,7 +140,14 @@ namespace AZ void SetDisplayName(AZStd::string_view displayName) { m_displayName = displayName; } void SetDescription(AZStd::string_view description) { m_description = description; } + //! Add a new property to this PropertySet. + //! @param name a unique for the property. Must be a C-style identifier. + //! @return the new PropertyDefinition, or null if the name was not valid. PropertyDefinition* AddProperty(AZStd::string_view name); + + //! Add a new nested PropertySet to this PropertySet. + //! @param name a unique for the property set. Must be a C-style identifier. + //! @return the new PropertySet, or null if the name was not valid. PropertySet* AddPropertySet(AZStd::string_view name); private: @@ -213,9 +220,9 @@ namespace AZ AZStd::vector m_groupsOld; //! [Deprecated] Use m_propertySets instead - //! Collection of all available user-facing properties AZStd::map> m_propertiesOld; - + + //! Collection of all available user-facing properties AZStd::vector> m_propertySets; }; @@ -257,11 +264,13 @@ namespace AZ //! @param propertySetId The full ID of a property set to find, like "levelA.levelB.levelC". //! @return the found PropertySet or null if it doesn't exist. const PropertySet* FindPropertySet(AZStd::string_view propertySetId) const; + PropertySet* FindPropertySet(AZStd::string_view propertySetId); //! Find the definition for a property with the given ID. //! @param propertyId The full ID of a property to find, like "baseColor.texture". //! @return the found PropertyDefinition or null if it doesn't exist. const PropertyDefinition* FindProperty(AZStd::string_view propertyId) const; + PropertyDefinition* FindProperty(AZStd::string_view propertyId); //! Tokenizes an ID string like "itemA.itemB.itemC" into a vector like ["itemA", "itemB", "itemC"]. static AZStd::vector TokenizeId(AZStd::string_view id); @@ -300,7 +309,10 @@ namespace AZ private: const PropertySet* FindPropertySet(AZStd::array_view parsedPropertySetId, AZStd::array_view> inPropertySetList) const; + PropertySet* FindPropertySet(AZStd::array_view parsedPropertySetId, AZStd::array_view> inPropertySetList); + const PropertyDefinition* FindProperty(AZStd::array_view parsedPropertyId, AZStd::array_view> inPropertySetList) const; + PropertyDefinition* FindProperty(AZStd::array_view parsedPropertyId, AZStd::array_view> inPropertySetList); // Function overloads for recursion, returns false to indicate that recursion should end. bool EnumeratePropertySets(const EnumeratePropertySetsCallback& callback, AZStd::string propertyIdContext, const AZStd::vector>& inPropertySetList) const; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp index 046dee9507..032d36636e 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp @@ -215,7 +215,7 @@ namespace AZ return PropertySet::AddPropertySet(propertySetId, m_propertyLayout.m_propertySets); } - PropertySet* parentPropertySet = const_cast(const_cast(this)->FindPropertySet(splitPropertySetId[0])); + PropertySet* parentPropertySet = FindPropertySet(splitPropertySetId[0]); if (!parentPropertySet) { @@ -235,8 +235,8 @@ namespace AZ AZ_Error("Material source data", false, "Property id '%.*s' is invalid. Properties must be added to a PropertySet (i.e. \"general.%.*s\").", AZ_STRING_ARG(propertyId), AZ_STRING_ARG(propertyId)); return nullptr; } - - PropertySet* parentPropertySet = const_cast(const_cast(this)->FindPropertySet(splitPropertyId[0])); + + PropertySet* parentPropertySet = FindPropertySet(splitPropertyId[0]); if (!parentPropertySet) { @@ -276,12 +276,23 @@ namespace AZ return nullptr; } + + MaterialTypeSourceData::PropertySet* MaterialTypeSourceData::FindPropertySet(AZStd::array_view parsedPropertySetId, AZStd::array_view> inPropertySetList) + { + return const_cast(const_cast(this)->FindPropertySet(parsedPropertySetId, inPropertySetList)); + } const MaterialTypeSourceData::PropertySet* MaterialTypeSourceData::FindPropertySet(AZStd::string_view propertySetId) const { AZStd::vector tokens = TokenizeId(propertySetId); return FindPropertySet(tokens, m_propertyLayout.m_propertySets); } + + MaterialTypeSourceData::PropertySet* MaterialTypeSourceData::FindPropertySet(AZStd::string_view propertySetId) + { + AZStd::vector tokens = TokenizeId(propertySetId); + return FindPropertySet(tokens, m_propertyLayout.m_propertySets); + } const MaterialTypeSourceData::PropertyDefinition* MaterialTypeSourceData::FindProperty( AZStd::array_view parsedPropertyId, @@ -316,12 +327,23 @@ namespace AZ return nullptr; } + + MaterialTypeSourceData::PropertyDefinition* MaterialTypeSourceData::FindProperty(AZStd::array_view parsedPropertyId, AZStd::array_view> inPropertySetList) + { + return const_cast(const_cast(this)->FindProperty(parsedPropertyId, inPropertySetList)); + } const MaterialTypeSourceData::PropertyDefinition* MaterialTypeSourceData::FindProperty(AZStd::string_view propertyId) const { AZStd::vector tokens = TokenizeId(propertyId); return FindProperty(tokens, m_propertyLayout.m_propertySets); } + + MaterialTypeSourceData::PropertyDefinition* MaterialTypeSourceData::FindProperty(AZStd::string_view propertyId) + { + AZStd::vector tokens = TokenizeId(propertyId); + return FindProperty(tokens, m_propertyLayout.m_propertySets); + } AZStd::vector MaterialTypeSourceData::TokenizeId(AZStd::string_view id) { @@ -428,7 +450,7 @@ namespace AZ const auto& propertyList = propertyListItr->second; for (auto& propertyDefinition : propertyList) { - PropertySet* propertySet = const_cast(const_cast(this)->FindPropertySet(group.m_name)); + PropertySet* propertySet = FindPropertySet(group.m_name); if (!propertySet) { diff --git a/Gems/Atom/RPI/Code/Tests/Common/ErrorMessageFinder.cpp b/Gems/Atom/RPI/Code/Tests/Common/ErrorMessageFinder.cpp index 06cdb073e9..fa88f145a6 100644 --- a/Gems/Atom/RPI/Code/Tests/Common/ErrorMessageFinder.cpp +++ b/Gems/Atom/RPI/Code/Tests/Common/ErrorMessageFinder.cpp @@ -84,7 +84,7 @@ namespace UnitTest } } - m_checked = true; + m_checked = true; } void ErrorMessageFinder::ReportFailure(const AZStd::string& failureMessage) diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Util/MaterialPropertyUtil.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Util/MaterialPropertyUtil.cpp index 568e701e3c..377fd46d69 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Util/MaterialPropertyUtil.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Util/MaterialPropertyUtil.cpp @@ -78,7 +78,7 @@ namespace AtomToolsFramework void ConvertToPropertyConfig(AtomToolsFramework::DynamicPropertyConfig& propertyConfig, const AZ::RPI::MaterialTypeSourceData::PropertyDefinition& propertyDefinition) { propertyConfig.m_dataType = ConvertToEditableType(propertyDefinition.m_dataType); - propertyConfig.m_name = propertyDefinition.m_name; + propertyConfig.m_name = propertyDefinition.GetName(); propertyConfig.m_displayName = propertyDefinition.m_displayName; propertyConfig.m_description = propertyDefinition.m_description; propertyConfig.m_defaultValue = ConvertToEditableType(propertyDefinition.m_value); diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp index c9ae970215..aa14b02bbe 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp @@ -587,7 +587,7 @@ namespace MaterialEditor // populate sourceData with properties that meet the filter m_materialTypeSourceData.EnumerateProperties([&](const AZStd::string& propertyIdContext, const auto& propertyDefinition) { - Name propertyId{propertyIdContext + propertyDefinition->m_name}; + Name propertyId{propertyIdContext + propertyDefinition->GetName()}; const auto it = m_properties.find(propertyId); if (it != m_properties.end() && propertyFilter(it->second)) @@ -603,8 +603,8 @@ namespace MaterialEditor } // 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); - sourceData.m_properties[groupName][propertyDefinition->m_name].m_value = propertyValue; + const AZStd::string groupName = propertyId.GetStringView().substr(0, propertyId.GetStringView().size() - propertyDefinition->GetName().size() - 1); + sourceData.m_properties[groupName][propertyDefinition->GetName()].m_value = propertyValue; } } return true; @@ -788,7 +788,7 @@ namespace MaterialEditor for (const auto& propertyDefinition : propertySet->GetProperties()) { // Assign id before conversion so it can be used in dynamic description - propertyConfig.m_id = propertyIdContext + propertySet->GetName() + "." + propertyDefinition->m_name; + propertyConfig.m_id = propertyIdContext + propertySet->GetName() + "." + propertyDefinition->GetName(); const auto& propertyIndex = m_materialAsset->GetMaterialPropertiesLayout()->FindPropertyIndex(propertyConfig.m_id); const bool propertyIndexInBounds = propertyIndex.IsValid() && propertyIndex.GetIndex() < m_materialAsset->GetPropertyValues().size(); @@ -877,6 +877,7 @@ namespace MaterialEditor m_properties[propertyConfig.m_id] = AtomToolsFramework::DynamicProperty(propertyConfig); } + // Add material functors that are in the top-level functors list. const MaterialFunctorSourceData::EditorContext editorContext = MaterialFunctorSourceData::EditorContext(m_materialSourceData.m_materialType, m_materialAsset->GetMaterialPropertiesLayout()); for (Ptr functorData : m_materialTypeSourceData.m_materialFunctorSourceData) @@ -897,7 +898,8 @@ namespace MaterialEditor return false; } } - + + // Add any material functors that are located inside each property set. bool enumerateResult = m_materialTypeSourceData.EnumeratePropertySets( [this](const AZStd::string&, const MaterialTypeSourceData::PropertySet* propertySet) { diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.cpp index 98e4ede2a9..3208683bf0 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.cpp @@ -185,7 +185,7 @@ namespace MaterialEditor AtomToolsFramework::DynamicProperty property; AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult( property, m_documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::GetProperty, - AZ::RPI::MaterialPropertyId(groupName, propertyDefinition->m_name)); + AZ::RPI::MaterialPropertyId(groupName, propertyDefinition->GetName())); group.m_properties.push_back(property); } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp index 9e990e2fc8..37fba346b8 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp @@ -307,7 +307,7 @@ namespace AZ AtomToolsFramework::DynamicPropertyConfig propertyConfig; // Assign id before conversion so it can be used in dynamic description - propertyConfig.m_id = AZ::RPI::MaterialPropertyId(groupName, propertyDefinition->m_name); + propertyConfig.m_id = AZ::RPI::MaterialPropertyId(groupName, propertyDefinition->GetName()); AtomToolsFramework::ConvertToPropertyConfig(propertyConfig, *propertyDefinition.get()); @@ -323,7 +323,6 @@ namespace AZ // 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); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp index d6342a2507..62982e4b4d 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp @@ -115,7 +115,7 @@ namespace AZ bool result = true; editData.m_materialTypeSourceData.EnumerateProperties([&](const AZStd::string& propertyIdContext, const AZ::RPI::MaterialTypeSourceData::PropertyDefinition* propertyDefinition) { - AZ::Name propertyId(propertyIdContext + propertyDefinition->m_name); + AZ::Name propertyId(propertyIdContext + propertyDefinition->GetName()); const AZ::RPI::MaterialPropertyIndex propertyIndex = editData.m_materialAsset->GetMaterialPropertiesLayout()->FindPropertyIndex(propertyId); @@ -148,10 +148,9 @@ 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; + const AZStd::string groupName = propertyId.GetStringView().substr(0, propertyId.GetStringView().size() - propertyDefinition->GetName().size() - 1); + exportData.m_properties[groupName][propertyDefinition->GetName()].m_value = propertyValue; return true; }); From 5e2bf1a46822a613d4db7ae8736c77f96345b99d Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Thu, 27 Jan 2022 14:14:50 -0800 Subject: [PATCH 15/20] Reverted changes to most of the material type files. I'll update those in a separate PR. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../Special/ShadowCatcher.materialtype | 58 +- .../Materials/Types/EnhancedPBR.materialtype | 2763 +++++++++-------- .../Assets/Materials/Types/Skin.materialtype | 1846 +++++------ .../Materials/Types/StandardPBR.materialtype | 1907 ++++++------ .../Materials/Types/AutoBrick.materialtype | 327 +- 5 files changed, 3456 insertions(+), 3445 deletions(-) diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Special/ShadowCatcher.materialtype b/Gems/Atom/Feature/Common/Assets/Materials/Special/ShadowCatcher.materialtype index 973f8b2147..d05f03c9a9 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Special/ShadowCatcher.materialtype +++ b/Gems/Atom/Feature/Common/Assets/Materials/Special/ShadowCatcher.materialtype @@ -2,40 +2,38 @@ "description": "Base material for the reflection probe visualization model.", "version": 1, "propertyLayout": { - "propertySets": [ - { - "name": "settings", - "properties": [ - { - "name": "opacity", - "displayName": "Opacity", - "description": "Opacity of the shadow effect.", - "type": "Float", - "defaultValue": 0.5, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_opacity" - } - }, - { - "name": "shadeAll", - "displayName": "Shade All", - "description": "Shades the entire geometry with the shadow color, not just what's in shadow. For debugging.", - "type": "Bool", - "connection": { - "type": "ShaderOption", - "name": "o_shadeAll" - } + "properties": { + "settings": [ + { + "name": "opacity", + "displayName": "Opacity", + "description": "Opacity of the shadow effect.", + "type": "Float", + "defaultValue": 0.5, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_opacity" } - ] - } - ] + }, + { + "name": "shadeAll", + "displayName": "Shade All", + "description": "Shades the entire geometry with the shadow color, not just what's in shadow. For debugging.", + "type": "Bool", + "connection": { + "type": "ShaderOption", + "name": "o_shadeAll" + } + } + ] + } }, "shaders": [ { "file": "ShadowCatcher.shader" } ] -} \ No newline at end of file +} + diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR.materialtype b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR.materialtype index a6af04fb89..eee9a0fc88 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR.materialtype +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR.materialtype @@ -10,1453 +10,1456 @@ } ], "propertyLayout": { - "propertySets": [ + "groups": [ { "name": "baseColor", "displayName": "Base Color", - "description": "Properties for configuring the surface reflected color for dielectrics or reflectance values for metals.", - "properties": [ - { - "name": "color", - "displayName": "Color", - "description": "Color is displayed as sRGB but the values are stored as linear color.", - "type": "Color", - "defaultValue": [ 1.0, 1.0, 1.0 ], - "connection": { - "type": "ShaderInput", - "name": "m_baseColor" - } - }, - { - "name": "factor", - "displayName": "Factor", - "description": "Strength factor for scaling the base color values. Zero (0.0) is black, white (1.0) is full color.", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_baseColorFactor" - } - }, - { - "name": "textureMap", - "displayName": "Texture", - "description": "Base color texture map", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_baseColorMap" - } - }, - { - "name": "useTexture", - "displayName": "Use Texture", - "description": "Whether to use the texture.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "textureMapUv", - "displayName": "UV", - "description": "Base color map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_baseColorMapUvIndex" - } - }, - { - "name": "textureBlendMode", - "displayName": "Texture Blend Mode", - "description": "Selects the equation to use when combining Color, Factor, and Texture.", - "type": "Enum", - "enumValues": [ "Multiply", "LinearLight", "Lerp", "Overlay" ], - "defaultValue": "Multiply", - "connection": { - "type": "ShaderOption", - "name": "o_baseColorTextureBlendMode" - } - } - ] + "description": "Properties for configuring the surface reflected color for dielectrics or reflectance values for metals." }, { "name": "metallic", "displayName": "Metallic", - "description": "Properties for configuring whether the surface is metallic or not.", - "properties": [ - { - "name": "factor", - "displayName": "Factor", - "description": "This value is linear, black is non-metal and white means raw metal.", - "type": "Float", - "defaultValue": 0.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_metallicFactor" - } - }, - { - "name": "textureMap", - "displayName": "Texture", - "description": "", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_metallicMap" - } - }, - { - "name": "useTexture", - "displayName": "Use Texture", - "description": "Whether to use the texture, or just default to the Factor value.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "textureMapUv", - "displayName": "UV", - "description": "Metallic map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_metallicMapUvIndex" - } - } - ] + "description": "Properties for configuring whether the surface is metallic or not." }, { "name": "roughness", "displayName": "Roughness", - "description": "Properties for configuring how rough the surface appears.", - "properties": [ - { - "name": "textureMap", - "displayName": "Texture", - "description": "Texture for defining surface roughness.", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_roughnessMap" - } - }, - { - "name": "useTexture", - "displayName": "Use Texture", - "description": "Whether to use the texture, or just default to the Factor value.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "textureMapUv", - "displayName": "UV", - "description": "Roughness map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_roughnessMapUvIndex" - } - }, - { - // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. - "name": "lowerBound", - "displayName": "Lower Bound", - "description": "The roughness value that corresponds to black in the texture.", - "type": "Float", - "defaultValue": 0.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_roughnessLowerBound" - } - }, - { - // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. - "name": "upperBound", - "displayName": "Upper Bound", - "description": "The roughness value that corresponds to white in the texture.", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_roughnessUpperBound" - } - }, - { - // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. - "name": "factor", - "displayName": "Factor", - "description": "Controls the roughness value", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_roughnessFactor" - } - } - ] + "description": "Properties for configuring how rough the surface appears." }, { "name": "specularF0", "displayName": "Specular Reflectance f0", - "description": "The constant f0 represents the specular reflectance at normal incidence (Fresnel 0 Angle). Used to adjust reflectance of non-metal surfaces.", - "properties": [ - { - "name": "factor", - "displayName": "Factor", - "description": "The default IOR is 1.5, which gives you 0.04 (4% of light reflected at 0 degree angle for dielectric materials). F0 values lie in the range 0-0.08, so that is why the default F0 slider is set on 0.5.", - "type": "Float", - "defaultValue": 0.5, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_specularF0Factor" - } - }, - { - "name": "textureMap", - "displayName": "Texture", - "description": "Texture for defining surface reflectance.", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_specularF0Map" - } - }, - { - "name": "useTexture", - "displayName": "Use Texture", - "description": "Whether to use the texture, or just default to the Factor value.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "textureMapUv", - "displayName": "UV", - "description": "Specular reflection map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_specularF0MapUvIndex" - } - }, - // Consider moving this to the "general" group to be consistent with StandardMultilayerPBR - { - "name": "enableMultiScatterCompensation", - "displayName": "Multiscattering Compensation", - "description": "Whether to enable multiple scattering compensation.", - "type": "Bool", - "connection": { - "type": "ShaderOption", - "name": "o_specularF0_enableMultiScatterCompensation" - } - } - ] + "description": "The constant f0 represents the specular reflectance at normal incidence (Fresnel 0 Angle). Used to adjust reflectance of non-metal surfaces." }, { "name": "normal", "displayName": "Normal", - "description": "Properties related to configuring surface normal.", - "properties": [ - { - "name": "textureMap", - "displayName": "Texture", - "description": "Texture for defining surface normal direction.", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_normalMap" - } - }, - { - "name": "useTexture", - "displayName": "Use Texture", - "description": "Whether to use the texture, or just rely on vertex normals.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "textureMapUv", - "displayName": "UV", - "description": "Normal map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_normalMapUvIndex" - } - }, - { - "name": "flipX", - "displayName": "Flip X Channel", - "description": "Flip tangent direction for this normal map.", - "type": "Bool", - "defaultValue": false, - "connection": { - "type": "ShaderInput", - "name": "m_flipNormalX" - } - }, - { - "name": "flipY", - "displayName": "Flip Y Channel", - "description": "Flip bitangent direction for this normal map.", - "type": "Bool", - "defaultValue": false, - "connection": { - "type": "ShaderInput", - "name": "m_flipNormalY" - } - }, - { - "name": "factor", - "displayName": "Factor", - "description": "Strength factor for scaling the values", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "softMax": 2.0, - "connection": { - "type": "ShaderInput", - "name": "m_normalFactor" - } - } - ] + "description": "Properties related to configuring surface normal." }, { "name": "detailLayerGroup", "displayName": "Detail Layer", - "description": "Properties for Fine Details Layer.", - "properties": [ - { - "name": "enableDetailLayer", - "displayName": "Enable Detail Layer", - "description": "Enable detail layer for fine details and scratches", - "type": "Bool", - "defaultValue": false - }, - { - "name": "blendDetailFactor", - "displayName": "Blend Factor", - "description": "Scales the overall impact of the detail layer.", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_detail_blendFactor" - } - }, - { - "name": "blendDetailMask", - "displayName": "Blend Mask", - "description": "Detailed blend mask for application of the detail maps.", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_detail_blendMask_texture" - } - }, - { - "name": "enableDetailMaskTexture", - "displayName": " Use Texture", - "description": "Enable detail blend mask", - "type": "Bool", - "defaultValue": true - }, - { - "name": "blendDetailMaskUv", - "displayName": " Blend Mask UV", - "description": "Which UV set to use for sampling the detail blend mask", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_detail_blendMask_uvIndex" - } - }, - { - "name": "textureMapUv", - "displayName": "Detail Map UVs", - "description": "Which UV set to use for detail map sampling", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_detail_allMapsUvIndex" - } - }, - { - "name": "enableBaseColor", - "displayName": "Enable Base Color", - "description": "Enable detail blending for base color", - "type": "Bool", - "defaultValue": false - }, - { - "name": "baseColorDetailMap", - "displayName": " Texture", - "description": "Detailed Base Color Texture", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_detail_baseColor_texture" - } - }, - { - "name": "baseColorDetailBlend", - "displayName": " Blend Factor", - "description": "How much to blend the detail layer into the base color.", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_detail_baseColor_factor" - } - }, - { - "name": "enableNormals", - "displayName": "Enable Normal", - "description": "Enable detail normal map to be used for fine detail normal such as scratches and small dents", - "type": "Bool", - "defaultValue": false - }, - { - "name": "normalDetailStrength", - "displayName": " Factor", - "description": "Strength factor for scaling the Detail Normal", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "softMax": 2.0, - "connection": { - "type": "ShaderInput", - "name": "m_detail_normal_factor" - } - }, - { - "name": "normalDetailMap", - "displayName": " Texture", - "description": "Detailed Normal map", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_detail_normal_texture" - } - }, - { - "name": "normalDetailFlipX", - "displayName": " Flip X Channel", - "description": "Flip Detail tangent direction for this normal map.", - "type": "Bool", - "defaultValue": false, - "connection": { - "type": "ShaderInput", - "name": "m_detail_normal_flipX" - } - }, - { - "name": "normalDetailFlipY", - "displayName": " Flip Y Channel", - "description": "Flip Detail bitangent direction for this normal map.", - "type": "Bool", - "defaultValue": false, - "connection": { - "type": "ShaderInput", - "name": "m_detail_normal_flipY" - } - } - ] + "description": "Properties for Fine Details Layer." }, { "name": "detailUV", "displayName": "Detail Layer UV", - "description": "Properties for modifying detail layer UV.", - "properties": [ - { - "name": "center", - "displayName": "Center", - "description": "Center point for scaling and rotation transformations.", - "type": "vector2", - "vectorLabels": [ "U", "V" ], - "defaultValue": [ 0.5, 0.5 ] - }, - { - "name": "tileU", - "displayName": "Tile U", - "description": "Scales texture coordinates in V.", - "type": "float", - "defaultValue": 1.0, - "step": 0.1 - }, - { - "name": "tileV", - "displayName": "Tile V", - "description": "Scales texture coordinates in V.", - "type": "float", - "defaultValue": 1.0, - "step": 0.1 - }, - { - "name": "offsetU", - "displayName": "Offset U", - "description": "Offsets texture coordinates in the U direction.", - "type": "float", - "defaultValue": 0.0, - "min": -1.0, - "max": 1.0 - }, - { - "name": "offsetV", - "displayName": "Offset V", - "description": "Offsets texture coordinates in the V direction.", - "type": "float", - "defaultValue": 0.0, - "min": -1.0, - "max": 1.0 - }, - { - "name": "rotateDegrees", - "displayName": "Rotate", - "description": "Rotates the texture coordinates (degrees).", - "type": "float", - "defaultValue": 0.0, - "min": -180.0, - "max": 180.0, - "step": 1.0 - }, - { - "name": "scale", - "displayName": "Scale", - "description": "Scales texture coordinates in both U and V.", - "type": "float", - "defaultValue": 1.0, - "step": 0.1 - } - ] + "description": "Properties for modifying detail layer UV." }, { "name": "anisotropy", "displayName": "Anisotropic Material Response", - "description": "How much is this material response anisotropic.", - "properties": [ - { - "name": "enableAnisotropy", - "displayName": "Enable Anisotropy", - "description": "Enable anisotropic surface response for non uniform reflection along the axis", - "type": "Bool", - "defaultValue": false, - "connection": { - "type": "ShaderOption", - "name": "o_enableAnisotropy" - } - }, - { - "name": "factor", - "displayName": "Anisotropy Factor", - "description": "Strength factor for the anisotropy: negative = along v, positive = along u", - "type": "Float", - "defaultValue": 0.0, - "min": -0.95, - "max": 0.95, - "connection": { - "type": "ShaderInput", - "name": "m_anisotropicFactor" - } - }, - { - "name": "anisotropyAngle", - "displayName": "Anisotropy Angle", - "description": "Anisotropy direction of major reflection axis: 0 = 0 degrees, 1.0 = 180 degrees", - "type": "Float", - "defaultValue": 0.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_anisotropicAngle" - } - } - ] + "description": "How much is this material response anisotropic." }, { "name": "occlusion", "displayName": "Occlusion", - "description": "Properties for baked textures that represent geometric occlusion of light.", - "properties": [ - { - "name": "diffuseTextureMap", - "displayName": "Diffuse AO", - "description": "Texture for defining occlusion area for diffuse ambient lighting.", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_diffuseOcclusionMap" - } - }, - { - "name": "diffuseUseTexture", - "displayName": " Use Texture", - "description": "Whether to use the Diffuse AO map.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "diffuseTextureMapUv", - "displayName": " UV", - "description": "Diffuse AO map UV set.", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_diffuseOcclusionMapUvIndex" - } - }, - { - "name": "diffuseFactor", - "displayName": " Factor", - "description": "Strength factor for scaling the values of Diffuse AO", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "softMax": 2.0, - "connection": { - "type": "ShaderInput", - "name": "m_diffuseOcclusionFactor" - } - }, - { - "name": "specularTextureMap", - "displayName": "Specular Cavity", - "description": "Texture for defining occlusion area for specular lighting.", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_specularOcclusionMap" - } - }, - { - "name": "specularUseTexture", - "displayName": " Use Texture", - "description": "Whether to use the Specular Cavity map.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "specularTextureMapUv", - "displayName": " UV", - "description": "Specular Cavity map UV set.", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_specularOcclusionMapUvIndex" - } - }, - { - "name": "specularFactor", - "displayName": " Factor", - "description": "Strength factor for scaling the values of Specular Cavity", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "softMax": 2.0, - "connection": { - "type": "ShaderInput", - "name": "m_specularOcclusionFactor" - } - } - ] + "description": "Properties for baked textures that represent geometric occlusion of light." }, { "name": "emissive", "displayName": "Emissive", - "description": "Properties to add light emission, independent of other lights in the scene.", - "properties": [ - { - "name": "enable", - "displayName": "Enable", - "description": "Enable the emissive group", - "type": "Bool", - "defaultValue": false - }, - { - "name": "unit", - "displayName": "Units", - "description": "The photometric units of the Intensity property.", - "type": "Enum", - "enumValues": ["Ev100"], - "defaultValue": "Ev100" - }, - { - "name": "color", - "displayName": "Color", - "description": "Color is displayed as sRGB but the values are stored as linear color.", - "type": "Color", - "defaultValue": [ 1.0, 1.0, 1.0 ], - "connection": { - "type": "ShaderInput", - "name": "m_emissiveColor" - } - }, - { - "name": "intensity", - "displayName": "Intensity", - "description": "The amount of energy emitted.", - "type": "Float", - "defaultValue": 4, - "min": -10, - "max": 20, - "softMin": -6, - "softMax": 16 - }, - { - "name": "textureMap", - "displayName": "Texture", - "description": "Texture for defining emissive area.", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_emissiveMap" - } - }, - { - "name": "useTexture", - "displayName": "Use Texture", - "description": "Whether to use the texture.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "textureMapUv", - "displayName": "UV", - "description": "Emissive map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_emissiveMapUvIndex" - } - } - ] + "description": "Properties to add light emission, independent of other lights in the scene." }, { "name": "subsurfaceScattering", "displayName": "Subsurface Scattering", - "description": "Properties for configuring subsurface scattering effects.", - "properties": [ - { - "name": "enableSubsurfaceScattering", - "displayName": "Subsurface Scattering", - "description": "Enable subsurface scattering feature, this will disable metallic and parallax mapping property due to incompatibility", - "type": "Bool", - "defaultValue": false, - "connection": { - "type": "ShaderOption", - "name": "o_enableSubsurfaceScattering" - } - }, - { - "name": "subsurfaceScatterFactor", - "displayName": " Factor", - "description": "Strength factor for scaling percentage of subsurface scattering effect applied", - "type": "float", - "defaultValue": 1.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_subsurfaceScatteringFactor" - } - }, - { - "name": "influenceMap", - "displayName": " Influence Map", - "description": "Texture for controlling the strength of subsurface scattering", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_subsurfaceScatteringInfluenceMap" - } - }, - { - "name": "useInfluenceMap", - "displayName": " Use Influence Map", - "description": "Whether to use the influence map.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "influenceMapUv", - "displayName": " UV", - "description": "Influence map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_subsurfaceScatteringInfluenceMapUvIndex" - } - }, - { - "name": "scatterColor", - "displayName": " Scatter color", - "description": "Color of volume light traveled through", - "type": "Color", - "defaultValue": [ 1.0, 0.27, 0.13 ] - }, - { - "name": "scatterDistance", - "displayName": " Scatter distance", - "description": "How far light traveled inside the volume", - "type": "float", - "defaultValue": 8, - "min": 0.0, - "softMax": 20.0 - }, - { - "name": "quality", - "displayName": " Quality", - "description": "How much percent of sample will be used for each pixel, more samples improve quality and reduce artifacts, especially when the scatter distance is relatively large, but slow down computation time, 1.0 = full set 200 samples per pixel", - "type": "float", - "defaultValue": 0.4, - "min": 0.2, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_subsurfaceScatteringQuality" - } - }, - { - "name": "transmissionMode", - "displayName": "Transmission", - "description": "Algorithm used for calculating transmission", - "type": "Enum", - "enumValues": [ "None", "ThickObject", "ThinObject" ], - "defaultValue": "None", - "connection": { - "type": "ShaderOption", - "name": "o_transmission_mode" - } - }, - { - "name": "thickness", - "displayName": " Thickness", - "description": "Normalized global thickness, the maxima between this value (multiplied by thickness map if enabled) and thickness from shadow map (if applicable) will be used as final thickness of pixel", - "type": "float", - "defaultValue": 0.5, - "min": 0.0, - "max": 1.0 - }, - { - "name": "thicknessMap", - "displayName": " Thickness Map", - "description": "Texture for controlling per pixel thickness", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_transmissionThicknessMap" - } - }, - { - "name": "useThicknessMap", - "displayName": " Use Thickness Map", - "description": "Whether to use the thickness map", - "type": "Bool", - "defaultValue": true - }, - { - "name": "thicknessMapUv", - "displayName": " UV", - "description": "Thickness map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_transmissionThicknessMapUvIndex" - } - }, - { - "name": "transmissionTint", - "displayName": " Transmission Tint", - "description": "Color of the volume light traveling through", - "type": "Color", - "defaultValue": [ 1.0, 0.8, 0.6 ] - }, - { - "name": "transmissionPower", - "displayName": " Power", - "description": "How much transmitted light scatter radially ", - "type": "float", - "defaultValue": 6.0, - "min": 0.0, - "softMax": 20.0 - }, - { - "name": "transmissionDistortion", - "displayName": " Distortion", - "description": "How much light direction distorted towards surface normal", - "type": "float", - "defaultValue": 0.1, - "min": 0.0, - "max": 1.0 - }, - { - "name": "transmissionAttenuation", - "displayName": " Attenuation", - "description": "How fast transmitted light fade with thickness", - "type": "float", - "defaultValue": 4.0, - "min": 0.0, - "softMax": 20.0 - }, - { - "name": "transmissionScale", - "displayName": " Scale", - "description": "Strength of transmission", - "type": "float", - "defaultValue": 3.0, - "min": 0.0, - "softMax": 20.0 - } - ] + "description": "Properties for configuring subsurface scattering effects." }, { "name": "clearCoat", "displayName": "Clear Coat", - "description": "Properties for configuring gloss clear coat", - "properties": [ - { - "name": "enable", - "displayName": "Enable", - "description": "Enable clear coat", - "type": "Bool", - "defaultValue": false - }, - { - "name": "factor", - "displayName": "Factor", - "description": "Strength factor for scaling the percentage of effect applied", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_clearCoatFactor" - } - }, - { - "name": "influenceMap", - "displayName": " Influence Map", - "description": "Strength factor texture", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_clearCoatInfluenceMap" - } - }, - { - "name": "useInfluenceMap", - "displayName": " Use Texture", - "description": "Whether to use the texture, or just default to the Factor value.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "influenceMapUv", - "displayName": " UV", - "description": "Strength factor map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_clearCoatInfluenceMapUvIndex" - } - }, - { - "name": "roughness", - "displayName": "Roughness", - "description": "Clear coat layer roughness", - "type": "Float", - "defaultValue": 0.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_clearCoatRoughness" - } - }, - { - "name": "roughnessMap", - "displayName": " Roughness Map", - "description": "Texture for defining surface roughness", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_clearCoatRoughnessMap" - } - }, - { - "name": "useRoughnessMap", - "displayName": " Use Texture", - "description": "Whether to use the texture, or just default to the roughness value.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "roughnessMapUv", - "displayName": " UV", - "description": "Roughness map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_clearCoatRoughnessMapUvIndex" - } - }, - { - "name": "normalStrength", - "displayName": "Normal Strength", - "description": "Scales the impact of the clear coat normal map", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "max": 2.0, - "connection": { - "type": "ShaderInput", - "name": "m_clearCoatNormalStrength" - } - }, - { - "name": "normalMap", - "displayName": "Normal Map", - "description": "Normal map for clear coat layer, as top layer material clear coat doesn't affect by base layer normal map", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_clearCoatNormalMap" - } - }, - { - "name": "useNormalMap", - "displayName": " Use Texture", - "description": "Whether to use the normal map", - "type": "Bool", - "defaultValue": true - }, - { - "name": "normalMapUv", - "displayName": " UV", - "description": "Normal map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_clearCoatNormalMapUvIndex" - } - } - ] - }, + "description": "Properties for configuring gloss clear coat" + }, { "name": "parallax", "displayName": "Displacement", - "description": "Properties for parallax effect produced by a height map.", - "properties": [ - { - "name": "textureMap", - "displayName": "Height Map", - "description": "Displacement height map to create parallax effect.", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_heightmap" - } - }, - { - "name": "useTexture", - "displayName": "Use Texture", - "description": "Whether to use the height map.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "textureMapUv", - "displayName": "UV", - "description": "Height map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_parallaxUvIndex" - } - }, - { - "name": "factor", - "displayName": "Height Map Scale", - "description": "The total height of the height map in local model units.", - "type": "Float", - "defaultValue": 0.05, - "min": 0.0, - "softMax": 0.1, - "connection": { - "type": "ShaderInput", - "name": "m_heightmapScale" - } - }, - { - "name": "offset", - "displayName": "Offset", - "description": "Adjusts the overall displacement amount in local model units.", - "type": "Float", - "defaultValue": 0.0, - "softMin": -0.1, - "softMax": 0.1, - "connection": { - "type": "ShaderInput", - "name": "m_heightmapOffset" - } - }, - { - "name": "algorithm", - "displayName": "Algorithm", - "description": "Select the algorithm to use for parallax mapping.", - "type": "Enum", - "enumValues": [ "Basic", "Steep", "POM", "Relief", "ContactRefinement" ], - "defaultValue": "POM", - "connection": { - "type": "ShaderOption", - "name": "o_parallax_algorithm" - } - }, - { - "name": "quality", - "displayName": "Quality", - "description": "Quality of parallax mapping.", - "type": "Enum", - "enumValues": [ "Low", "Medium", "High", "Ultra" ], - "defaultValue": "Low", - "connection": { - "type": "ShaderOption", - "name": "o_parallax_quality" - } - }, - { - "name": "pdo", - "displayName": "Pixel Depth Offset", - "description": "Enable PDO to offset the original pixel depths. This will affect any shaders using depth, for example, when receiving shadows.", - "type": "Bool", - "defaultValue": false, - "connection": { - "type": "ShaderOption", - "name": "o_parallax_enablePixelDepthOffset" - } - }, - { - "name": "showClipping", - "displayName": "Show Clipping", - "description": "Highlight areas where the height map is clipped by the mesh surface.", - "type": "Bool", - "defaultValue": false, - "connection": { - "type": "ShaderOption", - "name": "o_parallax_highlightClipping" - } - } - ] + "description": "Properties for parallax effect produced by a height map." }, { "name": "opacity", "displayName": "Opacity", - "description": "Properties for configuring the materials transparency.", - "properties": [ - { - "name": "mode", - "displayName": "Opacity Mode", - "description": "Indicates the general approach how transparency is to be applied.", - "type": "Enum", - "enumValues": [ "Opaque", "Cutout", "Blended", "TintedTransparent" ], - "defaultValue": "Opaque", - "connection": { - "type": "ShaderOption", - "name": "o_opacity_mode" - } - }, - { - "name": "alphaSource", - "displayName": "Alpha Source", - "description": "Indicates whether to get the opacity texture from the Base Color map (Packed) or from a separate greyscale texture (Split).", - "type": "Enum", - "enumValues": [ "Packed", "Split", "None" ], - "defaultValue": "Packed", - "connection": { - "type": "ShaderOption", - "name": "o_opacity_source" - } - }, - { - "name": "textureMap", - "displayName": "Texture", - "description": "Texture for defining surface opacity.", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_opacityMap" - } - }, - { - "name": "textureMapUv", - "displayName": "UV", - "description": "Opacity map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_opacityMapUvIndex" - } - }, - { - "name": "factor", - "displayName": "Factor", - "description": "Factor for cutout threshold and blending", - "type": "Float", - "min": 0.0, - "max": 1.0, - "defaultValue": 0.5, - "connection": { - "type": "ShaderInput", - "name": "m_opacityFactor" - } - }, - { - "name": "alphaAffectsSpecular", - "displayName": "Alpha affects specular", - "description": "How much the alpha value should also affect specular reflection. This should be 0.0 for materials where light can transmit through their physical surface (like glass), but 1.0 when alpha determines the very presence of a surface (like hair or grass)", - "type": "float", - "min": 0.0, - "max": 1.0, - "defaultValue": 0.0, - "connection": { - "type": "ShaderInput", - "name": "m_opacityAffectsSpecularFactor" - } - } - ] + "description": "Properties for configuring the materials transparency." }, { "name": "uv", "displayName": "UVs", - "description": "Properties for configuring UV transforms.", - "properties": [ - { - "name": "center", - "displayName": "Center", - "description": "Center point for scaling and rotation transformations.", - "type": "vector2", - "vectorLabels": [ "U", "V" ], - "defaultValue": [ 0.5, 0.5 ] - }, - { - "name": "tileU", - "displayName": "Tile U", - "description": "Scales texture coordinates in U.", - "type": "float", - "defaultValue": 1.0, - "step": 0.1 - }, - { - "name": "tileV", - "displayName": "Tile V", - "description": "Scales texture coordinates in V.", - "type": "float", - "defaultValue": 1.0, - "step": 0.1 - }, - { - "name": "offsetU", - "displayName": "Offset U", - "description": "Offsets texture coordinates in the U direction.", - "type": "float", - "defaultValue": 0.0, - "min": -1.0, - "max": 1.0 - }, - { - "name": "offsetV", - "displayName": "Offset V", - "description": "Offsets texture coordinates in the V direction.", - "type": "float", - "defaultValue": 0.0, - "min": -1.0, - "max": 1.0 - }, - { - "name": "rotateDegrees", - "displayName": "Rotate", - "description": "Rotates the texture coordinates (degrees).", - "type": "float", - "defaultValue": 0.0, - "min": -180.0, - "max": 180.0, - "step": 1.0 - }, - { - "name": "scale", - "displayName": "Scale", - "description": "Scales texture coordinates in both U and V.", - "type": "float", - "defaultValue": 1.0, - "step": 0.1 - } - ] + "description": "Properties for configuring UV transforms." }, { // Note: this property group is used in the DiffuseGlobalIllumination pass and not by the main forward shader "name": "irradiance", "displayName": "Irradiance", - "description": "Properties for configuring the irradiance used in global illumination.", - "properties": [ - { - "name": "color", - "displayName": "Color", - "description": "Color is displayed as sRGB but the values are stored as linear color.", - "type": "Color", - "defaultValue": [ 1.0, 1.0, 1.0 ] - }, - { - "name": "factor", - "displayName": "Factor", - "description": "Strength factor for scaling the irradiance color values. Zero (0.0) is black, white (1.0) is full color.", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "max": 1.0 - } - ] + "description": "Properties for configuring the irradiance used in global illumination." }, { "name": "general", "displayName": "General Settings", - "description": "General settings.", - "properties": [ - { - "name": "doubleSided", - "displayName": "Double-sided", - "description": "Whether to render back-faces or just front-faces.", - "type": "Bool" - }, - { - "name": "applySpecularAA", - "displayName": "Apply Specular AA", - "description": "Whether to apply specular anti-aliasing in the shader.", - "type": "Bool", - "defaultValue": false, - "connection": { - "type": "ShaderOption", - "name": "o_applySpecularAA" - } - }, - { - "name": "enableShadows", - "displayName": "Enable Shadows", - "description": "Whether to use the shadow maps.", - "type": "Bool", - "defaultValue": true, - "connection": { - "type": "ShaderOption", - "name": "o_enableShadows" - } - }, - { - "name": "enableDirectionalLights", - "displayName": "Enable Directional Lights", - "description": "Whether to use directional lights.", - "type": "Bool", - "defaultValue": true, - "connection": { - "type": "ShaderOption", - "name": "o_enableDirectionalLights" - } - }, - { - "name": "enablePunctualLights", - "displayName": "Enable Punctual Lights", - "description": "Whether to use punctual lights.", - "type": "Bool", - "defaultValue": true, - "connection": { - "type": "ShaderOption", - "name": "o_enablePunctualLights" - } - }, - { - "name": "enableAreaLights", - "displayName": "Enable Area Lights", - "description": "Whether to use area lights.", - "type": "Bool", - "defaultValue": true, - "connection": { - "type": "ShaderOption", - "name": "o_enableAreaLights" - } - }, - { - "name": "enableIBL", - "displayName": "Enable IBL", - "description": "Whether to use Image Based Lighting (IBL).", - "type": "Bool", - "defaultValue": true, - "connection": { - "type": "ShaderOption", - "name": "o_enableIBL" - } - }, - { - "name": "forwardPassIBLSpecular", - "displayName": "Forward Pass IBL Specular", - "description": "Whether to apply IBL specular in the forward pass.", - "type": "Bool", - "defaultValue": false, - "connection": { - "type": "ShaderOption", - "name": "o_materialUseForwardPassIBLSpecular" - } - } - ] + "description": "General settings." } - ] + ], + "properties": { + "general": [ + { + "name": "doubleSided", + "displayName": "Double-sided", + "description": "Whether to render back-faces or just front-faces.", + "type": "Bool" + }, + { + "name": "applySpecularAA", + "displayName": "Apply Specular AA", + "description": "Whether to apply specular anti-aliasing in the shader.", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderOption", + "name": "o_applySpecularAA" + } + }, + { + "name": "enableShadows", + "displayName": "Enable Shadows", + "description": "Whether to use the shadow maps.", + "type": "Bool", + "defaultValue": true, + "connection": { + "type": "ShaderOption", + "name": "o_enableShadows" + } + }, + { + "name": "enableDirectionalLights", + "displayName": "Enable Directional Lights", + "description": "Whether to use directional lights.", + "type": "Bool", + "defaultValue": true, + "connection": { + "type": "ShaderOption", + "name": "o_enableDirectionalLights" + } + }, + { + "name": "enablePunctualLights", + "displayName": "Enable Punctual Lights", + "description": "Whether to use punctual lights.", + "type": "Bool", + "defaultValue": true, + "connection": { + "type": "ShaderOption", + "name": "o_enablePunctualLights" + } + }, + { + "name": "enableAreaLights", + "displayName": "Enable Area Lights", + "description": "Whether to use area lights.", + "type": "Bool", + "defaultValue": true, + "connection": { + "type": "ShaderOption", + "name": "o_enableAreaLights" + } + }, + { + "name": "enableIBL", + "displayName": "Enable IBL", + "description": "Whether to use Image Based Lighting (IBL).", + "type": "Bool", + "defaultValue": true, + "connection": { + "type": "ShaderOption", + "name": "o_enableIBL" + } + }, + { + "name": "forwardPassIBLSpecular", + "displayName": "Forward Pass IBL Specular", + "description": "Whether to apply IBL specular in the forward pass.", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderOption", + "name": "o_materialUseForwardPassIBLSpecular" + } + } + ], + "baseColor": [ + { + "name": "color", + "displayName": "Color", + "description": "Color is displayed as sRGB but the values are stored as linear color.", + "type": "Color", + "defaultValue": [ 1.0, 1.0, 1.0 ], + "connection": { + "type": "ShaderInput", + "name": "m_baseColor" + } + }, + { + "name": "factor", + "displayName": "Factor", + "description": "Strength factor for scaling the base color values. Zero (0.0) is black, white (1.0) is full color.", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_baseColorFactor" + } + }, + { + "name": "textureMap", + "displayName": "Texture", + "description": "Base color texture map", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_baseColorMap" + } + }, + { + "name": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "textureMapUv", + "displayName": "UV", + "description": "Base color map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_baseColorMapUvIndex" + } + }, + { + "name": "textureBlendMode", + "displayName": "Texture Blend Mode", + "description": "Selects the equation to use when combining Color, Factor, and Texture.", + "type": "Enum", + "enumValues": [ "Multiply", "LinearLight", "Lerp", "Overlay" ], + "defaultValue": "Multiply", + "connection": { + "type": "ShaderOption", + "name": "o_baseColorTextureBlendMode" + } + } + ], + "metallic": [ + { + "name": "factor", + "displayName": "Factor", + "description": "This value is linear, black is non-metal and white means raw metal.", + "type": "Float", + "defaultValue": 0.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_metallicFactor" + } + }, + { + "name": "textureMap", + "displayName": "Texture", + "description": "", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_metallicMap" + } + }, + { + "name": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture, or just default to the Factor value.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "textureMapUv", + "displayName": "UV", + "description": "Metallic map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_metallicMapUvIndex" + } + } + ], + "roughness": [ + { + "name": "textureMap", + "displayName": "Texture", + "description": "Texture for defining surface roughness.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_roughnessMap" + } + }, + { + "name": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture, or just default to the Factor value.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "textureMapUv", + "displayName": "UV", + "description": "Roughness map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_roughnessMapUvIndex" + } + }, + { + // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. + "name": "lowerBound", + "displayName": "Lower Bound", + "description": "The roughness value that corresponds to black in the texture.", + "type": "Float", + "defaultValue": 0.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_roughnessLowerBound" + } + }, + { + // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. + "name": "upperBound", + "displayName": "Upper Bound", + "description": "The roughness value that corresponds to white in the texture.", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_roughnessUpperBound" + } + }, + { + // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. + "name": "factor", + "displayName": "Factor", + "description": "Controls the roughness value", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_roughnessFactor" + } + } + ], + "anisotropy": [ + { + "name": "enableAnisotropy", + "displayName": "Enable Anisotropy", + "description": "Enable anisotropic surface response for non uniform reflection along the axis", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderOption", + "name": "o_enableAnisotropy" + } + }, + { + "name": "factor", + "displayName": "Anisotropy Factor", + "description": "Strength factor for the anisotropy: negative = along v, positive = along u", + "type": "Float", + "defaultValue": 0.0, + "min": -0.95, + "max": 0.95, + "connection": { + "type": "ShaderInput", + "name": "m_anisotropicFactor" + } + }, + { + "name": "anisotropyAngle", + "displayName": "Anisotropy Angle", + "description": "Anisotropy direction of major reflection axis: 0 = 0 degrees, 1.0 = 180 degrees", + "type": "Float", + "defaultValue": 0.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_anisotropicAngle" + } + } + ], + "specularF0": [ + { + "name": "factor", + "displayName": "Factor", + "description": "The default IOR is 1.5, which gives you 0.04 (4% of light reflected at 0 degree angle for dielectric materials). F0 values lie in the range 0-0.08, so that is why the default F0 slider is set on 0.5.", + "type": "Float", + "defaultValue": 0.5, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_specularF0Factor" + } + }, + { + "name": "textureMap", + "displayName": "Texture", + "description": "Texture for defining surface reflectance.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_specularF0Map" + } + }, + { + "name": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture, or just default to the Factor value.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "textureMapUv", + "displayName": "UV", + "description": "Specular reflection map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_specularF0MapUvIndex" + } + }, + // Consider moving this to the "general" group to be consistent with StandardMultilayerPBR + { + "name": "enableMultiScatterCompensation", + "displayName": "Multiscattering Compensation", + "description": "Whether to enable multiple scattering compensation.", + "type": "Bool", + "connection": { + "type": "ShaderOption", + "name": "o_specularF0_enableMultiScatterCompensation" + } + } + ], + "clearCoat": [ + { + "name": "enable", + "displayName": "Enable", + "description": "Enable clear coat", + "type": "Bool", + "defaultValue": false + }, + { + "name": "factor", + "displayName": "Factor", + "description": "Strength factor for scaling the percentage of effect applied", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_clearCoatFactor" + } + }, + { + "name": "influenceMap", + "displayName": " Influence Map", + "description": "Strength factor texture", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_clearCoatInfluenceMap" + } + }, + { + "name": "useInfluenceMap", + "displayName": " Use Texture", + "description": "Whether to use the texture, or just default to the Factor value.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "influenceMapUv", + "displayName": " UV", + "description": "Strength factor map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_clearCoatInfluenceMapUvIndex" + } + }, + { + "name": "roughness", + "displayName": "Roughness", + "description": "Clear coat layer roughness", + "type": "Float", + "defaultValue": 0.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_clearCoatRoughness" + } + }, + { + "name": "roughnessMap", + "displayName": " Roughness Map", + "description": "Texture for defining surface roughness", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_clearCoatRoughnessMap" + } + }, + { + "name": "useRoughnessMap", + "displayName": " Use Texture", + "description": "Whether to use the texture, or just default to the roughness value.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "roughnessMapUv", + "displayName": " UV", + "description": "Roughness map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_clearCoatRoughnessMapUvIndex" + } + }, + { + "name": "normalStrength", + "displayName": "Normal Strength", + "description": "Scales the impact of the clear coat normal map", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 2.0, + "connection": { + "type": "ShaderInput", + "name": "m_clearCoatNormalStrength" + } + }, + { + "name": "normalMap", + "displayName": "Normal Map", + "description": "Normal map for clear coat layer, as top layer material clear coat doesn't affect by base layer normal map", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_clearCoatNormalMap" + } + }, + { + "name": "useNormalMap", + "displayName": " Use Texture", + "description": "Whether to use the normal map", + "type": "Bool", + "defaultValue": true + }, + { + "name": "normalMapUv", + "displayName": " UV", + "description": "Normal map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_clearCoatNormalMapUvIndex" + } + } + ], + "normal": [ + { + "name": "textureMap", + "displayName": "Texture", + "description": "Texture for defining surface normal direction.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_normalMap" + } + }, + { + "name": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture, or just rely on vertex normals.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "textureMapUv", + "displayName": "UV", + "description": "Normal map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_normalMapUvIndex" + } + }, + { + "name": "flipX", + "displayName": "Flip X Channel", + "description": "Flip tangent direction for this normal map.", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderInput", + "name": "m_flipNormalX" + } + }, + { + "name": "flipY", + "displayName": "Flip Y Channel", + "description": "Flip bitangent direction for this normal map.", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderInput", + "name": "m_flipNormalY" + } + }, + { + "name": "factor", + "displayName": "Factor", + "description": "Strength factor for scaling the values", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "softMax": 2.0, + "connection": { + "type": "ShaderInput", + "name": "m_normalFactor" + } + } + ], + "opacity": [ + { + "name": "mode", + "displayName": "Opacity Mode", + "description": "Indicates the general approach how transparency is to be applied.", + "type": "Enum", + "enumValues": [ "Opaque", "Cutout", "Blended", "TintedTransparent" ], + "defaultValue": "Opaque", + "connection": { + "type": "ShaderOption", + "name": "o_opacity_mode" + } + }, + { + "name": "alphaSource", + "displayName": "Alpha Source", + "description": "Indicates whether to get the opacity texture from the Base Color map (Packed) or from a separate greyscale texture (Split).", + "type": "Enum", + "enumValues": [ "Packed", "Split", "None" ], + "defaultValue": "Packed", + "connection": { + "type": "ShaderOption", + "name": "o_opacity_source" + } + }, + { + "name": "textureMap", + "displayName": "Texture", + "description": "Texture for defining surface opacity.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_opacityMap" + } + }, + { + "name": "textureMapUv", + "displayName": "UV", + "description": "Opacity map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_opacityMapUvIndex" + } + }, + { + "name": "factor", + "displayName": "Factor", + "description": "Factor for cutout threshold and blending", + "type": "Float", + "min": 0.0, + "max": 1.0, + "defaultValue": 0.5, + "connection": { + "type": "ShaderInput", + "name": "m_opacityFactor" + } + }, + { + "name": "alphaAffectsSpecular", + "displayName": "Alpha affects specular", + "description": "How much the alpha value should also affect specular reflection. This should be 0.0 for materials where light can transmit through their physical surface (like glass), but 1.0 when alpha determines the very presence of a surface (like hair or grass)", + "type": "float", + "min": 0.0, + "max": 1.0, + "defaultValue": 0.0, + "connection": { + "type": "ShaderInput", + "name": "m_opacityAffectsSpecularFactor" + } + } + ], + "uv": [ + { + "name": "center", + "displayName": "Center", + "description": "Center point for scaling and rotation transformations.", + "type": "vector2", + "vectorLabels": [ "U", "V" ], + "defaultValue": [ 0.5, 0.5 ] + }, + { + "name": "tileU", + "displayName": "Tile U", + "description": "Scales texture coordinates in U.", + "type": "float", + "defaultValue": 1.0, + "step": 0.1 + }, + { + "name": "tileV", + "displayName": "Tile V", + "description": "Scales texture coordinates in V.", + "type": "float", + "defaultValue": 1.0, + "step": 0.1 + }, + { + "name": "offsetU", + "displayName": "Offset U", + "description": "Offsets texture coordinates in the U direction.", + "type": "float", + "defaultValue": 0.0, + "min": -1.0, + "max": 1.0 + }, + { + "name": "offsetV", + "displayName": "Offset V", + "description": "Offsets texture coordinates in the V direction.", + "type": "float", + "defaultValue": 0.0, + "min": -1.0, + "max": 1.0 + }, + { + "name": "rotateDegrees", + "displayName": "Rotate", + "description": "Rotates the texture coordinates (degrees).", + "type": "float", + "defaultValue": 0.0, + "min": -180.0, + "max": 180.0, + "step": 1.0 + }, + { + "name": "scale", + "displayName": "Scale", + "description": "Scales texture coordinates in both U and V.", + "type": "float", + "defaultValue": 1.0, + "step": 0.1 + } + ], + "occlusion": [ + { + "name": "diffuseTextureMap", + "displayName": "Diffuse AO", + "description": "Texture for defining occlusion area for diffuse ambient lighting.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_diffuseOcclusionMap" + } + }, + { + "name": "diffuseUseTexture", + "displayName": " Use Texture", + "description": "Whether to use the Diffuse AO map.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "diffuseTextureMapUv", + "displayName": " UV", + "description": "Diffuse AO map UV set.", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_diffuseOcclusionMapUvIndex" + } + }, + { + "name": "diffuseFactor", + "displayName": " Factor", + "description": "Strength factor for scaling the values of Diffuse AO", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "softMax": 2.0, + "connection": { + "type": "ShaderInput", + "name": "m_diffuseOcclusionFactor" + } + }, + { + "name": "specularTextureMap", + "displayName": "Specular Cavity", + "description": "Texture for defining occlusion area for specular lighting.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_specularOcclusionMap" + } + }, + { + "name": "specularUseTexture", + "displayName": " Use Texture", + "description": "Whether to use the Specular Cavity map.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "specularTextureMapUv", + "displayName": " UV", + "description": "Specular Cavity map UV set.", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_specularOcclusionMapUvIndex" + } + }, + { + "name": "specularFactor", + "displayName": " Factor", + "description": "Strength factor for scaling the values of Specular Cavity", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "softMax": 2.0, + "connection": { + "type": "ShaderInput", + "name": "m_specularOcclusionFactor" + } + } + ], + "emissive": [ + { + "name": "enable", + "displayName": "Enable", + "description": "Enable the emissive group", + "type": "Bool", + "defaultValue": false + }, + { + "name": "unit", + "displayName": "Units", + "description": "The photometric units of the Intensity property.", + "type": "Enum", + "enumValues": ["Ev100"], + "defaultValue": "Ev100" + }, + { + "name": "color", + "displayName": "Color", + "description": "Color is displayed as sRGB but the values are stored as linear color.", + "type": "Color", + "defaultValue": [ 1.0, 1.0, 1.0 ], + "connection": { + "type": "ShaderInput", + "name": "m_emissiveColor" + } + }, + { + "name": "intensity", + "displayName": "Intensity", + "description": "The amount of energy emitted.", + "type": "Float", + "defaultValue": 4, + "min": -10, + "max": 20, + "softMin": -6, + "softMax": 16 + }, + { + "name": "textureMap", + "displayName": "Texture", + "description": "Texture for defining emissive area.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_emissiveMap" + } + }, + { + "name": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "textureMapUv", + "displayName": "UV", + "description": "Emissive map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_emissiveMapUvIndex" + } + } + ], + "parallax": [ + { + "name": "textureMap", + "displayName": "Height Map", + "description": "Displacement height map to create parallax effect.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_heightmap" + } + }, + { + "name": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the height map.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "textureMapUv", + "displayName": "UV", + "description": "Height map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_parallaxUvIndex" + } + }, + { + "name": "factor", + "displayName": "Height Map Scale", + "description": "The total height of the height map in local model units.", + "type": "Float", + "defaultValue": 0.05, + "min": 0.0, + "softMax": 0.1, + "connection": { + "type": "ShaderInput", + "name": "m_heightmapScale" + } + }, + { + "name": "offset", + "displayName": "Offset", + "description": "Adjusts the overall displacement amount in local model units.", + "type": "Float", + "defaultValue": 0.0, + "softMin": -0.1, + "softMax": 0.1, + "connection": { + "type": "ShaderInput", + "name": "m_heightmapOffset" + } + }, + { + "name": "algorithm", + "displayName": "Algorithm", + "description": "Select the algorithm to use for parallax mapping.", + "type": "Enum", + "enumValues": [ "Basic", "Steep", "POM", "Relief", "ContactRefinement" ], + "defaultValue": "POM", + "connection": { + "type": "ShaderOption", + "name": "o_parallax_algorithm" + } + }, + { + "name": "quality", + "displayName": "Quality", + "description": "Quality of parallax mapping.", + "type": "Enum", + "enumValues": [ "Low", "Medium", "High", "Ultra" ], + "defaultValue": "Low", + "connection": { + "type": "ShaderOption", + "name": "o_parallax_quality" + } + }, + { + "name": "pdo", + "displayName": "Pixel Depth Offset", + "description": "Enable PDO to offset the original pixel depths. This will affect any shaders using depth, for example, when receiving shadows.", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderOption", + "name": "o_parallax_enablePixelDepthOffset" + } + }, + { + "name": "showClipping", + "displayName": "Show Clipping", + "description": "Highlight areas where the height map is clipped by the mesh surface.", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderOption", + "name": "o_parallax_highlightClipping" + } + } + ], + "subsurfaceScattering": [ + { + "name": "enableSubsurfaceScattering", + "displayName": "Subsurface Scattering", + "description": "Enable subsurface scattering feature, this will disable metallic and parallax mapping property due to incompatibility", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderOption", + "name": "o_enableSubsurfaceScattering" + } + }, + { + "name": "subsurfaceScatterFactor", + "displayName": " Factor", + "description": "Strength factor for scaling percentage of subsurface scattering effect applied", + "type": "float", + "defaultValue": 1.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_subsurfaceScatteringFactor" + } + }, + { + "name": "influenceMap", + "displayName": " Influence Map", + "description": "Texture for controlling the strength of subsurface scattering", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_subsurfaceScatteringInfluenceMap" + } + }, + { + "name": "useInfluenceMap", + "displayName": " Use Influence Map", + "description": "Whether to use the influence map.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "influenceMapUv", + "displayName": " UV", + "description": "Influence map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_subsurfaceScatteringInfluenceMapUvIndex" + } + }, + { + "name": "scatterColor", + "displayName": " Scatter color", + "description": "Color of volume light traveled through", + "type": "Color", + "defaultValue": [ 1.0, 0.27, 0.13 ] + }, + { + "name": "scatterDistance", + "displayName": " Scatter distance", + "description": "How far light traveled inside the volume", + "type": "float", + "defaultValue": 8, + "min": 0.0, + "softMax": 20.0 + }, + { + "name": "quality", + "displayName": " Quality", + "description": "How much percent of sample will be used for each pixel, more samples improve quality and reduce artifacts, especially when the scatter distance is relatively large, but slow down computation time, 1.0 = full set 200 samples per pixel", + "type": "float", + "defaultValue": 0.4, + "min": 0.2, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_subsurfaceScatteringQuality" + } + }, + { + "name": "transmissionMode", + "displayName": "Transmission", + "description": "Algorithm used for calculating transmission", + "type": "Enum", + "enumValues": [ "None", "ThickObject", "ThinObject" ], + "defaultValue": "None", + "connection": { + "type": "ShaderOption", + "name": "o_transmission_mode" + } + }, + { + "name": "thickness", + "displayName": " Thickness", + "description": "Normalized global thickness, the maxima between this value (multiplied by thickness map if enabled) and thickness from shadow map (if applicable) will be used as final thickness of pixel", + "type": "float", + "defaultValue": 0.5, + "min": 0.0, + "max": 1.0 + }, + { + "name": "thicknessMap", + "displayName": " Thickness Map", + "description": "Texture for controlling per pixel thickness", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_transmissionThicknessMap" + } + }, + { + "name": "useThicknessMap", + "displayName": " Use Thickness Map", + "description": "Whether to use the thickness map", + "type": "Bool", + "defaultValue": true + }, + { + "name": "thicknessMapUv", + "displayName": " UV", + "description": "Thickness map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_transmissionThicknessMapUvIndex" + } + }, + { + "name": "transmissionTint", + "displayName": " Transmission Tint", + "description": "Color of the volume light traveling through", + "type": "Color", + "defaultValue": [ 1.0, 0.8, 0.6 ] + }, + { + "name": "transmissionPower", + "displayName": " Power", + "description": "How much transmitted light scatter radially ", + "type": "float", + "defaultValue": 6.0, + "min": 0.0, + "softMax": 20.0 + }, + { + "name": "transmissionDistortion", + "displayName": " Distortion", + "description": "How much light direction distorted towards surface normal", + "type": "float", + "defaultValue": 0.1, + "min": 0.0, + "max": 1.0 + }, + { + "name": "transmissionAttenuation", + "displayName": " Attenuation", + "description": "How fast transmitted light fade with thickness", + "type": "float", + "defaultValue": 4.0, + "min": 0.0, + "softMax": 20.0 + }, + { + "name": "transmissionScale", + "displayName": " Scale", + "description": "Strength of transmission", + "type": "float", + "defaultValue": 3.0, + "min": 0.0, + "softMax": 20.0 + } + ], + "detailLayerGroup": [ + { + "name": "enableDetailLayer", + "displayName": "Enable Detail Layer", + "description": "Enable detail layer for fine details and scratches", + "type": "Bool", + "defaultValue": false + }, + { + "name": "blendDetailFactor", + "displayName": "Blend Factor", + "description": "Scales the overall impact of the detail layer.", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_detail_blendFactor" + } + }, + { + "name": "blendDetailMask", + "displayName": "Blend Mask", + "description": "Detailed blend mask for application of the detail maps.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_detail_blendMask_texture" + } + }, + { + "name": "enableDetailMaskTexture", + "displayName": " Use Texture", + "description": "Enable detail blend mask", + "type": "Bool", + "defaultValue": true + }, + { + "name": "blendDetailMaskUv", + "displayName": " Blend Mask UV", + "description": "Which UV set to use for sampling the detail blend mask", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_detail_blendMask_uvIndex" + } + }, + { + "name": "textureMapUv", + "displayName": "Detail Map UVs", + "description": "Which UV set to use for detail map sampling", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_detail_allMapsUvIndex" + } + }, + { + "name": "enableBaseColor", + "displayName": "Enable Base Color", + "description": "Enable detail blending for base color", + "type": "Bool", + "defaultValue": false + }, + { + "name": "baseColorDetailMap", + "displayName": " Texture", + "description": "Detailed Base Color Texture", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_detail_baseColor_texture" + } + }, + { + "name": "baseColorDetailBlend", + "displayName": " Blend Factor", + "description": "How much to blend the detail layer into the base color.", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_detail_baseColor_factor" + } + }, + { + "name": "enableNormals", + "displayName": "Enable Normal", + "description": "Enable detail normal map to be used for fine detail normal such as scratches and small dents", + "type": "Bool", + "defaultValue": false + }, + { + "name": "normalDetailStrength", + "displayName": " Factor", + "description": "Strength factor for scaling the Detail Normal", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "softMax": 2.0, + "connection": { + "type": "ShaderInput", + "name": "m_detail_normal_factor" + } + }, + { + "name": "normalDetailMap", + "displayName": " Texture", + "description": "Detailed Normal map", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_detail_normal_texture" + } + }, + { + "name": "normalDetailFlipX", + "displayName": " Flip X Channel", + "description": "Flip Detail tangent direction for this normal map.", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderInput", + "name": "m_detail_normal_flipX" + } + }, + { + "name": "normalDetailFlipY", + "displayName": " Flip Y Channel", + "description": "Flip Detail bitangent direction for this normal map.", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderInput", + "name": "m_detail_normal_flipY" + } + } + ], + "detailUV": [ + { + "name": "center", + "displayName": "Center", + "description": "Center point for scaling and rotation transformations.", + "type": "vector2", + "vectorLabels": [ "U", "V" ], + "defaultValue": [ 0.5, 0.5 ] + }, + { + "name": "tileU", + "displayName": "Tile U", + "description": "Scales texture coordinates in V.", + "type": "float", + "defaultValue": 1.0, + "step": 0.1 + }, + { + "name": "tileV", + "displayName": "Tile V", + "description": "Scales texture coordinates in V.", + "type": "float", + "defaultValue": 1.0, + "step": 0.1 + }, + { + "name": "offsetU", + "displayName": "Offset U", + "description": "Offsets texture coordinates in the U direction.", + "type": "float", + "defaultValue": 0.0, + "min": -1.0, + "max": 1.0 + }, + { + "name": "offsetV", + "displayName": "Offset V", + "description": "Offsets texture coordinates in the V direction.", + "type": "float", + "defaultValue": 0.0, + "min": -1.0, + "max": 1.0 + }, + { + "name": "rotateDegrees", + "displayName": "Rotate", + "description": "Rotates the texture coordinates (degrees).", + "type": "float", + "defaultValue": 0.0, + "min": -180.0, + "max": 180.0, + "step": 1.0 + }, + { + "name": "scale", + "displayName": "Scale", + "description": "Scales texture coordinates in both U and V.", + "type": "float", + "defaultValue": 1.0, + "step": 0.1 + } + ], + "irradiance": [ + // Note: this property group is used in the DiffuseGlobalIllumination pass and not by the main forward shader + { + "name": "color", + "displayName": "Color", + "description": "Color is displayed as sRGB but the values are stored as linear color.", + "type": "Color", + "defaultValue": [ 1.0, 1.0, 1.0 ] + }, + { + "name": "factor", + "displayName": "Factor", + "description": "Strength factor for scaling the irradiance color values. Zero (0.0) is black, white (1.0) is full color.", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 1.0 + } + ] + } }, "shaders": [ { @@ -1684,4 +1687,4 @@ "UV0": "Tiled", "UV1": "Unwrapped" } -} +} \ No newline at end of file diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.materialtype b/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.materialtype index 6366bddff0..15eaf94df6 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.materialtype +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.materialtype @@ -2,968 +2,970 @@ "description": "Material Type tailored for rendering skin, with support for blended wrinkle maps that work with animated vertex blend shapes.", "version": 3, "propertyLayout": { - "propertySets": [ + "groups": [ { "name": "baseColor", "displayName": "Base Color", - "description": "Properties for configuring the surface reflected color for dielectrics or reflectance values for metals.", - "properties": [ - { - "name": "color", - "displayName": "Color", - "description": "Color is displayed as sRGB but the values are stored as linear color.", - "type": "Color", - "defaultValue": [ 1.0, 1.0, 1.0 ], - "connection": { - "type": "ShaderInput", - "name": "m_baseColor" - } - }, - { - "name": "factor", - "displayName": "Factor", - "description": "Strength factor for scaling the base color values. Zero (0.0) is black, white (1.0) is full color.", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_baseColorFactor" - } - }, - { - "name": "textureMap", - "displayName": "Texture", - "description": "Base color texture map", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_baseColorMap" - } - }, - { - "name": "useTexture", - "displayName": "Use Texture", - "description": "Whether to use the texture.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "textureMapUv", - "displayName": "UV", - "description": "Base color map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Unwrapped", - "connection": { - "type": "ShaderInput", - "name": "m_baseColorMapUvIndex" - } - }, - { - "name": "textureBlendMode", - "displayName": "Texture Blend Mode", - "description": "Selects the equation to use when combining Color, Factor, and Texture.", - "type": "Enum", - "enumValues": [ "Multiply", "LinearLight", "Lerp", "Overlay" ], - "defaultValue": "Multiply", - "connection": { - "type": "ShaderOption", - "name": "o_baseColorTextureBlendMode" - } - } - ] + "description": "Properties for configuring the surface reflected color for dielectrics or reflectance values for metals." }, { "name": "roughness", "displayName": "Roughness", - "description": "Properties for configuring how rough the surface appears.", - "properties": [ - { - "name": "textureMap", - "displayName": "Texture", - "description": "Texture for defining surface roughness.", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_roughnessMap" - } - }, - { - "name": "useTexture", - "displayName": "Use Texture", - "description": "Whether to use the texture, or just default to the Factor value.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "textureMapUv", - "displayName": "UV", - "description": "Roughness map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Unwrapped", - "connection": { - "type": "ShaderInput", - "name": "m_roughnessMapUvIndex" - } - }, - { - // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. - "name": "lowerBound", - "displayName": "Lower Bound", - "description": "The roughness value that corresponds to black in the texture.", - "type": "Float", - "defaultValue": 0.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_roughnessLowerBound" - } - }, - { - // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. - "name": "upperBound", - "displayName": "Upper Bound", - "description": "The roughness value that corresponds to white in the texture.", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_roughnessUpperBound" - } - }, - { - // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. - "name": "factor", - "displayName": "Factor", - "description": "Controls the roughness value", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_roughnessFactor" - } - } - ] + "description": "Properties for configuring how rough the surface appears." }, { "name": "specularF0", "displayName": "Specular Reflectance f0", - "description": "The constant f0 represents the specular reflectance at normal incidence (Fresnel 0 Angle). Used to adjust reflectance of non-metal surfaces.", - "properties": [ - { - "name": "factor", - "displayName": "Factor", - "description": "The default IOR is 1.5, which gives you 0.04 (4% of light reflected at 0 degree angle for dielectric materials). F0 values lie in the range 0-0.08, so that is why the default F0 slider is set on 0.5.", - "type": "Float", - "defaultValue": 0.5, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_specularF0Factor" - } - }, - { - "name": "textureMap", - "displayName": "Texture", - "description": "Texture for defining surface reflectance.", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_specularF0Map" - } - }, - { - "name": "useTexture", - "displayName": "Use Texture", - "description": "Whether to use the texture, or just default to the Factor value.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "textureMapUv", - "displayName": "UV", - "description": "Specular reflection map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Unwrapped", - "connection": { - "type": "ShaderInput", - "name": "m_specularF0MapUvIndex" - } - }, - // Consider moving this to the "general" group to be consistent with StandardMultilayerPBR - { - "name": "enableMultiScatterCompensation", - "displayName": "Multiscattering Compensation", - "description": "Whether to enable multiple scattering compensation.", - "type": "Bool", - "connection": { - "type": "ShaderOption", - "name": "o_specularF0_enableMultiScatterCompensation" - } - } - ] + "description": "The constant f0 represents the specular reflectance at normal incidence (Fresnel 0 Angle). Used to adjust reflectance of non-metal surfaces." }, { "name": "normal", "displayName": "Normal", - "description": "Properties related to configuring surface normal.", - "properties": [ - { - "name": "textureMap", - "displayName": "Texture", - "description": "Texture for defining surface normal direction.", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_normalMap" - } - }, - { - "name": "useTexture", - "displayName": "Use Texture", - "description": "Whether to use the texture, or just rely on vertex normals.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "textureMapUv", - "displayName": "UV", - "description": "Normal map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Unwrapped", - "connection": { - "type": "ShaderInput", - "name": "m_normalMapUvIndex" - } - }, - { - "name": "flipX", - "displayName": "Flip X Channel", - "description": "Flip tangent direction for this normal map.", - "type": "Bool", - "defaultValue": false, - "connection": { - "type": "ShaderInput", - "name": "m_flipNormalX" - } - }, - { - "name": "flipY", - "displayName": "Flip Y Channel", - "description": "Flip bitangent direction for this normal map.", - "type": "Bool", - "defaultValue": false, - "connection": { - "type": "ShaderInput", - "name": "m_flipNormalY" - } - }, - { - "name": "factor", - "displayName": "Factor", - "description": "Strength factor for scaling the values", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "softMax": 2.0, - "connection": { - "type": "ShaderInput", - "name": "m_normalFactor" - } - } - ] + "description": "Properties related to configuring surface normal." }, { "name": "detailLayerGroup", "displayName": "Detail Layer", - "description": "Properties for Fine Details Layer.", - "properties": [ - { - "name": "enableDetailLayer", - "displayName": "Enable Detail Layer", - "description": "Enable detail layer for fine details and scratches", - "type": "Bool", - "defaultValue": false - }, - { - "name": "blendDetailFactor", - "displayName": "Blend Factor", - "description": "Scales the overall impact of the detail layer.", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_detail_blendFactor" - } - }, - { - "name": "blendDetailMask", - "displayName": "Blend Mask", - "description": "Detailed blend mask for application of the detail maps.", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_detail_blendMask_texture" - } - }, - { - "name": "enableDetailMaskTexture", - "displayName": " Use Texture", - "description": "Enable detail blend mask", - "type": "Bool", - "defaultValue": true - }, - { - "name": "blendDetailMaskUv", - "displayName": " Blend Mask UV", - "description": "Which UV set to use for sampling the detail blend mask", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Unwrapped", - "connection": { - "type": "ShaderInput", - "name": "m_detail_blendMask_uvIndex" - } - }, - { - "name": "textureMapUv", - "displayName": "Detail Map UVs", - "description": "Which UV set to use for detail map sampling", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Unwrapped", - "connection": { - "type": "ShaderInput", - "name": "m_detail_allMapsUvIndex" - } - }, - { - "name": "enableBaseColor", - "displayName": "Enable Base Color", - "description": "Enable detail blending for base color", - "type": "Bool", - "defaultValue": false - }, - { - "name": "baseColorDetailMap", - "displayName": " Texture", - "description": "Detailed Base Color Texture", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_detail_baseColor_texture" - } - }, - { - "name": "baseColorDetailBlend", - "displayName": " Blend Factor", - "description": "How much to blend the detail layer into the base color.", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_detail_baseColor_factor" - } - }, - { - "name": "enableNormals", - "displayName": "Enable Normal", - "description": "Enable detail normal map to be used for fine detail normal such as scratches and small dents", - "type": "Bool", - "defaultValue": false - }, - { - "name": "normalDetailStrength", - "displayName": " Factor", - "description": "Strength factor for scaling the Detail Normal", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "softMax": 2.0, - "connection": { - "type": "ShaderInput", - "name": "m_detail_normal_factor" - } - }, - { - "name": "normalDetailMap", - "displayName": " Texture", - "description": "Detailed Normal map", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_detail_normal_texture" - } - }, - { - "name": "normalDetailFlipX", - "displayName": " Flip X Channel", - "description": "Flip Detail tangent direction for this normal map.", - "type": "Bool", - "defaultValue": false, - "connection": { - "type": "ShaderInput", - "name": "m_detail_normal_flipX" - } - }, - { - "name": "normalDetailFlipY", - "displayName": " Flip Y Channel", - "description": "Flip Detail bitangent direction for this normal map.", - "type": "Bool", - "defaultValue": false, - "connection": { - "type": "ShaderInput", - "name": "m_detail_normal_flipY" - } - } - ] + "description": "Properties for Fine Details Layer." }, { "name": "detailUV", "displayName": "Detail Layer UV", - "description": "Properties for modifying detail layer UV.", - "properties": [ - { - "name": "center", - "displayName": "Center", - "description": "Center point for scaling and rotation transformations.", - "type": "vector2", - "vectorLabels": [ "U", "V" ], - "defaultValue": [ 0.5, 0.5 ] - }, - { - "name": "tileU", - "displayName": "Tile U", - "description": "Scales texture coordinates in V.", - "type": "float", - "defaultValue": 1.0, - "step": 0.1 - }, - { - "name": "tileV", - "displayName": "Tile V", - "description": "Scales texture coordinates in V.", - "type": "float", - "defaultValue": 1.0, - "step": 0.1 - }, - { - "name": "offsetU", - "displayName": "Offset U", - "description": "Offsets texture coordinates in the U direction.", - "type": "float", - "defaultValue": 0.0, - "min": -1.0, - "max": 1.0 - }, - { - "name": "offsetV", - "displayName": "Offset V", - "description": "Offsets texture coordinates in the V direction.", - "type": "float", - "defaultValue": 0.0, - "min": -1.0, - "max": 1.0 - }, - { - "name": "rotateDegrees", - "displayName": "Rotate", - "description": "Rotates the texture coordinates (degrees).", - "type": "float", - "defaultValue": 0.0, - "min": -180.0, - "max": 180.0, - "step": 1.0 - }, - { - "name": "scale", - "displayName": "Scale", - "description": "Scales texture coordinates in both U and V.", - "type": "float", - "defaultValue": 1.0, - "step": 0.1 - } - ] + "description": "Properties for modifying detail layer UV." }, { "name": "occlusion", "displayName": "Occlusion", - "description": "Properties for baked textures that represent geometric occlusion of light.", - "properties": [ - { - "name": "diffuseTextureMap", - "displayName": "Diffuse AO", - "description": "Texture for defining occlusion area for diffuse ambient lighting.", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_diffuseOcclusionMap" - } - }, - { - "name": "diffuseUseTexture", - "displayName": " Use Texture", - "description": "Whether to use the Diffuse AO map.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "diffuseTextureMapUv", - "displayName": " UV", - "description": "Diffuse AO map UV set.", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_diffuseOcclusionMapUvIndex" - } - }, - { - "name": "diffuseFactor", - "displayName": " Factor", - "description": "Strength factor for scaling the values of Diffuse AO", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "softMax": 2.0, - "connection": { - "type": "ShaderInput", - "name": "m_diffuseOcclusionFactor" - } - }, - { - "name": "specularTextureMap", - "displayName": "Specular Cavity", - "description": "Texture for defining occlusion area for specular lighting.", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_specularOcclusionMap" - } - }, - { - "name": "specularUseTexture", - "displayName": " Use Texture", - "description": "Whether to use the Specular Cavity map.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "specularTextureMapUv", - "displayName": " UV", - "description": "Specular Cavity map UV set.", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_specularOcclusionMapUvIndex" - } - }, - { - "name": "specularFactor", - "displayName": " Factor", - "description": "Strength factor for scaling the values of Specular Cavity", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "softMax": 2.0, - "connection": { - "type": "ShaderInput", - "name": "m_specularOcclusionFactor" - } - } - ] + "description": "Properties for baked textures that represent geometric occlusion of light." }, { "name": "subsurfaceScattering", "displayName": "Subsurface Scattering", - "description": "Properties for configuring subsurface scattering effects.", - "properties": [ - { - "name": "enableSubsurfaceScattering", - "displayName": "Subsurface Scattering", - "description": "Enable subsurface scattering feature, this will disable metallic and parallax mapping property due to incompatibility", - "type": "Bool", - "defaultValue": false, - "connection": { - "type": "ShaderOption", - "name": "o_enableSubsurfaceScattering" - } - }, - { - "name": "subsurfaceScatterFactor", - "displayName": " Factor", - "description": "Strength factor for scaling percentage of subsurface scattering effect applied", - "type": "float", - "defaultValue": 1.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_subsurfaceScatteringFactor" - } - }, - { - "name": "influenceMap", - "displayName": " Influence Map", - "description": "Texture for controlling the strength of subsurface scattering", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_subsurfaceScatteringInfluenceMap" - } - }, - { - "name": "useInfluenceMap", - "displayName": " Use Influence Map", - "description": "Whether to use the influence map.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "influenceMapUv", - "displayName": " UV", - "description": "Influence map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Unwrapped", - "connection": { - "type": "ShaderInput", - "name": "m_subsurfaceScatteringInfluenceMapUvIndex" - } - }, - { - "name": "scatterColor", - "displayName": " Scatter color", - "description": "Color of volume light traveled through", - "type": "Color", - "defaultValue": [ 1.0, 0.27, 0.13 ] - }, - { - "name": "scatterDistance", - "displayName": " Scatter distance", - "description": "How far light traveled inside the volume", - "type": "float", - "defaultValue": 8, - "min": 0.0, - "softMax": 20.0 - }, - { - "name": "quality", - "displayName": " Quality", - "description": "How much percent of sample will be used for each pixel, more samples improve quality and reduce artifacts, especially when the scatter distance is relatively large, but slow down computation time, 1.0 = full set 200 samples per pixel", - "type": "float", - "defaultValue": 0.4, - "min": 0.2, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_subsurfaceScatteringQuality" - } - }, - { - "name": "transmissionMode", - "displayName": "Transmission", - "description": "Algorithm used for calculating transmission", - "type": "Enum", - "enumValues": [ "None", "ThickObject", "ThinObject" ], - "defaultValue": "None", - "connection": { - "type": "ShaderOption", - "name": "o_transmission_mode" - } - }, - { - "name": "thickness", - "displayName": " Thickness", - "description": "Normalized global thickness, the maxima between this value (multiplied by thickness map if enabled) and thickness from shadow map (if applicable) will be used as final thickness of pixel", - "type": "float", - "defaultValue": 0.5, - "min": 0.0, - "max": 1.0 - }, - { - "name": "thicknessMap", - "displayName": " Thickness Map", - "description": "Texture for controlling per pixel thickness", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_transmissionThicknessMap" - } - }, - { - "name": "useThicknessMap", - "displayName": " Use Thickness Map", - "description": "Whether to use the thickness map", - "type": "Bool", - "defaultValue": true - }, - { - "name": "thicknessMapUv", - "displayName": " UV", - "description": "Thickness map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Unwrapped", - "connection": { - "type": "ShaderInput", - "name": "m_transmissionThicknessMapUvIndex" - } - }, - { - "name": "transmissionTint", - "displayName": " Transmission Tint", - "description": "Color of the volume light traveling through", - "type": "Color", - "defaultValue": [ 1.0, 0.8, 0.6 ] - }, - { - "name": "transmissionPower", - "displayName": " Power", - "description": "How much transmitted light scatter radially ", - "type": "float", - "defaultValue": 6.0, - "min": 0.0, - "softMax": 20.0 - }, - { - "name": "transmissionDistortion", - "displayName": " Distortion", - "description": "How much light direction distorted towards surface normal", - "type": "float", - "defaultValue": 0.1, - "min": 0.0, - "max": 1.0 - }, - { - "name": "transmissionAttenuation", - "displayName": " Attenuation", - "description": "How fast transmitted light fade with thickness", - "type": "float", - "defaultValue": 4.0, - "min": 0.0, - "softMax": 20.0 - }, - { - "name": "transmissionScale", - "displayName": " Scale", - "description": "Strength of transmission", - "type": "float", - "defaultValue": 3.0, - "min": 0.0, - "softMax": 20.0 - } - ] + "description": "Properties for configuring subsurface scattering effects." }, { "name": "wrinkleLayers", "displayName": "Wrinkle Layers", - "description": "Properties for wrinkle maps to support morph animation, using vertex color blend weights.", - "properties": [ - { - "name": "enable", - "displayName": "Enable Wrinkle Layers", - "description": "Enable wrinkle layers for morph animations, using vertex color blend weights.", - "type": "Bool", - "defaultValue": false - }, - { - "name": "count", - "displayName": "Number Of Layers", - "description": "The number of wrinkle map layers to use. The blend values come from the 'COLOR0' vertex stream, where R/G/B/A correspond to wrinkle layers 1/2/3/4 respectively.", - "type": "UInt", - "defaultValue": 4, - "min": 1, - "max": 4 - }, - { - "name": "showBlendValues", - "displayName": "Show Blend Values", - "description": "Enable a debug mode that draws the blend values as red, green, blue, and white overlays.", - "type": "Bool", - "defaultValue": false - }, - { - "name": "enableBaseColor", - "displayName": "Enable Base Color Maps", - "description": "Enable support for blending the base color according to morph animations.", - "type": "Bool", - "defaultValue": false - }, - { - "name": "baseColorMap1", - "displayName": " Base Color 1", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_wrinkle_baseColor_texture1" - } - }, - { - "name": "baseColorMap2", - "displayName": " Base Color 2", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_wrinkle_baseColor_texture2" - } - }, - { - "name": "baseColorMap3", - "displayName": " Base Color 3", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_wrinkle_baseColor_texture3" - } - }, - { - "name": "baseColorMap4", - "displayName": " Base Color 4", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_wrinkle_baseColor_texture4" - } - }, - { - "name": "enableNormal", - "displayName": "Enable Normal Maps", - "description": "Enable support for blending the normal maps according to morph animations.", - "type": "Bool", - "defaultValue": false - }, - { - "name": "normalMap1", - "displayName": " Normals 1", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_wrinkle_normal_texture1" - } - }, - { - "name": "normalMap2", - "displayName": " Normals 2", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_wrinkle_normal_texture2" - } - }, - { - "name": "normalMap3", - "displayName": " Normals 3", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_wrinkle_normal_texture3" - } - }, - { - "name": "normalMap4", - "displayName": " Normals 4", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_wrinkle_normal_texture4" - } - } - ] + "description": "Properties for wrinkle maps to support morph animation, using vertex color blend weights." }, { "name": "general", "displayName": "General Settings", - "description": "General settings.", - "properties": [ - { - "name": "applySpecularAA", - "displayName": "Apply Specular AA", - "description": "Whether to apply specular anti-aliasing in the shader.", - "type": "Bool", - "defaultValue": false, - "connection": { - "type": "ShaderOption", - "name": "o_applySpecularAA" - } - }, - { - "name": "enableShadows", - "displayName": "Enable Shadows", - "description": "Whether to use the shadow maps.", - "type": "Bool", - "defaultValue": true, - "connection": { - "type": "ShaderOption", - "name": "o_enableShadows" - } - }, - { - "name": "enableDirectionalLights", - "displayName": "Enable Directional Lights", - "description": "Whether to use directional lights.", - "type": "Bool", - "defaultValue": true, - "connection": { - "type": "ShaderOption", - "name": "o_enableDirectionalLights" - } - }, - { - "name": "enablePunctualLights", - "displayName": "Enable Punctual Lights", - "description": "Whether to use punctual lights.", - "type": "Bool", - "defaultValue": true, - "connection": { - "type": "ShaderOption", - "name": "o_enablePunctualLights" - } - }, - { - "name": "enableAreaLights", - "displayName": "Enable Area Lights", - "description": "Whether to use area lights.", - "type": "Bool", - "defaultValue": true, - "connection": { - "type": "ShaderOption", - "name": "o_enableAreaLights" - } - }, - { - "name": "enableIBL", - "displayName": "Enable IBL", - "description": "Whether to use Image Based Lighting (IBL).", - "type": "Bool", - "defaultValue": true, - "connection": { - "type": "ShaderOption", - "name": "o_enableIBL" - } - } - ] + "description": "General settings." } - ] + ], + "properties": { + "general": [ + { + "name": "applySpecularAA", + "displayName": "Apply Specular AA", + "description": "Whether to apply specular anti-aliasing in the shader.", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderOption", + "name": "o_applySpecularAA" + } + }, + { + "name": "enableShadows", + "displayName": "Enable Shadows", + "description": "Whether to use the shadow maps.", + "type": "Bool", + "defaultValue": true, + "connection": { + "type": "ShaderOption", + "name": "o_enableShadows" + } + }, + { + "name": "enableDirectionalLights", + "displayName": "Enable Directional Lights", + "description": "Whether to use directional lights.", + "type": "Bool", + "defaultValue": true, + "connection": { + "type": "ShaderOption", + "name": "o_enableDirectionalLights" + } + }, + { + "name": "enablePunctualLights", + "displayName": "Enable Punctual Lights", + "description": "Whether to use punctual lights.", + "type": "Bool", + "defaultValue": true, + "connection": { + "type": "ShaderOption", + "name": "o_enablePunctualLights" + } + }, + { + "name": "enableAreaLights", + "displayName": "Enable Area Lights", + "description": "Whether to use area lights.", + "type": "Bool", + "defaultValue": true, + "connection": { + "type": "ShaderOption", + "name": "o_enableAreaLights" + } + }, + { + "name": "enableIBL", + "displayName": "Enable IBL", + "description": "Whether to use Image Based Lighting (IBL).", + "type": "Bool", + "defaultValue": true, + "connection": { + "type": "ShaderOption", + "name": "o_enableIBL" + } + } + ], + "baseColor": [ + { + "name": "color", + "displayName": "Color", + "description": "Color is displayed as sRGB but the values are stored as linear color.", + "type": "Color", + "defaultValue": [ 1.0, 1.0, 1.0 ], + "connection": { + "type": "ShaderInput", + "name": "m_baseColor" + } + }, + { + "name": "factor", + "displayName": "Factor", + "description": "Strength factor for scaling the base color values. Zero (0.0) is black, white (1.0) is full color.", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_baseColorFactor" + } + }, + { + "name": "textureMap", + "displayName": "Texture", + "description": "Base color texture map", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_baseColorMap" + } + }, + { + "name": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "textureMapUv", + "displayName": "UV", + "description": "Base color map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Unwrapped", + "connection": { + "type": "ShaderInput", + "name": "m_baseColorMapUvIndex" + } + }, + { + "name": "textureBlendMode", + "displayName": "Texture Blend Mode", + "description": "Selects the equation to use when combining Color, Factor, and Texture.", + "type": "Enum", + "enumValues": [ "Multiply", "LinearLight", "Lerp", "Overlay" ], + "defaultValue": "Multiply", + "connection": { + "type": "ShaderOption", + "name": "o_baseColorTextureBlendMode" + } + } + ], + "roughness": [ + { + "name": "textureMap", + "displayName": "Texture", + "description": "Texture for defining surface roughness.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_roughnessMap" + } + }, + { + "name": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture, or just default to the Factor value.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "textureMapUv", + "displayName": "UV", + "description": "Roughness map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Unwrapped", + "connection": { + "type": "ShaderInput", + "name": "m_roughnessMapUvIndex" + } + }, + { + // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. + "name": "lowerBound", + "displayName": "Lower Bound", + "description": "The roughness value that corresponds to black in the texture.", + "type": "Float", + "defaultValue": 0.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_roughnessLowerBound" + } + }, + { + // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. + "name": "upperBound", + "displayName": "Upper Bound", + "description": "The roughness value that corresponds to white in the texture.", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_roughnessUpperBound" + } + }, + { + // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. + "name": "factor", + "displayName": "Factor", + "description": "Controls the roughness value", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_roughnessFactor" + } + } + ], + "specularF0": [ + { + "name": "factor", + "displayName": "Factor", + "description": "The default IOR is 1.5, which gives you 0.04 (4% of light reflected at 0 degree angle for dielectric materials). F0 values lie in the range 0-0.08, so that is why the default F0 slider is set on 0.5.", + "type": "Float", + "defaultValue": 0.5, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_specularF0Factor" + } + }, + { + "name": "textureMap", + "displayName": "Texture", + "description": "Texture for defining surface reflectance.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_specularF0Map" + } + }, + { + "name": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture, or just default to the Factor value.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "textureMapUv", + "displayName": "UV", + "description": "Specular reflection map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Unwrapped", + "connection": { + "type": "ShaderInput", + "name": "m_specularF0MapUvIndex" + } + }, + // Consider moving this to the "general" group to be consistent with StandardMultilayerPBR + { + "name": "enableMultiScatterCompensation", + "displayName": "Multiscattering Compensation", + "description": "Whether to enable multiple scattering compensation.", + "type": "Bool", + "connection": { + "type": "ShaderOption", + "name": "o_specularF0_enableMultiScatterCompensation" + } + } + ], + "normal": [ + { + "name": "textureMap", + "displayName": "Texture", + "description": "Texture for defining surface normal direction.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_normalMap" + } + }, + { + "name": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture, or just rely on vertex normals.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "textureMapUv", + "displayName": "UV", + "description": "Normal map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Unwrapped", + "connection": { + "type": "ShaderInput", + "name": "m_normalMapUvIndex" + } + }, + { + "name": "flipX", + "displayName": "Flip X Channel", + "description": "Flip tangent direction for this normal map.", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderInput", + "name": "m_flipNormalX" + } + }, + { + "name": "flipY", + "displayName": "Flip Y Channel", + "description": "Flip bitangent direction for this normal map.", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderInput", + "name": "m_flipNormalY" + } + }, + { + "name": "factor", + "displayName": "Factor", + "description": "Strength factor for scaling the values", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "softMax": 2.0, + "connection": { + "type": "ShaderInput", + "name": "m_normalFactor" + } + } + ], + "occlusion": [ + { + "name": "diffuseTextureMap", + "displayName": "Diffuse AO", + "description": "Texture for defining occlusion area for diffuse ambient lighting.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_diffuseOcclusionMap" + } + }, + { + "name": "diffuseUseTexture", + "displayName": " Use Texture", + "description": "Whether to use the Diffuse AO map.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "diffuseTextureMapUv", + "displayName": " UV", + "description": "Diffuse AO map UV set.", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_diffuseOcclusionMapUvIndex" + } + }, + { + "name": "diffuseFactor", + "displayName": " Factor", + "description": "Strength factor for scaling the values of Diffuse AO", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "softMax": 2.0, + "connection": { + "type": "ShaderInput", + "name": "m_diffuseOcclusionFactor" + } + }, + { + "name": "specularTextureMap", + "displayName": "Specular Cavity", + "description": "Texture for defining occlusion area for specular lighting.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_specularOcclusionMap" + } + }, + { + "name": "specularUseTexture", + "displayName": " Use Texture", + "description": "Whether to use the Specular Cavity map.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "specularTextureMapUv", + "displayName": " UV", + "description": "Specular Cavity map UV set.", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_specularOcclusionMapUvIndex" + } + }, + { + "name": "specularFactor", + "displayName": " Factor", + "description": "Strength factor for scaling the values of Specular Cavity", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "softMax": 2.0, + "connection": { + "type": "ShaderInput", + "name": "m_specularOcclusionFactor" + } + } + ], + "subsurfaceScattering": [ + { + "name": "enableSubsurfaceScattering", + "displayName": "Subsurface Scattering", + "description": "Enable subsurface scattering feature, this will disable metallic and parallax mapping property due to incompatibility", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderOption", + "name": "o_enableSubsurfaceScattering" + } + }, + { + "name": "subsurfaceScatterFactor", + "displayName": " Factor", + "description": "Strength factor for scaling percentage of subsurface scattering effect applied", + "type": "float", + "defaultValue": 1.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_subsurfaceScatteringFactor" + } + }, + { + "name": "influenceMap", + "displayName": " Influence Map", + "description": "Texture for controlling the strength of subsurface scattering", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_subsurfaceScatteringInfluenceMap" + } + }, + { + "name": "useInfluenceMap", + "displayName": " Use Influence Map", + "description": "Whether to use the influence map.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "influenceMapUv", + "displayName": " UV", + "description": "Influence map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Unwrapped", + "connection": { + "type": "ShaderInput", + "name": "m_subsurfaceScatteringInfluenceMapUvIndex" + } + }, + { + "name": "scatterColor", + "displayName": " Scatter color", + "description": "Color of volume light traveled through", + "type": "Color", + "defaultValue": [ 1.0, 0.27, 0.13 ] + }, + { + "name": "scatterDistance", + "displayName": " Scatter distance", + "description": "How far light traveled inside the volume", + "type": "float", + "defaultValue": 8, + "min": 0.0, + "softMax": 20.0 + }, + { + "name": "quality", + "displayName": " Quality", + "description": "How much percent of sample will be used for each pixel, more samples improve quality and reduce artifacts, especially when the scatter distance is relatively large, but slow down computation time, 1.0 = full set 200 samples per pixel", + "type": "float", + "defaultValue": 0.4, + "min": 0.2, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_subsurfaceScatteringQuality" + } + }, + { + "name": "transmissionMode", + "displayName": "Transmission", + "description": "Algorithm used for calculating transmission", + "type": "Enum", + "enumValues": [ "None", "ThickObject", "ThinObject" ], + "defaultValue": "None", + "connection": { + "type": "ShaderOption", + "name": "o_transmission_mode" + } + }, + { + "name": "thickness", + "displayName": " Thickness", + "description": "Normalized global thickness, the maxima between this value (multiplied by thickness map if enabled) and thickness from shadow map (if applicable) will be used as final thickness of pixel", + "type": "float", + "defaultValue": 0.5, + "min": 0.0, + "max": 1.0 + }, + { + "name": "thicknessMap", + "displayName": " Thickness Map", + "description": "Texture for controlling per pixel thickness", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_transmissionThicknessMap" + } + }, + { + "name": "useThicknessMap", + "displayName": " Use Thickness Map", + "description": "Whether to use the thickness map", + "type": "Bool", + "defaultValue": true + }, + { + "name": "thicknessMapUv", + "displayName": " UV", + "description": "Thickness map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Unwrapped", + "connection": { + "type": "ShaderInput", + "name": "m_transmissionThicknessMapUvIndex" + } + }, + { + "name": "transmissionTint", + "displayName": " Transmission Tint", + "description": "Color of the volume light traveling through", + "type": "Color", + "defaultValue": [ 1.0, 0.8, 0.6 ] + }, + { + "name": "transmissionPower", + "displayName": " Power", + "description": "How much transmitted light scatter radially ", + "type": "float", + "defaultValue": 6.0, + "min": 0.0, + "softMax": 20.0 + }, + { + "name": "transmissionDistortion", + "displayName": " Distortion", + "description": "How much light direction distorted towards surface normal", + "type": "float", + "defaultValue": 0.1, + "min": 0.0, + "max": 1.0 + }, + { + "name": "transmissionAttenuation", + "displayName": " Attenuation", + "description": "How fast transmitted light fade with thickness", + "type": "float", + "defaultValue": 4.0, + "min": 0.0, + "softMax": 20.0 + }, + { + "name": "transmissionScale", + "displayName": " Scale", + "description": "Strength of transmission", + "type": "float", + "defaultValue": 3.0, + "min": 0.0, + "softMax": 20.0 + } + ], + "wrinkleLayers": [ + { + "name": "enable", + "displayName": "Enable Wrinkle Layers", + "description": "Enable wrinkle layers for morph animations, using vertex color blend weights.", + "type": "Bool", + "defaultValue": false + }, + { + "name": "count", + "displayName": "Number Of Layers", + "description": "The number of wrinkle map layers to use. The blend values come from the 'COLOR0' vertex stream, where R/G/B/A correspond to wrinkle layers 1/2/3/4 respectively.", + "type": "UInt", + "defaultValue": 4, + "min": 1, + "max": 4 + }, + { + "name": "showBlendValues", + "displayName": "Show Blend Values", + "description": "Enable a debug mode that draws the blend values as red, green, blue, and white overlays.", + "type": "Bool", + "defaultValue": false + }, + { + "name": "enableBaseColor", + "displayName": "Enable Base Color Maps", + "description": "Enable support for blending the base color according to morph animations.", + "type": "Bool", + "defaultValue": false + }, + { + "name": "baseColorMap1", + "displayName": " Base Color 1", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_wrinkle_baseColor_texture1" + } + }, + { + "name": "baseColorMap2", + "displayName": " Base Color 2", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_wrinkle_baseColor_texture2" + } + }, + { + "name": "baseColorMap3", + "displayName": " Base Color 3", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_wrinkle_baseColor_texture3" + } + }, + { + "name": "baseColorMap4", + "displayName": " Base Color 4", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_wrinkle_baseColor_texture4" + } + }, + { + "name": "enableNormal", + "displayName": "Enable Normal Maps", + "description": "Enable support for blending the normal maps according to morph animations.", + "type": "Bool", + "defaultValue": false + }, + { + "name": "normalMap1", + "displayName": " Normals 1", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_wrinkle_normal_texture1" + } + }, + { + "name": "normalMap2", + "displayName": " Normals 2", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_wrinkle_normal_texture2" + } + }, + { + "name": "normalMap3", + "displayName": " Normals 3", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_wrinkle_normal_texture3" + } + }, + { + "name": "normalMap4", + "displayName": " Normals 4", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_wrinkle_normal_texture4" + } + } + ], + "detailLayerGroup": [ + { + "name": "enableDetailLayer", + "displayName": "Enable Detail Layer", + "description": "Enable detail layer for fine details and scratches", + "type": "Bool", + "defaultValue": false + }, + { + "name": "blendDetailFactor", + "displayName": "Blend Factor", + "description": "Scales the overall impact of the detail layer.", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_detail_blendFactor" + } + }, + { + "name": "blendDetailMask", + "displayName": "Blend Mask", + "description": "Detailed blend mask for application of the detail maps.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_detail_blendMask_texture" + } + }, + { + "name": "enableDetailMaskTexture", + "displayName": " Use Texture", + "description": "Enable detail blend mask", + "type": "Bool", + "defaultValue": true + }, + { + "name": "blendDetailMaskUv", + "displayName": " Blend Mask UV", + "description": "Which UV set to use for sampling the detail blend mask", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Unwrapped", + "connection": { + "type": "ShaderInput", + "name": "m_detail_blendMask_uvIndex" + } + }, + { + "name": "textureMapUv", + "displayName": "Detail Map UVs", + "description": "Which UV set to use for detail map sampling", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Unwrapped", + "connection": { + "type": "ShaderInput", + "name": "m_detail_allMapsUvIndex" + } + }, + { + "name": "enableBaseColor", + "displayName": "Enable Base Color", + "description": "Enable detail blending for base color", + "type": "Bool", + "defaultValue": false + }, + { + "name": "baseColorDetailMap", + "displayName": " Texture", + "description": "Detailed Base Color Texture", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_detail_baseColor_texture" + } + }, + { + "name": "baseColorDetailBlend", + "displayName": " Blend Factor", + "description": "How much to blend the detail layer into the base color.", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_detail_baseColor_factor" + } + }, + { + "name": "enableNormals", + "displayName": "Enable Normal", + "description": "Enable detail normal map to be used for fine detail normal such as scratches and small dents", + "type": "Bool", + "defaultValue": false + }, + { + "name": "normalDetailStrength", + "displayName": " Factor", + "description": "Strength factor for scaling the Detail Normal", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "softMax": 2.0, + "connection": { + "type": "ShaderInput", + "name": "m_detail_normal_factor" + } + }, + { + "name": "normalDetailMap", + "displayName": " Texture", + "description": "Detailed Normal map", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_detail_normal_texture" + } + }, + { + "name": "normalDetailFlipX", + "displayName": " Flip X Channel", + "description": "Flip Detail tangent direction for this normal map.", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderInput", + "name": "m_detail_normal_flipX" + } + }, + { + "name": "normalDetailFlipY", + "displayName": " Flip Y Channel", + "description": "Flip Detail bitangent direction for this normal map.", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderInput", + "name": "m_detail_normal_flipY" + } + } + ], + "detailUV": [ + { + "name": "center", + "displayName": "Center", + "description": "Center point for scaling and rotation transformations.", + "type": "vector2", + "vectorLabels": [ "U", "V" ], + "defaultValue": [ 0.5, 0.5 ] + }, + { + "name": "tileU", + "displayName": "Tile U", + "description": "Scales texture coordinates in V.", + "type": "float", + "defaultValue": 1.0, + "step": 0.1 + }, + { + "name": "tileV", + "displayName": "Tile V", + "description": "Scales texture coordinates in V.", + "type": "float", + "defaultValue": 1.0, + "step": 0.1 + }, + { + "name": "offsetU", + "displayName": "Offset U", + "description": "Offsets texture coordinates in the U direction.", + "type": "float", + "defaultValue": 0.0, + "min": -1.0, + "max": 1.0 + }, + { + "name": "offsetV", + "displayName": "Offset V", + "description": "Offsets texture coordinates in the V direction.", + "type": "float", + "defaultValue": 0.0, + "min": -1.0, + "max": 1.0 + }, + { + "name": "rotateDegrees", + "displayName": "Rotate", + "description": "Rotates the texture coordinates (degrees).", + "type": "float", + "defaultValue": 0.0, + "min": -180.0, + "max": 180.0, + "step": 1.0 + }, + { + "name": "scale", + "displayName": "Scale", + "description": "Scales texture coordinates in both U and V.", + "type": "float", + "defaultValue": 1.0, + "step": 0.1 + } + ] + } }, "shaders": [ { diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR.materialtype b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR.materialtype index 0789d758b8..88e845ddf0 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR.materialtype +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR.materialtype @@ -10,1010 +10,1013 @@ } ], "propertyLayout": { - "propertySets": [ + "groups": [ { "name": "baseColor", "displayName": "Base Color", - "description": "Properties for configuring the surface reflected color for dielectrics or reflectance values for metals.", - "properties": [ - { - "name": "color", - "displayName": "Color", - "description": "Color is displayed as sRGB but the values are stored as linear color.", - "type": "Color", - "defaultValue": [ 1.0, 1.0, 1.0 ], - "connection": { - "type": "ShaderInput", - "name": "m_baseColor" - } - }, - { - "name": "factor", - "displayName": "Factor", - "description": "Strength factor for scaling the base color values. Zero (0.0) is black, white (1.0) is full color.", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_baseColorFactor" - } - }, - { - "name": "textureMap", - "displayName": "Texture", - "description": "Base color texture map", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_baseColorMap" - } - }, - { - "name": "useTexture", - "displayName": "Use Texture", - "description": "Whether to use the texture.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "textureMapUv", - "displayName": "UV", - "description": "Base color map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_baseColorMapUvIndex" - } - }, - { - "name": "textureBlendMode", - "displayName": "Texture Blend Mode", - "description": "Selects the equation to use when combining Color, Factor, and Texture.", - "type": "Enum", - "enumValues": [ "Multiply", "LinearLight", "Lerp", "Overlay" ], - "defaultValue": "Multiply", - "connection": { - "type": "ShaderOption", - "name": "o_baseColorTextureBlendMode" - } - } - ] + "description": "Properties for configuring the surface reflected color for dielectrics or reflectance values for metals." }, { "name": "metallic", "displayName": "Metallic", - "description": "Properties for configuring whether the surface is metallic or not.", - "properties": [ - { - "name": "factor", - "displayName": "Factor", - "description": "This value is linear, black is non-metal and white means raw metal.", - "type": "Float", - "defaultValue": 0.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_metallicFactor" - } - }, - { - "name": "textureMap", - "displayName": "Texture", - "description": "", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_metallicMap" - } - }, - { - "name": "useTexture", - "displayName": "Use Texture", - "description": "Whether to use the texture, or just default to the Factor value.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "textureMapUv", - "displayName": "UV", - "description": "Metallic map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_metallicMapUvIndex" - } - } - ] + "description": "Properties for configuring whether the surface is metallic or not." }, { "name": "roughness", "displayName": "Roughness", - "description": "Properties for configuring how rough the surface appears.", - "properties": [ - { - "name": "textureMap", - "displayName": "Texture", - "description": "Texture for defining surface roughness.", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_roughnessMap" - } - }, - { - "name": "useTexture", - "displayName": "Use Texture", - "description": "Whether to use the texture, or just default to the Factor value.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "textureMapUv", - "displayName": "UV", - "description": "Roughness map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_roughnessMapUvIndex" - } - }, - { - // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. - "name": "lowerBound", - "displayName": "Lower Bound", - "description": "The roughness value that corresponds to black in the texture.", - "type": "Float", - "defaultValue": 0.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_roughnessLowerBound" - } - }, - { - // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. - "name": "upperBound", - "displayName": "Upper Bound", - "description": "The roughness value that corresponds to white in the texture.", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_roughnessUpperBound" - } - }, - { - // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. - "name": "factor", - "displayName": "Factor", - "description": "Controls the roughness value", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_roughnessFactor" - } - } - ] + "description": "Properties for configuring how rough the surface appears." }, { "name": "specularF0", "displayName": "Specular Reflectance f0", - "description": "The constant f0 represents the specular reflectance at normal incidence (Fresnel 0 Angle). Used to adjust reflectance of non-metal surfaces.", - "properties": [ - { - "name": "factor", - "displayName": "Factor", - "description": "The default IOR is 1.5, which gives you 0.04 (4% of light reflected at 0 degree angle for dielectric materials). F0 values lie in the range 0-0.08, so that is why the default F0 slider is set on 0.5.", - "type": "Float", - "defaultValue": 0.5, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_specularF0Factor" - } - }, - { - "name": "textureMap", - "displayName": "Texture", - "description": "Texture for defining surface reflectance.", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_specularF0Map" - } - }, - { - "name": "useTexture", - "displayName": "Use Texture", - "description": "Whether to use the texture, or just default to the Factor value.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "textureMapUv", - "displayName": "UV", - "description": "Specular reflection map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_specularF0MapUvIndex" - } - }, - // Consider moving this to the "general" group to be consistent with StandardMultilayerPBR - { - "name": "enableMultiScatterCompensation", - "displayName": "Multiscattering Compensation", - "description": "Whether to enable multiple scattering compensation.", - "type": "Bool", - "connection": { - "type": "ShaderOption", - "name": "o_specularF0_enableMultiScatterCompensation" - } - } - ] + "description": "The constant f0 represents the specular reflectance at normal incidence (Fresnel 0 Angle). Used to adjust reflectance of non-metal surfaces." }, { "name": "normal", "displayName": "Normal", - "description": "Properties related to configuring surface normal.", - "properties": [ - { - "name": "textureMap", - "displayName": "Texture", - "description": "Texture for defining surface normal direction.", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_normalMap" - } - }, - { - "name": "useTexture", - "displayName": "Use Texture", - "description": "Whether to use the texture, or just rely on vertex normals.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "textureMapUv", - "displayName": "UV", - "description": "Normal map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_normalMapUvIndex" - } - }, - { - "name": "flipX", - "displayName": "Flip X Channel", - "description": "Flip tangent direction for this normal map.", - "type": "Bool", - "defaultValue": false, - "connection": { - "type": "ShaderInput", - "name": "m_flipNormalX" - } - }, - { - "name": "flipY", - "displayName": "Flip Y Channel", - "description": "Flip bitangent direction for this normal map.", - "type": "Bool", - "defaultValue": false, - "connection": { - "type": "ShaderInput", - "name": "m_flipNormalY" - } - }, - { - "name": "factor", - "displayName": "Factor", - "description": "Strength factor for scaling the values", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "softMax": 2.0, - "connection": { - "type": "ShaderInput", - "name": "m_normalFactor" - } - } - ] + "description": "Properties related to configuring surface normal." }, { "name": "occlusion", "displayName": "Occlusion", - "description": "Properties for baked textures that represent geometric occlusion of light.", - "properties": [ - { - "name": "diffuseTextureMap", - "displayName": "Diffuse AO", - "description": "Texture for defining occlusion area for diffuse ambient lighting.", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_diffuseOcclusionMap" - } - }, - { - "name": "diffuseUseTexture", - "displayName": " Use Texture", - "description": "Whether to use the Diffuse AO map.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "diffuseTextureMapUv", - "displayName": " UV", - "description": "Diffuse AO map UV set.", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_diffuseOcclusionMapUvIndex" - } - }, - { - "name": "diffuseFactor", - "displayName": " Factor", - "description": "Strength factor for scaling the values of Diffuse AO", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "softMax": 2.0, - "connection": { - "type": "ShaderInput", - "name": "m_diffuseOcclusionFactor" - } - }, - { - "name": "specularTextureMap", - "displayName": "Specular Cavity", - "description": "Texture for defining occlusion area for specular lighting.", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_specularOcclusionMap" - } - }, - { - "name": "specularUseTexture", - "displayName": " Use Texture", - "description": "Whether to use the Specular Cavity map.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "specularTextureMapUv", - "displayName": " UV", - "description": "Specular Cavity map UV set.", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_specularOcclusionMapUvIndex" - } - }, - { - "name": "specularFactor", - "displayName": " Factor", - "description": "Strength factor for scaling the values of Specular Cavity", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "softMax": 2.0, - "connection": { - "type": "ShaderInput", - "name": "m_specularOcclusionFactor" - } - } - ] + "description": "Properties for baked textures that represent geometric occlusion of light." }, { "name": "emissive", "displayName": "Emissive", - "description": "Properties to add light emission, independent of other lights in the scene.", - "properties": [ - { - "name": "enable", - "displayName": "Enable", - "description": "Enable the emissive group", - "type": "Bool", - "defaultValue": false - }, - { - "name": "unit", - "displayName": "Units", - "description": "The photometric units of the Intensity property.", - "type": "Enum", - "enumValues": ["Ev100"], - "defaultValue": "Ev100" - }, - { - "name": "color", - "displayName": "Color", - "description": "Color is displayed as sRGB but the values are stored as linear color.", - "type": "Color", - "defaultValue": [ 1.0, 1.0, 1.0 ], - "connection": { - "type": "ShaderInput", - "name": "m_emissiveColor" - } - }, - { - "name": "intensity", - "displayName": "Intensity", - "description": "The amount of energy emitted.", - "type": "Float", - "defaultValue": 4, - "min": -10, - "max": 20, - "softMin": -6, - "softMax": 16 - }, - { - "name": "textureMap", - "displayName": "Texture", - "description": "Texture for defining emissive area.", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_emissiveMap" - } - }, - { - "name": "useTexture", - "displayName": "Use Texture", - "description": "Whether to use the texture.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "textureMapUv", - "displayName": "UV", - "description": "Emissive map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_emissiveMapUvIndex" - } - } - ] + "description": "Properties to add light emission, independent of other lights in the scene." }, { "name": "clearCoat", "displayName": "Clear Coat", - "description": "Properties for configuring gloss clear coat", - "properties": [ - { - "name": "enable", - "displayName": "Enable", - "description": "Enable clear coat", - "type": "Bool", - "defaultValue": false - }, - { - "name": "factor", - "displayName": "Factor", - "description": "Strength factor for scaling the percentage of effect applied", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_clearCoatFactor" - } - }, - { - "name": "influenceMap", - "displayName": " Influence Map", - "description": "Strength factor texture", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_clearCoatInfluenceMap" - } - }, - { - "name": "useInfluenceMap", - "displayName": " Use Texture", - "description": "Whether to use the texture, or just default to the Factor value.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "influenceMapUv", - "displayName": " UV", - "description": "Strength factor map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_clearCoatInfluenceMapUvIndex" - } - }, - { - "name": "roughness", - "displayName": "Roughness", - "description": "Clear coat layer roughness", - "type": "Float", - "defaultValue": 0.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_clearCoatRoughness" - } - }, - { - "name": "roughnessMap", - "displayName": " Roughness Map", - "description": "Texture for defining surface roughness", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_clearCoatRoughnessMap" - } - }, - { - "name": "useRoughnessMap", - "displayName": " Use Texture", - "description": "Whether to use the texture, or just default to the roughness value.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "roughnessMapUv", - "displayName": " UV", - "description": "Roughness map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_clearCoatRoughnessMapUvIndex" - } - }, - { - "name": "normalStrength", - "displayName": "Normal Strength", - "description": "Scales the impact of the clear coat normal map", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "max": 2.0, - "connection": { - "type": "ShaderInput", - "name": "m_clearCoatNormalStrength" - } - }, - { - "name": "normalMap", - "displayName": "Normal Map", - "description": "Normal map for clear coat layer, as top layer material clear coat doesn't affect by base layer normal map", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_clearCoatNormalMap" - } - }, - { - "name": "useNormalMap", - "displayName": " Use Texture", - "description": "Whether to use the normal map", - "type": "Bool", - "defaultValue": true - }, - { - "name": "normalMapUv", - "displayName": " UV", - "description": "Normal map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_clearCoatNormalMapUvIndex" - } - } - ] - }, + "description": "Properties for configuring gloss clear coat" + }, { "name": "parallax", "displayName": "Displacement", - "description": "Properties for parallax effect produced by a height map.", - "properties": [ - { - "name": "textureMap", - "displayName": "Height Map", - "description": "Displacement height map to create parallax effect.", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_heightmap" - } - }, - { - "name": "useTexture", - "displayName": "Use Texture", - "description": "Whether to use the height map.", - "type": "Bool", - "defaultValue": true - }, - { - "name": "textureMapUv", - "displayName": "UV", - "description": "Height map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_parallaxUvIndex" - } - }, - { - "name": "factor", - "displayName": "Height Map Scale", - "description": "The total height of the height map in local model units.", - "type": "Float", - "defaultValue": 0.05, - "min": 0.0, - "softMax": 0.1, - "connection": { - "type": "ShaderInput", - "name": "m_heightmapScale" - } - }, - { - "name": "offset", - "displayName": "Offset", - "description": "Adjusts the overall displacement amount in local model units.", - "type": "Float", - "defaultValue": 0.0, - "softMin": -0.1, - "softMax": 0.1, - "connection": { - "type": "ShaderInput", - "name": "m_heightmapOffset" - } - }, - { - "name": "algorithm", - "displayName": "Algorithm", - "description": "Select the algorithm to use for parallax mapping.", - "type": "Enum", - "enumValues": [ "Basic", "Steep", "POM", "Relief", "ContactRefinement" ], - "defaultValue": "POM", - "connection": { - "type": "ShaderOption", - "name": "o_parallax_algorithm" - } - }, - { - "name": "quality", - "displayName": "Quality", - "description": "Quality of parallax mapping.", - "type": "Enum", - "enumValues": [ "Low", "Medium", "High", "Ultra" ], - "defaultValue": "Low", - "connection": { - "type": "ShaderOption", - "name": "o_parallax_quality" - } - }, - { - "name": "pdo", - "displayName": "Pixel Depth Offset", - "description": "Enable PDO to offset the original pixel depths. This will affect any shaders using depth, for example, when receiving shadows.", - "type": "Bool", - "defaultValue": false, - "connection": { - "type": "ShaderOption", - "name": "o_parallax_enablePixelDepthOffset" - } - }, - { - "name": "showClipping", - "displayName": "Show Clipping", - "description": "Highlight areas where the height map is clipped by the mesh surface.", - "type": "Bool", - "defaultValue": false, - "connection": { - "type": "ShaderOption", - "name": "o_parallax_highlightClipping" - } - } - ] + "description": "Properties for parallax effect produced by a height map." }, { "name": "opacity", "displayName": "Opacity", - "description": "Properties for configuring the materials transparency.", - "properties": [ - { - "name": "mode", - "displayName": "Opacity Mode", - "description": "Indicates the general approach how transparency is to be applied.", - "type": "Enum", - "enumValues": [ "Opaque", "Cutout", "Blended", "TintedTransparent" ], - "defaultValue": "Opaque", - "connection": { - "type": "ShaderOption", - "name": "o_opacity_mode" - } - }, - { - "name": "alphaSource", - "displayName": "Alpha Source", - "description": "Indicates whether to get the opacity texture from the Base Color map (Packed) or from a separate greyscale texture (Split).", - "type": "Enum", - "enumValues": [ "Packed", "Split", "None" ], - "defaultValue": "Packed", - "connection": { - "type": "ShaderOption", - "name": "o_opacity_source" - } - }, - { - "name": "textureMap", - "displayName": "Texture", - "description": "Texture for defining surface opacity.", - "type": "Image", - "connection": { - "type": "ShaderInput", - "name": "m_opacityMap" - } - }, - { - "name": "textureMapUv", - "displayName": "UV", - "description": "Opacity map UV set", - "type": "Enum", - "enumIsUv": true, - "defaultValue": "Tiled", - "connection": { - "type": "ShaderInput", - "name": "m_opacityMapUvIndex" - } - }, - { - "name": "factor", - "displayName": "Factor", - "description": "Factor for cutout threshold and blending", - "type": "Float", - "min": 0.0, - "max": 1.0, - "defaultValue": 0.5, - "connection": { - "type": "ShaderInput", - "name": "m_opacityFactor" - } - }, - { - "name": "alphaAffectsSpecular", - "displayName": "Alpha affects specular", - "description": "How much the alpha value should also affect specular reflection. This should be 0.0 for materials where light can transmit through their physical surface (like glass), but 1.0 when alpha determines the very presence of a surface (like hair or grass)", - "type": "float", - "min": 0.0, - "max": 1.0, - "defaultValue": 0.0, - "connection": { - "type": "ShaderInput", - "name": "m_opacityAffectsSpecularFactor" - } - } - ] + "description": "Properties for configuring the materials transparency." }, { "name": "uv", "displayName": "UVs", - "description": "Properties for configuring UV transforms.", - "properties": [ - { - "name": "center", - "displayName": "Center", - "description": "Center point for scaling and rotation transformations.", - "type": "vector2", - "vectorLabels": [ "U", "V" ], - "defaultValue": [ 0.5, 0.5 ] - }, - { - "name": "tileU", - "displayName": "Tile U", - "description": "Scales texture coordinates in U.", - "type": "float", - "defaultValue": 1.0, - "step": 0.1 - }, - { - "name": "tileV", - "displayName": "Tile V", - "description": "Scales texture coordinates in V.", - "type": "float", - "defaultValue": 1.0, - "step": 0.1 - }, - { - "name": "offsetU", - "displayName": "Offset U", - "description": "Offsets texture coordinates in the U direction.", - "type": "float", - "defaultValue": 0.0, - "min": -1.0, - "max": 1.0 - }, - { - "name": "offsetV", - "displayName": "Offset V", - "description": "Offsets texture coordinates in the V direction.", - "type": "float", - "defaultValue": 0.0, - "min": -1.0, - "max": 1.0 - }, - { - "name": "rotateDegrees", - "displayName": "Rotate", - "description": "Rotates the texture coordinates (degrees).", - "type": "float", - "defaultValue": 0.0, - "min": -180.0, - "max": 180.0, - "step": 1.0 - }, - { - "name": "scale", - "displayName": "Scale", - "description": "Scales texture coordinates in both U and V.", - "type": "float", - "defaultValue": 1.0, - "step": 0.1 - } - ] + "description": "Properties for configuring UV transforms." }, { // Note: this property group is used in the DiffuseGlobalIllumination pass, it is not read by the StandardPBR shader "name": "irradiance", "displayName": "Irradiance", - "description": "Properties for configuring the irradiance used in global illumination.", - "properties": [ - { - "name": "color", - "displayName": "Color", - "description": "Color is displayed as sRGB but the values are stored as linear color.", - "type": "Color", - "defaultValue": [ 1.0, 1.0, 1.0 ] - }, - { - "name": "factor", - "displayName": "Factor", - "description": "Strength factor for scaling the irradiance color values. Zero (0.0) is black, white (1.0) is full color.", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "max": 1.0 - } - ] + "description": "Properties for configuring the irradiance used in global illumination." }, { "name": "general", "displayName": "General Settings", - "description": "General settings.", - "properties": [ - { - "name": "doubleSided", - "displayName": "Double-sided", - "description": "Whether to render back-faces or just front-faces.", - "type": "Bool" - }, - { - "name": "applySpecularAA", - "displayName": "Apply Specular AA", - "description": "Whether to apply specular anti-aliasing in the shader.", - "type": "Bool", - "defaultValue": false, - "connection": { - "type": "ShaderOption", - "name": "o_applySpecularAA" - } - }, - { - "name": "enableShadows", - "displayName": "Enable Shadows", - "description": "Whether to use the shadow maps.", - "type": "Bool", - "defaultValue": true, - "connection": { - "type": "ShaderOption", - "name": "o_enableShadows" - } - }, - { - "name": "enableDirectionalLights", - "displayName": "Enable Directional Lights", - "description": "Whether to use directional lights.", - "type": "Bool", - "defaultValue": true, - "connection": { - "type": "ShaderOption", - "name": "o_enableDirectionalLights" - } - }, - { - "name": "enablePunctualLights", - "displayName": "Enable Punctual Lights", - "description": "Whether to use punctual lights.", - "type": "Bool", - "defaultValue": true, - "connection": { - "type": "ShaderOption", - "name": "o_enablePunctualLights" - } - }, - { - "name": "enableAreaLights", - "displayName": "Enable Area Lights", - "description": "Whether to use area lights.", - "type": "Bool", - "defaultValue": true, - "connection": { - "type": "ShaderOption", - "name": "o_enableAreaLights" - } - }, - { - "name": "enableIBL", - "displayName": "Enable IBL", - "description": "Whether to use Image Based Lighting (IBL).", - "type": "Bool", - "defaultValue": true, - "connection": { - "type": "ShaderOption", - "name": "o_enableIBL" - } - }, - { - "name": "forwardPassIBLSpecular", - "displayName": "Forward Pass IBL Specular", - "description": "Whether to apply IBL specular in the forward pass.", - "type": "Bool", - "defaultValue": false, - "connection": { - "type": "ShaderOption", - "name": "o_materialUseForwardPassIBLSpecular" - } - } - ] + "description": "General settings." } - ] + ], + "properties": { + "general": [ + { + "name": "doubleSided", + "displayName": "Double-sided", + "description": "Whether to render back-faces or just front-faces.", + "type": "Bool" + }, + { + "name": "applySpecularAA", + "displayName": "Apply Specular AA", + "description": "Whether to apply specular anti-aliasing in the shader.", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderOption", + "name": "o_applySpecularAA" + } + }, + { + "name": "enableShadows", + "displayName": "Enable Shadows", + "description": "Whether to use the shadow maps.", + "type": "Bool", + "defaultValue": true, + "connection": { + "type": "ShaderOption", + "name": "o_enableShadows" + } + }, + { + "name": "enableDirectionalLights", + "displayName": "Enable Directional Lights", + "description": "Whether to use directional lights.", + "type": "Bool", + "defaultValue": true, + "connection": { + "type": "ShaderOption", + "name": "o_enableDirectionalLights" + } + }, + { + "name": "enablePunctualLights", + "displayName": "Enable Punctual Lights", + "description": "Whether to use punctual lights.", + "type": "Bool", + "defaultValue": true, + "connection": { + "type": "ShaderOption", + "name": "o_enablePunctualLights" + } + }, + { + "name": "enableAreaLights", + "displayName": "Enable Area Lights", + "description": "Whether to use area lights.", + "type": "Bool", + "defaultValue": true, + "connection": { + "type": "ShaderOption", + "name": "o_enableAreaLights" + } + }, + { + "name": "enableIBL", + "displayName": "Enable IBL", + "description": "Whether to use Image Based Lighting (IBL).", + "type": "Bool", + "defaultValue": true, + "connection": { + "type": "ShaderOption", + "name": "o_enableIBL" + } + }, + { + "name": "forwardPassIBLSpecular", + "displayName": "Forward Pass IBL Specular", + "description": "Whether to apply IBL specular in the forward pass.", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderOption", + "name": "o_materialUseForwardPassIBLSpecular" + } + } + ], + "baseColor": [ + { + "name": "color", + "displayName": "Color", + "description": "Color is displayed as sRGB but the values are stored as linear color.", + "type": "Color", + "defaultValue": [ 1.0, 1.0, 1.0 ], + "connection": { + "type": "ShaderInput", + "name": "m_baseColor" + } + }, + { + "name": "factor", + "displayName": "Factor", + "description": "Strength factor for scaling the base color values. Zero (0.0) is black, white (1.0) is full color.", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_baseColorFactor" + } + }, + { + "name": "textureMap", + "displayName": "Texture", + "description": "Base color texture map", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_baseColorMap" + } + }, + { + "name": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "textureMapUv", + "displayName": "UV", + "description": "Base color map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_baseColorMapUvIndex" + } + }, + { + "name": "textureBlendMode", + "displayName": "Texture Blend Mode", + "description": "Selects the equation to use when combining Color, Factor, and Texture.", + "type": "Enum", + "enumValues": [ "Multiply", "LinearLight", "Lerp", "Overlay" ], + "defaultValue": "Multiply", + "connection": { + "type": "ShaderOption", + "name": "o_baseColorTextureBlendMode" + } + } + ], + "metallic": [ + { + "name": "factor", + "displayName": "Factor", + "description": "This value is linear, black is non-metal and white means raw metal.", + "type": "Float", + "defaultValue": 0.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_metallicFactor" + } + }, + { + "name": "textureMap", + "displayName": "Texture", + "description": "", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_metallicMap" + } + }, + { + "name": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture, or just default to the Factor value.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "textureMapUv", + "displayName": "UV", + "description": "Metallic map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_metallicMapUvIndex" + } + } + ], + "roughness": [ + { + "name": "textureMap", + "displayName": "Texture", + "description": "Texture for defining surface roughness.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_roughnessMap" + } + }, + { + "name": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture, or just default to the Factor value.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "textureMapUv", + "displayName": "UV", + "description": "Roughness map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_roughnessMapUvIndex" + } + }, + { + // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. + "name": "lowerBound", + "displayName": "Lower Bound", + "description": "The roughness value that corresponds to black in the texture.", + "type": "Float", + "defaultValue": 0.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_roughnessLowerBound" + } + }, + { + // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. + "name": "upperBound", + "displayName": "Upper Bound", + "description": "The roughness value that corresponds to white in the texture.", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_roughnessUpperBound" + } + }, + { + // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. + "name": "factor", + "displayName": "Factor", + "description": "Controls the roughness value", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_roughnessFactor" + } + } + ], + "specularF0": [ + { + "name": "factor", + "displayName": "Factor", + "description": "The default IOR is 1.5, which gives you 0.04 (4% of light reflected at 0 degree angle for dielectric materials). F0 values lie in the range 0-0.08, so that is why the default F0 slider is set on 0.5.", + "type": "Float", + "defaultValue": 0.5, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_specularF0Factor" + } + }, + { + "name": "textureMap", + "displayName": "Texture", + "description": "Texture for defining surface reflectance.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_specularF0Map" + } + }, + { + "name": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture, or just default to the Factor value.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "textureMapUv", + "displayName": "UV", + "description": "Specular reflection map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_specularF0MapUvIndex" + } + }, + // Consider moving this to the "general" group to be consistent with StandardMultilayerPBR + { + "name": "enableMultiScatterCompensation", + "displayName": "Multiscattering Compensation", + "description": "Whether to enable multiple scattering compensation.", + "type": "Bool", + "connection": { + "type": "ShaderOption", + "name": "o_specularF0_enableMultiScatterCompensation" + } + } + ], + "clearCoat": [ + { + "name": "enable", + "displayName": "Enable", + "description": "Enable clear coat", + "type": "Bool", + "defaultValue": false + }, + { + "name": "factor", + "displayName": "Factor", + "description": "Strength factor for scaling the percentage of effect applied", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_clearCoatFactor" + } + }, + { + "name": "influenceMap", + "displayName": " Influence Map", + "description": "Strength factor texture", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_clearCoatInfluenceMap" + } + }, + { + "name": "useInfluenceMap", + "displayName": " Use Texture", + "description": "Whether to use the texture, or just default to the Factor value.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "influenceMapUv", + "displayName": " UV", + "description": "Strength factor map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_clearCoatInfluenceMapUvIndex" + } + }, + { + "name": "roughness", + "displayName": "Roughness", + "description": "Clear coat layer roughness", + "type": "Float", + "defaultValue": 0.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_clearCoatRoughness" + } + }, + { + "name": "roughnessMap", + "displayName": " Roughness Map", + "description": "Texture for defining surface roughness", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_clearCoatRoughnessMap" + } + }, + { + "name": "useRoughnessMap", + "displayName": " Use Texture", + "description": "Whether to use the texture, or just default to the roughness value.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "roughnessMapUv", + "displayName": " UV", + "description": "Roughness map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_clearCoatRoughnessMapUvIndex" + } + }, + { + "name": "normalStrength", + "displayName": "Normal Strength", + "description": "Scales the impact of the clear coat normal map", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 2.0, + "connection": { + "type": "ShaderInput", + "name": "m_clearCoatNormalStrength" + } + }, + { + "name": "normalMap", + "displayName": "Normal Map", + "description": "Normal map for clear coat layer, as top layer material clear coat doesn't affect by base layer normal map", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_clearCoatNormalMap" + } + }, + { + "name": "useNormalMap", + "displayName": " Use Texture", + "description": "Whether to use the normal map", + "type": "Bool", + "defaultValue": true + }, + { + "name": "normalMapUv", + "displayName": " UV", + "description": "Normal map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_clearCoatNormalMapUvIndex" + } + } + ], + "normal": [ + { + "name": "textureMap", + "displayName": "Texture", + "description": "Texture for defining surface normal direction.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_normalMap" + } + }, + { + "name": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture, or just rely on vertex normals.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "textureMapUv", + "displayName": "UV", + "description": "Normal map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_normalMapUvIndex" + } + }, + { + "name": "flipX", + "displayName": "Flip X Channel", + "description": "Flip tangent direction for this normal map.", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderInput", + "name": "m_flipNormalX" + } + }, + { + "name": "flipY", + "displayName": "Flip Y Channel", + "description": "Flip bitangent direction for this normal map.", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderInput", + "name": "m_flipNormalY" + } + }, + { + "name": "factor", + "displayName": "Factor", + "description": "Strength factor for scaling the values", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "softMax": 2.0, + "connection": { + "type": "ShaderInput", + "name": "m_normalFactor" + } + } + ], + "opacity": [ + { + "name": "mode", + "displayName": "Opacity Mode", + "description": "Indicates the general approach how transparency is to be applied.", + "type": "Enum", + "enumValues": [ "Opaque", "Cutout", "Blended", "TintedTransparent" ], + "defaultValue": "Opaque", + "connection": { + "type": "ShaderOption", + "name": "o_opacity_mode" + } + }, + { + "name": "alphaSource", + "displayName": "Alpha Source", + "description": "Indicates whether to get the opacity texture from the Base Color map (Packed) or from a separate greyscale texture (Split).", + "type": "Enum", + "enumValues": [ "Packed", "Split", "None" ], + "defaultValue": "Packed", + "connection": { + "type": "ShaderOption", + "name": "o_opacity_source" + } + }, + { + "name": "textureMap", + "displayName": "Texture", + "description": "Texture for defining surface opacity.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_opacityMap" + } + }, + { + "name": "textureMapUv", + "displayName": "UV", + "description": "Opacity map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_opacityMapUvIndex" + } + }, + { + "name": "factor", + "displayName": "Factor", + "description": "Factor for cutout threshold and blending", + "type": "Float", + "min": 0.0, + "max": 1.0, + "defaultValue": 0.5, + "connection": { + "type": "ShaderInput", + "name": "m_opacityFactor" + } + }, + { + "name": "alphaAffectsSpecular", + "displayName": "Alpha affects specular", + "description": "How much the alpha value should also affect specular reflection. This should be 0.0 for materials where light can transmit through their physical surface (like glass), but 1.0 when alpha determines the very presence of a surface (like hair or grass)", + "type": "float", + "min": 0.0, + "max": 1.0, + "defaultValue": 0.0, + "connection": { + "type": "ShaderInput", + "name": "m_opacityAffectsSpecularFactor" + } + } + ], + "uv": [ + { + "name": "center", + "displayName": "Center", + "description": "Center point for scaling and rotation transformations.", + "type": "vector2", + "vectorLabels": [ "U", "V" ], + "defaultValue": [ 0.5, 0.5 ] + }, + { + "name": "tileU", + "displayName": "Tile U", + "description": "Scales texture coordinates in U.", + "type": "float", + "defaultValue": 1.0, + "step": 0.1 + }, + { + "name": "tileV", + "displayName": "Tile V", + "description": "Scales texture coordinates in V.", + "type": "float", + "defaultValue": 1.0, + "step": 0.1 + }, + { + "name": "offsetU", + "displayName": "Offset U", + "description": "Offsets texture coordinates in the U direction.", + "type": "float", + "defaultValue": 0.0, + "min": -1.0, + "max": 1.0 + }, + { + "name": "offsetV", + "displayName": "Offset V", + "description": "Offsets texture coordinates in the V direction.", + "type": "float", + "defaultValue": 0.0, + "min": -1.0, + "max": 1.0 + }, + { + "name": "rotateDegrees", + "displayName": "Rotate", + "description": "Rotates the texture coordinates (degrees).", + "type": "float", + "defaultValue": 0.0, + "min": -180.0, + "max": 180.0, + "step": 1.0 + }, + { + "name": "scale", + "displayName": "Scale", + "description": "Scales texture coordinates in both U and V.", + "type": "float", + "defaultValue": 1.0, + "step": 0.1 + } + ], + "occlusion": [ + { + "name": "diffuseTextureMap", + "displayName": "Diffuse AO", + "description": "Texture for defining occlusion area for diffuse ambient lighting.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_diffuseOcclusionMap" + } + }, + { + "name": "diffuseUseTexture", + "displayName": " Use Texture", + "description": "Whether to use the Diffuse AO map.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "diffuseTextureMapUv", + "displayName": " UV", + "description": "Diffuse AO map UV set.", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_diffuseOcclusionMapUvIndex" + } + }, + { + "name": "diffuseFactor", + "displayName": " Factor", + "description": "Strength factor for scaling the values of Diffuse AO", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "softMax": 2.0, + "connection": { + "type": "ShaderInput", + "name": "m_diffuseOcclusionFactor" + } + }, + { + "name": "specularTextureMap", + "displayName": "Specular Cavity", + "description": "Texture for defining occlusion area for specular lighting.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_specularOcclusionMap" + } + }, + { + "name": "specularUseTexture", + "displayName": " Use Texture", + "description": "Whether to use the Specular Cavity map.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "specularTextureMapUv", + "displayName": " UV", + "description": "Specular Cavity map UV set.", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_specularOcclusionMapUvIndex" + } + }, + { + "name": "specularFactor", + "displayName": " Factor", + "description": "Strength factor for scaling the values of Specular Cavity", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "softMax": 2.0, + "connection": { + "type": "ShaderInput", + "name": "m_specularOcclusionFactor" + } + } + ], + "emissive": [ + { + "name": "enable", + "displayName": "Enable", + "description": "Enable the emissive group", + "type": "Bool", + "defaultValue": false + }, + { + "name": "unit", + "displayName": "Units", + "description": "The photometric units of the Intensity property.", + "type": "Enum", + "enumValues": ["Ev100"], + "defaultValue": "Ev100" + }, + { + "name": "color", + "displayName": "Color", + "description": "Color is displayed as sRGB but the values are stored as linear color.", + "type": "Color", + "defaultValue": [ 1.0, 1.0, 1.0 ], + "connection": { + "type": "ShaderInput", + "name": "m_emissiveColor" + } + }, + { + "name": "intensity", + "displayName": "Intensity", + "description": "The amount of energy emitted.", + "type": "Float", + "defaultValue": 4, + "min": -10, + "max": 20, + "softMin": -6, + "softMax": 16 + }, + { + "name": "textureMap", + "displayName": "Texture", + "description": "Texture for defining emissive area.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_emissiveMap" + } + }, + { + "name": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "textureMapUv", + "displayName": "UV", + "description": "Emissive map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_emissiveMapUvIndex" + } + } + ], + "parallax": [ + { + "name": "textureMap", + "displayName": "Height Map", + "description": "Displacement height map to create parallax effect.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "name": "m_heightmap" + } + }, + { + "name": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the height map.", + "type": "Bool", + "defaultValue": true + }, + { + "name": "textureMapUv", + "displayName": "UV", + "description": "Height map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_parallaxUvIndex" + } + }, + { + "name": "factor", + "displayName": "Height Map Scale", + "description": "The total height of the height map in local model units.", + "type": "Float", + "defaultValue": 0.05, + "min": 0.0, + "softMax": 0.1, + "connection": { + "type": "ShaderInput", + "name": "m_heightmapScale" + } + }, + { + "name": "offset", + "displayName": "Offset", + "description": "Adjusts the overall displacement amount in local model units.", + "type": "Float", + "defaultValue": 0.0, + "softMin": -0.1, + "softMax": 0.1, + "connection": { + "type": "ShaderInput", + "name": "m_heightmapOffset" + } + }, + { + "name": "algorithm", + "displayName": "Algorithm", + "description": "Select the algorithm to use for parallax mapping.", + "type": "Enum", + "enumValues": [ "Basic", "Steep", "POM", "Relief", "ContactRefinement" ], + "defaultValue": "POM", + "connection": { + "type": "ShaderOption", + "name": "o_parallax_algorithm" + } + }, + { + "name": "quality", + "displayName": "Quality", + "description": "Quality of parallax mapping.", + "type": "Enum", + "enumValues": [ "Low", "Medium", "High", "Ultra" ], + "defaultValue": "Low", + "connection": { + "type": "ShaderOption", + "name": "o_parallax_quality" + } + }, + { + "name": "pdo", + "displayName": "Pixel Depth Offset", + "description": "Enable PDO to offset the original pixel depths. This will affect any shaders using depth, for example, when receiving shadows.", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderOption", + "name": "o_parallax_enablePixelDepthOffset" + } + }, + { + "name": "showClipping", + "displayName": "Show Clipping", + "description": "Highlight areas where the height map is clipped by the mesh surface.", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderOption", + "name": "o_parallax_highlightClipping" + } + } + ], + "irradiance": [ + // Note: this property group is used in the DiffuseGlobalIllumination pass and not by the main forward shader + { + "name": "color", + "displayName": "Color", + "description": "Color is displayed as sRGB but the values are stored as linear color.", + "type": "Color", + "defaultValue": [ 1.0, 1.0, 1.0 ] + }, + { + "name": "factor", + "displayName": "Factor", + "description": "Strength factor for scaling the irradiance color values. Zero (0.0) is black, white (1.0) is full color.", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 1.0 + } + ] + } }, "shaders": [ { diff --git a/Gems/Atom/TestData/TestData/Materials/Types/AutoBrick.materialtype b/Gems/Atom/TestData/TestData/Materials/Types/AutoBrick.materialtype index e29599c45c..cf0bffa058 100644 --- a/Gems/Atom/TestData/TestData/Materials/Types/AutoBrick.materialtype +++ b/Gems/Atom/TestData/TestData/Materials/Types/AutoBrick.materialtype @@ -2,174 +2,176 @@ "description": "This is an example of a custom material type using Atom's PBR shading model: procedurally generated brick or tile.", "version": 3, "propertyLayout": { - "propertySets": [ + "groups": [ { "name": "shape", "displayName": "Shape", - "description": "Properties for configuring size, shape, and position of the bricks.", - "properties": [ - { - "name": "brickWidth", - "displayName": "Brick Width", - "description": "The width of each brick.", - "type": "Float", - "defaultValue": 0.1, - "min": 0.0, - "softMax": 0.2, - "step": 0.001, - "connection": { - "type": "ShaderInput", - "name": "m_brickWidth" - } - }, - { - "name": "brickHeight", - "displayName": "Brick Height", - "description": "The height of each brick.", - "type": "Float", - "defaultValue": 0.05, - "min": 0.0, - "softMax": 0.2, - "step": 0.001, - "connection": { - "type": "ShaderInput", - "name": "m_brickHeight" - } - }, - { - "name": "brickOffset", - "displayName": "Offset", - "description": "The offset of each stack of bricks as a percentage of brick width.", - "type": "Float", - "defaultValue": 0.5, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_brickOffset" - } - }, - { - "name": "lineWidth", - "displayName": "Line Width", - "description": "The width of the grout lines.", - "type": "Float", - "defaultValue": 0.01, - "min": 0.0, - "softMax": 0.02, - "step": 0.0001, - "connection": { - "type": "ShaderInput", - "name": "m_lineWidth" - } - }, - { - "name": "lineDepth", - "displayName": "Line Depth", - "description": "The depth of the grout lines.", - "type": "Float", - "defaultValue": 0.01, - "min": 0.0, - "softMax": 0.02, - "connection": { - "type": "ShaderInput", - "name": "m_lineDepth" - } - } - ] + "description": "Properties for configuring size, shape, and position of the bricks." }, { "name": "appearance", "displayName": "Appearance", - "description": "Properties for configuring the appearance of the bricks and grout lines.", - "properties": [ - { - "name": "noiseTexture", - "type": "Image", - "defaultValue": "TestData/Textures/noise512.png", - "visibility": "Hidden", - "connection": { - "type": "ShaderInput", - "name": "m_noise" - } - }, - { - "name": "brickColor", - "displayName": "Brick Color", - "description": "The color of the bricks.", - "type": "Color", - "defaultValue": [1.0,1.0,1.0], - "connection": { - "type": "ShaderInput", - "name": "m_brickColor" - } - }, - { - "name": "brickColorNoise", - "displayName": "Brick Color Noise", - "description": "Scale the variation of brick color.", - "type": "Float", - "defaultValue": 0.25, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_brickNoiseFactor" - } - }, - { - "name": "lineColor", - "displayName": "Line Color", - "description": "The color of the grout lines.", - "type": "Color", - "defaultValue": [0.5,0.5,0.5], - "connection": { - "type": "ShaderInput", - "name": "m_lineColor" - } - }, - { - "name": "lineColorNoise", - "displayName": "Line Color Noise", - "description": "Scale the variation of grout line color.", - "type": "Float", - "defaultValue": 0.25, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_lineNoiseFactor" - } - }, - { - "name": "brickColorBleed", - "displayName": "Brick Color Bleed", - "description": "Distance into the grout line that the brick color will continue.", - "type": "Float", - "defaultValue": 0.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_brickColorBleed" - } - }, - { - "name": "ao", - "displayName": "Ambient Occlusion", - "description": "The strength of baked ambient occlusion in the grout lines.", - "type": "Float", - "defaultValue": 0.5, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "name": "m_aoFactor" - } - } - ] + "description": "Properties for configuring the appearance of the bricks and grout lines." } - ] + ], + "properties": { + "shape": [ + { + "name": "brickWidth", + "displayName": "Brick Width", + "description": "The width of each brick.", + "type": "Float", + "defaultValue": 0.1, + "min": 0.0, + "softMax": 0.2, + "step": 0.001, + "connection": { + "type": "ShaderInput", + "name": "m_brickWidth" + } + }, + { + "name": "brickHeight", + "displayName": "Brick Height", + "description": "The height of each brick.", + "type": "Float", + "defaultValue": 0.05, + "min": 0.0, + "softMax": 0.2, + "step": 0.001, + "connection": { + "type": "ShaderInput", + "name": "m_brickHeight" + } + }, + { + "name": "brickOffset", + "displayName": "Offset", + "description": "The offset of each stack of bricks as a percentage of brick width.", + "type": "Float", + "defaultValue": 0.5, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_brickOffset" + } + }, + { + "name": "lineWidth", + "displayName": "Line Width", + "description": "The width of the grout lines.", + "type": "Float", + "defaultValue": 0.01, + "min": 0.0, + "softMax": 0.02, + "step": 0.0001, + "connection": { + "type": "ShaderInput", + "name": "m_lineWidth" + } + }, + { + "name": "lineDepth", + "displayName": "Line Depth", + "description": "The depth of the grout lines.", + "type": "Float", + "defaultValue": 0.01, + "min": 0.0, + "softMax": 0.02, + "connection": { + "type": "ShaderInput", + "name": "m_lineDepth" + } + } + ], + "appearance": [ + { + "name": "noiseTexture", + "type": "Image", + "defaultValue": "TestData/Textures/noise512.png", + "visibility": "Hidden", + "connection": { + "type": "ShaderInput", + "name": "m_noise" + } + }, + { + "name": "brickColor", + "displayName": "Brick Color", + "description": "The color of the bricks.", + "type": "Color", + "defaultValue": [1.0,1.0,1.0], + "connection": { + "type": "ShaderInput", + "name": "m_brickColor" + } + }, + { + "name": "brickColorNoise", + "displayName": "Brick Color Noise", + "description": "Scale the variation of brick color.", + "type": "Float", + "defaultValue": 0.25, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_brickNoiseFactor" + } + }, + { + "name": "lineColor", + "displayName": "Line Color", + "description": "The color of the grout lines.", + "type": "Color", + "defaultValue": [0.5,0.5,0.5], + "connection": { + "type": "ShaderInput", + "name": "m_lineColor" + } + }, + { + "name": "lineColorNoise", + "displayName": "Line Color Noise", + "description": "Scale the variation of grout line color.", + "type": "Float", + "defaultValue": 0.25, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_lineNoiseFactor" + } + }, + { + "name": "brickColorBleed", + "displayName": "Brick Color Bleed", + "description": "Distance into the grout line that the brick color will continue.", + "type": "Float", + "defaultValue": 0.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_brickColorBleed" + } + }, + { + "name": "ao", + "displayName": "Ambient Occlusion", + "description": "The strength of baked ambient occlusion in the grout lines.", + "type": "Float", + "defaultValue": 0.5, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "name": "m_aoFactor" + } + } + ] + } }, "shaders": [ { @@ -185,5 +187,8 @@ { "file": "Shaders/Depth/DepthPass.shader" } + ], + "functors": [ ] -} \ No newline at end of file +} + From b9a80dee325164cc035cbd1728de7f4a364905b3 Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Thu, 27 Jan 2022 14:17:09 -0800 Subject: [PATCH 16/20] Fixed newline at end of file. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../Common/Assets/Materials/Types/EnhancedPBR.materialtype | 2 +- .../Feature/Common/Assets/Materials/Types/Skin.materialtype | 2 +- .../Common/Assets/Materials/Types/StandardPBR.materialtype | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR.materialtype b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR.materialtype index eee9a0fc88..d4b5882f21 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR.materialtype +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR.materialtype @@ -1687,4 +1687,4 @@ "UV0": "Tiled", "UV1": "Unwrapped" } -} \ No newline at end of file +} diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.materialtype b/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.materialtype index 15eaf94df6..a49eba7975 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.materialtype +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.materialtype @@ -1101,4 +1101,4 @@ "UV0": "Tiled", "UV1": "Unwrapped" } -} \ No newline at end of file +} diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR.materialtype b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR.materialtype index 88e845ddf0..f324394309 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR.materialtype +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR.materialtype @@ -1199,4 +1199,4 @@ "UV0": "Tiled", "UV1": "Unwrapped" } -} \ No newline at end of file +} From 1de540ae3f2adb73650a740a8251bd37b8b0d8a2 Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Thu, 27 Jan 2022 14:48:50 -0800 Subject: [PATCH 17/20] Updated code to use span instead of array_view as this was replaced on the development branch. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../RPI.Edit/Material/MaterialTypeSourceData.h | 8 ++++---- .../RPI.Edit/Material/MaterialPropertyId.cpp | 4 ++-- .../RPI.Edit/Material/MaterialTypeSourceData.cpp | 14 +++++++------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialTypeSourceData.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialTypeSourceData.h index 6c439195f1..35cc7fe09a 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialTypeSourceData.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialTypeSourceData.h @@ -308,11 +308,11 @@ namespace AZ private: - const PropertySet* FindPropertySet(AZStd::array_view parsedPropertySetId, AZStd::array_view> inPropertySetList) const; - PropertySet* FindPropertySet(AZStd::array_view parsedPropertySetId, AZStd::array_view> inPropertySetList); + const PropertySet* FindPropertySet(AZStd::span parsedPropertySetId, AZStd::span> inPropertySetList) const; + PropertySet* FindPropertySet(AZStd::span parsedPropertySetId, AZStd::span> inPropertySetList); - const PropertyDefinition* FindProperty(AZStd::array_view parsedPropertyId, AZStd::array_view> inPropertySetList) const; - PropertyDefinition* FindProperty(AZStd::array_view parsedPropertyId, AZStd::array_view> inPropertySetList); + const PropertyDefinition* FindProperty(AZStd::span parsedPropertyId, AZStd::span> inPropertySetList) const; + PropertyDefinition* FindProperty(AZStd::span parsedPropertyId, AZStd::span> inPropertySetList); // Function overloads for recursion, returns false to indicate that recursion should end. bool EnumeratePropertySets(const EnumeratePropertySetsCallback& callback, AZStd::string propertyIdContext, const AZStd::vector>& inPropertySetList) const; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyId.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyId.cpp index 1a9b91f431..1f5581e417 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyId.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyId.cpp @@ -88,7 +88,7 @@ namespace AZ { } - MaterialPropertyId::MaterialPropertyId(const AZStd::array_view groupNames, AZStd::string_view propertyName) + MaterialPropertyId::MaterialPropertyId(const AZStd::span groupNames, AZStd::string_view propertyName) { for (const auto& name : groupNames) { @@ -118,7 +118,7 @@ namespace AZ } } - MaterialPropertyId::MaterialPropertyId(const AZStd::array_view names) + MaterialPropertyId::MaterialPropertyId(const AZStd::span names) { for (const auto& name : names) { diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp index 032d36636e..4aa0a77370 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp @@ -247,7 +247,7 @@ namespace AZ return parentPropertySet->AddProperty(splitPropertyId[1]); } - const MaterialTypeSourceData::PropertySet* MaterialTypeSourceData::FindPropertySet(AZStd::array_view parsedPropertySetId, AZStd::array_view> inPropertySetList) const + const MaterialTypeSourceData::PropertySet* MaterialTypeSourceData::FindPropertySet(AZStd::span parsedPropertySetId, AZStd::span> inPropertySetList) const { for (const auto& propertySet : inPropertySetList) { @@ -261,7 +261,7 @@ namespace AZ } else { - AZStd::array_view subPath{parsedPropertySetId.begin() + 1, parsedPropertySetId.end()}; + AZStd::span subPath{parsedPropertySetId.begin() + 1, parsedPropertySetId.end()}; if (!subPath.empty()) { @@ -277,7 +277,7 @@ namespace AZ return nullptr; } - MaterialTypeSourceData::PropertySet* MaterialTypeSourceData::FindPropertySet(AZStd::array_view parsedPropertySetId, AZStd::array_view> inPropertySetList) + MaterialTypeSourceData::PropertySet* MaterialTypeSourceData::FindPropertySet(AZStd::span parsedPropertySetId, AZStd::span> inPropertySetList) { return const_cast(const_cast(this)->FindPropertySet(parsedPropertySetId, inPropertySetList)); } @@ -295,14 +295,14 @@ namespace AZ } const MaterialTypeSourceData::PropertyDefinition* MaterialTypeSourceData::FindProperty( - AZStd::array_view parsedPropertyId, - AZStd::array_view> inPropertySetList) const + AZStd::span parsedPropertyId, + AZStd::span> inPropertySetList) const { for (const auto& propertySet : inPropertySetList) { if (propertySet->m_name == parsedPropertyId[0]) { - AZStd::array_view subPath {parsedPropertyId.begin() + 1, parsedPropertyId.end()}; + AZStd::span subPath {parsedPropertyId.begin() + 1, parsedPropertyId.end()}; if (subPath.size() == 1) { @@ -328,7 +328,7 @@ namespace AZ return nullptr; } - MaterialTypeSourceData::PropertyDefinition* MaterialTypeSourceData::FindProperty(AZStd::array_view parsedPropertyId, AZStd::array_view> inPropertySetList) + MaterialTypeSourceData::PropertyDefinition* MaterialTypeSourceData::FindProperty(AZStd::span parsedPropertyId, AZStd::span> inPropertySetList) { return const_cast(const_cast(this)->FindProperty(parsedPropertyId, inPropertySetList)); } From c2e220ce491f69b5764e2199e5b223b3dc088e4d Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Thu, 27 Jan 2022 16:11:26 -0800 Subject: [PATCH 18/20] Renamed property 'set' to property 'group' for consistency with the prior naming. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../Material/MaterialTypeSourceData.h | 86 ++--- .../Material/MaterialTypeSourceData.cpp | 200 +++++----- .../Material/MaterialSourceDataTests.cpp | 4 +- .../Material/MaterialTypeSourceDataTests.cpp | 346 +++++++++--------- .../Materials/Types/MinimalPBR.materialtype | 2 +- .../Code/Source/Document/MaterialDocument.cpp | 26 +- .../MaterialInspector/MaterialInspector.cpp | 14 +- .../EditorMaterialComponentInspector.cpp | 14 +- .../Material/EditorMaterialComponentUtil.cpp | 2 +- 9 files changed, 347 insertions(+), 347 deletions(-) diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialTypeSourceData.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialTypeSourceData.h index 35cc7fe09a..40f82c8ec7 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialTypeSourceData.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialTypeSourceData.h @@ -118,47 +118,47 @@ namespace AZ using PropertyList = AZStd::vector>; - struct PropertySet + struct PropertyGroup { friend class MaterialTypeSourceData; - AZ_CLASS_ALLOCATOR(PropertySet, SystemAllocator, 0); - AZ_TYPE_INFO(AZ::RPI::MaterialTypeSourceData::PropertySet, "{BA3AA0E4-C74D-4FD0-ADB2-00B060F06314}"); + AZ_CLASS_ALLOCATOR(PropertyGroup, SystemAllocator, 0); + AZ_TYPE_INFO(AZ::RPI::MaterialTypeSourceData::PropertyGroup, "{BA3AA0E4-C74D-4FD0-ADB2-00B060F06314}"); public: - PropertySet() = default; - AZ_DISABLE_COPY(PropertySet) + PropertyGroup() = default; + AZ_DISABLE_COPY(PropertyGroup) const AZStd::string& GetName() const { return m_name; } const AZStd::string& GetDisplayName() const { return m_displayName; } const AZStd::string& GetDescription() const { return m_description; } const PropertyList& GetProperties() const { return m_properties; } - const AZStd::vector>& GetPropertySets() const { return m_propertySets; } + const AZStd::vector>& GetPropertyGroups() const { return m_propertyGroups; } const AZStd::vector>& GetFunctors() const { return m_materialFunctorSourceData; } void SetDisplayName(AZStd::string_view displayName) { m_displayName = displayName; } void SetDescription(AZStd::string_view description) { m_description = description; } - //! Add a new property to this PropertySet. + //! Add a new property to this PropertyGroup. //! @param name a unique for the property. Must be a C-style identifier. //! @return the new PropertyDefinition, or null if the name was not valid. PropertyDefinition* AddProperty(AZStd::string_view name); - //! Add a new nested PropertySet to this PropertySet. - //! @param name a unique for the property set. Must be a C-style identifier. - //! @return the new PropertySet, or null if the name was not valid. - PropertySet* AddPropertySet(AZStd::string_view name); + //! Add a new nested PropertyGroup to this PropertyGroup. + //! @param name a unique for the property group. Must be a C-style identifier. + //! @return the new PropertyGroup, or null if the name was not valid. + PropertyGroup* AddPropertyGroup(AZStd::string_view name); private: - static PropertySet* AddPropertySet(AZStd::string_view name, AZStd::vector>& toPropertySetList); + static PropertyGroup* AddPropertyGroup(AZStd::string_view name, AZStd::vector>& toPropertyGroupList); AZStd::string m_name; AZStd::string m_displayName; AZStd::string m_description; PropertyList m_properties; - AZStd::vector> m_propertySets; + AZStd::vector> m_propertyGroups; AZStd::vector> m_materialFunctorSourceData; }; @@ -215,15 +215,15 @@ namespace AZ //! This field is unused, and has been replaced by MaterialTypeSourceData::m_version below. It is kept for legacy file compatibility to suppress warnings and errors. uint32_t m_versionOld = 0; - //! [Deprecated] Use m_propertySets instead + //! [Deprecated] Use m_propertyGroups instead //! List of groups that will contain the available properties AZStd::vector m_groupsOld; - //! [Deprecated] Use m_propertySets instead + //! [Deprecated] Use m_propertyGroups instead AZStd::map> m_propertiesOld; //! Collection of all available user-facing properties - AZStd::vector> m_propertySets; + AZStd::vector> m_propertyGroups; }; AZStd::string m_description; @@ -247,24 +247,24 @@ namespace AZ //! Copy over UV custom names to the properties enum values. void ResolveUvEnums(); - //! Add a new PropertySet for containing properties or other PropertySets. - //! @param propertySetId The ID of the new property set. To add as a nested PropertySet, use a full path ID like "levelA.levelB.levelC"; in this case a property set "levelA.levelB" must already exist. - //! @return a pointer to the new PropertySet or null if there was a problem (an AZ_Error will be reported). - PropertySet* AddPropertySet(AZStd::string_view propertySetId); + //! Add a new PropertyGroup for containing properties or other PropertyGroups. + //! @param propertyGroupId The ID of the new property group. To add as a nested PropertyGroup, use a full path ID like "levelA.levelB.levelC"; in this case a property group "levelA.levelB" must already exist. + //! @return a pointer to the new PropertyGroup or null if there was a problem (an AZ_Error will be reported). + PropertyGroup* AddPropertyGroup(AZStd::string_view propertyGroupId); - //! Add a new property to a PropertySet. - //! @param propertyId The ID of the new property, like "layerBlend.factor" or "layer2.roughness.texture". The indicated property set must already exist. + //! Add a new property to a PropertyGroup. + //! @param propertyId The ID of the new property, like "layerBlend.factor" or "layer2.roughness.texture". The indicated property group must already exist. //! @return a pointer to the new PropertyDefinition or null if there was a problem (an AZ_Error will be reported). PropertyDefinition* AddProperty(AZStd::string_view propertyId); - //! Return the PropertyLayout containing the tree of property sets and property definitions. + //! Return the PropertyLayout containing the tree of property groups and property definitions. const PropertyLayout& GetPropertyLayout() const { return m_propertyLayout; } - //! Find the PropertySet with the given ID. - //! @param propertySetId The full ID of a property set to find, like "levelA.levelB.levelC". - //! @return the found PropertySet or null if it doesn't exist. - const PropertySet* FindPropertySet(AZStd::string_view propertySetId) const; - PropertySet* FindPropertySet(AZStd::string_view propertySetId); + //! Find the PropertyGroup with the given ID. + //! @param propertyGroupId The full ID of a property group to find, like "levelA.levelB.levelC". + //! @return the found PropertyGroup or null if it doesn't exist. + const PropertyGroup* FindPropertyGroup(AZStd::string_view propertyGroupId) const; + PropertyGroup* FindPropertyGroup(AZStd::string_view propertyGroupId); //! Find the definition for a property with the given ID. //! @param propertyId The full ID of a property to find, like "baseColor.texture". @@ -280,14 +280,14 @@ namespace AZ //! Call back function type used with the enumeration functions. //! Return false to terminate the traversal. - using EnumeratePropertySetsCallback = AZStd::function; - //! Recursively traverses all of the property sets contained in the material type, executing a callback function for each. + //! Recursively traverses all of the property groups contained in the material type, executing a callback function for each. //! @return false if the enumeration was terminated early by the callback returning false. - bool EnumeratePropertySets(const EnumeratePropertySetsCallback& callback) const; + bool EnumeratePropertyGroups(const EnumeratePropertyGroupsCallback& callback) const; //! Call back function type used with the numeration functions. //! Return false to terminate the traversal. @@ -303,31 +303,31 @@ namespace AZ Outcome> CreateMaterialTypeAsset(Data::AssetId assetId, AZStd::string_view materialTypeSourceFilePath = "", bool elevateWarnings = true) const; //! If the data was loaded from an old format file (i.e. where "groups" and "properties" were separate sections), - //! this converts to the new format where properties are listed inside property sets. + //! this converts to the new format where properties are listed inside property groups. bool ConvertToNewDataFormat(); private: - const PropertySet* FindPropertySet(AZStd::span parsedPropertySetId, AZStd::span> inPropertySetList) const; - PropertySet* FindPropertySet(AZStd::span parsedPropertySetId, AZStd::span> inPropertySetList); + const PropertyGroup* FindPropertyGroup(AZStd::span parsedPropertyGroupId, AZStd::span> inPropertyGroupList) const; + PropertyGroup* FindPropertyGroup(AZStd::span parsedPropertyGroupId, AZStd::span> inPropertyGroupList); - const PropertyDefinition* FindProperty(AZStd::span parsedPropertyId, AZStd::span> inPropertySetList) const; - PropertyDefinition* FindProperty(AZStd::span parsedPropertyId, AZStd::span> inPropertySetList); + const PropertyDefinition* FindProperty(AZStd::span parsedPropertyId, AZStd::span> inPropertyGroupList) const; + PropertyDefinition* FindProperty(AZStd::span parsedPropertyId, AZStd::span> inPropertyGroupList); // Function overloads for recursion, returns false to indicate that recursion should end. - bool EnumeratePropertySets(const EnumeratePropertySetsCallback& callback, AZStd::string propertyIdContext, const AZStd::vector>& inPropertySetList) const; - bool EnumerateProperties(const EnumeratePropertiesCallback& callback, AZStd::string propertyIdContext, const AZStd::vector>& inPropertySetList) const; + bool EnumeratePropertyGroups(const EnumeratePropertyGroupsCallback& callback, AZStd::string propertyIdContext, const AZStd::vector>& inPropertyGroupList) const; + bool EnumerateProperties(const EnumeratePropertiesCallback& callback, AZStd::string propertyIdContext, const AZStd::vector>& inPropertyGroupList) const; - //! Recursively populates a material asset with properties from the tree of material property sets. + //! Recursively populates a material asset with properties from the tree of material property groups. //! @param materialTypeSourceFilePath path to the material type file that is being processed, used to look up relative paths - //! @param propertyNameContext the accumulated prefix that should be applied to any property names encountered in the current @propertySet - //! @param propertySet the current PropertySet that is being processed + //! @param propertyNameContext the accumulated prefix that should be applied to any property names encountered in the current @propertyGroup + //! @param propertyGroup the current PropertyGroup that is being processed //! @return false if errors are detected and processing should abort bool BuildPropertyList( const AZStd::string& materialTypeSourceFilePath, MaterialTypeAssetCreator& materialTypeAssetCreator, AZStd::vector& propertyNameContext, - const MaterialTypeSourceData::PropertySet* propertySet) const; + const MaterialTypeSourceData::PropertyGroup* propertyGroup) const; //! Construct a complete list of group definitions, including implicit groups, arranged in the same order as the source data. //! Groups with the same name will be consolidated into a single entry. diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp index 4aa0a77370..b9a5754732 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp @@ -58,9 +58,9 @@ namespace AZ serializeContext->Class()->Version(4); serializeContext->Class()->Version(1); - serializeContext->RegisterGenericType>(); + serializeContext->RegisterGenericType>(); serializeContext->RegisterGenericType>(); - serializeContext->RegisterGenericType>>(); + serializeContext->RegisterGenericType>>(); serializeContext->RegisterGenericType>>(); serializeContext->RegisterGenericType(); @@ -88,22 +88,22 @@ namespace AZ ->Field("options", &ShaderVariantReferenceData::m_shaderOptionValues) ; - serializeContext->Class() + serializeContext->Class() ->Version(1) - ->Field("name", &PropertySet::m_name) - ->Field("displayName", &PropertySet::m_displayName) - ->Field("description", &PropertySet::m_description) - ->Field("properties", &PropertySet::m_properties) - ->Field("propertySets", &PropertySet::m_propertySets) - ->Field("functors", &PropertySet::m_materialFunctorSourceData) + ->Field("name", &PropertyGroup::m_name) + ->Field("displayName", &PropertyGroup::m_displayName) + ->Field("description", &PropertyGroup::m_description) + ->Field("properties", &PropertyGroup::m_properties) + ->Field("propertyGroups", &PropertyGroup::m_propertyGroups) + ->Field("functors", &PropertyGroup::m_materialFunctorSourceData) ; serializeContext->Class() - ->Version(3) // Added propertySets + ->Version(3) // Added propertyGroups ->Field("version", &PropertyLayout::m_versionOld) //< Deprecated, preserved for backward compatibility, replaced by MaterialTypeSourceData::version - ->Field("groups", &PropertyLayout::m_groupsOld) //< Deprecated, preserved for backward compatibility, replaced by propertySets - ->Field("properties", &PropertyLayout::m_propertiesOld) //< Deprecated, preserved for backward compatibility, replaced by propertySets - ->Field("propertySets", &PropertyLayout::m_propertySets) + ->Field("groups", &PropertyLayout::m_groupsOld) //< Deprecated, preserved for backward compatibility, replaced by propertyGroups + ->Field("properties", &PropertyLayout::m_propertiesOld) //< Deprecated, preserved for backward compatibility, replaced by propertyGroups + ->Field("propertyGroups", &PropertyLayout::m_propertyGroups) ; serializeContext->RegisterGenericType(); @@ -132,16 +132,16 @@ namespace AZ const float MaterialTypeSourceData::PropertyDefinition::DefaultMax = std::numeric_limits::max(); const float MaterialTypeSourceData::PropertyDefinition::DefaultStep = 0.1f; - /*static*/ MaterialTypeSourceData::PropertySet* MaterialTypeSourceData::PropertySet::AddPropertySet(AZStd::string_view name, AZStd::vector>& toPropertySetList) + /*static*/ MaterialTypeSourceData::PropertyGroup* MaterialTypeSourceData::PropertyGroup::AddPropertyGroup(AZStd::string_view name, AZStd::vector>& toPropertyGroupList) { - auto iter = AZStd::find_if(toPropertySetList.begin(), toPropertySetList.end(), [name](const AZStd::unique_ptr& existingPropertySet) + auto iter = AZStd::find_if(toPropertyGroupList.begin(), toPropertyGroupList.end(), [name](const AZStd::unique_ptr& existingPropertyGroup) { - return existingPropertySet->m_name == name; + return existingPropertyGroup->m_name == name; }); - if (iter != toPropertySetList.end()) + if (iter != toPropertyGroupList.end()) { - AZ_Error("Material source data", false, "PropertySet named '%.*s' already exists", AZ_STRING_ARG(name)); + AZ_Error("Material source data", false, "PropertyGroup named '%.*s' already exists", AZ_STRING_ARG(name)); return nullptr; } @@ -151,12 +151,12 @@ namespace AZ return nullptr; } - toPropertySetList.push_back(AZStd::make_unique()); - toPropertySetList.back()->m_name = name; - return toPropertySetList.back().get(); + toPropertyGroupList.push_back(AZStd::make_unique()); + toPropertyGroupList.back()->m_name = name; + return toPropertyGroupList.back().get(); } - MaterialTypeSourceData::PropertyDefinition* MaterialTypeSourceData::PropertySet::AddProperty(AZStd::string_view name) + MaterialTypeSourceData::PropertyDefinition* MaterialTypeSourceData::PropertyGroup::AddProperty(AZStd::string_view name) { auto propertyIter = AZStd::find_if(m_properties.begin(), m_properties.end(), [name](const AZStd::unique_ptr& existingProperty) { @@ -165,18 +165,18 @@ namespace AZ if (propertyIter != m_properties.end()) { - AZ_Error("Material source data", false, "PropertySet '%s' already contains a property named '%.*s'", m_name.c_str(), AZ_STRING_ARG(name)); + AZ_Error("Material source data", false, "PropertyGroup '%s' already contains a property named '%.*s'", m_name.c_str(), AZ_STRING_ARG(name)); return nullptr; } - auto propertySetIter = AZStd::find_if(m_propertySets.begin(), m_propertySets.end(), [name](const AZStd::unique_ptr& existingPropertySet) + auto propertyGroupIter = AZStd::find_if(m_propertyGroups.begin(), m_propertyGroups.end(), [name](const AZStd::unique_ptr& existingPropertyGroup) { - return existingPropertySet->m_name == name; + return existingPropertyGroup->m_name == name; }); - if (propertySetIter != m_propertySets.end()) + if (propertyGroupIter != m_propertyGroups.end()) { - AZ_Error("Material source data", false, "Property name '%.*s' collides with a PropertySet of the same name", AZ_STRING_ARG(name)); + AZ_Error("Material source data", false, "Property name '%.*s' collides with a PropertyGroup of the same name", AZ_STRING_ARG(name)); return nullptr; } @@ -190,7 +190,7 @@ namespace AZ return m_properties.back().get(); } - MaterialTypeSourceData::PropertySet* MaterialTypeSourceData::PropertySet::AddPropertySet(AZStd::string_view name) + MaterialTypeSourceData::PropertyGroup* MaterialTypeSourceData::PropertyGroup::AddPropertyGroup(AZStd::string_view name) { auto iter = AZStd::find_if(m_properties.begin(), m_properties.end(), [name](const AZStd::unique_ptr& existingProperty) { @@ -199,31 +199,31 @@ namespace AZ if (iter != m_properties.end()) { - AZ_Error("Material source data", false, "PropertySet name '%.*s' collides with a Property of the same name", AZ_STRING_ARG(name)); + AZ_Error("Material source data", false, "PropertyGroup name '%.*s' collides with a Property of the same name", AZ_STRING_ARG(name)); return nullptr; } - return AddPropertySet(name, m_propertySets); + return AddPropertyGroup(name, m_propertyGroups); } - MaterialTypeSourceData::PropertySet* MaterialTypeSourceData::AddPropertySet(AZStd::string_view propertySetId) + MaterialTypeSourceData::PropertyGroup* MaterialTypeSourceData::AddPropertyGroup(AZStd::string_view propertyGroupId) { - AZStd::vector splitPropertySetId = SplitId(propertySetId); + AZStd::vector splitPropertyGroupId = SplitId(propertyGroupId); - if (splitPropertySetId.size() == 1) + if (splitPropertyGroupId.size() == 1) { - return PropertySet::AddPropertySet(propertySetId, m_propertyLayout.m_propertySets); + return PropertyGroup::AddPropertyGroup(propertyGroupId, m_propertyLayout.m_propertyGroups); } - PropertySet* parentPropertySet = FindPropertySet(splitPropertySetId[0]); + PropertyGroup* parentPropertyGroup = FindPropertyGroup(splitPropertyGroupId[0]); - if (!parentPropertySet) + if (!parentPropertyGroup) { - AZ_Error("Material source data", false, "PropertySet '%.*s' does not exists", AZ_STRING_ARG(splitPropertySetId[0])); + AZ_Error("Material source data", false, "PropertyGroup '%.*s' does not exists", AZ_STRING_ARG(splitPropertyGroupId[0])); return nullptr; } - return parentPropertySet->AddPropertySet(splitPropertySetId[1]); + return parentPropertyGroup->AddPropertyGroup(splitPropertyGroupId[1]); } MaterialTypeSourceData::PropertyDefinition* MaterialTypeSourceData::AddProperty(AZStd::string_view propertyId) @@ -232,40 +232,40 @@ namespace AZ if (splitPropertyId.size() == 1) { - AZ_Error("Material source data", false, "Property id '%.*s' is invalid. Properties must be added to a PropertySet (i.e. \"general.%.*s\").", AZ_STRING_ARG(propertyId), AZ_STRING_ARG(propertyId)); + AZ_Error("Material source data", false, "Property id '%.*s' is invalid. Properties must be added to a PropertyGroup (i.e. \"general.%.*s\").", AZ_STRING_ARG(propertyId), AZ_STRING_ARG(propertyId)); return nullptr; } - PropertySet* parentPropertySet = FindPropertySet(splitPropertyId[0]); + PropertyGroup* parentPropertyGroup = FindPropertyGroup(splitPropertyId[0]); - if (!parentPropertySet) + if (!parentPropertyGroup) { - AZ_Error("Material source data", false, "PropertySet '%.*s' does not exists", AZ_STRING_ARG(splitPropertyId[0])); + AZ_Error("Material source data", false, "PropertyGroup '%.*s' does not exists", AZ_STRING_ARG(splitPropertyId[0])); return nullptr; } - return parentPropertySet->AddProperty(splitPropertyId[1]); + return parentPropertyGroup->AddProperty(splitPropertyId[1]); } - const MaterialTypeSourceData::PropertySet* MaterialTypeSourceData::FindPropertySet(AZStd::span parsedPropertySetId, AZStd::span> inPropertySetList) const + const MaterialTypeSourceData::PropertyGroup* MaterialTypeSourceData::FindPropertyGroup(AZStd::span parsedPropertyGroupId, AZStd::span> inPropertyGroupList) const { - for (const auto& propertySet : inPropertySetList) + for (const auto& propertyGroup : inPropertyGroupList) { - if (propertySet->m_name != parsedPropertySetId[0]) + if (propertyGroup->m_name != parsedPropertyGroupId[0]) { continue; } - else if (parsedPropertySetId.size() == 1) + else if (parsedPropertyGroupId.size() == 1) { - return propertySet.get(); + return propertyGroup.get(); } else { - AZStd::span subPath{parsedPropertySetId.begin() + 1, parsedPropertySetId.end()}; + AZStd::span subPath{parsedPropertyGroupId.begin() + 1, parsedPropertyGroupId.end()}; if (!subPath.empty()) { - const MaterialTypeSourceData::PropertySet* propertySubset = FindPropertySet(subPath, propertySet->m_propertySets); + const MaterialTypeSourceData::PropertyGroup* propertySubset = FindPropertyGroup(subPath, propertyGroup->m_propertyGroups); if (propertySubset) { return propertySubset; @@ -277,36 +277,36 @@ namespace AZ return nullptr; } - MaterialTypeSourceData::PropertySet* MaterialTypeSourceData::FindPropertySet(AZStd::span parsedPropertySetId, AZStd::span> inPropertySetList) + MaterialTypeSourceData::PropertyGroup* MaterialTypeSourceData::FindPropertyGroup(AZStd::span parsedPropertyGroupId, AZStd::span> inPropertyGroupList) { - return const_cast(const_cast(this)->FindPropertySet(parsedPropertySetId, inPropertySetList)); + return const_cast(const_cast(this)->FindPropertyGroup(parsedPropertyGroupId, inPropertyGroupList)); } - const MaterialTypeSourceData::PropertySet* MaterialTypeSourceData::FindPropertySet(AZStd::string_view propertySetId) const + const MaterialTypeSourceData::PropertyGroup* MaterialTypeSourceData::FindPropertyGroup(AZStd::string_view propertyGroupId) const { - AZStd::vector tokens = TokenizeId(propertySetId); - return FindPropertySet(tokens, m_propertyLayout.m_propertySets); + AZStd::vector tokens = TokenizeId(propertyGroupId); + return FindPropertyGroup(tokens, m_propertyLayout.m_propertyGroups); } - MaterialTypeSourceData::PropertySet* MaterialTypeSourceData::FindPropertySet(AZStd::string_view propertySetId) + MaterialTypeSourceData::PropertyGroup* MaterialTypeSourceData::FindPropertyGroup(AZStd::string_view propertyGroupId) { - AZStd::vector tokens = TokenizeId(propertySetId); - return FindPropertySet(tokens, m_propertyLayout.m_propertySets); + AZStd::vector tokens = TokenizeId(propertyGroupId); + return FindPropertyGroup(tokens, m_propertyLayout.m_propertyGroups); } const MaterialTypeSourceData::PropertyDefinition* MaterialTypeSourceData::FindProperty( AZStd::span parsedPropertyId, - AZStd::span> inPropertySetList) const + AZStd::span> inPropertyGroupList) const { - for (const auto& propertySet : inPropertySetList) + for (const auto& propertyGroup : inPropertyGroupList) { - if (propertySet->m_name == parsedPropertyId[0]) + if (propertyGroup->m_name == parsedPropertyId[0]) { AZStd::span subPath {parsedPropertyId.begin() + 1, parsedPropertyId.end()}; if (subPath.size() == 1) { - for (AZStd::unique_ptr& property : propertySet->m_properties) + for (AZStd::unique_ptr& property : propertyGroup->m_properties) { if (property->GetName() == subPath[0]) { @@ -316,7 +316,7 @@ namespace AZ } else if(subPath.size() > 1) { - const MaterialTypeSourceData::PropertyDefinition* property = FindProperty(subPath, propertySet->m_propertySets); + const MaterialTypeSourceData::PropertyDefinition* property = FindProperty(subPath, propertyGroup->m_propertyGroups); if (property) { return property; @@ -328,21 +328,21 @@ namespace AZ return nullptr; } - MaterialTypeSourceData::PropertyDefinition* MaterialTypeSourceData::FindProperty(AZStd::span parsedPropertyId, AZStd::span> inPropertySetList) + MaterialTypeSourceData::PropertyDefinition* MaterialTypeSourceData::FindProperty(AZStd::span parsedPropertyId, AZStd::span> inPropertyGroupList) { - return const_cast(const_cast(this)->FindProperty(parsedPropertyId, inPropertySetList)); + return const_cast(const_cast(this)->FindProperty(parsedPropertyId, inPropertyGroupList)); } const MaterialTypeSourceData::PropertyDefinition* MaterialTypeSourceData::FindProperty(AZStd::string_view propertyId) const { AZStd::vector tokens = TokenizeId(propertyId); - return FindProperty(tokens, m_propertyLayout.m_propertySets); + return FindProperty(tokens, m_propertyLayout.m_propertyGroups); } MaterialTypeSourceData::PropertyDefinition* MaterialTypeSourceData::FindProperty(AZStd::string_view propertyId) { AZStd::vector tokens = TokenizeId(propertyId); - return FindProperty(tokens, m_propertyLayout.m_propertySets); + return FindProperty(tokens, m_propertyLayout.m_propertyGroups); } AZStd::vector MaterialTypeSourceData::TokenizeId(AZStd::string_view id) @@ -376,18 +376,18 @@ namespace AZ return parts; } - bool MaterialTypeSourceData::EnumeratePropertySets(const EnumeratePropertySetsCallback& callback, AZStd::string propertyNameContext, const AZStd::vector>& inPropertySetList) const + bool MaterialTypeSourceData::EnumeratePropertyGroups(const EnumeratePropertyGroupsCallback& callback, AZStd::string propertyNameContext, const AZStd::vector>& inPropertyGroupList) const { - for (auto& propertySet : inPropertySetList) + for (auto& propertyGroup : inPropertyGroupList) { - if (!callback(propertyNameContext, propertySet.get())) + if (!callback(propertyNameContext, propertyGroup.get())) { return false; // Stop processing } - const AZStd::string propertyNameContext2 = propertyNameContext + propertySet->m_name + "."; + const AZStd::string propertyNameContext2 = propertyNameContext + propertyGroup->m_name + "."; - if (!EnumeratePropertySets(callback, propertyNameContext2, propertySet->m_propertySets)) + if (!EnumeratePropertyGroups(callback, propertyNameContext2, propertyGroup->m_propertyGroups)) { return false; // Stop processing } @@ -396,24 +396,24 @@ namespace AZ return true; } - bool MaterialTypeSourceData::EnumeratePropertySets(const EnumeratePropertySetsCallback& callback) const + bool MaterialTypeSourceData::EnumeratePropertyGroups(const EnumeratePropertyGroupsCallback& callback) const { if (!callback) { return false; } - return EnumeratePropertySets(callback, {}, m_propertyLayout.m_propertySets); + return EnumeratePropertyGroups(callback, {}, m_propertyLayout.m_propertyGroups); } - bool MaterialTypeSourceData::EnumerateProperties(const EnumeratePropertiesCallback& callback, AZStd::string propertyNameContext, const AZStd::vector>& inPropertySetList) const + bool MaterialTypeSourceData::EnumerateProperties(const EnumeratePropertiesCallback& callback, AZStd::string propertyNameContext, const AZStd::vector>& inPropertyGroupList) const { - for (auto& propertySet : inPropertySetList) + for (auto& propertyGroup : inPropertyGroupList) { - const AZStd::string propertyNameContext2 = propertyNameContext + propertySet->m_name + "."; + const AZStd::string propertyNameContext2 = propertyNameContext + propertyGroup->m_name + "."; - for (auto& property : propertySet->m_properties) + for (auto& property : propertyGroup->m_properties) { if (!callback(propertyNameContext2, property.get())) { @@ -421,7 +421,7 @@ namespace AZ } } - if (!EnumerateProperties(callback, propertyNameContext2, propertySet->m_propertySets)) + if (!EnumerateProperties(callback, propertyNameContext2, propertyGroup->m_propertyGroups)) { return false; // Stop processing } @@ -437,7 +437,7 @@ namespace AZ return false; } - return EnumerateProperties(callback, {}, m_propertyLayout.m_propertySets); + return EnumerateProperties(callback, {}, m_propertyLayout.m_propertyGroups); } bool MaterialTypeSourceData::ConvertToNewDataFormat() @@ -450,18 +450,18 @@ namespace AZ const auto& propertyList = propertyListItr->second; for (auto& propertyDefinition : propertyList) { - PropertySet* propertySet = FindPropertySet(group.m_name); + PropertyGroup* propertyGroup = FindPropertyGroup(group.m_name); - if (!propertySet) + if (!propertyGroup) { - m_propertyLayout.m_propertySets.emplace_back(AZStd::make_unique()); - m_propertyLayout.m_propertySets.back()->m_name = group.m_name; - m_propertyLayout.m_propertySets.back()->m_displayName = group.m_displayName; - m_propertyLayout.m_propertySets.back()->m_description = group.m_description; - propertySet = m_propertyLayout.m_propertySets.back().get(); + m_propertyLayout.m_propertyGroups.emplace_back(AZStd::make_unique()); + m_propertyLayout.m_propertyGroups.back()->m_name = group.m_name; + m_propertyLayout.m_propertyGroups.back()->m_displayName = group.m_displayName; + m_propertyLayout.m_propertyGroups.back()->m_description = group.m_description; + propertyGroup = m_propertyLayout.m_propertyGroups.back().get(); } - PropertyDefinition* newProperty = propertySet->AddProperty(propertyDefinition.GetName()); + PropertyDefinition* newProperty = propertyGroup->AddProperty(propertyDefinition.GetName()); *newProperty = propertyDefinition; } @@ -533,9 +533,9 @@ namespace AZ const AZStd::string& materialTypeSourceFilePath, MaterialTypeAssetCreator& materialTypeAssetCreator, AZStd::vector& propertyNameContext, - const MaterialTypeSourceData::PropertySet* propertySet) const + const MaterialTypeSourceData::PropertyGroup* propertyGroup) const { - for (const AZStd::unique_ptr& property : propertySet->m_properties) + for (const AZStd::unique_ptr& property : propertyGroup->m_properties) { // Register the property... @@ -547,15 +547,15 @@ namespace AZ return false; } - auto propertySetIter = AZStd::find_if(propertySet->GetPropertySets().begin(), propertySet->GetPropertySets().end(), - [&property](const AZStd::unique_ptr& existingPropertySet) + auto propertyGroupIter = AZStd::find_if(propertyGroup->GetPropertyGroups().begin(), propertyGroup->GetPropertyGroups().end(), + [&property](const AZStd::unique_ptr& existingPropertyGroup) { - return existingPropertySet->GetName() == property->GetName(); + return existingPropertyGroup->GetName() == property->GetName(); }); - if (propertySetIter != propertySet->GetPropertySets().end()) + if (propertyGroupIter != propertyGroup->GetPropertyGroups().end()) { - AZ_Error("Material source data", false, "Material property '%s' collides with a PropertySet with the same ID.", propertyId.GetCStr()); + AZ_Error("Material source data", false, "Material property '%s' collides with a PropertyGroup with the same ID.", propertyId.GetCStr()); return false; } @@ -650,7 +650,7 @@ namespace AZ } } - for (const AZStd::unique_ptr& propertySubset : propertySet->m_propertySets) + for (const AZStd::unique_ptr& propertySubset : propertyGroup->m_propertyGroups) { propertyNameContext.push_back(propertySubset->m_name); @@ -670,7 +670,7 @@ namespace AZ // We cannot create the MaterialFunctor until after all the properties are added because // CreateFunctor() may need to look up properties in the MaterialPropertiesLayout - for (auto& functorData : propertySet->m_materialFunctorSourceData) + for (auto& functorData : propertyGroup->m_materialFunctorSourceData) { MaterialFunctorSourceData::FunctorResult result = functorData->CreateFunctor( MaterialFunctorSourceData::RuntimeContext( @@ -795,11 +795,11 @@ namespace AZ } } - for (const AZStd::unique_ptr& propertySet : m_propertyLayout.m_propertySets) + for (const AZStd::unique_ptr& propertyGroup : m_propertyLayout.m_propertyGroups) { AZStd::vector propertyNameContext; - propertyNameContext.push_back(propertySet->m_name); - bool success = BuildPropertyList(materialTypeSourceFilePath, materialTypeAssetCreator, propertyNameContext, propertySet.get()); + propertyNameContext.push_back(propertyGroup->m_name); + bool success = BuildPropertyList(materialTypeSourceFilePath, materialTypeAssetCreator, propertyNameContext, propertyGroup.get()); if (!success) { diff --git a/Gems/Atom/RPI/Code/Tests/Material/MaterialSourceDataTests.cpp b/Gems/Atom/RPI/Code/Tests/Material/MaterialSourceDataTests.cpp index 7b8475bf69..2bd257d55b 100644 --- a/Gems/Atom/RPI/Code/Tests/Material/MaterialSourceDataTests.cpp +++ b/Gems/Atom/RPI/Code/Tests/Material/MaterialSourceDataTests.cpp @@ -93,7 +93,7 @@ namespace UnitTest { "version": 10, "propertyLayout": { - "propertySets": [ + "propertyGroups": [ { "name": "general", "properties": [ @@ -471,7 +471,7 @@ namespace UnitTest const AZStd::string simpleMaterialTypeJson = R"( { "propertyLayout": { - "propertySets": + "propertyGroups": [ { "name": "general", diff --git a/Gems/Atom/RPI/Code/Tests/Material/MaterialTypeSourceDataTests.cpp b/Gems/Atom/RPI/Code/Tests/Material/MaterialTypeSourceDataTests.cpp index 2ecf2369f9..206073e96a 100644 --- a/Gems/Atom/RPI/Code/Tests/Material/MaterialTypeSourceDataTests.cpp +++ b/Gems/Atom/RPI/Code/Tests/Material/MaterialTypeSourceDataTests.cpp @@ -360,18 +360,18 @@ namespace UnitTest { MaterialTypeSourceData sourceData; - // Here we are building up multiple layers of property sets and properties, using a variety of different Add functions, - // going through the MaterialTypeSourceData or going to the PropertySet directly. + // Here we are building up multiple layers of property groups and properties, using a variety of different Add functions, + // going through the MaterialTypeSourceData or going to the PropertyGroup directly. - MaterialTypeSourceData::PropertySet* layer1 = sourceData.AddPropertySet("layer1"); - MaterialTypeSourceData::PropertySet* layer2 = sourceData.AddPropertySet("layer2"); - MaterialTypeSourceData::PropertySet* blend = sourceData.AddPropertySet("blend"); + MaterialTypeSourceData::PropertyGroup* layer1 = sourceData.AddPropertyGroup("layer1"); + MaterialTypeSourceData::PropertyGroup* layer2 = sourceData.AddPropertyGroup("layer2"); + MaterialTypeSourceData::PropertyGroup* blend = sourceData.AddPropertyGroup("blend"); - MaterialTypeSourceData::PropertySet* layer1_baseColor = layer1->AddPropertySet("baseColor"); - MaterialTypeSourceData::PropertySet* layer2_baseColor = layer2->AddPropertySet("baseColor"); + MaterialTypeSourceData::PropertyGroup* layer1_baseColor = layer1->AddPropertyGroup("baseColor"); + MaterialTypeSourceData::PropertyGroup* layer2_baseColor = layer2->AddPropertyGroup("baseColor"); - MaterialTypeSourceData::PropertySet* layer1_roughness = sourceData.AddPropertySet("layer1.roughness"); - MaterialTypeSourceData::PropertySet* layer2_roughness = sourceData.AddPropertySet("layer2.roughness"); + MaterialTypeSourceData::PropertyGroup* layer1_roughness = sourceData.AddPropertyGroup("layer1.roughness"); + MaterialTypeSourceData::PropertyGroup* layer2_roughness = sourceData.AddPropertyGroup("layer2.roughness"); MaterialTypeSourceData::PropertyDefinition* layer1_baseColor_texture = layer1_baseColor->AddProperty("texture"); MaterialTypeSourceData::PropertyDefinition* layer2_baseColor_texture = layer2_baseColor->AddProperty("texture"); @@ -380,9 +380,9 @@ namespace UnitTest MaterialTypeSourceData::PropertyDefinition* layer2_roughness_texture = sourceData.AddProperty("layer2.roughness.texture"); // We're doing clear coat only on layer2, for brevity - MaterialTypeSourceData::PropertySet* layer2_clearCoat = layer2->AddPropertySet("clearCoat"); - MaterialTypeSourceData::PropertySet* layer2_clearCoat_roughness = layer2_clearCoat->AddPropertySet("roughness"); - MaterialTypeSourceData::PropertySet* layer2_clearCoat_normal = layer2_clearCoat->AddPropertySet("normal"); + MaterialTypeSourceData::PropertyGroup* layer2_clearCoat = layer2->AddPropertyGroup("clearCoat"); + MaterialTypeSourceData::PropertyGroup* layer2_clearCoat_roughness = layer2_clearCoat->AddPropertyGroup("roughness"); + MaterialTypeSourceData::PropertyGroup* layer2_clearCoat_normal = layer2_clearCoat->AddPropertyGroup("normal"); MaterialTypeSourceData::PropertyDefinition* layer2_clearCoat_enabled = layer2_clearCoat->AddProperty("enabled"); MaterialTypeSourceData::PropertyDefinition* layer2_clearCoat_roughness_texture = layer2_clearCoat_roughness->AddProperty("texture"); MaterialTypeSourceData::PropertyDefinition* layer2_clearCoat_normal_texture = layer2_clearCoat_normal->AddProperty("texture"); @@ -396,27 +396,27 @@ namespace UnitTest EXPECT_EQ(nullptr, sourceData.FindProperty("layer1.DoesNotExist")); EXPECT_EQ(nullptr, sourceData.FindProperty("layer1.baseColor.DoesNotExist")); EXPECT_EQ(nullptr, sourceData.FindProperty("baseColor.texture")); - EXPECT_EQ(nullptr, sourceData.FindProperty("baseColor")); // This is a property set, not a property - EXPECT_EQ(nullptr, sourceData.FindPropertySet("baseColor.texture")); // This is a property, not a property set + EXPECT_EQ(nullptr, sourceData.FindProperty("baseColor")); // This is a property group, not a property + EXPECT_EQ(nullptr, sourceData.FindPropertyGroup("baseColor.texture")); // This is a property, not a property group - EXPECT_EQ(layer1, sourceData.FindPropertySet("layer1")); - EXPECT_EQ(layer2, sourceData.FindPropertySet("layer2")); - EXPECT_EQ(blend, sourceData.FindPropertySet("blend")); + EXPECT_EQ(layer1, sourceData.FindPropertyGroup("layer1")); + EXPECT_EQ(layer2, sourceData.FindPropertyGroup("layer2")); + EXPECT_EQ(blend, sourceData.FindPropertyGroup("blend")); - EXPECT_EQ(layer1_baseColor, sourceData.FindPropertySet("layer1.baseColor")); - EXPECT_EQ(layer2_baseColor, sourceData.FindPropertySet("layer2.baseColor")); + EXPECT_EQ(layer1_baseColor, sourceData.FindPropertyGroup("layer1.baseColor")); + EXPECT_EQ(layer2_baseColor, sourceData.FindPropertyGroup("layer2.baseColor")); - EXPECT_EQ(layer1_roughness, sourceData.FindPropertySet("layer1.roughness")); - EXPECT_EQ(layer2_roughness, sourceData.FindPropertySet("layer2.roughness")); + EXPECT_EQ(layer1_roughness, sourceData.FindPropertyGroup("layer1.roughness")); + EXPECT_EQ(layer2_roughness, sourceData.FindPropertyGroup("layer2.roughness")); EXPECT_EQ(layer1_baseColor_texture, sourceData.FindProperty("layer1.baseColor.texture")); EXPECT_EQ(layer2_baseColor_texture, sourceData.FindProperty("layer2.baseColor.texture")); EXPECT_EQ(layer1_roughness_texture, sourceData.FindProperty("layer1.roughness.texture")); EXPECT_EQ(layer2_roughness_texture, sourceData.FindProperty("layer2.roughness.texture")); - EXPECT_EQ(layer2_clearCoat, sourceData.FindPropertySet("layer2.clearCoat")); - EXPECT_EQ(layer2_clearCoat_roughness, sourceData.FindPropertySet("layer2.clearCoat.roughness")); - EXPECT_EQ(layer2_clearCoat_normal, sourceData.FindPropertySet("layer2.clearCoat.normal")); + EXPECT_EQ(layer2_clearCoat, sourceData.FindPropertyGroup("layer2.clearCoat")); + EXPECT_EQ(layer2_clearCoat_roughness, sourceData.FindPropertyGroup("layer2.clearCoat.roughness")); + EXPECT_EQ(layer2_clearCoat_normal, sourceData.FindPropertyGroup("layer2.clearCoat.normal")); EXPECT_EQ(layer2_clearCoat_enabled, sourceData.FindProperty("layer2.clearCoat.enabled")); EXPECT_EQ(layer2_clearCoat_roughness_texture, sourceData.FindProperty("layer2.clearCoat.roughness.texture")); @@ -425,39 +425,39 @@ namespace UnitTest EXPECT_EQ(blend_factor, sourceData.FindProperty("blend.factor")); - // Check EnumeratePropertySets + // Check EnumeratePropertyGroups - struct EnumeratePropertySetsResult + struct EnumeratePropertyGroupsResult { AZStd::string m_propertyIdContext; - const MaterialTypeSourceData::PropertySet* m_propertySet; + const MaterialTypeSourceData::PropertyGroup* m_propertyGroup; - void Check(AZStd::string expectedIdContext, const MaterialTypeSourceData::PropertySet* expectedPropertySet) + void Check(AZStd::string expectedIdContext, const MaterialTypeSourceData::PropertyGroup* expectedPropertyGroup) { EXPECT_EQ(expectedIdContext, m_propertyIdContext); - EXPECT_EQ(expectedPropertySet, m_propertySet); + EXPECT_EQ(expectedPropertyGroup, m_propertyGroup); } }; - AZStd::vector enumeratePropertySetsResults; + AZStd::vector enumeratePropertyGroupsResults; - sourceData.EnumeratePropertySets([&enumeratePropertySetsResults](const AZStd::string& propertyIdContext, const MaterialTypeSourceData::PropertySet* propertySet) + sourceData.EnumeratePropertyGroups([&enumeratePropertyGroupsResults](const AZStd::string& propertyIdContext, const MaterialTypeSourceData::PropertyGroup* propertyGroup) { - enumeratePropertySetsResults.push_back(EnumeratePropertySetsResult{propertyIdContext, propertySet}); + enumeratePropertyGroupsResults.push_back(EnumeratePropertyGroupsResult{propertyIdContext, propertyGroup}); return true; }); int resultIndex = 0; - enumeratePropertySetsResults[resultIndex++].Check("", layer1); - enumeratePropertySetsResults[resultIndex++].Check("layer1.", layer1_baseColor); - enumeratePropertySetsResults[resultIndex++].Check("layer1.", layer1_roughness); - enumeratePropertySetsResults[resultIndex++].Check("", layer2); - enumeratePropertySetsResults[resultIndex++].Check("layer2.", layer2_baseColor); - enumeratePropertySetsResults[resultIndex++].Check("layer2.", layer2_roughness); - enumeratePropertySetsResults[resultIndex++].Check("layer2.", layer2_clearCoat); - enumeratePropertySetsResults[resultIndex++].Check("layer2.clearCoat.", layer2_clearCoat_roughness); - enumeratePropertySetsResults[resultIndex++].Check("layer2.clearCoat.", layer2_clearCoat_normal); - enumeratePropertySetsResults[resultIndex++].Check("", blend); - EXPECT_EQ(resultIndex, enumeratePropertySetsResults.size()); + enumeratePropertyGroupsResults[resultIndex++].Check("", layer1); + enumeratePropertyGroupsResults[resultIndex++].Check("layer1.", layer1_baseColor); + enumeratePropertyGroupsResults[resultIndex++].Check("layer1.", layer1_roughness); + enumeratePropertyGroupsResults[resultIndex++].Check("", layer2); + enumeratePropertyGroupsResults[resultIndex++].Check("layer2.", layer2_baseColor); + enumeratePropertyGroupsResults[resultIndex++].Check("layer2.", layer2_roughness); + enumeratePropertyGroupsResults[resultIndex++].Check("layer2.", layer2_clearCoat); + enumeratePropertyGroupsResults[resultIndex++].Check("layer2.clearCoat.", layer2_clearCoat_roughness); + enumeratePropertyGroupsResults[resultIndex++].Check("layer2.clearCoat.", layer2_clearCoat_normal); + enumeratePropertyGroupsResults[resultIndex++].Check("", blend); + EXPECT_EQ(resultIndex, enumeratePropertyGroupsResults.size()); // Check EnumerateProperties @@ -497,39 +497,39 @@ namespace UnitTest { MaterialTypeSourceData sourceData; - MaterialTypeSourceData::PropertySet* propertySet = sourceData.AddPropertySet("main"); + MaterialTypeSourceData::PropertyGroup* propertyGroup = sourceData.AddPropertyGroup("main"); ErrorMessageFinder errorMessageFinder; errorMessageFinder.AddExpectedErrorMessage("'' is not a valid identifier"); errorMessageFinder.AddExpectedErrorMessage("'main.' is not a valid identifier"); errorMessageFinder.AddExpectedErrorMessage("'base-color' is not a valid identifier"); - EXPECT_FALSE(propertySet->AddProperty("")); - EXPECT_FALSE(propertySet->AddProperty("main.")); + EXPECT_FALSE(propertyGroup->AddProperty("")); + EXPECT_FALSE(propertyGroup->AddProperty("main.")); EXPECT_FALSE(sourceData.AddProperty("main.base-color")); - EXPECT_TRUE(propertySet->GetProperties().empty()); + EXPECT_TRUE(propertyGroup->GetProperties().empty()); errorMessageFinder.CheckExpectedErrorsFound(); } - TEST_F(MaterialTypeSourceDataTests, AddPropertySet_Error_InvalidName) + TEST_F(MaterialTypeSourceDataTests, AddPropertyGroup_Error_InvalidName) { MaterialTypeSourceData sourceData; - MaterialTypeSourceData::PropertySet* propertySet = sourceData.AddPropertySet("general"); + MaterialTypeSourceData::PropertyGroup* propertyGroup = sourceData.AddPropertyGroup("general"); ErrorMessageFinder errorMessageFinder; errorMessageFinder.AddExpectedErrorMessage("'' is not a valid identifier", 2); errorMessageFinder.AddExpectedErrorMessage("'base-color' is not a valid identifier"); errorMessageFinder.AddExpectedErrorMessage("'look@it' is not a valid identifier"); - EXPECT_FALSE(propertySet->AddPropertySet("")); - EXPECT_FALSE(sourceData.AddPropertySet("")); - EXPECT_FALSE(sourceData.AddPropertySet("base-color")); - EXPECT_FALSE(sourceData.AddPropertySet("general.look@it")); + EXPECT_FALSE(propertyGroup->AddPropertyGroup("")); + EXPECT_FALSE(sourceData.AddPropertyGroup("")); + EXPECT_FALSE(sourceData.AddPropertyGroup("base-color")); + EXPECT_FALSE(sourceData.AddPropertyGroup("general.look@it")); - EXPECT_TRUE(propertySet->GetProperties().empty()); + EXPECT_TRUE(propertyGroup->GetProperties().empty()); errorMessageFinder.CheckExpectedErrorsFound(); } @@ -538,16 +538,16 @@ namespace UnitTest { MaterialTypeSourceData sourceData; - MaterialTypeSourceData::PropertySet* propertySet = sourceData.AddPropertySet("main"); + MaterialTypeSourceData::PropertyGroup* propertyGroup = sourceData.AddPropertyGroup("main"); ErrorMessageFinder errorMessageFinder; - errorMessageFinder.AddExpectedErrorMessage("PropertySet 'main' already contains a property named 'foo'", 2); + errorMessageFinder.AddExpectedErrorMessage("PropertyGroup 'main' already contains a property named 'foo'", 2); - EXPECT_TRUE(propertySet->AddProperty("foo")); - EXPECT_FALSE(propertySet->AddProperty("foo")); + EXPECT_TRUE(propertyGroup->AddProperty("foo")); + EXPECT_FALSE(propertyGroup->AddProperty("foo")); EXPECT_FALSE(sourceData.AddProperty("main.foo")); - EXPECT_EQ(propertySet->GetProperties().size(), 1); + EXPECT_EQ(propertyGroup->GetProperties().size(), 1); errorMessageFinder.CheckExpectedErrorsFound(); } @@ -555,66 +555,66 @@ namespace UnitTest TEST_F(MaterialTypeSourceDataTests, AddProperty_Error_AddLooseProperty) { MaterialTypeSourceData sourceData; - ErrorMessageFinder errorMessageFinder("Property id 'foo' is invalid. Properties must be added to a PropertySet"); + ErrorMessageFinder errorMessageFinder("Property id 'foo' is invalid. Properties must be added to a PropertyGroup"); EXPECT_FALSE(sourceData.AddProperty("foo")); errorMessageFinder.CheckExpectedErrorsFound(); } - TEST_F(MaterialTypeSourceDataTests, AddProperty_Error_PropertySetDoesNotExist ) + TEST_F(MaterialTypeSourceDataTests, AddProperty_Error_PropertyGroupDoesNotExist ) { MaterialTypeSourceData sourceData; - ErrorMessageFinder errorMessageFinder("PropertySet 'DNE' does not exists"); + ErrorMessageFinder errorMessageFinder("PropertyGroup 'DNE' does not exists"); EXPECT_FALSE(sourceData.AddProperty("DNE.foo")); errorMessageFinder.CheckExpectedErrorsFound(); } - TEST_F(MaterialTypeSourceDataTests, AddPropertySet_Error_PropertySetDoesNotExist ) + TEST_F(MaterialTypeSourceDataTests, AddPropertyGroup_Error_PropertyGroupDoesNotExist ) { MaterialTypeSourceData sourceData; - ErrorMessageFinder errorMessageFinder("PropertySet 'DNE' does not exists"); - EXPECT_FALSE(sourceData.AddPropertySet("DNE.foo")); + ErrorMessageFinder errorMessageFinder("PropertyGroup 'DNE' does not exists"); + EXPECT_FALSE(sourceData.AddPropertyGroup("DNE.foo")); errorMessageFinder.CheckExpectedErrorsFound(); } - TEST_F(MaterialTypeSourceDataTests, AddPropertySet_Error_AddDuplicatePropertySet) + TEST_F(MaterialTypeSourceDataTests, AddPropertyGroup_Error_AddDuplicatePropertyGroup) { MaterialTypeSourceData sourceData; - MaterialTypeSourceData::PropertySet* propertySet = sourceData.AddPropertySet("main"); - sourceData.AddPropertySet("main.level2"); + MaterialTypeSourceData::PropertyGroup* propertyGroup = sourceData.AddPropertyGroup("main"); + sourceData.AddPropertyGroup("main.level2"); ErrorMessageFinder errorMessageFinder; - errorMessageFinder.AddExpectedErrorMessage("PropertySet named 'main' already exists", 1); - errorMessageFinder.AddExpectedErrorMessage("PropertySet named 'level2' already exists", 2); + errorMessageFinder.AddExpectedErrorMessage("PropertyGroup named 'main' already exists", 1); + errorMessageFinder.AddExpectedErrorMessage("PropertyGroup named 'level2' already exists", 2); - EXPECT_FALSE(sourceData.AddPropertySet("main")); - EXPECT_FALSE(sourceData.AddPropertySet("main.level2")); - EXPECT_FALSE(propertySet->AddPropertySet("level2")); + EXPECT_FALSE(sourceData.AddPropertyGroup("main")); + EXPECT_FALSE(sourceData.AddPropertyGroup("main.level2")); + EXPECT_FALSE(propertyGroup->AddPropertyGroup("level2")); errorMessageFinder.CheckExpectedErrorsFound(); - EXPECT_EQ(sourceData.GetPropertyLayout().m_propertySets.size(), 1); - EXPECT_EQ(propertySet->GetPropertySets().size(), 1); + EXPECT_EQ(sourceData.GetPropertyLayout().m_propertyGroups.size(), 1); + EXPECT_EQ(propertyGroup->GetPropertyGroups().size(), 1); } - TEST_F(MaterialTypeSourceDataTests, AddPropertySet_Error_NameCollidesWithProperty ) + TEST_F(MaterialTypeSourceDataTests, AddPropertyGroup_Error_NameCollidesWithProperty ) { MaterialTypeSourceData sourceData; - sourceData.AddPropertySet("main"); + sourceData.AddPropertyGroup("main"); sourceData.AddProperty("main.foo"); - ErrorMessageFinder errorMessageFinder("PropertySet name 'foo' collides with a Property of the same name"); - EXPECT_FALSE(sourceData.AddPropertySet("main.foo")); + ErrorMessageFinder errorMessageFinder("PropertyGroup name 'foo' collides with a Property of the same name"); + EXPECT_FALSE(sourceData.AddPropertyGroup("main.foo")); errorMessageFinder.CheckExpectedErrorsFound(); } - TEST_F(MaterialTypeSourceDataTests, AddProperty_Error_NameCollidesWithPropertySet ) + TEST_F(MaterialTypeSourceDataTests, AddProperty_Error_NameCollidesWithPropertyGroup ) { MaterialTypeSourceData sourceData; - sourceData.AddPropertySet("main"); - sourceData.AddPropertySet("main.foo"); + sourceData.AddPropertyGroup("main"); + sourceData.AddPropertyGroup("main.foo"); - ErrorMessageFinder errorMessageFinder("Property name 'foo' collides with a PropertySet of the same name"); + ErrorMessageFinder errorMessageFinder("Property name 'foo' collides with a PropertyGroup of the same name"); EXPECT_FALSE(sourceData.AddProperty("main.foo")); errorMessageFinder.CheckExpectedErrorsFound(); } @@ -627,11 +627,11 @@ namespace UnitTest sourceData.m_uvNameMap["UV1"] = "Unwrapped"; sourceData.m_uvNameMap["UV2"] = "Other"; - sourceData.AddPropertySet("a"); - sourceData.AddPropertySet("a.b"); - sourceData.AddPropertySet("c"); - sourceData.AddPropertySet("c.d"); - sourceData.AddPropertySet("c.d.e"); + sourceData.AddPropertyGroup("a"); + sourceData.AddPropertyGroup("a.b"); + sourceData.AddPropertyGroup("c"); + sourceData.AddPropertyGroup("c.d"); + sourceData.AddPropertyGroup("c.d.e"); MaterialTypeSourceData::PropertyDefinition* enum1 = sourceData.AddProperty("a.enum1"); MaterialTypeSourceData::PropertyDefinition* enum2 = sourceData.AddProperty("a.b.enum2"); @@ -820,8 +820,8 @@ namespace UnitTest sourceData.m_shaderCollection.push_back(MaterialTypeSourceData::ShaderVariantReferenceData{ TestShaderFilename }); - MaterialTypeSourceData::PropertySet* propertySet = sourceData.AddPropertySet("general"); - MaterialTypeSourceData::PropertyDefinition* property = propertySet->AddProperty("MyBool"); + MaterialTypeSourceData::PropertyGroup* propertyGroup = sourceData.AddPropertyGroup("general"); + MaterialTypeSourceData::PropertyDefinition* property = propertyGroup->AddProperty("MyBool"); property->m_displayName = "My Bool"; property->m_description = "This is a bool"; property->m_dataType = MaterialPropertyDataType::Bool; @@ -845,8 +845,8 @@ namespace UnitTest sourceData.m_shaderCollection.push_back(MaterialTypeSourceData::ShaderVariantReferenceData{ TestShaderFilename }); - MaterialTypeSourceData::PropertySet* propertySet = sourceData.AddPropertySet("general"); - MaterialTypeSourceData::PropertyDefinition* property = propertySet->AddProperty("MyFloat"); + MaterialTypeSourceData::PropertyGroup* propertyGroup = sourceData.AddPropertyGroup("general"); + MaterialTypeSourceData::PropertyDefinition* property = propertyGroup->AddProperty("MyFloat"); property->m_displayName = "My Float"; property->m_description = "This is a float"; property->m_min = 0.0f; @@ -874,8 +874,8 @@ namespace UnitTest sourceData.m_shaderCollection.push_back(MaterialTypeSourceData::ShaderVariantReferenceData{ TestShaderFilename }); - MaterialTypeSourceData::PropertySet* propertySet = sourceData.AddPropertySet("general"); - MaterialTypeSourceData::PropertyDefinition* property = propertySet->AddProperty("MyImage"); + MaterialTypeSourceData::PropertyGroup* propertyGroup = sourceData.AddPropertyGroup("general"); + MaterialTypeSourceData::PropertyDefinition* property = propertyGroup->AddProperty("MyImage"); property->m_displayName = "My Image"; property->m_description = "This is an image"; property->m_dataType = MaterialPropertyDataType::Image; @@ -898,8 +898,8 @@ namespace UnitTest sourceData.m_shaderCollection.push_back(MaterialTypeSourceData::ShaderVariantReferenceData{TestShaderFilename}); - MaterialTypeSourceData::PropertySet* propertySet = sourceData.AddPropertySet("general"); - MaterialTypeSourceData::PropertyDefinition* property = propertySet->AddProperty("MyInt"); + MaterialTypeSourceData::PropertyGroup* propertyGroup = sourceData.AddPropertyGroup("general"); + MaterialTypeSourceData::PropertyDefinition* property = propertyGroup->AddProperty("MyInt"); property->m_displayName = "My Integer"; property->m_dataType = MaterialPropertyDataType::Int; property->m_outputConnections.push_back(MaterialTypeSourceData::PropertyConnection{MaterialPropertyOutputType::ShaderOption, AZStd::string("o_foo"), 0}); @@ -920,8 +920,8 @@ namespace UnitTest sourceData.m_shaderCollection.push_back(MaterialTypeSourceData::ShaderVariantReferenceData{TestShaderFilename}); - MaterialTypeSourceData::PropertySet* propertySet = sourceData.AddPropertySet("general"); - MaterialTypeSourceData::PropertyDefinition* property = propertySet->AddProperty("MyInt"); + MaterialTypeSourceData::PropertyGroup* propertyGroup = sourceData.AddPropertyGroup("general"); + MaterialTypeSourceData::PropertyDefinition* property = propertyGroup->AddProperty("MyInt"); property->m_dataType = MaterialPropertyDataType::Int; property->m_outputConnections.push_back(MaterialTypeSourceData::PropertyConnection{MaterialPropertyOutputType::ShaderOption, AZStd::string("DoesNotExist"), 0}); @@ -937,7 +937,7 @@ namespace UnitTest const AZStd::string inputJson = R"( { "propertyLayout": { - "propertySets": [ + "propertyGroups": [ { "name": "not a valid name because it has spaces", "properties": [ @@ -967,7 +967,7 @@ namespace UnitTest const AZStd::string inputJson = R"( { "propertyLayout": { - "propertySets": [ + "propertyGroups": [ { "name": "general", "properties": [ @@ -997,7 +997,7 @@ namespace UnitTest const AZStd::string inputJson = R"( { "propertyLayout": { - "propertySets": [ + "propertyGroups": [ { "name": "general", "properties": [ @@ -1027,12 +1027,12 @@ namespace UnitTest errorMessageFinder.CheckExpectedErrorsFound(); } - TEST_F(MaterialTypeSourceDataTests, CreateMaterialTypeAsset_Error_PropertyAndPropertySetNameCollision) + TEST_F(MaterialTypeSourceDataTests, CreateMaterialTypeAsset_Error_PropertyAndPropertyGroupNameCollision) { const AZStd::string inputJson = R"( { "propertyLayout": { - "propertySets": [ + "propertyGroups": [ { "name": "general", "properties": [ @@ -1041,7 +1041,7 @@ namespace UnitTest "type": "Bool" } ], - "propertySets": [ + "propertyGroups": [ { "name": "foo", "properties": [ @@ -1062,7 +1062,7 @@ namespace UnitTest JsonTestResult loadResult = LoadTestDataFromJson(sourceData, inputJson); EXPECT_EQ(loadResult.m_jsonResultCode.GetProcessing(), JsonSerializationResult::Processing::Completed); - ErrorMessageFinder errorMessageFinder("Material property 'general.foo' collides with a PropertySet with the same ID"); + ErrorMessageFinder errorMessageFinder("Material property 'general.foo' collides with a PropertyGroup with the same ID"); auto materialTypeOutcome = sourceData.CreateMaterialTypeAsset(Uuid::CreateRandom()); EXPECT_FALSE(materialTypeOutcome.IsSuccess()); errorMessageFinder.CheckExpectedErrorsFound(); @@ -1117,8 +1117,8 @@ namespace UnitTest sourceData.m_shaderCollection.push_back(MaterialTypeSourceData::ShaderVariantReferenceData{ "shaderB.shader" }); sourceData.m_shaderCollection.push_back(MaterialTypeSourceData::ShaderVariantReferenceData{ "shaderC.shader" }); - MaterialTypeSourceData::PropertySet* propertySet = sourceData.AddPropertySet("general"); - MaterialTypeSourceData::PropertyDefinition* property = propertySet->AddProperty("MyInt"); + MaterialTypeSourceData::PropertyGroup* propertyGroup = sourceData.AddPropertyGroup("general"); + MaterialTypeSourceData::PropertyDefinition* property = propertyGroup->AddProperty("MyInt"); property->m_displayName = "Integer"; property->m_description = "Integer property that is connected to multiple shader settings"; @@ -1176,8 +1176,8 @@ namespace UnitTest { MaterialTypeSourceData sourceData; - MaterialTypeSourceData::PropertySet* propertySet = sourceData.AddPropertySet("general"); - MaterialTypeSourceData::PropertyDefinition* property = propertySet->AddProperty("floatForFunctor"); + MaterialTypeSourceData::PropertyGroup* propertyGroup = sourceData.AddPropertyGroup("general"); + MaterialTypeSourceData::PropertyDefinition* property = propertyGroup->AddProperty("floatForFunctor"); property->m_displayName = "Float for Functor"; property->m_description = "This float is processed by a functor, not with a direct connection"; @@ -1221,9 +1221,9 @@ namespace UnitTest sourceData.m_shaderCollection.push_back(MaterialTypeSourceData::ShaderVariantReferenceData{TestShaderFilename}); sourceData.m_shaderCollection.push_back(MaterialTypeSourceData::ShaderVariantReferenceData{TestShaderFilename}); - MaterialTypeSourceData::PropertySet* propertySet = sourceData.AddPropertySet("general"); - MaterialTypeSourceData::PropertyDefinition* property1 = propertySet->AddProperty("EnableSpecialPassA"); - MaterialTypeSourceData::PropertyDefinition* property2 = propertySet->AddProperty("EnableSpecialPassB"); + MaterialTypeSourceData::PropertyGroup* propertyGroup = sourceData.AddPropertyGroup("general"); + MaterialTypeSourceData::PropertyDefinition* property1 = propertyGroup->AddProperty("EnableSpecialPassA"); + MaterialTypeSourceData::PropertyDefinition* property2 = propertyGroup->AddProperty("EnableSpecialPassB"); property1->m_displayName = property2->m_displayName = "Enable Special Pass"; property1->m_description = property2->m_description = "This is a bool to enable an extra shader/pass"; @@ -1279,8 +1279,8 @@ namespace UnitTest sourceData.m_shaderCollection.push_back(MaterialTypeSourceData::ShaderVariantReferenceData{TestShaderFilename}); sourceData.m_shaderCollection.push_back(MaterialTypeSourceData::ShaderVariantReferenceData{TestShaderFilename}); - MaterialTypeSourceData::PropertySet* propertySet = sourceData.AddPropertySet("general"); - MaterialTypeSourceData::PropertyDefinition* property = propertySet->AddProperty("MyProperty"); + MaterialTypeSourceData::PropertyGroup* propertyGroup = sourceData.AddPropertyGroup("general"); + MaterialTypeSourceData::PropertyDefinition* property = propertyGroup->AddProperty("MyProperty"); property->m_dataType = MaterialPropertyDataType::Bool; // Note that we don't fill property->m_outputConnections because this is not a direct-connected property @@ -1307,12 +1307,12 @@ namespace UnitTest EXPECT_TRUE(materialTypeAsset->GetShaderCollection()[0].MaterialOwnsShaderOption(Name{"o_bar"})); } - TEST_F(MaterialTypeSourceDataTests, CreateMaterialTypeAsset_FunctorIsInsidePropertySet) + TEST_F(MaterialTypeSourceDataTests, CreateMaterialTypeAsset_FunctorIsInsidePropertyGroup) { MaterialTypeSourceData sourceData; - MaterialTypeSourceData::PropertySet* propertySet = sourceData.AddPropertySet("general"); - MaterialTypeSourceData::PropertyDefinition* property = propertySet->AddProperty("floatForFunctor"); + MaterialTypeSourceData::PropertyGroup* propertyGroup = sourceData.AddPropertyGroup("general"); + MaterialTypeSourceData::PropertyDefinition* property = propertyGroup->AddProperty("floatForFunctor"); property->m_dataType = MaterialPropertyDataType::Float; @@ -1360,7 +1360,7 @@ namespace UnitTest property->m_value = value; }; - sourceData.AddPropertySet("general"); + sourceData.AddPropertyGroup("general"); addProperty(MaterialPropertyDataType::Bool, "general.MyBool", "m_bool", true); addProperty(MaterialPropertyDataType::Float, "general.MyFloat", "m_float", 1.2f); @@ -1387,7 +1387,7 @@ namespace UnitTest CheckPropertyValue>(materialTypeAsset, Name{"general.MyImage"}, m_testImageAsset); } - TEST_F(MaterialTypeSourceDataTests, CreateMaterialTypeAsset_NestedPropertySets) + TEST_F(MaterialTypeSourceDataTests, CreateMaterialTypeAsset_NestedPropertyGroups) { RHI::Ptr layeredMaterialSrgLayout = RHI::ShaderResourceGroupLayout::Create(); layeredMaterialSrgLayout->SetName(Name{"MaterialSrg"}); @@ -1428,16 +1428,16 @@ namespace UnitTest property->m_value = value; }; - sourceData.AddPropertySet("layer1"); - sourceData.AddPropertySet("layer2"); - sourceData.AddPropertySet("blend"); - sourceData.AddPropertySet("layer1.baseColor"); - sourceData.AddPropertySet("layer2.baseColor"); - sourceData.AddPropertySet("layer1.roughness"); - sourceData.AddPropertySet("layer2.roughness"); - sourceData.AddPropertySet("layer2.clearCoat"); - sourceData.AddPropertySet("layer2.clearCoat.roughness"); - sourceData.AddPropertySet("layer2.clearCoat.normal"); + sourceData.AddPropertyGroup("layer1"); + sourceData.AddPropertyGroup("layer2"); + sourceData.AddPropertyGroup("blend"); + sourceData.AddPropertyGroup("layer1.baseColor"); + sourceData.AddPropertyGroup("layer2.baseColor"); + sourceData.AddPropertyGroup("layer1.roughness"); + sourceData.AddPropertyGroup("layer2.roughness"); + sourceData.AddPropertyGroup("layer2.clearCoat"); + sourceData.AddPropertyGroup("layer2.clearCoat.roughness"); + sourceData.AddPropertyGroup("layer2.clearCoat.normal"); addSrgProperty(MaterialPropertyDataType::Image, MaterialPropertyOutputType::ShaderInput, "layer1.baseColor.texture", "m_layer1_baseColor_texture", AZStd::string{TestImageFilename}); addSrgProperty(MaterialPropertyDataType::Image, MaterialPropertyOutputType::ShaderInput, "layer1.roughness.texture", "m_layer1_roughness_texture", AZStd::string{TestImageFilename}); @@ -1487,7 +1487,7 @@ namespace UnitTest } ], "propertyLayout": { - "propertySets": [ + "propertyGroups": [ { "name": "groupA", "displayName": "Property Group A", @@ -1545,8 +1545,8 @@ namespace UnitTest { "name": "groupC", "displayName": "Property Group C", - "description": "Property group C has a nested property set", - "propertySets": [ + "description": "Property group C has a nested property group", + "propertyGroups": [ { "name": "groupD", "displayName": "Property Group D", @@ -1616,27 +1616,27 @@ namespace UnitTest EXPECT_EQ(material.m_versionUpdates[0].m_actions[0].m_renameTo, "groupA.foo"); - EXPECT_EQ(material.GetPropertyLayout().m_propertySets.size(), 3); - EXPECT_TRUE(material.FindPropertySet("groupA") != nullptr); - EXPECT_TRUE(material.FindPropertySet("groupB") != nullptr); - EXPECT_TRUE(material.FindPropertySet("groupC") != nullptr); - EXPECT_TRUE(material.FindPropertySet("groupC.groupD") != nullptr); - EXPECT_TRUE(material.FindPropertySet("groupC.groupE") != nullptr); - EXPECT_EQ(material.FindPropertySet("groupA")->GetDisplayName(), "Property Group A"); - EXPECT_EQ(material.FindPropertySet("groupB")->GetDisplayName(), "Property Group B"); - EXPECT_EQ(material.FindPropertySet("groupC")->GetDisplayName(), "Property Group C"); - EXPECT_EQ(material.FindPropertySet("groupC.groupD")->GetDisplayName(), "Property Group D"); - EXPECT_EQ(material.FindPropertySet("groupC.groupE")->GetDisplayName(), "Property Group E"); - EXPECT_EQ(material.FindPropertySet("groupA")->GetDescription(), "Description of property group A"); - EXPECT_EQ(material.FindPropertySet("groupB")->GetDescription(), "Description of property group B"); - EXPECT_EQ(material.FindPropertySet("groupC")->GetDescription(), "Property group C has a nested property set"); - EXPECT_EQ(material.FindPropertySet("groupC.groupD")->GetDescription(), "Description of property group D"); - EXPECT_EQ(material.FindPropertySet("groupC.groupE")->GetDescription(), "Description of property group E"); - EXPECT_EQ(material.FindPropertySet("groupA")->GetProperties().size(), 2); - EXPECT_EQ(material.FindPropertySet("groupB")->GetProperties().size(), 2); - EXPECT_EQ(material.FindPropertySet("groupC")->GetProperties().size(), 0); - EXPECT_EQ(material.FindPropertySet("groupC.groupD")->GetProperties().size(), 1); - EXPECT_EQ(material.FindPropertySet("groupC.groupE")->GetProperties().size(), 1); + EXPECT_EQ(material.GetPropertyLayout().m_propertyGroups.size(), 3); + EXPECT_TRUE(material.FindPropertyGroup("groupA") != nullptr); + EXPECT_TRUE(material.FindPropertyGroup("groupB") != nullptr); + EXPECT_TRUE(material.FindPropertyGroup("groupC") != nullptr); + EXPECT_TRUE(material.FindPropertyGroup("groupC.groupD") != nullptr); + EXPECT_TRUE(material.FindPropertyGroup("groupC.groupE") != nullptr); + EXPECT_EQ(material.FindPropertyGroup("groupA")->GetDisplayName(), "Property Group A"); + EXPECT_EQ(material.FindPropertyGroup("groupB")->GetDisplayName(), "Property Group B"); + EXPECT_EQ(material.FindPropertyGroup("groupC")->GetDisplayName(), "Property Group C"); + EXPECT_EQ(material.FindPropertyGroup("groupC.groupD")->GetDisplayName(), "Property Group D"); + EXPECT_EQ(material.FindPropertyGroup("groupC.groupE")->GetDisplayName(), "Property Group E"); + EXPECT_EQ(material.FindPropertyGroup("groupA")->GetDescription(), "Description of property group A"); + EXPECT_EQ(material.FindPropertyGroup("groupB")->GetDescription(), "Description of property group B"); + EXPECT_EQ(material.FindPropertyGroup("groupC")->GetDescription(), "Property group C has a nested property group"); + EXPECT_EQ(material.FindPropertyGroup("groupC.groupD")->GetDescription(), "Description of property group D"); + EXPECT_EQ(material.FindPropertyGroup("groupC.groupE")->GetDescription(), "Description of property group E"); + EXPECT_EQ(material.FindPropertyGroup("groupA")->GetProperties().size(), 2); + EXPECT_EQ(material.FindPropertyGroup("groupB")->GetProperties().size(), 2); + EXPECT_EQ(material.FindPropertyGroup("groupC")->GetProperties().size(), 0); + EXPECT_EQ(material.FindPropertyGroup("groupC.groupD")->GetProperties().size(), 1); + EXPECT_EQ(material.FindPropertyGroup("groupC.groupE")->GetProperties().size(), 1); EXPECT_NE(material.FindProperty("groupA.foo"), nullptr); EXPECT_NE(material.FindProperty("groupA.bar"), nullptr); @@ -1670,10 +1670,10 @@ namespace UnitTest EXPECT_EQ(material.FindProperty("groupC.groupD.foo")->m_value, -1); EXPECT_EQ(material.FindProperty("groupC.groupE.bar")->m_value, 0u); - EXPECT_EQ(material.FindPropertySet("groupA")->GetFunctors().size(), 1); - EXPECT_EQ(material.FindPropertySet("groupB")->GetFunctors().size(), 1); - Ptr functorA = material.FindPropertySet("groupA")->GetFunctors()[0]->GetActualSourceData(); - Ptr functorB = material.FindPropertySet("groupB")->GetFunctors()[0]->GetActualSourceData(); + EXPECT_EQ(material.FindPropertyGroup("groupA")->GetFunctors().size(), 1); + EXPECT_EQ(material.FindPropertyGroup("groupB")->GetFunctors().size(), 1); + Ptr functorA = material.FindPropertyGroup("groupA")->GetFunctors()[0]->GetActualSourceData(); + Ptr functorB = material.FindPropertyGroup("groupB")->GetFunctors()[0]->GetActualSourceData(); EXPECT_TRUE(azrtti_cast(functorA.get())); EXPECT_EQ(azrtti_cast(functorA.get())->m_enablePassPropertyId, "foo"); EXPECT_EQ(azrtti_cast(functorA.get())->m_shaderIndex, 1); @@ -1708,7 +1708,7 @@ namespace UnitTest // (The "store" part of the test was not included because the saved data will be the new format). // Notable differences include: // 1) the key "id" is used instead of "name" - // 2) the group metadata, property definitions, and functors are all defined in different sections rather than in a property set + // 2) the group metadata, property definitions, and functors are all defined in different sections rather than in a unified property group definition const AZStd::string inputJson = R"( { @@ -1798,25 +1798,25 @@ namespace UnitTest // Before conversion to the new format, the data is in the old place EXPECT_EQ(material.GetPropertyLayout().m_groupsOld.size(), 2); EXPECT_EQ(material.GetPropertyLayout().m_propertiesOld.size(), 2); - EXPECT_EQ(material.GetPropertyLayout().m_propertySets.size(), 0); + EXPECT_EQ(material.GetPropertyLayout().m_propertyGroups.size(), 0); material.ConvertToNewDataFormat(); // After conversion to the new format, the data is in the new place EXPECT_EQ(material.GetPropertyLayout().m_groupsOld.size(), 0); EXPECT_EQ(material.GetPropertyLayout().m_propertiesOld.size(), 0); - EXPECT_EQ(material.GetPropertyLayout().m_propertySets.size(), 2); + EXPECT_EQ(material.GetPropertyLayout().m_propertyGroups.size(), 2); EXPECT_EQ(material.m_description, "This is a general description about the material"); - EXPECT_TRUE(material.FindPropertySet("groupA") != nullptr); - EXPECT_TRUE(material.FindPropertySet("groupB") != nullptr); - EXPECT_EQ(material.FindPropertySet("groupA")->GetDisplayName(), "Property Group A"); - EXPECT_EQ(material.FindPropertySet("groupB")->GetDisplayName(), "Property Group B"); - EXPECT_EQ(material.FindPropertySet("groupA")->GetDescription(), "Description of property group A"); - EXPECT_EQ(material.FindPropertySet("groupB")->GetDescription(), "Description of property group B"); - EXPECT_EQ(material.FindPropertySet("groupA")->GetProperties().size(), 2); - EXPECT_EQ(material.FindPropertySet("groupB")->GetProperties().size(), 2); + EXPECT_TRUE(material.FindPropertyGroup("groupA") != nullptr); + EXPECT_TRUE(material.FindPropertyGroup("groupB") != nullptr); + EXPECT_EQ(material.FindPropertyGroup("groupA")->GetDisplayName(), "Property Group A"); + EXPECT_EQ(material.FindPropertyGroup("groupB")->GetDisplayName(), "Property Group B"); + EXPECT_EQ(material.FindPropertyGroup("groupA")->GetDescription(), "Description of property group A"); + EXPECT_EQ(material.FindPropertyGroup("groupB")->GetDescription(), "Description of property group B"); + EXPECT_EQ(material.FindPropertyGroup("groupA")->GetProperties().size(), 2); + EXPECT_EQ(material.FindPropertyGroup("groupB")->GetProperties().size(), 2); EXPECT_TRUE(material.FindProperty("groupA.foo") != nullptr); EXPECT_TRUE(material.FindProperty("groupA.bar") != nullptr); @@ -1840,10 +1840,10 @@ namespace UnitTest EXPECT_EQ(material.FindProperty("groupB.foo")->m_value, 0.5f); EXPECT_EQ(material.FindProperty("groupB.bar")->m_value, AZ::Color(0.5f, 0.5f, 0.5f, 1.0f)); - // The functors can appear either at the top level or within each property set. The format conversion + // The functors can appear either at the top level or within each property group. The format conversion // function doesn't know how to move the functors, and they will be left at the top level. - EXPECT_EQ(material.FindPropertySet("groupA")->GetFunctors().size(), 0); - EXPECT_EQ(material.FindPropertySet("groupB")->GetFunctors().size(), 0); + EXPECT_EQ(material.FindPropertyGroup("groupA")->GetFunctors().size(), 0); + EXPECT_EQ(material.FindPropertyGroup("groupB")->GetFunctors().size(), 0); EXPECT_EQ(material.m_shaderCollection.size(), 2); EXPECT_EQ(material.m_shaderCollection[0].m_shaderFilePath, "ForwardPass.shader"); @@ -1873,7 +1873,7 @@ namespace UnitTest { "description": "", "propertyLayout": { - "propertySets": [ + "propertyGroups": [ { "name": "general", "displayName": "General", @@ -1915,7 +1915,7 @@ namespace UnitTest { MaterialTypeSourceData sourceData; - MaterialTypeSourceData::PropertyDefinition* propertySource = sourceData.AddPropertySet("general")->AddProperty("a"); + MaterialTypeSourceData::PropertyDefinition* propertySource = sourceData.AddPropertyGroup("general")->AddProperty("a"); propertySource->m_dataType = MaterialPropertyDataType::Int; propertySource->m_value = 0; diff --git a/Gems/Atom/TestData/TestData/Materials/Types/MinimalPBR.materialtype b/Gems/Atom/TestData/TestData/Materials/Types/MinimalPBR.materialtype index 5876a3a858..641b0089a5 100644 --- a/Gems/Atom/TestData/TestData/Materials/Types/MinimalPBR.materialtype +++ b/Gems/Atom/TestData/TestData/Materials/Types/MinimalPBR.materialtype @@ -2,7 +2,7 @@ "description": "Base Material with properties used to define Standard PBR, a metallic-roughness Physically-Based Rendering (PBR) material shading model.", "version": 3, "propertyLayout": { - "propertySets": [ + "propertyGroups": [ { "name": "settings", "displayName": "Settings", diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp index 96b98cef51..c441762710 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp @@ -602,7 +602,7 @@ namespace MaterialEditor return false; } - // TODO: Support populating the Material Editor with nested property sets, not just the top level. + // TODO: Support populating the Material Editor with nested property groups, not just the top level. const AZStd::string groupName = propertyId.GetStringView().substr(0, propertyId.GetStringView().size() - propertyDefinition->GetName().size() - 1); sourceData.m_properties[groupName][propertyDefinition->GetName()].m_value = propertyValue; } @@ -781,14 +781,14 @@ namespace MaterialEditor // Populate the property map from a combination of source data and assets // Assets must still be used for now because they contain the final accumulated value after all other materials // in the hierarchy are applied - m_materialTypeSourceData.EnumeratePropertySets([this, &parentPropertyValues](const AZStd::string& propertyIdContext, const MaterialTypeSourceData::PropertySet* propertySet) + m_materialTypeSourceData.EnumeratePropertyGroups([this, &parentPropertyValues](const AZStd::string& propertyIdContext, const MaterialTypeSourceData::PropertyGroup* propertyGroup) { AtomToolsFramework::DynamicPropertyConfig propertyConfig; - for (const auto& propertyDefinition : propertySet->GetProperties()) + for (const auto& propertyDefinition : propertyGroup->GetProperties()) { // Assign id before conversion so it can be used in dynamic description - propertyConfig.m_id = propertyIdContext + propertySet->GetName() + "." + propertyDefinition->GetName(); + propertyConfig.m_id = propertyIdContext + propertyGroup->GetName() + "." + propertyDefinition->GetName(); const auto& propertyIndex = m_materialAsset->GetMaterialPropertiesLayout()->FindPropertyIndex(propertyConfig.m_id); const bool propertyIndexInBounds = propertyIndex.IsValid() && propertyIndex.GetIndex() < m_materialAsset->GetPropertyValues().size(); @@ -801,9 +801,9 @@ namespace MaterialEditor propertyConfig.m_originalValue = AtomToolsFramework::ConvertToEditableType(m_materialAsset->GetPropertyValues()[propertyIndex.GetIndex()]); propertyConfig.m_parentValue = AtomToolsFramework::ConvertToEditableType(parentPropertyValues[propertyIndex.GetIndex()]); - // TODO: Support populating the Material Editor with nested property sets, not just the top level. + // TODO: Support populating the Material Editor with nested property groups, not just the top level. // (Does DynamicPropertyConfig really even need m_groupName?) - propertyConfig.m_groupName = propertySet->GetDisplayName(); + propertyConfig.m_groupName = propertyGroup->GetDisplayName(); m_properties[propertyConfig.m_id] = AtomToolsFramework::DynamicProperty(propertyConfig); } } @@ -812,10 +812,10 @@ namespace MaterialEditor }); // Populate the property group visibility map - // TODO: Support populating the Material Editor with nested property sets, not just the top level. - for (const AZStd::unique_ptr& propertySet : m_materialTypeSourceData.GetPropertyLayout().m_propertySets) + // TODO: Support populating the Material Editor with nested property groups, not just the top level. + for (const AZStd::unique_ptr& propertyGroup : m_materialTypeSourceData.GetPropertyLayout().m_propertyGroups) { - m_propertyGroupVisibility[AZ::Name{propertySet->GetName()}] = true; + m_propertyGroupVisibility[AZ::Name{propertyGroup->GetName()}] = true; } // Adding properties for material type and parent as part of making dynamic @@ -899,14 +899,14 @@ namespace MaterialEditor } } - // Add any material functors that are located inside each property set. - bool enumerateResult = m_materialTypeSourceData.EnumeratePropertySets( - [this](const AZStd::string&, const MaterialTypeSourceData::PropertySet* propertySet) + // Add any material functors that are located inside each property group. + bool enumerateResult = m_materialTypeSourceData.EnumeratePropertyGroups( + [this](const AZStd::string&, const MaterialTypeSourceData::PropertyGroup* propertyGroup) { const MaterialFunctorSourceData::EditorContext editorContext = MaterialFunctorSourceData::EditorContext( m_materialSourceData.m_materialType, m_materialAsset->GetMaterialPropertiesLayout()); - for (Ptr functorData : propertySet->GetFunctors()) + for (Ptr functorData : propertyGroup->GetFunctors()) { MaterialFunctorSourceData::FunctorResult result = functorData->CreateFunctor(editorContext); diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.cpp index 3208683bf0..1402ad9f24 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.cpp @@ -171,16 +171,16 @@ namespace MaterialEditor MaterialDocumentRequestBus::EventResult( materialTypeSourceData, m_documentId, &MaterialDocumentRequestBus::Events::GetMaterialTypeSourceData); - // TODO: Support populating the Material Editor with nested property sets, not just the top level. - for (const AZStd::unique_ptr& propertySet : materialTypeSourceData->GetPropertyLayout().m_propertySets) + // TODO: Support populating the Material Editor with nested property groups, not just the top level. + for (const AZStd::unique_ptr& propertyGroup : materialTypeSourceData->GetPropertyLayout().m_propertyGroups) { - const AZStd::string& groupName = propertySet->GetName(); - const AZStd::string& groupDisplayName = !propertySet->GetDisplayName().empty() ? propertySet->GetDisplayName() : groupName; - const AZStd::string& groupDescription = !propertySet->GetDescription().empty() ? propertySet->GetDescription() : groupDisplayName; + const AZStd::string& groupName = propertyGroup->GetName(); + const AZStd::string& groupDisplayName = !propertyGroup->GetDisplayName().empty() ? propertyGroup->GetDisplayName() : groupName; + const AZStd::string& groupDescription = !propertyGroup->GetDescription().empty() ? propertyGroup->GetDescription() : groupDisplayName; auto& group = m_groups[groupName]; - group.m_properties.reserve(propertySet->GetProperties().size()); - for (const auto& propertyDefinition : propertySet->GetProperties()) + group.m_properties.reserve(propertyGroup->GetProperties().size()); + for (const auto& propertyDefinition : propertyGroup->GetProperties()) { AtomToolsFramework::DynamicProperty property; AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult( diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp index 37fba346b8..dde81e77b5 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp @@ -293,16 +293,16 @@ namespace AZ void MaterialPropertyInspector::AddPropertiesGroup() { // 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& propertySet : m_editData.m_materialTypeSourceData.GetPropertyLayout().m_propertySets) + // TODO: Support populating the Material Editor with nested property groups, not just the top level. + for (const AZStd::unique_ptr& propertyGroup : m_editData.m_materialTypeSourceData.GetPropertyLayout().m_propertyGroups) { - const AZStd::string& groupName = propertySet->GetName(); - const AZStd::string& groupDisplayName = !propertySet->GetDisplayName().empty() ? propertySet->GetDisplayName() : groupName; - const AZStd::string& groupDescription = !propertySet->GetDescription().empty() ? propertySet->GetDescription() : groupDisplayName; + const AZStd::string& groupName = propertyGroup->GetName(); + const AZStd::string& groupDisplayName = !propertyGroup->GetDisplayName().empty() ? propertyGroup->GetDisplayName() : groupName; + const AZStd::string& groupDescription = !propertyGroup->GetDescription().empty() ? propertyGroup->GetDescription() : groupDisplayName; auto& group = m_groups[groupName]; - group.m_properties.reserve(propertySet->GetProperties().size()); - for (const auto& propertyDefinition : propertySet->GetProperties()) + group.m_properties.reserve(propertyGroup->GetProperties().size()); + for (const auto& propertyDefinition : propertyGroup->GetProperties()) { AtomToolsFramework::DynamicPropertyConfig propertyConfig; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp index 62982e4b4d..dde9644c50 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp @@ -148,7 +148,7 @@ namespace AZ return true; } - // TODO: Support populating the Material Editor with nested property sets, not just the top level. + // TODO: Support populating the Material Editor with nested property groups, not just the top level. const AZStd::string groupName = propertyId.GetStringView().substr(0, propertyId.GetStringView().size() - propertyDefinition->GetName().size() - 1); exportData.m_properties[groupName][propertyDefinition->GetName()].m_value = propertyValue; return true; From fa037d5d7dad0228377729ffc34bb77e767303cd Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Thu, 27 Jan 2022 16:49:17 -0800 Subject: [PATCH 19/20] Updated MaterialSourceData::CreateMaterialAssetFromSourceData to use MaterialUtils::LoadMaterialTypeSourceData which calls ConvertToNewDataFormat(). This was needed by Material Editor to succesfully load old-format material types. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../Code/Source/RPI.Edit/Material/MaterialSourceData.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp index 2fa4ff648e..ae7889aa93 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp @@ -217,14 +217,14 @@ namespace AZ return Failure(); } - MaterialTypeSourceData materialTypeSourceData; - if (!AZ::RPI::JsonUtils::LoadObjectFromFile(materialTypeSourcePath, materialTypeSourceData)) + auto materialTypeLoadOutcome = MaterialUtils::LoadMaterialTypeSourceData(materialTypeSourcePath); + if (!materialTypeLoadOutcome) { AZ_Error("MaterialSourceData", false, "Failed to load MaterialTypeSourceData: '%s'.", materialTypeSourcePath.c_str()); return Failure(); } - materialTypeSourceData.ResolveUvEnums(); + MaterialTypeSourceData materialTypeSourceData = materialTypeLoadOutcome.TakeValue(); const auto materialTypeAsset = materialTypeSourceData.CreateMaterialTypeAsset(materialTypeAssetId.GetValue(), materialTypeSourcePath, elevateWarnings); From 4c426ea5a611ea8904554e9c4271c552ac2eaa6e Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Mon, 31 Jan 2022 09:44:41 -0800 Subject: [PATCH 20/20] Fixed compile issue in unity builds. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../Code/Include/Atom/RPI.Edit/Material/MaterialTypeSourceData.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialTypeSourceData.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialTypeSourceData.h index 40f82c8ec7..79c73495e0 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialTypeSourceData.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialTypeSourceData.h @@ -22,6 +22,7 @@ namespace AZ namespace RPI { class MaterialTypeAsset; + class MaterialTypeAssetCreator; class MaterialFunctorSourceDataHolder; class JsonMaterialPropertySerializer;