Merge pull request #7537 from aws-lumberyard-dev/Atom/santorac/RemixableMaterialTypes4_Layering
Added Support For Factoring-Out Material Property Groups
This commit is contained in:
+3
-3
@@ -82,9 +82,9 @@ namespace AZ
|
||||
AddMaterialPropertyDependency(functor, functor->m_scatterDistanceColor);
|
||||
AddMaterialPropertyDependency(functor, functor->m_scatterDistanceIntensity);
|
||||
|
||||
functor->m_scatterDistance = context.GetShaderResourceGroupLayout()->FindShaderInputConstantIndex(Name{ m_scatterDistance });
|
||||
functor->m_transmissionParams = context.GetShaderResourceGroupLayout()->FindShaderInputConstantIndex(Name{ m_transmissionParams });
|
||||
functor->m_transmissionTintThickness = context.GetShaderResourceGroupLayout()->FindShaderInputConstantIndex(Name{ m_transmissionTintThickness });
|
||||
functor->m_scatterDistance = context.FindShaderInputConstantIndex(Name{ m_scatterDistance });
|
||||
functor->m_transmissionParams = context.FindShaderInputConstantIndex(Name{ m_transmissionParams });
|
||||
functor->m_transmissionTintThickness = context.FindShaderInputConstantIndex(Name{ m_transmissionTintThickness });
|
||||
|
||||
if (functor->m_scatterDistance.IsNull())
|
||||
{
|
||||
|
||||
@@ -62,7 +62,7 @@ namespace AZ
|
||||
AddMaterialPropertyDependency(functor, functor->m_translateY);
|
||||
AddMaterialPropertyDependency(functor, functor->m_rotateDegrees);
|
||||
|
||||
functor->m_transformMatrix = context.GetShaderResourceGroupLayout()->FindShaderInputConstantIndex(Name{m_transformMatrix});
|
||||
functor->m_transformMatrix = context.FindShaderInputConstantIndex(Name{m_transformMatrix});
|
||||
|
||||
if (functor->m_transformMatrix.IsNull())
|
||||
{
|
||||
@@ -74,7 +74,7 @@ namespace AZ
|
||||
// In that case, the.materialtype file will not provide the name of an inverse matrix because it doesn't have one.
|
||||
if (!m_transformMatrixInverse.empty())
|
||||
{
|
||||
functor->m_transformMatrixInverse = context.GetShaderResourceGroupLayout()->FindShaderInputConstantIndex(Name{m_transformMatrixInverse});
|
||||
functor->m_transformMatrixInverse = context.FindShaderInputConstantIndex(Name{m_transformMatrixInverse});
|
||||
|
||||
if (functor->m_transformMatrixInverse.IsNull())
|
||||
{
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/RTTI/TypeInfo.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
#include <AzCore/std/string/string_view.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace RPI
|
||||
{
|
||||
//! Settings for custom JSON serializers to get context about loading a file
|
||||
class JsonFileLoadContext final
|
||||
{
|
||||
public:
|
||||
AZ_TYPE_INFO(JsonFileLoadContext, "{314942B3-A74A-49D2-822D-CD56F8E3C0F8}");
|
||||
|
||||
void PushFilePath(AZStd::string path);
|
||||
AZStd::string_view GetFilePath() const;
|
||||
void PopFilePath();
|
||||
|
||||
private:
|
||||
// Using vector instead of stack because stack doesn't have a copy constructor
|
||||
AZStd::vector<AZStd::string> m_thisFilePath;
|
||||
};
|
||||
|
||||
} // namespace RPI
|
||||
} // namespace AZ
|
||||
@@ -11,7 +11,6 @@
|
||||
#include <AzCore/JSON/document.h>
|
||||
#include <AzCore/Serialization/Json/JsonSerialization.h>
|
||||
#include <AzCore/Serialization/Json/JsonUtils.h>
|
||||
#include <Atom/RPI.Edit/Common/JsonFileLoadContext.h>
|
||||
#include <Atom/RPI.Edit/Common/JsonReportingHelper.h>
|
||||
|
||||
namespace AZ
|
||||
@@ -52,13 +51,9 @@ namespace AZ
|
||||
|
||||
rapidjson::Document& document = loadOutcome.GetValue();
|
||||
|
||||
AZ::RPI::JsonFileLoadContext fileLoadContext;
|
||||
fileLoadContext.PushFilePath(path);
|
||||
|
||||
AZ::JsonDeserializerSettings jsonSettings;
|
||||
AZ::RPI::JsonReportingHelper reportingHelper;
|
||||
reportingHelper.Attach(jsonSettings);
|
||||
jsonSettings.m_metadata.Add(AZStd::move(fileLoadContext));
|
||||
|
||||
AZ::JsonSerialization::Load(objectData, document, jsonSettings);
|
||||
if (reportingHelper.ErrorsReported())
|
||||
|
||||
@@ -41,7 +41,10 @@ namespace AZ
|
||||
// Calls a lua function that returns a list of strings.
|
||||
Outcome<AZStd::vector<Name>, void> GetNameListFromLuaScript(AZ::ScriptContext& scriptContext, const char* luaFunctionName) const;
|
||||
|
||||
FunctorResult CreateFunctor(const AZStd::string& materialTypeSourceFilePath, const MaterialPropertiesLayout* propertiesLayout) const;
|
||||
FunctorResult CreateFunctor(
|
||||
const AZStd::string& materialTypeSourceFilePath,
|
||||
const MaterialPropertiesLayout* propertiesLayout,
|
||||
const MaterialNameContext* materialNameContext) const;
|
||||
|
||||
// Only one of these should have data
|
||||
AZStd::string m_luaSourceFile;
|
||||
|
||||
@@ -31,6 +31,7 @@ namespace AZ
|
||||
class MaterialPropertiesLayout;
|
||||
class ShaderOptionGroupLayout;
|
||||
class JsonMaterialFunctorSourceDataSerializer;
|
||||
class MaterialNameContext;
|
||||
|
||||
//! This is an abstract base class for initializing MaterialFunctor objects.
|
||||
//! Material functors provide custom logic and calculations to configure shaders, render states, and more.
|
||||
@@ -54,11 +55,17 @@ namespace AZ
|
||||
struct RuntimeContext
|
||||
{
|
||||
public:
|
||||
RuntimeContext(const AZStd::string& materialTypeFilePath, const MaterialPropertiesLayout* materialPropertiesLayout, const RHI::ShaderResourceGroupLayout* shaderResourceGroupLayout, const ShaderCollection* shaderCollection)
|
||||
RuntimeContext(
|
||||
const AZStd::string& materialTypeFilePath,
|
||||
const MaterialPropertiesLayout* materialPropertiesLayout,
|
||||
const RHI::ShaderResourceGroupLayout* shaderResourceGroupLayout,
|
||||
const ShaderCollection* shaderCollection,
|
||||
const MaterialNameContext* materialNameContext)
|
||||
: m_materialTypeFilePath(materialTypeFilePath)
|
||||
, m_materialPropertiesLayout(materialPropertiesLayout)
|
||||
, m_shaderResourceGroupLayout(shaderResourceGroupLayout)
|
||||
, m_shaderCollection(shaderCollection)
|
||||
, m_materialNameContext(materialNameContext)
|
||||
{}
|
||||
|
||||
const AZStd::string& GetMaterialTypeSourceFilePath() const { return m_materialTypeFilePath; }
|
||||
@@ -66,6 +73,10 @@ namespace AZ
|
||||
const MaterialPropertiesLayout* GetMaterialPropertiesLayout() const;
|
||||
const RHI::ShaderResourceGroupLayout* GetShaderResourceGroupLayout() const;
|
||||
|
||||
//! Find the index of a ShaderResourceGroup input. This will automatically apply the MaterialNameContext.
|
||||
RHI::ShaderInputConstantIndex FindShaderInputConstantIndex(Name inputName) const;
|
||||
RHI::ShaderInputImageIndex FindShaderInputImageIndex(Name inputName) const;
|
||||
|
||||
//! Returns the number of shaders available in this material type.
|
||||
AZStd::size_t GetShaderCount() const;
|
||||
|
||||
@@ -77,16 +88,18 @@ namespace AZ
|
||||
AZStd::vector<AZ::Name> GetShaderTags() const;
|
||||
|
||||
//! Find a property's index by its name. It will report error and return a Null index if it fails.
|
||||
MaterialPropertyIndex FindMaterialPropertyIndex(const Name& propertyName) const;
|
||||
//! This will also automatically apply the MaterialNameContext.
|
||||
MaterialPropertyIndex FindMaterialPropertyIndex(Name propertyId) const;
|
||||
|
||||
//! Find a shader option index using an option name from the shader by index or tag.
|
||||
//! This will also automatically apply the MaterialNameContext.
|
||||
//! @param shaderIndex index into the material type's list of shader options
|
||||
//! @param shaderTag tag name to index into the material type's list of shader options
|
||||
//! @param optionName the name of the option to find
|
||||
//! @param reportErrors if true, report an error message when if the option name was not found.
|
||||
//! @return the found index, or an empty handle if the option could not be found
|
||||
ShaderOptionIndex FindShaderOptionIndex(AZStd::size_t shaderIndex, const Name& optionName, bool reportErrors = true) const;
|
||||
ShaderOptionIndex FindShaderOptionIndex(const AZ::Name& shaderTag, const Name& optionName, bool reportErrors = true) const;
|
||||
ShaderOptionIndex FindShaderOptionIndex(AZStd::size_t shaderIndex, Name optionName, bool reportErrors = true) const;
|
||||
ShaderOptionIndex FindShaderOptionIndex(const AZ::Name& shaderTag, Name optionName, bool reportErrors = true) const;
|
||||
|
||||
//! Return true if a shaderIndex is within the range of the number of shaders defined in this material.
|
||||
//! And also report an error message if the index is invalid.
|
||||
@@ -96,19 +109,32 @@ namespace AZ
|
||||
//! And also report an error message if shaderTag is invalid.
|
||||
bool CheckShaderTagValid(const AZ::Name& shaderTag) const;
|
||||
|
||||
//! Returns the name context for the functor.
|
||||
//! It acts like a namespace for any names that the MaterialFunctorSourceData might reference. The namespace
|
||||
//! is automatically applied by the other relevant functions of this RuntimeContext class.
|
||||
//! Note that by default the MaterialNameContext is not saved as part of the final MaterialFunctor class
|
||||
//! (most CreateFunctor() implementations should convert names to indexes anyway) but CreateFunctor() can
|
||||
//! copy it to the created MaterialFunctor for use at runtime if needed.
|
||||
const MaterialNameContext* GetNameContext() const { return m_materialNameContext; }
|
||||
|
||||
private:
|
||||
const AZStd::string m_materialTypeFilePath;
|
||||
const MaterialPropertiesLayout* m_materialPropertiesLayout;
|
||||
const RHI::ShaderResourceGroupLayout* m_shaderResourceGroupLayout;
|
||||
const ShaderCollection* m_shaderCollection;
|
||||
const MaterialNameContext* m_materialNameContext;
|
||||
};
|
||||
|
||||
struct EditorContext
|
||||
{
|
||||
public:
|
||||
EditorContext(const AZStd::string& materialTypeFilePath, const MaterialPropertiesLayout* materialPropertiesLayout)
|
||||
EditorContext(
|
||||
const AZStd::string& materialTypeFilePath,
|
||||
const MaterialPropertiesLayout* materialPropertiesLayout,
|
||||
const MaterialNameContext* materialNameContext)
|
||||
: m_materialTypeFilePath(materialTypeFilePath)
|
||||
, m_materialPropertiesLayout(materialPropertiesLayout)
|
||||
, m_materialNameContext(materialNameContext)
|
||||
{}
|
||||
|
||||
const AZStd::string& GetMaterialTypeSourceFilePath() const { return m_materialTypeFilePath; }
|
||||
@@ -116,11 +142,21 @@ namespace AZ
|
||||
const MaterialPropertiesLayout* GetMaterialPropertiesLayout() const;
|
||||
|
||||
//! Find a property's index by its name. It will report error and return a Null index if it fails.
|
||||
MaterialPropertyIndex FindMaterialPropertyIndex(const Name& propertyName) const;
|
||||
//! This will also automatically apply the MaterialNameContext.
|
||||
MaterialPropertyIndex FindMaterialPropertyIndex(Name propertyId) const;
|
||||
|
||||
//! Returns the name context for the functor.
|
||||
//! It acts like a namespace for any names that the MaterialFunctorSourceData might reference. The namespace
|
||||
//! is automatically applied by the other relevant functions of this RuntimeContext class.
|
||||
//! Note that by default the MaterialNameContext is not saved as part of the final MaterialFunctor class
|
||||
//! (most CreateFunctor() implementations should convert names to indexes anyway) but CreateFunctor() can
|
||||
//! copy it to the created MaterialFunctor for use at runtime if needed.
|
||||
const MaterialNameContext* GetNameContext() const { return m_materialNameContext; }
|
||||
|
||||
private:
|
||||
const AZStd::string m_materialTypeFilePath;
|
||||
const MaterialPropertiesLayout* m_materialPropertiesLayout;
|
||||
const MaterialNameContext* m_materialNameContext;
|
||||
};
|
||||
|
||||
//! Creates a fully initialized MaterialFunctor object that is ready to be serialized to the cache.
|
||||
|
||||
@@ -22,9 +22,14 @@ namespace AZ
|
||||
//! The groups are optional, in which case the full property ID will just be like "propertyName".
|
||||
class MaterialPropertyId
|
||||
{
|
||||
public:
|
||||
public:
|
||||
//! Returns whether the name is a valid C-style identifier
|
||||
static bool IsValidName(AZStd::string_view name);
|
||||
static bool IsValidName(const AZ::Name& name);
|
||||
|
||||
//! Returns whether the name is a valid C-style identifier, and reports errors if it is not.
|
||||
static bool CheckIsValidName(AZStd::string_view name);
|
||||
static bool CheckIsValidName(const AZ::Name& name);
|
||||
|
||||
//! Creates a MaterialPropertyId from a full name string like "groupA.groupB.[...].propertyName" or just "propertyName".
|
||||
//! Also checks the name for validity.
|
||||
|
||||
@@ -131,15 +131,17 @@ namespace AZ
|
||||
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<AZStd::unique_ptr<PropertyGroup>>& GetPropertyGroups() const { return m_propertyGroups; }
|
||||
const AZStd::vector<Ptr<MaterialFunctorSourceDataHolder>>& GetFunctors() const { return m_materialFunctorSourceData; }
|
||||
const AZStd::string& GetName() const;
|
||||
const AZStd::string& GetDisplayName() const;
|
||||
const AZStd::string& GetDescription() const;
|
||||
const PropertyList& GetProperties() const;
|
||||
const AZStd::string& GetShaderInputsPrefix() const;
|
||||
const AZStd::string& GetShaderOptionsPrefix() const;
|
||||
const AZStd::vector<AZStd::unique_ptr<PropertyGroup>>& GetPropertyGroups() const;
|
||||
const AZStd::vector<Ptr<MaterialFunctorSourceDataHolder>>& GetFunctors() const;
|
||||
|
||||
void SetDisplayName(AZStd::string_view displayName) { m_displayName = displayName; }
|
||||
void SetDescription(AZStd::string_view description) { m_description = description; }
|
||||
void SetDisplayName(AZStd::string_view displayName);
|
||||
void SetDescription(AZStd::string_view description);
|
||||
|
||||
//! Add a new property to this PropertyGroup.
|
||||
//! @param name a unique for the property. Must be a C-style identifier.
|
||||
@@ -158,6 +160,8 @@ namespace AZ
|
||||
AZStd::string m_name;
|
||||
AZStd::string m_displayName;
|
||||
AZStd::string m_description;
|
||||
AZStd::string m_shaderInputsPrefix; //!< The name of all SRG inputs under this group will get this prefix.
|
||||
AZStd::string m_shaderOptionsPrefix; //!< The name of all shader options under this group will get this prefix.
|
||||
PropertyList m_properties;
|
||||
AZStd::vector<AZStd::unique_ptr<PropertyGroup>> m_propertyGroups;
|
||||
AZStd::vector<Ptr<MaterialFunctorSourceDataHolder>> m_materialFunctorSourceData;
|
||||
@@ -279,12 +283,13 @@ namespace AZ
|
||||
//! Splits an ID string like "itemA.itemB.itemC" into a vector like ["itemA.itemB", "itemC"].
|
||||
static AZStd::vector<AZStd::string_view> SplitId(AZStd::string_view id);
|
||||
|
||||
//! Describes a path in the hierarchy of property groups, with the top level group at the beginning and a leaf-most group at the end.
|
||||
using PropertyGroupStack = AZStd::vector<const PropertyGroup*>;
|
||||
|
||||
//! Call back function type used with the enumeration functions.
|
||||
//! The PropertyGroupStack contains the stack of property groups at the current point in the traversal.
|
||||
//! Return false to terminate the traversal.
|
||||
using EnumeratePropertyGroupsCallback = AZStd::function<bool(
|
||||
const AZStd::string&, // The property ID context (i.e. "levelA.levelB.")
|
||||
const PropertyGroup* // the next property group in the tree
|
||||
)>;
|
||||
using EnumeratePropertyGroupsCallback = AZStd::function<bool(const PropertyGroupStack&)>;
|
||||
|
||||
//! 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.
|
||||
@@ -293,14 +298,17 @@ namespace AZ
|
||||
//! Call back function type used with the numeration functions.
|
||||
//! Return false to terminate the traversal.
|
||||
using EnumeratePropertiesCallback = AZStd::function<bool(
|
||||
const AZStd::string&, // The property ID context (i.e. "levelA.levelB."
|
||||
const PropertyDefinition* // the property definition object
|
||||
const PropertyDefinition*, // the property definition object
|
||||
const MaterialNameContext& // The name context that the property is in, used to scope properties and shader connections (i.e. "levelA.levelB.")
|
||||
)>;
|
||||
|
||||
//! 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;
|
||||
|
||||
//! Returns a MaterialNameContext for a specific path through the property group hierarchy.
|
||||
static MaterialNameContext MakeMaterialNameContext(const MaterialTypeSourceData::PropertyGroupStack& propertyGroupStack);
|
||||
|
||||
Outcome<Data::Asset<MaterialTypeAsset>> 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),
|
||||
@@ -316,18 +324,21 @@ namespace AZ
|
||||
PropertyDefinition* FindProperty(AZStd::span<AZStd::string_view> parsedPropertyId, AZStd::span<AZStd::unique_ptr<PropertyGroup>> inPropertyGroupList);
|
||||
|
||||
// Function overloads for recursion, returns false to indicate that recursion should end.
|
||||
bool EnumeratePropertyGroups(const EnumeratePropertyGroupsCallback& callback, AZStd::string propertyIdContext, const AZStd::vector<AZStd::unique_ptr<PropertyGroup>>& inPropertyGroupList) const;
|
||||
bool EnumerateProperties(const EnumeratePropertiesCallback& callback, AZStd::string propertyIdContext, const AZStd::vector<AZStd::unique_ptr<PropertyGroup>>& inPropertyGroupList) const;
|
||||
bool EnumeratePropertyGroups(const EnumeratePropertyGroupsCallback& callback, PropertyGroupStack& propertyGroupStack, const AZStd::vector<AZStd::unique_ptr<PropertyGroup>>& inPropertyGroupList) const;
|
||||
bool EnumerateProperties(const EnumeratePropertiesCallback& callback, MaterialNameContext nameContext, const AZStd::vector<AZStd::unique_ptr<PropertyGroup>>& inPropertyGroupList) const;
|
||||
|
||||
static void ExtendNameContext(MaterialNameContext& nameContext, const MaterialTypeSourceData::PropertyGroup& propertyGroup);
|
||||
|
||||
//! Recursively populates a material asset with properties from the tree of material property groups.
|
||||
//! Recursively populates a material type 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 @propertyGroup
|
||||
//! @param materialTypeAssetCreator properties will be added to this creator
|
||||
//! @param materialNameContext the accumulated name context that should be applied to any property names or connection 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<AZStd::string>& propertyNameContext,
|
||||
MaterialNameContext materialNameContext,
|
||||
const MaterialTypeSourceData::PropertyGroup* propertyGroup) const;
|
||||
|
||||
//! Construct a complete list of group definitions, including implicit groups, arranged in the same order as the source data.
|
||||
@@ -337,7 +348,7 @@ namespace AZ
|
||||
|
||||
PropertyLayout m_propertyLayout;
|
||||
};
|
||||
|
||||
|
||||
//! The wrapper class for derived material functors.
|
||||
//! It is used in deserialization so that derived material functors can be deserialized by name.
|
||||
class MaterialFunctorSourceDataHolder final
|
||||
|
||||
@@ -29,6 +29,8 @@ namespace AZ
|
||||
|
||||
namespace MaterialUtils
|
||||
{
|
||||
using ImportedJsonFiles = AZStd::unordered_set<AZStd::string>;
|
||||
|
||||
enum class GetImageAssetResult
|
||||
{
|
||||
Empty, //! No image was actually requested, the path was empty
|
||||
@@ -49,12 +51,13 @@ namespace AZ
|
||||
//! @return if resolving is successful. An error will be reported if it fails.
|
||||
bool ResolveMaterialPropertyEnumValue(const MaterialPropertyDescriptor* propertyDescriptor, const AZ::Name& enumName, MaterialPropertyValue& outResolvedValue);
|
||||
|
||||
//! Load a material type from a json file. If the file path is relative, the loaded json document must be provided.
|
||||
//! Load a material type from a json file or document.
|
||||
//! Otherwise, it will use the passed in document first if not null, or load the json document from the path.
|
||||
//! @param filePath a relative path if document is provided, an absolute path if document is not provided.
|
||||
//! @param document the loaded json document.
|
||||
AZ::Outcome<MaterialTypeSourceData> LoadMaterialTypeSourceData(const AZStd::string& filePath, const rapidjson::Value* document = nullptr);
|
||||
|
||||
//! @param filePath path to the JSON file to load, unless the @document is already provided. In either case, this path will be used to resolve any relative file references.
|
||||
//! @param document an optional already loaded json document.
|
||||
//! @param importedFiles receives the list of files that were imported by the JSON serializer
|
||||
AZ::Outcome<MaterialTypeSourceData> LoadMaterialTypeSourceData(const AZStd::string& filePath, rapidjson::Document* document = nullptr, ImportedJsonFiles* importedFiles = nullptr);
|
||||
|
||||
//! Load a material from a json file.
|
||||
AZ::Outcome<MaterialSourceData> LoadMaterialSourceData(const AZStd::string& filePath, const rapidjson::Value* document = nullptr, bool warningsAsErrors = false);
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include <Atom/RPI.Reflect/Material/MaterialFunctor.h>
|
||||
#include <Atom/RPI.Reflect/Material/MaterialPropertyDescriptor.h>
|
||||
#include <Atom/RPI.Reflect/Material/MaterialNameContext.h>
|
||||
#include <Atom/RHI.Reflect/Limits.h>
|
||||
|
||||
namespace UnitTest
|
||||
@@ -60,12 +61,8 @@ namespace AZ
|
||||
AZStd::unique_ptr<AZ::BehaviorContext> m_sriptBehaviorContext;
|
||||
AZStd::unique_ptr<AZ::ScriptContext> m_scriptContext;
|
||||
|
||||
// These are prefix strings that will be applied to every name lookup in the lua functor.
|
||||
// This allows the lua script to be reused in different contexts.
|
||||
AZStd::string m_propertyNamePrefix;
|
||||
AZStd::string m_srgNamePrefix;
|
||||
AZStd::string m_optionsNamePrefix;
|
||||
|
||||
MaterialNameContext m_materialNameContext;
|
||||
|
||||
enum class ScriptStatus
|
||||
{
|
||||
Uninitialized,
|
||||
@@ -84,15 +81,11 @@ namespace AZ
|
||||
|
||||
explicit LuaMaterialFunctorCommonContext(MaterialFunctor::RuntimeContext* runtimeContextImpl,
|
||||
const MaterialPropertyFlags* materialPropertyDependencies,
|
||||
const AZStd::string& propertyNamePrefix,
|
||||
const AZStd::string& srgNamePrefix,
|
||||
const AZStd::string& optionsNamePrefix);
|
||||
const MaterialNameContext &materialNameContext);
|
||||
|
||||
explicit LuaMaterialFunctorCommonContext(MaterialFunctor::EditorContext* editorContextImpl,
|
||||
const MaterialPropertyFlags* materialPropertyDependencies,
|
||||
const AZStd::string& propertyNamePrefix,
|
||||
const AZStd::string& srgNamePrefix,
|
||||
const AZStd::string& optionsNamePrefix);
|
||||
const MaterialNameContext &materialNameContext);
|
||||
|
||||
//! Returns false if PSO changes are not allowed, and may report errors or warnings
|
||||
bool CheckPsoChangesAllowed();
|
||||
@@ -112,11 +105,7 @@ namespace AZ
|
||||
|
||||
AZStd::string GetMaterialPropertyDependenciesString() const;
|
||||
|
||||
// These are prefix strings that will be applied to every name lookup in the lua functor.
|
||||
// This allows the lua script to be reused in different contexts.
|
||||
const AZStd::string& m_propertyNamePrefix;
|
||||
const AZStd::string& m_srgNamePrefix;
|
||||
const AZStd::string& m_optionsNamePrefix;
|
||||
const MaterialNameContext &m_materialNameContext;
|
||||
|
||||
private:
|
||||
|
||||
@@ -284,9 +273,7 @@ namespace AZ
|
||||
|
||||
explicit LuaMaterialFunctorRuntimeContext(MaterialFunctor::RuntimeContext* runtimeContextImpl,
|
||||
const MaterialPropertyFlags* materialPropertyDependencies,
|
||||
const AZStd::string& propertyNamePrefix,
|
||||
const AZStd::string& srgNamePrefix,
|
||||
const AZStd::string& optionsNamePrefix);
|
||||
const MaterialNameContext &materialNameContext);
|
||||
|
||||
template<typename Type>
|
||||
Type GetMaterialPropertyValue(const char* name) const;
|
||||
@@ -324,9 +311,7 @@ namespace AZ
|
||||
|
||||
explicit LuaMaterialFunctorEditorContext(MaterialFunctor::EditorContext* editorContextImpl,
|
||||
const MaterialPropertyFlags* materialPropertyDependencies,
|
||||
const AZStd::string& propertyNamePrefix,
|
||||
const AZStd::string& srgNamePrefix,
|
||||
const AZStd::string& optionsNamePrefix);
|
||||
const MaterialNameContext &materialNameContext);
|
||||
|
||||
template<typename Type>
|
||||
Type GetMaterialPropertyValue(const char* name) const;
|
||||
|
||||
@@ -49,8 +49,8 @@ namespace AZ
|
||||
|
||||
//! MaterialFunctor objects provide custom logic and calculations to configure shaders, render states,
|
||||
//! editor metadata, and more.
|
||||
//! Atom will provide an implementation of this class that uses a script to define the custom logic
|
||||
//! for a convenient workflow. Clients may also provide their own custom hard-coded implementations
|
||||
//! Atom provides a LuaMaterialFunctor subclass that uses a script to define the custom logic
|
||||
//! for a convenient workflow. Developers may also provide their own custom hard-coded implementations
|
||||
//! as an optimization rather than taking the scripted approach.
|
||||
//! Any custom subclasses of MaterialFunctor will also need a corresponding MaterialFunctorSourceData subclass
|
||||
//! to create the functor at build-time. Depending on the builder context, clients can choose to create a runtime
|
||||
@@ -91,11 +91,11 @@ namespace AZ
|
||||
//! Get the property value. The type must be one of those in MaterialPropertyValue.
|
||||
//! Otherwise, a compile error will be reported.
|
||||
template<typename Type>
|
||||
const Type& GetMaterialPropertyValue(const Name& propertyName) const;
|
||||
const Type& GetMaterialPropertyValue(const Name& propertyId) const;
|
||||
template<typename Type>
|
||||
const Type& GetMaterialPropertyValue(const MaterialPropertyIndex& index) const;
|
||||
//! Get the property value. GetMaterialPropertyValue<T>() is equivalent to GetMaterialPropertyValue().GetValue<T>().
|
||||
const MaterialPropertyValue& GetMaterialPropertyValue(const Name& propertyName) const;
|
||||
const MaterialPropertyValue& GetMaterialPropertyValue(const Name& propertyId) const;
|
||||
const MaterialPropertyValue& GetMaterialPropertyValue(const MaterialPropertyIndex& index) const;
|
||||
|
||||
const MaterialPropertiesLayout* GetMaterialPropertiesLayout() const { return m_materialPropertiesLayout.get(); }
|
||||
@@ -164,19 +164,19 @@ namespace AZ
|
||||
{
|
||||
friend class LuaMaterialFunctorEditorContext;
|
||||
public:
|
||||
const MaterialPropertyDynamicMetadata* GetMaterialPropertyMetadata(const Name& propertyName) const;
|
||||
const MaterialPropertyDynamicMetadata* GetMaterialPropertyMetadata(const Name& propertyId) const;
|
||||
const MaterialPropertyDynamicMetadata* GetMaterialPropertyMetadata(const MaterialPropertyIndex& index) const;
|
||||
|
||||
const MaterialPropertyGroupDynamicMetadata* GetMaterialPropertyGroupMetadata(const Name& propertyName) const;
|
||||
const MaterialPropertyGroupDynamicMetadata* GetMaterialPropertyGroupMetadata(const Name& propertyId) const;
|
||||
|
||||
//! Get the property value. The type must be one of those in MaterialPropertyValue.
|
||||
//! Otherwise, a compile error will be reported.
|
||||
template<typename Type>
|
||||
const Type& GetMaterialPropertyValue(const Name& propertyName) const;
|
||||
const Type& GetMaterialPropertyValue(const Name& propertyId) const;
|
||||
template<typename Type>
|
||||
const Type& GetMaterialPropertyValue(const MaterialPropertyIndex& index) const;
|
||||
//! Get the property value. GetMaterialPropertyValue<T>() is equivalent to GetMaterialPropertyValue().GetValue<T>().
|
||||
const MaterialPropertyValue& GetMaterialPropertyValue(const Name& propertyName) const;
|
||||
const MaterialPropertyValue& GetMaterialPropertyValue(const Name& propertyId) const;
|
||||
const MaterialPropertyValue& GetMaterialPropertyValue(const MaterialPropertyIndex& index) const;
|
||||
|
||||
const MaterialPropertiesLayout* GetMaterialPropertiesLayout() const { return m_materialPropertiesLayout.get(); }
|
||||
@@ -184,22 +184,22 @@ namespace AZ
|
||||
MaterialPropertyPsoHandling GetMaterialPropertyPsoHandling() const { return MaterialPropertyPsoHandling::Allowed; }
|
||||
|
||||
//! Set the visibility dynamic metadata of a material property.
|
||||
bool SetMaterialPropertyVisibility(const Name& propertyName, MaterialPropertyVisibility visibility);
|
||||
bool SetMaterialPropertyVisibility(const Name& propertyId, MaterialPropertyVisibility visibility);
|
||||
bool SetMaterialPropertyVisibility(const MaterialPropertyIndex& index, MaterialPropertyVisibility visibility);
|
||||
|
||||
bool SetMaterialPropertyDescription(const Name& propertyName, AZStd::string description);
|
||||
bool SetMaterialPropertyDescription(const Name& propertyId, AZStd::string description);
|
||||
bool SetMaterialPropertyDescription(const MaterialPropertyIndex& index, AZStd::string description);
|
||||
|
||||
bool SetMaterialPropertyMinValue(const Name& propertyName, const MaterialPropertyValue& min);
|
||||
bool SetMaterialPropertyMinValue(const Name& propertyId, const MaterialPropertyValue& min);
|
||||
bool SetMaterialPropertyMinValue(const MaterialPropertyIndex& index, const MaterialPropertyValue& min);
|
||||
|
||||
bool SetMaterialPropertyMaxValue(const Name& propertyName, const MaterialPropertyValue& max);
|
||||
bool SetMaterialPropertyMaxValue(const Name& propertyId, const MaterialPropertyValue& max);
|
||||
bool SetMaterialPropertyMaxValue(const MaterialPropertyIndex& index, const MaterialPropertyValue& max);
|
||||
|
||||
bool SetMaterialPropertySoftMinValue(const Name& propertyName, const MaterialPropertyValue& min);
|
||||
bool SetMaterialPropertySoftMinValue(const Name& propertyId, const MaterialPropertyValue& min);
|
||||
bool SetMaterialPropertySoftMinValue(const MaterialPropertyIndex& index, const MaterialPropertyValue& min);
|
||||
|
||||
bool SetMaterialPropertySoftMaxValue(const Name& propertyName, const MaterialPropertyValue& max);
|
||||
bool SetMaterialPropertySoftMaxValue(const Name& propertyId, const MaterialPropertyValue& max);
|
||||
bool SetMaterialPropertySoftMaxValue(const MaterialPropertyIndex& index, const MaterialPropertyValue& max);
|
||||
|
||||
bool SetMaterialPropertyGroupVisibility(const Name& propertyGroupName, MaterialPropertyGroupVisibility visibility);
|
||||
@@ -218,8 +218,8 @@ namespace AZ
|
||||
);
|
||||
|
||||
private:
|
||||
MaterialPropertyDynamicMetadata* QueryMaterialPropertyMetadata(const Name& propertyName) const;
|
||||
MaterialPropertyGroupDynamicMetadata* QueryMaterialPropertyGroupMetadata(const Name& propertyGroupName) const;
|
||||
MaterialPropertyDynamicMetadata* QueryMaterialPropertyMetadata(const Name& propertyId) const;
|
||||
MaterialPropertyGroupDynamicMetadata* QueryMaterialPropertyGroupMetadata(const Name& propertyGroupId) const;
|
||||
|
||||
const AZStd::vector<MaterialPropertyValue>& m_materialPropertyValues;
|
||||
RHI::ConstPtr<MaterialPropertiesLayout> m_materialPropertiesLayout;
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
class ReflectContext;
|
||||
class Name;
|
||||
|
||||
namespace RPI
|
||||
{
|
||||
//! This acts like a namespace description for various types of identifiers that appear in .materialtype files.
|
||||
//! When reusable property groups are nested inside other property groups, they usually need alternate naming
|
||||
//! to connect to the appropriate shader inputs. For example, a baseColor property group inside a "layer1" group
|
||||
//! needs to connect to "m_layer1_baseColor_texture" and the same property definition is repeated inside a "layer2"
|
||||
//! group where it connects to "m_layer2_baseColor_texture". This data structure provides the name context, like
|
||||
//! "m_layer1_" or "m_layer2_".
|
||||
class MaterialNameContext
|
||||
{
|
||||
public:
|
||||
AZ_TYPE_INFO(MaterialNameContext, "{AAC9BB28-F463-455D-8467-F877E50E1FA7}")
|
||||
|
||||
static void Reflect(ReflectContext* context);
|
||||
|
||||
MaterialNameContext() = default;
|
||||
|
||||
//! Extends the name context to a deeper property group.
|
||||
void ExtendPropertyIdContext(AZStd::string_view nameContext, bool insertDelimiter=true);
|
||||
void ExtendSrgInputContext(AZStd::string_view nameContext);
|
||||
void ExtendShaderOptionContext(AZStd::string_view nameContext);
|
||||
|
||||
//! Applies the name context to a given leaf name.
|
||||
bool ContextualizeProperty(Name& propertyName) const;
|
||||
bool ContextualizeSrgInput(Name& srgInputName) const;
|
||||
bool ContextualizeShaderOption(Name& shaderOptionName) const;
|
||||
bool ContextualizeProperty(AZStd::string& propertyName) const;
|
||||
bool ContextualizeSrgInput(AZStd::string& srgInputName) const;
|
||||
bool ContextualizeShaderOption(AZStd::string& shaderOptionName) const;
|
||||
|
||||
//! Returns true if there is some non-default name context.
|
||||
bool HasContextForProperties() const;
|
||||
bool HasContextForSrgInputs() const;
|
||||
bool HasContextForShaderOptions() const;
|
||||
|
||||
//! Returns true if the name context is empty.
|
||||
bool IsDefault() const;
|
||||
|
||||
private:
|
||||
AZStd::string m_propertyIdContext;
|
||||
AZStd::string m_srgInputNameContext;
|
||||
AZStd::string m_shaderOptionNameContext;
|
||||
};
|
||||
|
||||
} // namespace RPI
|
||||
} // namespace AZ
|
||||
@@ -11,7 +11,6 @@
|
||||
#include <Atom/RPI.Edit/Material/MaterialTypeSourceData.h>
|
||||
#include <Atom/RPI.Edit/Material/MaterialUtils.h>
|
||||
#include <Atom/RPI.Edit/Common/AssetUtils.h>
|
||||
#include <Atom/RPI.Edit/Common/JsonFileLoadContext.h>
|
||||
#include <Atom/RPI.Edit/Common/JsonReportingHelper.h>
|
||||
#include <Atom/RPI.Edit/Common/JsonUtils.h>
|
||||
#include <AzCore/Serialization/Json/JsonUtils.h>
|
||||
@@ -52,7 +51,7 @@ namespace AZ
|
||||
{
|
||||
AssetBuilderSDK::AssetBuilderDesc materialBuilderDescriptor;
|
||||
materialBuilderDescriptor.m_name = JobKey;
|
||||
materialBuilderDescriptor.m_version = 119; // new material file format
|
||||
materialBuilderDescriptor.m_version = 123; // nested property layers
|
||||
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<MaterialBuilder>();
|
||||
@@ -161,13 +160,21 @@ namespace AZ
|
||||
const bool isMaterialTypeFile = AzFramework::StringFunc::Path::IsExtension(request.m_sourceFile.c_str(), MaterialTypeSourceData::Extension);
|
||||
if (isMaterialTypeFile)
|
||||
{
|
||||
auto materialTypeSourceData = MaterialUtils::LoadMaterialTypeSourceData(fullSourcePath, &document);
|
||||
MaterialUtils::ImportedJsonFiles importedJsonFiles;
|
||||
auto materialTypeSourceData = MaterialUtils::LoadMaterialTypeSourceData(fullSourcePath, &document, &importedJsonFiles);
|
||||
|
||||
if (!materialTypeSourceData.IsSuccess())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto& importedJsonFile : importedJsonFiles)
|
||||
{
|
||||
AssetBuilderSDK::SourceFileDependency sourceDependency;
|
||||
sourceDependency.m_sourceFileDependencyPath = importedJsonFile;
|
||||
response.m_sourceFileDependencyList.push_back(sourceDependency);
|
||||
}
|
||||
|
||||
for (auto& shader : materialTypeSourceData.GetValue().m_shaderCollection)
|
||||
{
|
||||
AddPossibleDependencies(request.m_sourceFile,
|
||||
@@ -243,7 +250,7 @@ namespace AZ
|
||||
response.m_result = AssetBuilderSDK::CreateJobsResultCode::Success;
|
||||
}
|
||||
|
||||
AZ::Data::Asset<MaterialTypeAsset> CreateMaterialTypeAsset(AZStd::string_view materialTypeSourceFilePath, const rapidjson::Value& json)
|
||||
AZ::Data::Asset<MaterialTypeAsset> CreateMaterialTypeAsset(AZStd::string_view materialTypeSourceFilePath, rapidjson::Document& json)
|
||||
{
|
||||
auto materialType = MaterialUtils::LoadMaterialTypeSourceData(materialTypeSourceFilePath, &json);
|
||||
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Atom/RPI.Edit/Common/JsonFileLoadContext.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace RPI
|
||||
{
|
||||
// Note, we use string not string_view on purpose because m_thisFilePath.push_back() will make a new string anyway.
|
||||
void JsonFileLoadContext::PushFilePath(AZStd::string path)
|
||||
{
|
||||
m_thisFilePath.push_back(AZStd::move(path));
|
||||
}
|
||||
|
||||
AZStd::string_view JsonFileLoadContext::GetFilePath() const
|
||||
{
|
||||
if (m_thisFilePath.empty())
|
||||
{
|
||||
return "";
|
||||
}
|
||||
else
|
||||
{
|
||||
return m_thisFilePath.back();
|
||||
}
|
||||
}
|
||||
|
||||
void JsonFileLoadContext::PopFilePath()
|
||||
{
|
||||
m_thisFilePath.pop_back();
|
||||
}
|
||||
|
||||
} // namespace RPI
|
||||
} // namespace AZ
|
||||
@@ -115,16 +115,26 @@ namespace AZ
|
||||
|
||||
RPI::LuaMaterialFunctorSourceData::FunctorResult LuaMaterialFunctorSourceData::CreateFunctor(
|
||||
const AZStd::string& materialTypeSourceFilePath,
|
||||
const MaterialPropertiesLayout* propertiesLayout
|
||||
const MaterialPropertiesLayout* propertiesLayout,
|
||||
const MaterialNameContext* materialNameContext
|
||||
) const
|
||||
{
|
||||
using namespace RPI;
|
||||
|
||||
RPI::Ptr<LuaMaterialFunctor> functor = aznew LuaMaterialFunctor;
|
||||
|
||||
functor->m_propertyNamePrefix = m_propertyNamePrefix;
|
||||
functor->m_srgNamePrefix = m_srgNamePrefix;
|
||||
functor->m_optionsNamePrefix = m_optionsNamePrefix;
|
||||
if (materialNameContext->IsDefault())
|
||||
{
|
||||
// This is a legacy feature that was used for a while to support reusing the same functor for multiple layers in StandardMultilayerPbr.materialtype.
|
||||
// Now that we have support for nested property groups, this functionality is only supported for functors at the top level, for backward compatibility.
|
||||
functor->m_materialNameContext.ExtendPropertyIdContext(m_propertyNamePrefix, false);
|
||||
functor->m_materialNameContext.ExtendSrgInputContext(m_srgNamePrefix);
|
||||
functor->m_materialNameContext.ExtendShaderOptionContext(m_optionsNamePrefix);
|
||||
}
|
||||
else
|
||||
{
|
||||
functor->m_materialNameContext = *materialNameContext;
|
||||
}
|
||||
|
||||
if (!m_luaScript.empty() && !m_luaSourceFile.empty())
|
||||
{
|
||||
@@ -188,7 +198,10 @@ namespace AZ
|
||||
|
||||
for (const Name& materialProperty : materialPropertyDependencies.GetValue())
|
||||
{
|
||||
MaterialPropertyIndex index = propertiesLayout->FindPropertyIndex(Name{m_propertyNamePrefix + materialProperty.GetCStr()});
|
||||
Name propertyName{materialProperty};
|
||||
functor->m_materialNameContext.ContextualizeProperty(propertyName);
|
||||
|
||||
MaterialPropertyIndex index = propertiesLayout->FindPropertyIndex(propertyName);
|
||||
if (!index.IsValid())
|
||||
{
|
||||
AZ_Error("LuaMaterialFunctorSourceData", false, "Property '%s' is not found in material type.", materialProperty.GetCStr());
|
||||
@@ -205,14 +218,16 @@ namespace AZ
|
||||
{
|
||||
return CreateFunctor(
|
||||
context.GetMaterialTypeSourceFilePath(),
|
||||
context.GetMaterialPropertiesLayout());
|
||||
context.GetMaterialPropertiesLayout(),
|
||||
context.GetNameContext());
|
||||
}
|
||||
|
||||
RPI::LuaMaterialFunctorSourceData::FunctorResult LuaMaterialFunctorSourceData::CreateFunctor(const EditorContext& context) const
|
||||
{
|
||||
return CreateFunctor(
|
||||
context.GetMaterialTypeSourceFilePath(),
|
||||
context.GetMaterialPropertiesLayout());
|
||||
context.GetMaterialPropertiesLayout(),
|
||||
context.GetNameContext());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <Atom/RPI.Reflect/Material/MaterialFunctor.h>
|
||||
#include <Atom/RPI.Reflect/Material/ShaderCollection.h>
|
||||
#include <Atom/RPI.Reflect/Material/MaterialPropertiesLayout.h>
|
||||
#include <Atom/RPI.Reflect/Material/MaterialNameContext.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/Serialization/Json/RegistrationContext.h>
|
||||
|
||||
@@ -66,17 +67,20 @@ namespace AZ
|
||||
return m_shaderResourceGroupLayout;
|
||||
}
|
||||
|
||||
MaterialPropertyIndex MaterialFunctorSourceData::RuntimeContext::FindMaterialPropertyIndex(const Name& propertyName) const
|
||||
MaterialPropertyIndex MaterialFunctorSourceData::RuntimeContext::FindMaterialPropertyIndex(Name propertyId) const
|
||||
{
|
||||
MaterialPropertyIndex propertyIndex = m_materialPropertiesLayout->FindPropertyIndex(propertyName);
|
||||
m_materialNameContext->ContextualizeProperty(propertyId);
|
||||
MaterialPropertyIndex propertyIndex = m_materialPropertiesLayout->FindPropertyIndex(propertyId);
|
||||
|
||||
AZ_Error("MaterialFunctorSourceData", propertyIndex.IsValid(), "Could not find property '%s'.", propertyName.GetCStr());
|
||||
AZ_Error("MaterialFunctorSourceData", propertyIndex.IsValid(), "Could not find property '%s'.", propertyId.GetCStr());
|
||||
|
||||
return propertyIndex;
|
||||
}
|
||||
|
||||
ShaderOptionIndex MaterialFunctorSourceData::RuntimeContext::FindShaderOptionIndex(AZStd::size_t shaderIndex, const Name& optionName, bool reportErrors) const
|
||||
ShaderOptionIndex MaterialFunctorSourceData::RuntimeContext::FindShaderOptionIndex(AZStd::size_t shaderIndex, Name optionName, bool reportErrors) const
|
||||
{
|
||||
m_materialNameContext->ContextualizeShaderOption(optionName);
|
||||
|
||||
const ShaderOptionGroupLayout* shaderOptionGroupLayout = GetShaderOptionGroupLayout(shaderIndex);
|
||||
|
||||
if (shaderOptionGroupLayout)
|
||||
@@ -92,8 +96,10 @@ namespace AZ
|
||||
return ShaderOptionIndex();
|
||||
}
|
||||
|
||||
AZ::RPI::ShaderOptionIndex MaterialFunctorSourceData::RuntimeContext::FindShaderOptionIndex(const AZ::Name& shaderTag, const Name& optionName, bool reportErrors /*= true*/) const
|
||||
AZ::RPI::ShaderOptionIndex MaterialFunctorSourceData::RuntimeContext::FindShaderOptionIndex(const AZ::Name& shaderTag, Name optionName, bool reportErrors /*= true*/) const
|
||||
{
|
||||
m_materialNameContext->ContextualizeShaderOption(optionName);
|
||||
|
||||
const ShaderOptionGroupLayout* shaderOptionGroupLayout = GetShaderOptionGroupLayout(shaderTag);
|
||||
|
||||
if (shaderOptionGroupLayout)
|
||||
@@ -122,19 +128,33 @@ namespace AZ
|
||||
AZ_Error("MaterialFunctorSourceData", valid, "Shader tag '%s' is invalid", shaderTag.GetCStr());
|
||||
return valid;
|
||||
}
|
||||
|
||||
RHI::ShaderInputConstantIndex MaterialFunctorSourceData::RuntimeContext::FindShaderInputConstantIndex(Name inputName) const
|
||||
{
|
||||
m_materialNameContext->ContextualizeSrgInput(inputName);
|
||||
return m_shaderResourceGroupLayout->FindShaderInputConstantIndex(inputName);
|
||||
}
|
||||
|
||||
RHI::ShaderInputImageIndex MaterialFunctorSourceData::RuntimeContext::FindShaderInputImageIndex(Name inputName) const
|
||||
{
|
||||
m_materialNameContext->ContextualizeSrgInput(inputName);
|
||||
return m_shaderResourceGroupLayout->FindShaderInputImageIndex(inputName);
|
||||
}
|
||||
|
||||
const MaterialPropertiesLayout* MaterialFunctorSourceData::EditorContext::GetMaterialPropertiesLayout() const
|
||||
{
|
||||
return m_materialPropertiesLayout;
|
||||
}
|
||||
|
||||
MaterialPropertyIndex MaterialFunctorSourceData::EditorContext::FindMaterialPropertyIndex(const Name& propertyName) const
|
||||
MaterialPropertyIndex MaterialFunctorSourceData::EditorContext::FindMaterialPropertyIndex(Name propertyId) const
|
||||
{
|
||||
MaterialPropertyIndex propertyIndex = m_materialPropertiesLayout->FindPropertyIndex(propertyName);
|
||||
m_materialNameContext->ContextualizeProperty(propertyId);
|
||||
MaterialPropertyIndex propertyIndex = m_materialPropertiesLayout->FindPropertyIndex(propertyId);
|
||||
|
||||
AZ_Error("MaterialFunctorSourceData", propertyIndex.IsValid(), "Could not find property '%s'", propertyName.GetCStr());
|
||||
AZ_Error("MaterialFunctorSourceData", propertyIndex.IsValid(), "Could not find property '%s'", propertyId.GetCStr());
|
||||
|
||||
return propertyIndex;
|
||||
}
|
||||
|
||||
} // namespace RPI
|
||||
} // namespace AZ
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#include <Atom/RPI.Edit/Material/MaterialFunctorSourceDataSerializer.h>
|
||||
#include <Atom/RPI.Edit/Material/MaterialTypeSourceData.h>
|
||||
#include <Atom/RPI.Edit/Common/AssetUtils.h>
|
||||
#include <Atom/RPI.Edit/Common/JsonFileLoadContext.h>
|
||||
#include <Atom/RPI.Edit/Material/MaterialFunctorSourceDataRegistration.h>
|
||||
#include <AzCore/Serialization/Json/JsonUtils.h>
|
||||
|
||||
|
||||
@@ -25,11 +25,29 @@ namespace AZ
|
||||
return IsValidName(name.GetStringView());
|
||||
}
|
||||
|
||||
bool MaterialPropertyId::CheckIsValidName(AZStd::string_view name)
|
||||
{
|
||||
if (IsValidName(name))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Error("MaterialPropertyId", false, "'%.*s' is not a valid identifier", AZ_STRING_ARG(name));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool MaterialPropertyId::CheckIsValidName(const AZ::Name& name)
|
||||
{
|
||||
return CheckIsValidName(name.GetStringView());
|
||||
}
|
||||
|
||||
bool MaterialPropertyId::IsValid() const
|
||||
{
|
||||
return !m_fullName.IsEmpty();
|
||||
}
|
||||
|
||||
|
||||
MaterialPropertyId MaterialPropertyId::Parse(AZStd::string_view fullPropertyId)
|
||||
{
|
||||
AZStd::vector<AZStd::string> tokens;
|
||||
@@ -94,14 +112,14 @@ namespace AZ
|
||||
{
|
||||
if (!IsValidName(name))
|
||||
{
|
||||
AZ_Error("MaterialPropertyId", false, "'%s' is not a valid identifier.", name.c_str());
|
||||
AZ_Error("MaterialPropertyId", false, "Group name '%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));
|
||||
AZ_Error("MaterialPropertyId", false, "Property name '%.*s' is not a valid identifier.", AZ_STRING_ARG(propertyName));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
#include <Atom/RPI.Edit/Material/MaterialConverterBus.h>
|
||||
|
||||
#include <Atom/RPI.Edit/Common/AssetUtils.h>
|
||||
#include <Atom/RPI.Edit/Common/JsonFileLoadContext.h>
|
||||
#include <Atom/RPI.Edit/Common/JsonReportingHelper.h>
|
||||
#include <Atom/RPI.Edit/Common/JsonUtils.h>
|
||||
|
||||
@@ -263,7 +262,7 @@ namespace AZ
|
||||
return Failure();
|
||||
}
|
||||
|
||||
auto materialTypeLoadOutcome = MaterialUtils::LoadMaterialTypeSourceData(materialTypeSourcePath);
|
||||
auto materialTypeLoadOutcome = MaterialUtils::LoadMaterialTypeSourceData(materialTypeSourcePath, nullptr, sourceDependencies);
|
||||
if (!materialTypeLoadOutcome)
|
||||
{
|
||||
AZ_Error("MaterialSourceData", false, "Failed to load MaterialTypeSourceData: '%s'.", materialTypeSourcePath.c_str());
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <Atom/RPI.Reflect/Material/MaterialTypeAssetCreator.h>
|
||||
#include <Atom/RPI.Reflect/Material/MaterialFunctor.h>
|
||||
#include <Atom/RPI.Reflect/Material/MaterialVersionUpdate.h>
|
||||
#include <Atom/RPI.Reflect/Material/MaterialNameContext.h>
|
||||
#include <Atom/RPI.Reflect/Shader/ShaderOptionGroup.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/Serialization/Json/RegistrationContext.h>
|
||||
@@ -89,10 +90,12 @@ namespace AZ
|
||||
;
|
||||
|
||||
serializeContext->Class<PropertyGroup>()
|
||||
->Version(1)
|
||||
->Version(2)
|
||||
->Field("name", &PropertyGroup::m_name)
|
||||
->Field("displayName", &PropertyGroup::m_displayName)
|
||||
->Field("description", &PropertyGroup::m_description)
|
||||
->Field("shaderInputsPrefix", &PropertyGroup::m_shaderInputsPrefix)
|
||||
->Field("shaderOptionsPrefix", &PropertyGroup::m_shaderOptionsPrefix)
|
||||
->Field("properties", &PropertyGroup::m_properties)
|
||||
->Field("propertyGroups", &PropertyGroup::m_propertyGroups)
|
||||
->Field("functors", &PropertyGroup::m_materialFunctorSourceData)
|
||||
@@ -134,30 +137,84 @@ namespace AZ
|
||||
|
||||
/*static*/ MaterialTypeSourceData::PropertyGroup* MaterialTypeSourceData::PropertyGroup::AddPropertyGroup(AZStd::string_view name, AZStd::vector<AZStd::unique_ptr<PropertyGroup>>& toPropertyGroupList)
|
||||
{
|
||||
if (!MaterialPropertyId::CheckIsValidName(name))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto iter = AZStd::find_if(toPropertyGroupList.begin(), toPropertyGroupList.end(), [name](const AZStd::unique_ptr<PropertyGroup>& existingPropertyGroup)
|
||||
{
|
||||
return existingPropertyGroup->m_name == name;
|
||||
});
|
||||
|
||||
|
||||
if (iter != toPropertyGroupList.end())
|
||||
{
|
||||
AZ_Error("Material source data", false, "PropertyGroup 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;
|
||||
}
|
||||
|
||||
toPropertyGroupList.push_back(AZStd::make_unique<PropertyGroup>());
|
||||
toPropertyGroupList.back()->m_name = name;
|
||||
return toPropertyGroupList.back().get();
|
||||
}
|
||||
|
||||
const AZStd::string& MaterialTypeSourceData::PropertyGroup::GetName() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
const AZStd::string& MaterialTypeSourceData::PropertyGroup::GetDisplayName() const
|
||||
{
|
||||
return m_displayName;
|
||||
}
|
||||
|
||||
const AZStd::string& MaterialTypeSourceData::PropertyGroup::GetDescription() const
|
||||
{
|
||||
return m_description;
|
||||
}
|
||||
|
||||
const MaterialTypeSourceData::PropertyList& MaterialTypeSourceData::PropertyGroup::GetProperties() const
|
||||
{
|
||||
return m_properties;
|
||||
}
|
||||
|
||||
const AZStd::string& MaterialTypeSourceData::PropertyGroup::GetShaderInputsPrefix() const
|
||||
{
|
||||
return m_shaderInputsPrefix;
|
||||
}
|
||||
|
||||
const AZStd::string& MaterialTypeSourceData::PropertyGroup::GetShaderOptionsPrefix() const
|
||||
{
|
||||
return m_shaderOptionsPrefix;
|
||||
}
|
||||
|
||||
const AZStd::vector<AZStd::unique_ptr<MaterialTypeSourceData::PropertyGroup>>& MaterialTypeSourceData::PropertyGroup::GetPropertyGroups() const
|
||||
{
|
||||
return m_propertyGroups;
|
||||
}
|
||||
|
||||
const AZStd::vector<Ptr<MaterialFunctorSourceDataHolder>>& MaterialTypeSourceData::PropertyGroup::GetFunctors() const
|
||||
{
|
||||
return m_materialFunctorSourceData;
|
||||
}
|
||||
|
||||
void MaterialTypeSourceData::PropertyGroup::SetDisplayName(AZStd::string_view displayName)
|
||||
{
|
||||
m_displayName = displayName;
|
||||
}
|
||||
|
||||
void MaterialTypeSourceData::PropertyGroup::SetDescription(AZStd::string_view description)
|
||||
{
|
||||
m_description = description;
|
||||
}
|
||||
|
||||
MaterialTypeSourceData::PropertyDefinition* MaterialTypeSourceData::PropertyGroup::AddProperty(AZStd::string_view name)
|
||||
{
|
||||
if (!MaterialPropertyId::CheckIsValidName(name))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto propertyIter = AZStd::find_if(m_properties.begin(), m_properties.end(), [name](const AZStd::unique_ptr<PropertyDefinition>& existingProperty)
|
||||
{
|
||||
return existingProperty->GetName() == name;
|
||||
@@ -180,12 +237,6 @@ namespace AZ
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!MaterialPropertyId::IsValidName(name))
|
||||
{
|
||||
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<PropertyDefinition>(name));
|
||||
return m_properties.back().get();
|
||||
}
|
||||
@@ -265,10 +316,10 @@ namespace AZ
|
||||
|
||||
if (!subPath.empty())
|
||||
{
|
||||
const MaterialTypeSourceData::PropertyGroup* propertySubset = FindPropertyGroup(subPath, propertyGroup->m_propertyGroups);
|
||||
if (propertySubset)
|
||||
const MaterialTypeSourceData::PropertyGroup* propertySubgroup = FindPropertyGroup(subPath, propertyGroup->m_propertyGroups);
|
||||
if (propertySubgroup)
|
||||
{
|
||||
return propertySubset;
|
||||
return propertySubgroup;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -376,21 +427,23 @@ namespace AZ
|
||||
return parts;
|
||||
}
|
||||
|
||||
bool MaterialTypeSourceData::EnumeratePropertyGroups(const EnumeratePropertyGroupsCallback& callback, AZStd::string propertyNameContext, const AZStd::vector<AZStd::unique_ptr<PropertyGroup>>& inPropertyGroupList) const
|
||||
bool MaterialTypeSourceData::EnumeratePropertyGroups(const EnumeratePropertyGroupsCallback& callback, PropertyGroupStack& propertyGroupStack, const AZStd::vector<AZStd::unique_ptr<PropertyGroup>>& inPropertyGroupList) const
|
||||
{
|
||||
for (auto& propertyGroup : inPropertyGroupList)
|
||||
{
|
||||
if (!callback(propertyNameContext, propertyGroup.get()))
|
||||
propertyGroupStack.push_back(propertyGroup.get());
|
||||
|
||||
if (!callback(propertyGroupStack))
|
||||
{
|
||||
return false; // Stop processing
|
||||
}
|
||||
|
||||
if (!EnumeratePropertyGroups(callback, propertyGroupStack, propertyGroup->m_propertyGroups))
|
||||
{
|
||||
return false; // Stop processing
|
||||
}
|
||||
|
||||
const AZStd::string propertyNameContext2 = propertyNameContext + propertyGroup->m_name + ".";
|
||||
|
||||
if (!EnumeratePropertyGroups(callback, propertyNameContext2, propertyGroup->m_propertyGroups))
|
||||
{
|
||||
return false; // Stop processing
|
||||
}
|
||||
propertyGroupStack.pop_back();
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -403,25 +456,26 @@ namespace AZ
|
||||
return false;
|
||||
}
|
||||
|
||||
return EnumeratePropertyGroups(callback, {}, m_propertyLayout.m_propertyGroups);
|
||||
PropertyGroupStack propertyGroupStack;
|
||||
return EnumeratePropertyGroups(callback, propertyGroupStack, m_propertyLayout.m_propertyGroups);
|
||||
}
|
||||
|
||||
bool MaterialTypeSourceData::EnumerateProperties(const EnumeratePropertiesCallback& callback, AZStd::string propertyNameContext, const AZStd::vector<AZStd::unique_ptr<PropertyGroup>>& inPropertyGroupList) const
|
||||
bool MaterialTypeSourceData::EnumerateProperties(const EnumeratePropertiesCallback& callback, MaterialNameContext nameContext, const AZStd::vector<AZStd::unique_ptr<PropertyGroup>>& inPropertyGroupList) const
|
||||
{
|
||||
|
||||
for (auto& propertyGroup : inPropertyGroupList)
|
||||
{
|
||||
const AZStd::string propertyNameContext2 = propertyNameContext + propertyGroup->m_name + ".";
|
||||
MaterialNameContext groupNameContext = nameContext;
|
||||
ExtendNameContext(groupNameContext, *propertyGroup);
|
||||
|
||||
for (auto& property : propertyGroup->m_properties)
|
||||
{
|
||||
if (!callback(propertyNameContext2, property.get()))
|
||||
if (!callback(property.get(), groupNameContext))
|
||||
{
|
||||
return false; // Stop processing
|
||||
}
|
||||
}
|
||||
|
||||
if (!EnumerateProperties(callback, propertyNameContext2, propertyGroup->m_propertyGroups))
|
||||
if (!EnumerateProperties(callback, groupNameContext, propertyGroup->m_propertyGroups))
|
||||
{
|
||||
return false; // Stop processing
|
||||
}
|
||||
@@ -483,7 +537,7 @@ namespace AZ
|
||||
enumValues.push_back(uvNamePair.second);
|
||||
}
|
||||
|
||||
EnumerateProperties([&enumValues](const AZStd::string&, const MaterialTypeSourceData::PropertyDefinition* property)
|
||||
EnumerateProperties([&enumValues](const MaterialTypeSourceData::PropertyDefinition* property, const MaterialNameContext&)
|
||||
{
|
||||
if (property->m_dataType == AZ::RPI::MaterialPropertyDataType::Enum && property->m_enumIsUv)
|
||||
{
|
||||
@@ -529,24 +583,48 @@ namespace AZ
|
||||
return groupDefinitions;
|
||||
}
|
||||
|
||||
void MaterialTypeSourceData::ExtendNameContext(MaterialNameContext& nameContext, const MaterialTypeSourceData::PropertyGroup& propertyGroup)
|
||||
{
|
||||
nameContext.ExtendPropertyIdContext(propertyGroup.m_name);
|
||||
nameContext.ExtendShaderOptionContext(propertyGroup.m_shaderOptionsPrefix);
|
||||
nameContext.ExtendSrgInputContext(propertyGroup.m_shaderInputsPrefix);
|
||||
}
|
||||
|
||||
/*static*/ MaterialNameContext MaterialTypeSourceData::MakeMaterialNameContext(const MaterialTypeSourceData::PropertyGroupStack& propertyGroupStack)
|
||||
{
|
||||
MaterialNameContext nameContext;
|
||||
for (auto& group : propertyGroupStack)
|
||||
{
|
||||
ExtendNameContext(nameContext, *group);
|
||||
}
|
||||
return nameContext;
|
||||
}
|
||||
|
||||
bool MaterialTypeSourceData::BuildPropertyList(
|
||||
const AZStd::string& materialTypeSourceFilePath,
|
||||
MaterialTypeAssetCreator& materialTypeAssetCreator,
|
||||
AZStd::vector<AZStd::string>& propertyNameContext,
|
||||
MaterialNameContext materialNameContext,
|
||||
const MaterialTypeSourceData::PropertyGroup* propertyGroup) const
|
||||
{
|
||||
{
|
||||
if (!MaterialPropertyId::CheckIsValidName(propertyGroup->m_name))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ExtendNameContext(materialNameContext, *propertyGroup);
|
||||
|
||||
for (const AZStd::unique_ptr<PropertyDefinition>& property : propertyGroup->m_properties)
|
||||
{
|
||||
// Register the property...
|
||||
|
||||
MaterialPropertyId propertyId{propertyNameContext, property->GetName()};
|
||||
|
||||
if (!propertyId.IsValid())
|
||||
if (!MaterialPropertyId::CheckIsValidName(property->GetName()))
|
||||
{
|
||||
// MaterialPropertyId reports an error message
|
||||
return false;
|
||||
}
|
||||
|
||||
Name propertyId{property->GetName()};
|
||||
materialNameContext.ContextualizeProperty(propertyId);
|
||||
|
||||
auto propertyGroupIter = AZStd::find_if(propertyGroup->GetPropertyGroups().begin(), propertyGroup->GetPropertyGroups().end(),
|
||||
[&property](const AZStd::unique_ptr<PropertyGroup>& existingPropertyGroup)
|
||||
{
|
||||
@@ -572,18 +650,23 @@ namespace AZ
|
||||
{
|
||||
case MaterialPropertyOutputType::ShaderInput:
|
||||
{
|
||||
materialTypeAssetCreator.ConnectMaterialPropertyToShaderInput(Name{output.m_fieldName});
|
||||
Name fieldName{output.m_fieldName};
|
||||
materialNameContext.ContextualizeSrgInput(fieldName);
|
||||
materialTypeAssetCreator.ConnectMaterialPropertyToShaderInput(fieldName);
|
||||
break;
|
||||
}
|
||||
case MaterialPropertyOutputType::ShaderOption:
|
||||
{
|
||||
Name fieldName{output.m_fieldName};
|
||||
materialNameContext.ContextualizeShaderOption(fieldName);
|
||||
|
||||
if (output.m_shaderIndex >= 0)
|
||||
{
|
||||
materialTypeAssetCreator.ConnectMaterialPropertyToShaderOption(Name{output.m_fieldName}, output.m_shaderIndex);
|
||||
materialTypeAssetCreator.ConnectMaterialPropertyToShaderOption(fieldName, output.m_shaderIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
materialTypeAssetCreator.ConnectMaterialPropertyToShaderOptions(Name{output.m_fieldName});
|
||||
materialTypeAssetCreator.ConnectMaterialPropertyToShaderOptions(fieldName);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -650,17 +733,13 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
for (const AZStd::unique_ptr<PropertyGroup>& propertySubset : propertyGroup->m_propertyGroups)
|
||||
for (const AZStd::unique_ptr<PropertyGroup>& propertySubgroup : propertyGroup->m_propertyGroups)
|
||||
{
|
||||
propertyNameContext.push_back(propertySubset->m_name);
|
||||
|
||||
bool success = BuildPropertyList(
|
||||
materialTypeSourceFilePath,
|
||||
materialTypeAssetCreator,
|
||||
propertyNameContext,
|
||||
propertySubset.get());
|
||||
|
||||
propertyNameContext.pop_back();
|
||||
materialNameContext,
|
||||
propertySubgroup.get());
|
||||
|
||||
if (!success)
|
||||
{
|
||||
@@ -677,7 +756,8 @@ namespace AZ
|
||||
materialTypeSourceFilePath,
|
||||
materialTypeAssetCreator.GetMaterialPropertiesLayout(),
|
||||
materialTypeAssetCreator.GetMaterialShaderResourceGroupLayout(),
|
||||
materialTypeAssetCreator.GetShaderCollection()
|
||||
materialTypeAssetCreator.GetShaderCollection(),
|
||||
&materialNameContext
|
||||
)
|
||||
);
|
||||
|
||||
@@ -688,9 +768,10 @@ namespace AZ
|
||||
{
|
||||
materialTypeAssetCreator.AddMaterialFunctor(functor);
|
||||
|
||||
for (const AZ::Name& optionName : functorData->GetActualSourceData()->GetShaderOptionDependencies())
|
||||
for (AZ::Name optionName : functorData->GetActualSourceData()->GetShaderOptionDependencies())
|
||||
{
|
||||
materialTypeAssetCreator.ClaimShaderOptionOwnership(Name{optionName.GetCStr()});
|
||||
materialNameContext.ContextualizeShaderOption(optionName);
|
||||
materialTypeAssetCreator.ClaimShaderOptionOwnership(optionName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -795,11 +876,9 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
for (const AZStd::unique_ptr<PropertyGroup>& propertyGroup : m_propertyLayout.m_propertyGroups)
|
||||
for (const AZStd::unique_ptr<PropertyGroup>& propertyGroup : m_propertyLayout.m_propertyGroups)
|
||||
{
|
||||
AZStd::vector<AZStd::string> propertyNameContext;
|
||||
propertyNameContext.push_back(propertyGroup->m_name);
|
||||
bool success = BuildPropertyList(materialTypeSourceFilePath, materialTypeAssetCreator, propertyNameContext, propertyGroup.get());
|
||||
bool success = BuildPropertyList(materialTypeSourceFilePath, materialTypeAssetCreator, MaterialNameContext{}, propertyGroup.get());
|
||||
|
||||
if (!success)
|
||||
{
|
||||
@@ -807,6 +886,8 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
MaterialNameContext nameContext;
|
||||
|
||||
// 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)
|
||||
@@ -816,7 +897,8 @@ namespace AZ
|
||||
materialTypeSourceFilePath,
|
||||
materialTypeAssetCreator.GetMaterialPropertiesLayout(),
|
||||
materialTypeAssetCreator.GetMaterialShaderResourceGroupLayout(),
|
||||
materialTypeAssetCreator.GetShaderCollection()
|
||||
materialTypeAssetCreator.GetShaderCollection(),
|
||||
&nameContext
|
||||
)
|
||||
);
|
||||
|
||||
@@ -866,6 +948,6 @@ namespace AZ
|
||||
return Failure();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace RPI
|
||||
} // namespace AZ
|
||||
|
||||
@@ -15,11 +15,11 @@
|
||||
#include <Atom/RPI.Edit/Material/MaterialSourceData.h>
|
||||
#include <Atom/RPI.Edit/Material/MaterialTypeSourceData.h>
|
||||
#include <Atom/RPI.Edit/Common/JsonReportingHelper.h>
|
||||
#include <Atom/RPI.Edit/Common/JsonFileLoadContext.h>
|
||||
#include <Atom/RPI.Edit/Common/JsonUtils.h>
|
||||
#include <AzCore/Serialization/Json/JsonUtils.h>
|
||||
#include <AzCore/Serialization/Json/BaseJsonSerializer.h>
|
||||
#include <AzCore/Serialization/Json/JsonSerializationResult.h>
|
||||
#include <AzCore/Serialization/Json/JsonImporter.h>
|
||||
#include <AzCore/Settings/SettingsRegistry.h>
|
||||
|
||||
#include <AzCore/std/string/string.h>
|
||||
@@ -74,20 +74,38 @@ namespace AZ
|
||||
outResolvedValue = enumValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
AZ::Outcome<MaterialTypeSourceData> LoadMaterialTypeSourceData(const AZStd::string& filePath, const rapidjson::Value* document)
|
||||
|
||||
AZ::Outcome<MaterialTypeSourceData> LoadMaterialTypeSourceData(const AZStd::string& filePath, rapidjson::Document* document, ImportedJsonFiles* importedFiles)
|
||||
{
|
||||
AZ::Outcome<rapidjson::Document, AZStd::string> loadOutcome;
|
||||
rapidjson::Document localDocument;
|
||||
|
||||
if (document == nullptr)
|
||||
{
|
||||
loadOutcome = AZ::JsonSerializationUtils::ReadJsonFile(filePath, AZ::RPI::JsonUtils::DefaultMaxFileSize);
|
||||
AZ::Outcome<rapidjson::Document, AZStd::string> loadOutcome = AZ::JsonSerializationUtils::ReadJsonFile(filePath, AZ::RPI::JsonUtils::DefaultMaxFileSize);
|
||||
if (!loadOutcome.IsSuccess())
|
||||
{
|
||||
AZ_Error("MaterialUtils", false, "%s", loadOutcome.GetError().c_str());
|
||||
return AZ::Failure();
|
||||
}
|
||||
|
||||
document = &loadOutcome.GetValue();
|
||||
localDocument = loadOutcome.TakeValue();
|
||||
document = &localDocument;
|
||||
}
|
||||
|
||||
AZ::BaseJsonImporter jsonImporter;
|
||||
AZ::JsonImportSettings importSettings;
|
||||
importSettings.m_importer = &jsonImporter;
|
||||
importSettings.m_loadedJsonPath = filePath;
|
||||
AZ::JsonSerializationResult::ResultCode result = AZ::JsonSerialization::ResolveImports(document->GetObject(), document->GetAllocator(), importSettings);
|
||||
if (result.GetProcessing() != AZ::JsonSerializationResult::Processing::Completed)
|
||||
{
|
||||
AZ_Error("MaterialUtils", false, "%s", result.ToString(filePath).c_str());
|
||||
return AZ::Failure();
|
||||
}
|
||||
|
||||
if (importedFiles)
|
||||
{
|
||||
*importedFiles = importSettings.m_importer->GetImportedFiles();
|
||||
}
|
||||
|
||||
MaterialTypeSourceData materialType;
|
||||
@@ -97,11 +115,6 @@ namespace AZ
|
||||
JsonReportingHelper reportingHelper;
|
||||
reportingHelper.Attach(settings);
|
||||
|
||||
// This is required by some custom material serializers to support relative path references.
|
||||
JsonFileLoadContext fileLoadContext;
|
||||
fileLoadContext.PushFilePath(filePath);
|
||||
settings.m_metadata.Add(fileLoadContext);
|
||||
|
||||
JsonSerialization::Load(materialType, *document, settings);
|
||||
materialType.ConvertToNewDataFormat();
|
||||
materialType.ResolveUvEnums();
|
||||
|
||||
@@ -27,6 +27,7 @@ namespace AZ
|
||||
MaterialAsset::Reflect(context);
|
||||
MaterialPropertiesLayout::Reflect(context);
|
||||
MaterialFunctor::Reflect(context);
|
||||
MaterialNameContext::Reflect(context);
|
||||
LuaMaterialFunctor::Reflect(context);
|
||||
ReflectMaterialDynamicMetadata(context);
|
||||
}
|
||||
|
||||
@@ -29,9 +29,7 @@ namespace AZ
|
||||
serializeContext->Class<LuaMaterialFunctor, RPI::MaterialFunctor>()
|
||||
->Version(1)
|
||||
->Field("scriptAsset", &LuaMaterialFunctor::m_scriptAsset)
|
||||
->Field("propertyNamePrefix", &LuaMaterialFunctor::m_propertyNamePrefix)
|
||||
->Field("srgNamePrefix", &LuaMaterialFunctor::m_srgNamePrefix)
|
||||
->Field("optionsNamePrefix", &LuaMaterialFunctor::m_optionsNamePrefix)
|
||||
->Field("materialNameContext", &LuaMaterialFunctor::m_materialNameContext)
|
||||
;
|
||||
}
|
||||
}
|
||||
@@ -127,7 +125,7 @@ namespace AZ
|
||||
|
||||
if (m_scriptStatus == ScriptStatus::Ready)
|
||||
{
|
||||
LuaMaterialFunctorRuntimeContext luaContext{&context, &GetMaterialPropertyDependencies(), m_propertyNamePrefix, m_srgNamePrefix, m_optionsNamePrefix};
|
||||
LuaMaterialFunctorRuntimeContext luaContext{&context, &GetMaterialPropertyDependencies(), m_materialNameContext};
|
||||
AZ::ScriptDataContext call;
|
||||
if (m_scriptContext->Call("Process", call))
|
||||
{
|
||||
@@ -145,7 +143,7 @@ namespace AZ
|
||||
|
||||
if (m_scriptStatus == ScriptStatus::Ready)
|
||||
{
|
||||
LuaMaterialFunctorEditorContext luaContext{&context, &GetMaterialPropertyDependencies(), m_propertyNamePrefix, m_srgNamePrefix, m_optionsNamePrefix};
|
||||
LuaMaterialFunctorEditorContext luaContext{&context, &GetMaterialPropertyDependencies(), m_materialNameContext};
|
||||
AZ::ScriptDataContext call;
|
||||
if (m_scriptContext->Call("ProcessEditor", call))
|
||||
{
|
||||
@@ -157,27 +155,19 @@ namespace AZ
|
||||
|
||||
LuaMaterialFunctorCommonContext::LuaMaterialFunctorCommonContext(MaterialFunctor::RuntimeContext* runtimeContextImpl,
|
||||
const MaterialPropertyFlags* materialPropertyDependencies,
|
||||
const AZStd::string& propertyNamePrefix,
|
||||
const AZStd::string& srgNamePrefix,
|
||||
const AZStd::string& optionsNamePrefix)
|
||||
const MaterialNameContext& materialNameContext)
|
||||
: m_runtimeContextImpl(runtimeContextImpl)
|
||||
, m_materialPropertyDependencies(materialPropertyDependencies)
|
||||
, m_propertyNamePrefix(propertyNamePrefix)
|
||||
, m_srgNamePrefix(srgNamePrefix)
|
||||
, m_optionsNamePrefix(optionsNamePrefix)
|
||||
, m_materialNameContext(materialNameContext)
|
||||
{
|
||||
}
|
||||
|
||||
LuaMaterialFunctorCommonContext::LuaMaterialFunctorCommonContext(MaterialFunctor::EditorContext* editorContextImpl,
|
||||
const MaterialPropertyFlags* materialPropertyDependencies,
|
||||
const AZStd::string& propertyNamePrefix,
|
||||
const AZStd::string& srgNamePrefix,
|
||||
const AZStd::string& optionsNamePrefix)
|
||||
const MaterialNameContext& materialNameContext)
|
||||
: m_editorContextImpl(editorContextImpl)
|
||||
, m_materialPropertyDependencies(materialPropertyDependencies)
|
||||
, m_propertyNamePrefix(propertyNamePrefix)
|
||||
, m_srgNamePrefix(srgNamePrefix)
|
||||
, m_optionsNamePrefix(optionsNamePrefix)
|
||||
, m_materialNameContext(materialNameContext)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -256,7 +246,8 @@ namespace AZ
|
||||
{
|
||||
MaterialPropertyIndex propertyIndex;
|
||||
|
||||
Name propertyFullName{m_propertyNamePrefix + name};
|
||||
Name propertyFullName{name};
|
||||
m_materialNameContext.ContextualizeProperty(propertyFullName);
|
||||
|
||||
propertyIndex = GetMaterialPropertiesLayout()->FindPropertyIndex(propertyFullName);
|
||||
|
||||
@@ -361,10 +352,8 @@ namespace AZ
|
||||
|
||||
LuaMaterialFunctorRuntimeContext::LuaMaterialFunctorRuntimeContext(MaterialFunctor::RuntimeContext* runtimeContextImpl,
|
||||
const MaterialPropertyFlags* materialPropertyDependencies,
|
||||
const AZStd::string& propertyNamePrefix,
|
||||
const AZStd::string& srgNamePrefix,
|
||||
const AZStd::string& optionsNamePrefix)
|
||||
: LuaMaterialFunctorCommonContext(runtimeContextImpl, materialPropertyDependencies, propertyNamePrefix, srgNamePrefix, optionsNamePrefix)
|
||||
const MaterialNameContext& materialNameContext)
|
||||
: LuaMaterialFunctorCommonContext(runtimeContextImpl, materialPropertyDependencies, materialNameContext)
|
||||
, m_runtimeContextImpl(runtimeContextImpl)
|
||||
{
|
||||
}
|
||||
@@ -379,7 +368,8 @@ namespace AZ
|
||||
{
|
||||
bool didSetOne = false;
|
||||
|
||||
Name fullOptionName{m_optionsNamePrefix + name};
|
||||
Name fullOptionName{name};
|
||||
m_materialNameContext.ContextualizeShaderOption(fullOptionName);
|
||||
|
||||
for (AZStd::size_t i = 0; i < m_runtimeContextImpl->m_shaderCollection->size(); ++i)
|
||||
{
|
||||
@@ -429,7 +419,8 @@ namespace AZ
|
||||
|
||||
RHI::ShaderInputConstantIndex LuaMaterialFunctorRuntimeContext::GetShaderInputConstantIndex(const char* name, const char* functionName) const
|
||||
{
|
||||
Name fullInputName{m_srgNamePrefix + name};
|
||||
Name fullInputName{name};
|
||||
m_materialNameContext.ContextualizeSrgInput(fullInputName);
|
||||
|
||||
RHI::ShaderInputConstantIndex index = m_runtimeContextImpl->m_shaderResourceGroup->FindShaderInputConstantIndex(fullInputName);
|
||||
|
||||
@@ -524,10 +515,8 @@ namespace AZ
|
||||
|
||||
LuaMaterialFunctorEditorContext::LuaMaterialFunctorEditorContext(MaterialFunctor::EditorContext* editorContextImpl,
|
||||
const MaterialPropertyFlags* materialPropertyDependencies,
|
||||
const AZStd::string& propertyNamePrefix,
|
||||
const AZStd::string& srgNamePrefix,
|
||||
const AZStd::string& optionsNamePrefix)
|
||||
: LuaMaterialFunctorCommonContext(editorContextImpl, materialPropertyDependencies, propertyNamePrefix, srgNamePrefix, optionsNamePrefix)
|
||||
const MaterialNameContext& materialNameContext)
|
||||
: LuaMaterialFunctorCommonContext(editorContextImpl, materialPropertyDependencies, materialNameContext)
|
||||
, m_editorContextImpl(editorContextImpl)
|
||||
{
|
||||
}
|
||||
@@ -598,7 +587,9 @@ namespace AZ
|
||||
{
|
||||
if (m_editorContextImpl)
|
||||
{
|
||||
return m_editorContextImpl->SetMaterialPropertyGroupVisibility(Name{m_propertyNamePrefix + name}, visibility);
|
||||
Name fullName{name};
|
||||
m_materialNameContext.ContextualizeProperty(fullName);
|
||||
return m_editorContextImpl->SetMaterialPropertyGroupVisibility(fullName, visibility);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -607,7 +598,9 @@ namespace AZ
|
||||
{
|
||||
if (m_editorContextImpl)
|
||||
{
|
||||
return m_editorContextImpl->SetMaterialPropertyVisibility(Name{m_propertyNamePrefix + name}, visibility);
|
||||
Name fullName{name};
|
||||
m_materialNameContext.ContextualizeProperty(fullName);
|
||||
return m_editorContextImpl->SetMaterialPropertyVisibility(fullName, visibility);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -616,7 +609,9 @@ namespace AZ
|
||||
{
|
||||
if (m_editorContextImpl)
|
||||
{
|
||||
return m_editorContextImpl->SetMaterialPropertyDescription(Name{m_propertyNamePrefix + name}, description);
|
||||
Name fullName{name};
|
||||
m_materialNameContext.ContextualizeProperty(fullName);
|
||||
return m_editorContextImpl->SetMaterialPropertyDescription(fullName, description);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -155,9 +155,9 @@ namespace AZ
|
||||
, m_materialPropertyDependencies(materialPropertyDependencies)
|
||||
{}
|
||||
|
||||
const MaterialPropertyDynamicMetadata* MaterialFunctor::EditorContext::GetMaterialPropertyMetadata(const Name& propertyName) const
|
||||
const MaterialPropertyDynamicMetadata* MaterialFunctor::EditorContext::GetMaterialPropertyMetadata(const Name& propertyId) const
|
||||
{
|
||||
return QueryMaterialPropertyMetadata(propertyName);
|
||||
return QueryMaterialPropertyMetadata(propertyId);
|
||||
}
|
||||
|
||||
const MaterialPropertyDynamicMetadata* MaterialFunctor::EditorContext::GetMaterialPropertyMetadata(const MaterialPropertyIndex& index) const
|
||||
@@ -166,9 +166,9 @@ namespace AZ
|
||||
return GetMaterialPropertyMetadata(name);
|
||||
}
|
||||
|
||||
const MaterialPropertyGroupDynamicMetadata* MaterialFunctor::EditorContext::GetMaterialPropertyGroupMetadata(const Name& propertyName) const
|
||||
const MaterialPropertyGroupDynamicMetadata* MaterialFunctor::EditorContext::GetMaterialPropertyGroupMetadata(const Name& propertyId) const
|
||||
{
|
||||
return QueryMaterialPropertyGroupMetadata(propertyName);
|
||||
return QueryMaterialPropertyGroupMetadata(propertyId);
|
||||
}
|
||||
|
||||
bool MaterialFunctor::EditorContext::SetMaterialPropertyGroupVisibility(const Name& propertyGroupName, MaterialPropertyGroupVisibility visibility)
|
||||
@@ -188,9 +188,9 @@ namespace AZ
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MaterialFunctor::EditorContext::SetMaterialPropertyVisibility(const Name& propertyName, MaterialPropertyVisibility visibility)
|
||||
bool MaterialFunctor::EditorContext::SetMaterialPropertyVisibility(const Name& propertyId, MaterialPropertyVisibility visibility)
|
||||
{
|
||||
MaterialPropertyDynamicMetadata* metadata = QueryMaterialPropertyMetadata(propertyName);
|
||||
MaterialPropertyDynamicMetadata* metadata = QueryMaterialPropertyMetadata(propertyId);
|
||||
if (!metadata)
|
||||
{
|
||||
return false;
|
||||
@@ -199,7 +199,7 @@ namespace AZ
|
||||
if (metadata->m_visibility != visibility)
|
||||
{
|
||||
metadata->m_visibility = visibility;
|
||||
m_updatedPropertiesOut.insert(propertyName);
|
||||
m_updatedPropertiesOut.insert(propertyId);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -211,9 +211,9 @@ namespace AZ
|
||||
return SetMaterialPropertyVisibility(name, visibility);
|
||||
}
|
||||
|
||||
bool MaterialFunctor::EditorContext::SetMaterialPropertyDescription(const Name& propertyName, AZStd::string description)
|
||||
bool MaterialFunctor::EditorContext::SetMaterialPropertyDescription(const Name& propertyId, AZStd::string description)
|
||||
{
|
||||
MaterialPropertyDynamicMetadata* metadata = QueryMaterialPropertyMetadata(propertyName);
|
||||
MaterialPropertyDynamicMetadata* metadata = QueryMaterialPropertyMetadata(propertyId);
|
||||
if (!metadata)
|
||||
{
|
||||
return false;
|
||||
@@ -222,7 +222,7 @@ namespace AZ
|
||||
if (metadata->m_description != description)
|
||||
{
|
||||
metadata->m_description = description;
|
||||
m_updatedPropertiesOut.insert(propertyName);
|
||||
m_updatedPropertiesOut.insert(propertyId);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -234,9 +234,9 @@ namespace AZ
|
||||
return SetMaterialPropertyDescription(name, description);
|
||||
}
|
||||
|
||||
bool MaterialFunctor::EditorContext::SetMaterialPropertyMinValue(const Name& propertyName, const MaterialPropertyValue& min)
|
||||
bool MaterialFunctor::EditorContext::SetMaterialPropertyMinValue(const Name& propertyId, const MaterialPropertyValue& min)
|
||||
{
|
||||
MaterialPropertyDynamicMetadata* metadata = QueryMaterialPropertyMetadata(propertyName);
|
||||
MaterialPropertyDynamicMetadata* metadata = QueryMaterialPropertyMetadata(propertyId);
|
||||
if (!metadata)
|
||||
{
|
||||
return false;
|
||||
@@ -245,7 +245,7 @@ namespace AZ
|
||||
if(metadata->m_propertyRange.m_min != min)
|
||||
{
|
||||
metadata->m_propertyRange.m_min = min;
|
||||
m_updatedPropertiesOut.insert(propertyName);
|
||||
m_updatedPropertiesOut.insert(propertyId);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -257,9 +257,9 @@ namespace AZ
|
||||
return SetMaterialPropertyMinValue(name, min);
|
||||
}
|
||||
|
||||
bool MaterialFunctor::EditorContext::SetMaterialPropertyMaxValue(const Name& propertyName, const MaterialPropertyValue& max)
|
||||
bool MaterialFunctor::EditorContext::SetMaterialPropertyMaxValue(const Name& propertyId, const MaterialPropertyValue& max)
|
||||
{
|
||||
MaterialPropertyDynamicMetadata* metadata = QueryMaterialPropertyMetadata(propertyName);
|
||||
MaterialPropertyDynamicMetadata* metadata = QueryMaterialPropertyMetadata(propertyId);
|
||||
if (!metadata)
|
||||
{
|
||||
return false;
|
||||
@@ -268,7 +268,7 @@ namespace AZ
|
||||
if (metadata->m_propertyRange.m_max != max)
|
||||
{
|
||||
metadata->m_propertyRange.m_max = max;
|
||||
m_updatedPropertiesOut.insert(propertyName);
|
||||
m_updatedPropertiesOut.insert(propertyId);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -280,9 +280,9 @@ namespace AZ
|
||||
return SetMaterialPropertyMaxValue(name, max);
|
||||
}
|
||||
|
||||
bool MaterialFunctor::EditorContext::SetMaterialPropertySoftMinValue(const Name& propertyName, const MaterialPropertyValue& min)
|
||||
bool MaterialFunctor::EditorContext::SetMaterialPropertySoftMinValue(const Name& propertyId, const MaterialPropertyValue& min)
|
||||
{
|
||||
MaterialPropertyDynamicMetadata* metadata = QueryMaterialPropertyMetadata(propertyName);
|
||||
MaterialPropertyDynamicMetadata* metadata = QueryMaterialPropertyMetadata(propertyId);
|
||||
if (!metadata)
|
||||
{
|
||||
return false;
|
||||
@@ -291,7 +291,7 @@ namespace AZ
|
||||
if (metadata->m_propertyRange.m_softMin != min)
|
||||
{
|
||||
metadata->m_propertyRange.m_softMin = min;
|
||||
m_updatedPropertiesOut.insert(propertyName);
|
||||
m_updatedPropertiesOut.insert(propertyId);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -303,9 +303,9 @@ namespace AZ
|
||||
return SetMaterialPropertySoftMinValue(name, min);
|
||||
}
|
||||
|
||||
bool MaterialFunctor::EditorContext::SetMaterialPropertySoftMaxValue(const Name& propertyName, const MaterialPropertyValue& max)
|
||||
bool MaterialFunctor::EditorContext::SetMaterialPropertySoftMaxValue(const Name& propertyId, const MaterialPropertyValue& max)
|
||||
{
|
||||
MaterialPropertyDynamicMetadata* metadata = QueryMaterialPropertyMetadata(propertyName);
|
||||
MaterialPropertyDynamicMetadata* metadata = QueryMaterialPropertyMetadata(propertyId);
|
||||
if (!metadata)
|
||||
{
|
||||
return false;
|
||||
@@ -314,7 +314,7 @@ namespace AZ
|
||||
if (metadata->m_propertyRange.m_softMax != max)
|
||||
{
|
||||
metadata->m_propertyRange.m_softMax = max;
|
||||
m_updatedPropertiesOut.insert(propertyName);
|
||||
m_updatedPropertiesOut.insert(propertyId);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -326,24 +326,24 @@ namespace AZ
|
||||
return SetMaterialPropertySoftMaxValue(name, max);
|
||||
}
|
||||
|
||||
MaterialPropertyDynamicMetadata* MaterialFunctor::EditorContext::QueryMaterialPropertyMetadata(const Name& propertyName) const
|
||||
MaterialPropertyDynamicMetadata* MaterialFunctor::EditorContext::QueryMaterialPropertyMetadata(const Name& propertyId) const
|
||||
{
|
||||
auto it = m_propertyMetadata.find(propertyName);
|
||||
auto it = m_propertyMetadata.find(propertyId);
|
||||
if (it == m_propertyMetadata.end())
|
||||
{
|
||||
AZ_Error("MaterialFunctor", false, "Couldn't find metadata for material property: %s.", propertyName.GetCStr());
|
||||
AZ_Error("MaterialFunctor", false, "Couldn't find metadata for material property: %s.", propertyId.GetCStr());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &it->second;
|
||||
}
|
||||
|
||||
MaterialPropertyGroupDynamicMetadata* MaterialFunctor::EditorContext::QueryMaterialPropertyGroupMetadata(const Name& propertyGroupName) const
|
||||
MaterialPropertyGroupDynamicMetadata* MaterialFunctor::EditorContext::QueryMaterialPropertyGroupMetadata(const Name& propertyGroupId) const
|
||||
{
|
||||
auto it = m_propertyGroupMetadata.find(propertyGroupName);
|
||||
auto it = m_propertyGroupMetadata.find(propertyGroupId);
|
||||
if (it == m_propertyGroupMetadata.end())
|
||||
{
|
||||
AZ_Error("MaterialFunctor", false, "Couldn't find metadata for material property group: %s.", propertyGroupName.GetCStr());
|
||||
AZ_Error("MaterialFunctor", false, "Couldn't find metadata for material property group: %s.", propertyGroupId.GetCStr());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -357,20 +357,20 @@ namespace AZ
|
||||
}
|
||||
|
||||
// explicit template instantiation
|
||||
template const bool& MaterialFunctor::RuntimeContext::GetMaterialPropertyValue<bool> (const Name& propertyName) const;
|
||||
template const int32_t& MaterialFunctor::RuntimeContext::GetMaterialPropertyValue<int32_t> (const Name& propertyName) const;
|
||||
template const uint32_t& MaterialFunctor::RuntimeContext::GetMaterialPropertyValue<uint32_t> (const Name& propertyName) const;
|
||||
template const float& MaterialFunctor::RuntimeContext::GetMaterialPropertyValue<float> (const Name& propertyName) const;
|
||||
template const Vector2& MaterialFunctor::RuntimeContext::GetMaterialPropertyValue<Vector2> (const Name& propertyName) const;
|
||||
template const Vector3& MaterialFunctor::RuntimeContext::GetMaterialPropertyValue<Vector3> (const Name& propertyName) const;
|
||||
template const Vector4& MaterialFunctor::RuntimeContext::GetMaterialPropertyValue<Vector4> (const Name& propertyName) const;
|
||||
template const Color& MaterialFunctor::RuntimeContext::GetMaterialPropertyValue<Color> (const Name& propertyName) const;
|
||||
template const Data::Instance<Image>& MaterialFunctor::RuntimeContext::GetMaterialPropertyValue<Data::Instance<Image>>(const Name& propertyName) const;
|
||||
template const bool& MaterialFunctor::RuntimeContext::GetMaterialPropertyValue<bool> (const Name& propertyId) const;
|
||||
template const int32_t& MaterialFunctor::RuntimeContext::GetMaterialPropertyValue<int32_t> (const Name& propertyId) const;
|
||||
template const uint32_t& MaterialFunctor::RuntimeContext::GetMaterialPropertyValue<uint32_t> (const Name& propertyId) const;
|
||||
template const float& MaterialFunctor::RuntimeContext::GetMaterialPropertyValue<float> (const Name& propertyId) const;
|
||||
template const Vector2& MaterialFunctor::RuntimeContext::GetMaterialPropertyValue<Vector2> (const Name& propertyId) const;
|
||||
template const Vector3& MaterialFunctor::RuntimeContext::GetMaterialPropertyValue<Vector3> (const Name& propertyId) const;
|
||||
template const Vector4& MaterialFunctor::RuntimeContext::GetMaterialPropertyValue<Vector4> (const Name& propertyId) const;
|
||||
template const Color& MaterialFunctor::RuntimeContext::GetMaterialPropertyValue<Color> (const Name& propertyId) const;
|
||||
template const Data::Instance<Image>& MaterialFunctor::RuntimeContext::GetMaterialPropertyValue<Data::Instance<Image>>(const Name& propertyId) const;
|
||||
|
||||
template<typename Type>
|
||||
const Type& MaterialFunctor::RuntimeContext::GetMaterialPropertyValue(const Name& propertyName) const
|
||||
const Type& MaterialFunctor::RuntimeContext::GetMaterialPropertyValue(const Name& propertyId) const
|
||||
{
|
||||
return GetMaterialPropertyValue(propertyName).GetValue<Type>();
|
||||
return GetMaterialPropertyValue(propertyId).GetValue<Type>();
|
||||
}
|
||||
|
||||
// explicit template instantiation
|
||||
@@ -391,19 +391,19 @@ namespace AZ
|
||||
}
|
||||
|
||||
// explicit template instantiation
|
||||
template const bool& MaterialFunctor::EditorContext::GetMaterialPropertyValue<bool> (const Name& propertyName) const;
|
||||
template const int32_t& MaterialFunctor::EditorContext::GetMaterialPropertyValue<int32_t> (const Name& propertyName) const;
|
||||
template const uint32_t& MaterialFunctor::EditorContext::GetMaterialPropertyValue<uint32_t> (const Name& propertyName) const;
|
||||
template const float& MaterialFunctor::EditorContext::GetMaterialPropertyValue<float> (const Name& propertyName) const;
|
||||
template const Vector2& MaterialFunctor::EditorContext::GetMaterialPropertyValue<Vector2> (const Name& propertyName) const;
|
||||
template const Vector3& MaterialFunctor::EditorContext::GetMaterialPropertyValue<Vector3> (const Name& propertyName) const;
|
||||
template const Vector4& MaterialFunctor::EditorContext::GetMaterialPropertyValue<Vector4> (const Name& propertyName) const;
|
||||
template const Color& MaterialFunctor::EditorContext::GetMaterialPropertyValue<Color> (const Name& propertyName) const;
|
||||
template const bool& MaterialFunctor::EditorContext::GetMaterialPropertyValue<bool> (const Name& propertyId) const;
|
||||
template const int32_t& MaterialFunctor::EditorContext::GetMaterialPropertyValue<int32_t> (const Name& propertyId) const;
|
||||
template const uint32_t& MaterialFunctor::EditorContext::GetMaterialPropertyValue<uint32_t> (const Name& propertyId) const;
|
||||
template const float& MaterialFunctor::EditorContext::GetMaterialPropertyValue<float> (const Name& propertyId) const;
|
||||
template const Vector2& MaterialFunctor::EditorContext::GetMaterialPropertyValue<Vector2> (const Name& propertyId) const;
|
||||
template const Vector3& MaterialFunctor::EditorContext::GetMaterialPropertyValue<Vector3> (const Name& propertyId) const;
|
||||
template const Vector4& MaterialFunctor::EditorContext::GetMaterialPropertyValue<Vector4> (const Name& propertyId) const;
|
||||
template const Color& MaterialFunctor::EditorContext::GetMaterialPropertyValue<Color> (const Name& propertyId) const;
|
||||
|
||||
template<typename Type>
|
||||
const Type& MaterialFunctor::EditorContext::GetMaterialPropertyValue(const Name& propertyName) const
|
||||
const Type& MaterialFunctor::EditorContext::GetMaterialPropertyValue(const Name& propertyId) const
|
||||
{
|
||||
return GetMaterialPropertyValue(propertyName).GetValue<Type>();
|
||||
return GetMaterialPropertyValue(propertyId).GetValue<Type>();
|
||||
}
|
||||
|
||||
// explicit template instantiation
|
||||
@@ -436,9 +436,9 @@ namespace AZ
|
||||
return m_materialPropertyValues[index.GetIndex()];
|
||||
}
|
||||
|
||||
const MaterialPropertyValue& MaterialFunctor::RuntimeContext::GetMaterialPropertyValue(const Name& propertyName) const
|
||||
const MaterialPropertyValue& MaterialFunctor::RuntimeContext::GetMaterialPropertyValue(const Name& propertyId) const
|
||||
{
|
||||
MaterialPropertyIndex index = m_materialPropertiesLayout->FindPropertyIndex(propertyName);
|
||||
MaterialPropertyIndex index = m_materialPropertiesLayout->FindPropertyIndex(propertyId);
|
||||
return GetMaterialPropertyValue(index);
|
||||
}
|
||||
|
||||
@@ -449,9 +449,9 @@ namespace AZ
|
||||
return m_materialPropertyValues[index.GetIndex()];
|
||||
}
|
||||
|
||||
const MaterialPropertyValue& MaterialFunctor::EditorContext::GetMaterialPropertyValue(const Name& propertyName) const
|
||||
const MaterialPropertyValue& MaterialFunctor::EditorContext::GetMaterialPropertyValue(const Name& propertyId) const
|
||||
{
|
||||
MaterialPropertyIndex index = m_materialPropertiesLayout->FindPropertyIndex(propertyName);
|
||||
MaterialPropertyIndex index = m_materialPropertiesLayout->FindPropertyIndex(propertyId);
|
||||
return GetMaterialPropertyValue(index);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* 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 <Atom/RPI.Reflect/Material/MaterialNameContext.h>
|
||||
#include <AzCore/RTTI/ReflectContext.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/Name/Name.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace RPI
|
||||
{
|
||||
void MaterialNameContext::Reflect(ReflectContext* context)
|
||||
{
|
||||
if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<MaterialNameContext>()
|
||||
->Version(1)
|
||||
->Field("propertyIdContext", &MaterialNameContext::m_propertyIdContext)
|
||||
->Field("srgInputNameContext", &MaterialNameContext::m_srgInputNameContext)
|
||||
->Field("shaderOptionNameContext", &MaterialNameContext::m_shaderOptionNameContext)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
bool MaterialNameContext::IsDefault() const
|
||||
{
|
||||
return m_propertyIdContext.empty() && m_srgInputNameContext.empty() && m_shaderOptionNameContext.empty();
|
||||
}
|
||||
|
||||
void MaterialNameContext::ExtendPropertyIdContext(AZStd::string_view nameContext, bool insertDelimiter)
|
||||
{
|
||||
m_propertyIdContext += nameContext;
|
||||
if (insertDelimiter && !nameContext.empty() && !nameContext.ends_with("."))
|
||||
{
|
||||
m_propertyIdContext += ".";
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialNameContext::ExtendSrgInputContext(AZStd::string_view nameContext)
|
||||
{
|
||||
m_srgInputNameContext += nameContext;
|
||||
}
|
||||
|
||||
void MaterialNameContext::ExtendShaderOptionContext(AZStd::string_view nameContext)
|
||||
{
|
||||
m_shaderOptionNameContext += nameContext;
|
||||
}
|
||||
|
||||
bool MaterialNameContext::ContextualizeProperty(Name& propertyName) const
|
||||
{
|
||||
if (m_propertyIdContext.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
propertyName = m_propertyIdContext + propertyName.GetCStr();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MaterialNameContext::ContextualizeSrgInput(Name& srgInputName) const
|
||||
{
|
||||
if (m_srgInputNameContext.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
srgInputName = m_srgInputNameContext + srgInputName.GetCStr();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MaterialNameContext::ContextualizeShaderOption(Name& shaderOptionName) const
|
||||
{
|
||||
if (m_shaderOptionNameContext.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
shaderOptionName = m_shaderOptionNameContext + shaderOptionName.GetCStr();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MaterialNameContext::ContextualizeProperty(AZStd::string& propertyName) const
|
||||
{
|
||||
if (m_propertyIdContext.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
propertyName = m_propertyIdContext + propertyName;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MaterialNameContext::ContextualizeSrgInput(AZStd::string& srgInputName) const
|
||||
{
|
||||
if (m_srgInputNameContext.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
srgInputName = m_srgInputNameContext + srgInputName;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MaterialNameContext::ContextualizeShaderOption(AZStd::string& shaderOptionName) const
|
||||
{
|
||||
if (m_shaderOptionNameContext.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
shaderOptionName = m_shaderOptionNameContext + shaderOptionName;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MaterialNameContext::HasContextForProperties() const
|
||||
{
|
||||
return !m_propertyIdContext.empty();
|
||||
}
|
||||
|
||||
bool MaterialNameContext::HasContextForSrgInputs() const
|
||||
{
|
||||
return !m_srgInputNameContext.empty();
|
||||
}
|
||||
|
||||
bool MaterialNameContext::HasContextForShaderOptions() const
|
||||
{
|
||||
return !m_shaderOptionNameContext.empty();
|
||||
}
|
||||
} // namespace RPI
|
||||
} // namespace AZ
|
||||
@@ -16,7 +16,6 @@
|
||||
#include <AzCore/IO/ByteContainerStream.h>
|
||||
#include <AzCore/JSON/prettywriter.h>
|
||||
#include <AzCore/Serialization/Json/JsonUtils.h>
|
||||
#include <Atom/RPI.Edit/Common/JsonFileLoadContext.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
@@ -46,17 +45,12 @@ namespace UnitTest
|
||||
|
||||
//! Uses JsonSerialization to load JSON data into a reflected object
|
||||
template<typename T>
|
||||
JsonTestResult LoadTestDataFromJson(T& object, rapidjson::Value& json, AZ::RPI::JsonFileLoadContext* jsonFileLoadContext = nullptr)
|
||||
JsonTestResult LoadTestDataFromJson(T& object, rapidjson::Value& json)
|
||||
{
|
||||
JsonTestResult result;
|
||||
|
||||
AZ::JsonDeserializerSettings settings;
|
||||
|
||||
if (jsonFileLoadContext)
|
||||
{
|
||||
settings.m_metadata.Add(*jsonFileLoadContext);
|
||||
}
|
||||
|
||||
settings.m_reporting = [&result](AZStd::string_view message, AZ::JsonSerializationResult::ResultCode resultCode, AZStd::string_view path)
|
||||
{
|
||||
JsonTestResult::Report report;
|
||||
@@ -74,14 +68,14 @@ namespace UnitTest
|
||||
|
||||
//! Uses JsonSerialization to load JSON data from a string into a reflected object
|
||||
template<typename T>
|
||||
JsonTestResult LoadTestDataFromJson(T& object, AZStd::string_view jsonText, AZ::RPI::JsonFileLoadContext* jsonFileLoadContext = nullptr)
|
||||
JsonTestResult LoadTestDataFromJson(T& object, AZStd::string_view jsonText)
|
||||
{
|
||||
auto parseResult = AZ::JsonSerializationUtils::ReadJsonString(jsonText);
|
||||
|
||||
EXPECT_TRUE(parseResult.IsSuccess()) << parseResult.GetError().c_str();
|
||||
if (parseResult.IsSuccess())
|
||||
{
|
||||
return LoadTestDataFromJson(object, parseResult.GetValue(), jsonFileLoadContext);
|
||||
return LoadTestDataFromJson(object, parseResult.GetValue());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -35,11 +35,14 @@ namespace UnitTest
|
||||
LuaMaterialFunctorSourceData functorSourceData;
|
||||
functorSourceData.m_luaScript = script;
|
||||
|
||||
MaterialNameContext nameContext;
|
||||
|
||||
MaterialFunctorSourceData::RuntimeContext createFunctorContext{
|
||||
"Dummy.materialtype",
|
||||
materialTypeCreator.GetMaterialPropertiesLayout(),
|
||||
materialTypeCreator.GetMaterialShaderResourceGroupLayout(),
|
||||
materialTypeCreator.GetShaderCollection()
|
||||
materialTypeCreator.GetShaderCollection(),
|
||||
&nameContext
|
||||
};
|
||||
|
||||
MaterialFunctorSourceData::FunctorResult result = functorSourceData.CreateFunctor(createFunctorContext);
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
#include <Atom/RPI.Reflect/Material/MaterialTypeAsset.h>
|
||||
#include <Atom/RPI.Reflect/Material/MaterialTypeAssetCreator.h>
|
||||
#include <Atom/RPI.Reflect/Material/MaterialAssetCreator.h>
|
||||
#include <Atom/RPI.Reflect/Material/MaterialNameContext.h>
|
||||
#include <Atom/RPI.Reflect/Shader/ShaderAssetCreator.h>
|
||||
#include <Atom/RPI.Edit/Material/MaterialFunctorSourceData.h>
|
||||
#include <Atom/RPI.Public/Material/Material.h>
|
||||
#include <Material/MaterialAssetTestUtils.h>
|
||||
@@ -256,12 +258,15 @@ namespace UnitTest
|
||||
functorSourceData.m_registedPropertyName = registedPropertyName.GetStringView();
|
||||
functorSourceData.m_unregistedPropertyName = unregistedPropertyName.GetStringView();
|
||||
|
||||
MaterialNameContext nameContext;
|
||||
|
||||
MaterialFunctorSourceData::FunctorResult result = functorSourceData.CreateFunctor(
|
||||
MaterialFunctorSourceData::RuntimeContext(
|
||||
"Dummy.materialtype",
|
||||
materialTypeCreator.GetMaterialPropertiesLayout(),
|
||||
materialTypeCreator.GetMaterialShaderResourceGroupLayout(),
|
||||
materialTypeCreator.GetShaderCollection()
|
||||
materialTypeCreator.GetShaderCollection(),
|
||||
&nameContext
|
||||
)
|
||||
);
|
||||
|
||||
@@ -310,4 +315,169 @@ namespace UnitTest
|
||||
m_testMaterialTypeAsset = {};
|
||||
m_testMaterialAsset = {};
|
||||
}
|
||||
|
||||
TEST_F(MaterialFunctorTests, UseNameContextInFunctorSourceData_PropertyLookup)
|
||||
{
|
||||
class FindPropertyIndexTestFunctor : public MaterialFunctor
|
||||
{
|
||||
public:
|
||||
MaterialPropertyIndex m_foundIndex;
|
||||
};
|
||||
|
||||
class FindPropertyIndexTestFunctorSourceData : public MaterialFunctorSourceData
|
||||
{
|
||||
public:
|
||||
Name m_materialPropertyName;
|
||||
|
||||
using MaterialFunctorSourceData::CreateFunctor;
|
||||
FunctorResult CreateFunctor(const RuntimeContext& runtimeContext) const override
|
||||
{
|
||||
RPI::Ptr<FindPropertyIndexTestFunctor> functor = aznew FindPropertyIndexTestFunctor;
|
||||
functor->m_foundIndex = runtimeContext.FindMaterialPropertyIndex(m_materialPropertyName);
|
||||
return Success(RPI::Ptr<MaterialFunctor>(functor));
|
||||
}
|
||||
};
|
||||
|
||||
Data::Asset<MaterialTypeAsset> materialTypeAsset;
|
||||
MaterialTypeAssetCreator materialTypeCreator;
|
||||
materialTypeCreator.Begin(Uuid::CreateRandom());
|
||||
materialTypeCreator.BeginMaterialProperty(Name{"layer1.baseColor.factor"}, MaterialPropertyDataType::Float);
|
||||
materialTypeCreator.EndMaterialProperty();
|
||||
materialTypeCreator.End(materialTypeAsset);
|
||||
|
||||
FindPropertyIndexTestFunctorSourceData sourceData;
|
||||
sourceData.m_materialPropertyName = "factor";
|
||||
|
||||
MaterialNameContext nameContext;
|
||||
nameContext.ExtendPropertyIdContext("layer1");
|
||||
nameContext.ExtendPropertyIdContext("baseColor");
|
||||
|
||||
MaterialFunctorSourceData::RuntimeContext createFunctorContext(
|
||||
"",
|
||||
materialTypeAsset->GetMaterialPropertiesLayout(),
|
||||
nullptr,
|
||||
nullptr,
|
||||
&nameContext);
|
||||
|
||||
RPI::Ptr<MaterialFunctor> functor = sourceData.CreateFunctor(createFunctorContext).TakeValue();
|
||||
|
||||
EXPECT_TRUE(reinterpret_cast<FindPropertyIndexTestFunctor*>(functor.get())->m_foundIndex.IsValid());
|
||||
}
|
||||
|
||||
TEST_F(MaterialFunctorTests, UseNameContextInFunctorSourceData_ShaderOptionLookup)
|
||||
{
|
||||
class FindShaderOptionIndexTestFunctor : public MaterialFunctor
|
||||
{
|
||||
public:
|
||||
ShaderOptionIndex m_foundIndex;
|
||||
};
|
||||
|
||||
class FindShaderOptionIndexTestFunctorSourceData : public MaterialFunctorSourceData
|
||||
{
|
||||
public:
|
||||
Name m_shaderOptionName;
|
||||
|
||||
using MaterialFunctorSourceData::CreateFunctor;
|
||||
FunctorResult CreateFunctor(const RuntimeContext& runtimeContext) const override
|
||||
{
|
||||
RPI::Ptr<FindShaderOptionIndexTestFunctor> functor = aznew FindShaderOptionIndexTestFunctor;
|
||||
functor->m_foundIndex = runtimeContext.FindShaderOptionIndex(0, m_shaderOptionName);
|
||||
return Success(RPI::Ptr<MaterialFunctor>(functor));
|
||||
}
|
||||
};
|
||||
|
||||
RPI::Ptr<RPI::ShaderOptionGroupLayout> shaderOptionLayout = RPI::ShaderOptionGroupLayout::Create();
|
||||
shaderOptionLayout->AddShaderOption(
|
||||
RPI::ShaderOptionDescriptor{Name("o_layer1_baseColor_useTexture"), RPI::ShaderOptionType::Boolean, 0, 0, CreateBoolShaderOptionValues()});
|
||||
shaderOptionLayout->Finalize();
|
||||
|
||||
Data::Asset<ShaderAsset> shaderAsset = CreateTestShaderAsset(Uuid::CreateRandom(), nullptr, shaderOptionLayout);
|
||||
|
||||
Data::Asset<MaterialTypeAsset> materialTypeAsset;
|
||||
MaterialTypeAssetCreator materialTypeCreator;
|
||||
materialTypeCreator.Begin(Uuid::CreateRandom());
|
||||
materialTypeCreator.AddShader(shaderAsset);
|
||||
materialTypeCreator.End(materialTypeAsset);
|
||||
|
||||
FindShaderOptionIndexTestFunctorSourceData sourceData;
|
||||
sourceData.m_shaderOptionName = "useTexture";
|
||||
|
||||
MaterialNameContext nameContext;
|
||||
nameContext.ExtendShaderOptionContext("o_layer1_baseColor_");
|
||||
|
||||
MaterialFunctorSourceData::RuntimeContext createFunctorContext(
|
||||
"",
|
||||
nullptr,
|
||||
nullptr,
|
||||
&materialTypeAsset->GetShaderCollection(),
|
||||
&nameContext);
|
||||
|
||||
RPI::Ptr<MaterialFunctor> functor = sourceData.CreateFunctor(createFunctorContext).TakeValue();
|
||||
|
||||
EXPECT_TRUE(reinterpret_cast<FindShaderOptionIndexTestFunctor*>(functor.get())->m_foundIndex.IsValid());
|
||||
}
|
||||
|
||||
TEST_F(MaterialFunctorTests, UseNameContextInFunctorSourceData_ShaderConstantLookup)
|
||||
{
|
||||
class FindShaderInputIndexTestFunctor : public MaterialFunctor
|
||||
{
|
||||
public:
|
||||
RHI::ShaderInputConstantIndex m_foundConstantIndex;
|
||||
RHI::ShaderInputImageIndex m_foundImageIndex;
|
||||
};
|
||||
|
||||
class FindShaderInputIndexTestFunctorSourceData : public MaterialFunctorSourceData
|
||||
{
|
||||
public:
|
||||
Name m_shaderConstantName;
|
||||
Name m_shaderImageName;
|
||||
|
||||
using MaterialFunctorSourceData::CreateFunctor;
|
||||
FunctorResult CreateFunctor(const RuntimeContext& runtimeContext) const override
|
||||
{
|
||||
RPI::Ptr<FindShaderInputIndexTestFunctor> functor = aznew FindShaderInputIndexTestFunctor;
|
||||
functor->m_foundConstantIndex = runtimeContext.FindShaderInputConstantIndex(m_shaderConstantName);
|
||||
functor->m_foundImageIndex = runtimeContext.FindShaderInputImageIndex(m_shaderImageName);
|
||||
return Success(RPI::Ptr<MaterialFunctor>(functor));
|
||||
}
|
||||
};
|
||||
|
||||
AZ::RHI::Ptr<AZ::RHI::ShaderResourceGroupLayout> srgLayout = RHI::ShaderResourceGroupLayout::Create();
|
||||
srgLayout->SetName(Name("MaterialSrg"));
|
||||
srgLayout->SetUniqueId(Uuid::CreateRandom().ToString<AZStd::string>()); // Any random string will suffice.
|
||||
srgLayout->SetBindingSlot(SrgBindingSlot::Material);
|
||||
srgLayout->AddShaderInput(RHI::ShaderInputConstantDescriptor{Name{ "m_layer1_baseColor_factor" }, 0, 4, 0});
|
||||
srgLayout->AddShaderInput(RHI::ShaderInputImageDescriptor{Name{ "m_layer1_baseColor_texture" }, RHI::ShaderInputImageAccess::Read, RHI::ShaderInputImageType::Image2D, 1, 1});
|
||||
srgLayout->Finalize();
|
||||
|
||||
Data::Asset<ShaderAsset> shaderAsset = CreateTestShaderAsset(Uuid::CreateRandom(), srgLayout);
|
||||
|
||||
Data::Asset<MaterialTypeAsset> materialTypeAsset;
|
||||
MaterialTypeAssetCreator materialTypeCreator;
|
||||
materialTypeCreator.Begin(Uuid::CreateRandom());
|
||||
materialTypeCreator.AddShader(shaderAsset);
|
||||
materialTypeCreator.End(materialTypeAsset);
|
||||
|
||||
FindShaderInputIndexTestFunctorSourceData sourceData;
|
||||
sourceData.m_shaderConstantName = "factor";
|
||||
sourceData.m_shaderImageName = "texture";
|
||||
|
||||
MaterialNameContext nameContext;
|
||||
nameContext.ExtendSrgInputContext("m_layer1_baseColor_");
|
||||
|
||||
MaterialFunctorSourceData::RuntimeContext createFunctorContext(
|
||||
"",
|
||||
nullptr,
|
||||
srgLayout.get(),
|
||||
nullptr,
|
||||
&nameContext);
|
||||
|
||||
RPI::Ptr<MaterialFunctor> functor = sourceData.CreateFunctor(createFunctorContext).TakeValue();
|
||||
|
||||
EXPECT_TRUE(reinterpret_cast<FindShaderInputIndexTestFunctor*>(functor.get())->m_foundConstantIndex.IsValid());
|
||||
EXPECT_TRUE(reinterpret_cast<FindShaderInputIndexTestFunctor*>(functor.get())->m_foundImageIndex.IsValid());
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <Atom/RPI.Reflect/Material/MaterialTypeAsset.h>
|
||||
#include <Atom/RPI.Reflect/Material/MaterialPropertiesLayout.h>
|
||||
#include <Atom/RPI.Reflect/Material/MaterialTypeAssetCreator.h>
|
||||
#include <Atom/RPI.Reflect/Material/MaterialNameContext.h>
|
||||
|
||||
namespace JsonSerializationTests
|
||||
{
|
||||
@@ -256,13 +257,16 @@ namespace UnitTest
|
||||
|
||||
JsonTestResult loadResult = LoadTestDataFromJson(*functorData, inputJson);
|
||||
|
||||
MaterialNameContext nameContext;
|
||||
|
||||
// Where type resolving happens.
|
||||
MaterialFunctorSourceData::FunctorResult functorResult = functorData->CreateFunctor(
|
||||
MaterialFunctorSourceData::RuntimeContext(
|
||||
"Dummy.materialtype",
|
||||
m_materialTypeCreator.GetMaterialPropertiesLayout(),
|
||||
m_materialTypeCreator.GetMaterialShaderResourceGroupLayout(),
|
||||
m_materialTypeCreator.GetShaderCollection()
|
||||
m_materialTypeCreator.GetShaderCollection(),
|
||||
&nameContext
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
@@ -16,11 +16,14 @@
|
||||
#include <Atom/RPI.Edit/Material/MaterialTypeSourceData.h>
|
||||
#include <Atom/RPI.Edit/Common/AssetUtils.h>
|
||||
#include <Atom/RPI.Edit/Material/MaterialFunctorSourceDataRegistration.h>
|
||||
#include <Atom/RPI.Edit/Material/MaterialUtils.h>
|
||||
#include <Atom/RPI.Reflect/Image/StreamingImageAsset.h>
|
||||
#include <Atom/RPI.Reflect/Shader/ShaderOptionGroup.h>
|
||||
#include <Atom/RPI.Reflect/Material/MaterialNameContext.h>
|
||||
#include <Atom/RPI.Public/Shader/ShaderResourceGroup.h>
|
||||
#include <Atom/RPI.Public/Material/Material.h>
|
||||
|
||||
#include <AzCore/Utils/Utils.h>
|
||||
#include <AzCore/Serialization/Json/JsonUtils.h>
|
||||
#include <AzCore/Serialization/Json/JsonSerialization.h>
|
||||
#include <AzFramework/StringFunc/StringFunc.h>
|
||||
@@ -35,6 +38,7 @@ namespace UnitTest
|
||||
{
|
||||
protected:
|
||||
|
||||
AZ::IO::FixedMaxPath m_tempFolder;
|
||||
RHI::Ptr<RHI::ShaderResourceGroupLayout> m_testMaterialSrgLayout;
|
||||
Data::Asset<ShaderAsset> m_testShaderAsset;
|
||||
Data::Asset<ShaderAsset> m_testShaderAsset2;
|
||||
@@ -249,6 +253,59 @@ namespace UnitTest
|
||||
AZStd::string m_enablePropertyName;
|
||||
};
|
||||
|
||||
// All this functor does is save the MaterialNameContext
|
||||
class SaveNameContextTestFunctor final
|
||||
: public AZ::RPI::MaterialFunctor
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(SaveNameContextTestFunctor, "{FD680069-B430-4278-9E5B-A2B9617627D5}", AZ::RPI::MaterialFunctor);
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<SaveNameContextTestFunctor, AZ::RPI::MaterialFunctor>()
|
||||
->Version(1)
|
||||
->Field("nameContext", &SaveNameContextTestFunctor::m_nameContext);
|
||||
}
|
||||
}
|
||||
|
||||
using AZ::RPI::MaterialFunctor::Process;
|
||||
void Process(AZ::RPI::MaterialFunctor::RuntimeContext&) override
|
||||
{
|
||||
// Intentionally empty, this is where the functor would do it's normal processing,
|
||||
// but all this test functor does is store the MaterialNameContext.
|
||||
}
|
||||
|
||||
MaterialNameContext m_nameContext;
|
||||
};
|
||||
|
||||
// All this functor does is save the MaterialNameContext
|
||||
class SaveNameContextTestFunctorSourceData final
|
||||
: public MaterialFunctorSourceData
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(SaveNameContextTestFunctorSourceData, "{4261A2EC-4AB6-420E-884A-18D1A36500BE}", MaterialFunctorSourceData);
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<SaveNameContextTestFunctorSourceData>()
|
||||
->Version(1)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
using MaterialFunctorSourceData::CreateFunctor;
|
||||
FunctorResult CreateFunctor([[maybe_unused]] const RuntimeContext& context) const override
|
||||
{
|
||||
Ptr<SaveNameContextTestFunctor> functor = aznew SaveNameContextTestFunctor;
|
||||
functor->m_nameContext = *context.GetNameContext();
|
||||
return Success(Ptr<MaterialFunctor>(functor));
|
||||
}
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Reflect(ReflectContext* context) override
|
||||
@@ -262,6 +319,7 @@ namespace UnitTest
|
||||
Splat3FunctorSourceData::Reflect(context);
|
||||
EnableShaderFunctorSourceData::Reflect(context);
|
||||
SetShaderOptionFunctorSourceData::Reflect(context);
|
||||
SaveNameContextTestFunctorSourceData::Reflect(context);
|
||||
}
|
||||
|
||||
void SetUp() override
|
||||
@@ -273,6 +331,7 @@ namespace UnitTest
|
||||
AZ::RPI::MaterialFunctorSourceDataRegistration::Get()->RegisterMaterialFunctor("Splat3", azrtti_typeid<Splat3FunctorSourceData>());
|
||||
AZ::RPI::MaterialFunctorSourceDataRegistration::Get()->RegisterMaterialFunctor("EnableShader", azrtti_typeid<EnableShaderFunctorSourceData>());
|
||||
AZ::RPI::MaterialFunctorSourceDataRegistration::Get()->RegisterMaterialFunctor("SetShaderOption", azrtti_typeid<SetShaderOptionFunctorSourceData>());
|
||||
AZ::RPI::MaterialFunctorSourceDataRegistration::Get()->RegisterMaterialFunctor("SaveNameContext", azrtti_typeid<SaveNameContextTestFunctorSourceData>());
|
||||
|
||||
const Name materialSrgId{"MaterialSrg"};
|
||||
m_testMaterialSrgLayout = RHI::ShaderResourceGroupLayout::Create();
|
||||
@@ -326,6 +385,9 @@ namespace UnitTest
|
||||
AZStd::string testImageFilepathAbsolute(TestImageFilepathAbsolute);
|
||||
AzFramework::StringFunc::Path::Normalize(testImageFilepathAbsolute);
|
||||
m_assetSystemStub.RegisterSourceInfo(testImageFilepathAbsolute.c_str(), testImageAssetInfo2, "");
|
||||
|
||||
m_tempFolder = AZ::Utils::GetExecutableDirectory();
|
||||
m_tempFolder = m_tempFolder/"temp"/"MaterialTypeSourceDataTest";
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
@@ -426,54 +488,62 @@ namespace UnitTest
|
||||
|
||||
struct EnumeratePropertyGroupsResult
|
||||
{
|
||||
AZStd::string m_propertyIdContext;
|
||||
const MaterialTypeSourceData::PropertyGroup* m_propertyGroup;
|
||||
MaterialNameContext m_nameContext;
|
||||
|
||||
void Check(AZStd::string expectedIdContext, const MaterialTypeSourceData::PropertyGroup* expectedPropertyGroup)
|
||||
void Check(AZStd::string expectedGroupId)
|
||||
{
|
||||
EXPECT_EQ(expectedIdContext, m_propertyIdContext);
|
||||
EXPECT_EQ(expectedPropertyGroup, m_propertyGroup);
|
||||
Name imaginaryProperty{"someChildProperty"};
|
||||
m_nameContext.ContextualizeProperty(imaginaryProperty);
|
||||
|
||||
EXPECT_EQ(expectedGroupId + ".someChildProperty", imaginaryProperty.GetStringView());
|
||||
}
|
||||
};
|
||||
AZStd::vector<EnumeratePropertyGroupsResult> enumeratePropertyGroupsResults;
|
||||
|
||||
sourceData.EnumeratePropertyGroups([&enumeratePropertyGroupsResults](const AZStd::string& propertyIdContext, const MaterialTypeSourceData::PropertyGroup* propertyGroup)
|
||||
sourceData.EnumeratePropertyGroups([&enumeratePropertyGroupsResults](
|
||||
const MaterialTypeSourceData::PropertyGroupStack& propertyGroupStack)
|
||||
{
|
||||
enumeratePropertyGroupsResults.push_back(EnumeratePropertyGroupsResult{propertyIdContext, propertyGroup});
|
||||
MaterialNameContext nameContext = MaterialTypeSourceData::MakeMaterialNameContext(propertyGroupStack);
|
||||
enumeratePropertyGroupsResults.push_back(EnumeratePropertyGroupsResult{nameContext});
|
||||
return true;
|
||||
});
|
||||
|
||||
int resultIndex = 0;
|
||||
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);
|
||||
enumeratePropertyGroupsResults[resultIndex++].Check("layer1");
|
||||
enumeratePropertyGroupsResults[resultIndex++].Check("layer1.baseColor");
|
||||
enumeratePropertyGroupsResults[resultIndex++].Check("layer1.roughness");
|
||||
enumeratePropertyGroupsResults[resultIndex++].Check("layer2");
|
||||
enumeratePropertyGroupsResults[resultIndex++].Check("layer2.baseColor");
|
||||
enumeratePropertyGroupsResults[resultIndex++].Check("layer2.roughness");
|
||||
enumeratePropertyGroupsResults[resultIndex++].Check("layer2.clearCoat");
|
||||
enumeratePropertyGroupsResults[resultIndex++].Check("layer2.clearCoat.roughness");
|
||||
enumeratePropertyGroupsResults[resultIndex++].Check("layer2.clearCoat.normal");
|
||||
enumeratePropertyGroupsResults[resultIndex++].Check("blend");
|
||||
EXPECT_EQ(resultIndex, enumeratePropertyGroupsResults.size());
|
||||
|
||||
// Check EnumerateProperties
|
||||
|
||||
struct EnumeratePropertiesResult
|
||||
{
|
||||
AZStd::string m_propertyIdContext;
|
||||
const MaterialTypeSourceData::PropertyDefinition* m_propertyDefinition;
|
||||
MaterialNameContext m_materialNameContext;
|
||||
|
||||
void Check(AZStd::string expectedIdContext, const MaterialTypeSourceData::PropertyDefinition* expectedPropertyDefinition)
|
||||
{
|
||||
EXPECT_EQ(expectedIdContext, m_propertyIdContext);
|
||||
Name propertyFullId{m_propertyDefinition->GetName()};
|
||||
m_materialNameContext.ContextualizeProperty(propertyFullId);
|
||||
|
||||
AZStd::string expectedPropertyId = expectedIdContext + expectedPropertyDefinition->GetName();
|
||||
|
||||
EXPECT_EQ(expectedPropertyId, propertyFullId.GetStringView());
|
||||
EXPECT_EQ(expectedPropertyDefinition, m_propertyDefinition);
|
||||
}
|
||||
};
|
||||
AZStd::vector<EnumeratePropertiesResult> enumeratePropertiesResults;
|
||||
|
||||
sourceData.EnumerateProperties([&enumeratePropertiesResults](const AZStd::string& propertyIdContext, const MaterialTypeSourceData::PropertyDefinition* propertyDefinition)
|
||||
sourceData.EnumerateProperties([&enumeratePropertiesResults](const MaterialTypeSourceData::PropertyDefinition* propertyDefinition, const MaterialNameContext& nameContext)
|
||||
{
|
||||
enumeratePropertiesResults.push_back(EnumeratePropertiesResult{propertyIdContext, propertyDefinition});
|
||||
enumeratePropertiesResults.push_back(EnumeratePropertiesResult{propertyDefinition, nameContext});
|
||||
return true;
|
||||
});
|
||||
|
||||
@@ -1462,6 +1532,8 @@ namespace UnitTest
|
||||
{
|
||||
// Note that serialization of individual fields within material properties is thoroughly tested in
|
||||
// MaterialPropertySerializerTests, so the sample property data used here is cursory.
|
||||
// We also don't cover fields related to providing name contexts for nested property groups, like
|
||||
// "shaderInputsPrefix" and "shaderOptionsPrefix" as those are covered in CreateMaterialTypeAsset_NestedGroups*.
|
||||
|
||||
const AZStd::string inputJson = R"(
|
||||
{
|
||||
@@ -1690,7 +1762,7 @@ namespace UnitTest
|
||||
JsonTestResult storeResult = StoreTestDataToJson(material, outputJson);
|
||||
ExpectSimilarJson(inputJson, outputJson);
|
||||
}
|
||||
|
||||
|
||||
TEST_F(MaterialTypeSourceDataTests, LoadAllFieldsUsingOldFormat)
|
||||
{
|
||||
// The content of this test was copied from LoadAndStoreJson_AllFields to prove backward compatibility.
|
||||
@@ -1952,4 +2024,213 @@ namespace UnitTest
|
||||
|
||||
errorMessageFinder.CheckExpectedErrorsFound();
|
||||
}
|
||||
|
||||
TEST_F(MaterialTypeSourceDataTests, LoadWithImportedJson)
|
||||
{
|
||||
const AZStd::string propertyGroupJson = R"(
|
||||
{
|
||||
"name": "myGroup",
|
||||
"displayName": "My Group",
|
||||
"description": "This group is defined in a separate JSON file",
|
||||
"properties": [
|
||||
{
|
||||
"name": "foo",
|
||||
"type": "Bool"
|
||||
},
|
||||
{
|
||||
"name": "bar",
|
||||
"type": "Float"
|
||||
}
|
||||
]
|
||||
}
|
||||
)";
|
||||
|
||||
IO::FixedMaxPath propertyGroupJsonFilePath = m_tempFolder/"MyPropertyGroup.json";
|
||||
AZ::Utils::WriteFile(propertyGroupJson, propertyGroupJsonFilePath.c_str());
|
||||
|
||||
const AZStd::string materialTypeJson = R"(
|
||||
{
|
||||
"propertyLayout": {
|
||||
"propertyGroups": [
|
||||
{ "$import": "MyPropertyGroup.json" }
|
||||
]
|
||||
}
|
||||
}
|
||||
)";
|
||||
|
||||
IO::FixedMaxPath materialTypeJsonFilePath = m_tempFolder/"TestImport.materialtype";
|
||||
AZ::Utils::WriteFile(materialTypeJson, materialTypeJsonFilePath.c_str());
|
||||
|
||||
auto loadMaterialTypeResult = MaterialUtils::LoadMaterialTypeSourceData(materialTypeJsonFilePath.c_str());
|
||||
EXPECT_TRUE(loadMaterialTypeResult);
|
||||
MaterialTypeSourceData materialType = loadMaterialTypeResult.TakeValue();
|
||||
|
||||
EXPECT_EQ(materialType.GetPropertyLayout().m_propertyGroups.size(), 1);
|
||||
EXPECT_TRUE(materialType.FindPropertyGroup("myGroup") != nullptr);
|
||||
EXPECT_EQ(materialType.FindPropertyGroup("myGroup")->GetDisplayName(), "My Group");
|
||||
EXPECT_EQ(materialType.FindPropertyGroup("myGroup")->GetDescription(), "This group is defined in a separate JSON file");
|
||||
EXPECT_EQ(materialType.FindPropertyGroup("myGroup")->GetProperties().size(), 2);
|
||||
EXPECT_NE(materialType.FindProperty("myGroup.foo"), nullptr);
|
||||
EXPECT_NE(materialType.FindProperty("myGroup.bar"), nullptr);
|
||||
EXPECT_EQ(materialType.FindProperty("myGroup.foo")->GetName(), "foo");
|
||||
EXPECT_EQ(materialType.FindProperty("myGroup.bar")->GetName(), "bar");
|
||||
EXPECT_EQ(materialType.FindProperty("myGroup.foo")->m_dataType, MaterialPropertyDataType::Bool);
|
||||
EXPECT_EQ(materialType.FindProperty("myGroup.bar")->m_dataType, MaterialPropertyDataType::Float);
|
||||
}
|
||||
|
||||
TEST_F(MaterialTypeSourceDataTests, CreateMaterialTypeAsset_NestedGroupNameContext)
|
||||
{
|
||||
const Name materialSrgId{"MaterialSrg"};
|
||||
RHI::Ptr<RHI::ShaderResourceGroupLayout> materialSrgLayout = RHI::ShaderResourceGroupLayout::Create();
|
||||
materialSrgLayout->SetName(materialSrgId);
|
||||
materialSrgLayout->SetBindingSlot(SrgBindingSlot::Material);
|
||||
materialSrgLayout->AddShaderInput(RHI::ShaderInputImageDescriptor{ Name{ "m_unused1" }, RHI::ShaderInputImageAccess::Read, RHI::ShaderInputImageType::Image2D, 1, 1 });
|
||||
materialSrgLayout->AddShaderInput(RHI::ShaderInputImageDescriptor{ Name{ "m_unused2" }, RHI::ShaderInputImageAccess::Read, RHI::ShaderInputImageType::Image2D, 1, 1 });
|
||||
materialSrgLayout->AddShaderInput(RHI::ShaderInputImageDescriptor{ Name{ "m_groupA_m_groupB_m_texture" }, RHI::ShaderInputImageAccess::Read, RHI::ShaderInputImageType::Image2D, 1, 1 });
|
||||
materialSrgLayout->AddShaderInput(RHI::ShaderInputConstantDescriptor{ Name{ "m_unused3" }, 0, 4, 0 });
|
||||
materialSrgLayout->AddShaderInput(RHI::ShaderInputConstantDescriptor{ Name{ "m_groupA_m_groupB_m_number" }, 4, 4, 0 });
|
||||
EXPECT_TRUE(materialSrgLayout->Finalize());
|
||||
|
||||
Ptr<ShaderOptionGroupLayout> shaderOptions = ShaderOptionGroupLayout::Create();
|
||||
shaderOptions->AddShaderOption(ShaderOptionDescriptor{Name{"o_unused"}, ShaderOptionType::Boolean, 0, 0, CreateBoolShaderOptionValues()});
|
||||
shaderOptions->AddShaderOption(ShaderOptionDescriptor{Name{"o_groupA_o_groupB_o_useTexture"}, ShaderOptionType::Boolean, 1, 1, CreateBoolShaderOptionValues()});
|
||||
shaderOptions->AddShaderOption(ShaderOptionDescriptor{Name{"o_groupA_o_groupB_o_useTextureAlt"}, ShaderOptionType::Boolean, 2, 2, CreateBoolShaderOptionValues()});
|
||||
shaderOptions->Finalize();
|
||||
|
||||
Data::Asset<ShaderAsset> shaderAsset = CreateTestShaderAsset(Uuid::CreateRandom(), materialSrgLayout, shaderOptions);
|
||||
|
||||
Data::AssetInfo testShaderAssetInfo;
|
||||
testShaderAssetInfo.m_assetId = shaderAsset.GetId();
|
||||
m_assetSystemStub.RegisterSourceInfo("NestedGroupNameContext.shader", testShaderAssetInfo, "");
|
||||
|
||||
const AZStd::string materialTypeJson = R"(
|
||||
{
|
||||
"propertyLayout": {
|
||||
"propertyGroups": [
|
||||
{
|
||||
"name": "groupA",
|
||||
"shaderInputsPrefix": "m_groupA_",
|
||||
"shaderOptionsPrefix": "o_groupA_",
|
||||
"propertyGroups": [
|
||||
{
|
||||
"name": "groupB",
|
||||
"shaderInputsPrefix": "m_groupB_",
|
||||
"shaderOptionsPrefix": "o_groupB_",
|
||||
"properties": [
|
||||
{
|
||||
"name": "number",
|
||||
"type": "Float",
|
||||
"connection": {
|
||||
"type": "ShaderInput",
|
||||
"name": "m_number"
|
||||
}
|
||||
}
|
||||
],
|
||||
"propertyGroups": [
|
||||
{
|
||||
"name": "groupC",
|
||||
"properties": [
|
||||
{
|
||||
"name": "textureMap",
|
||||
"type": "Image",
|
||||
"connection": {
|
||||
"type": "ShaderInput",
|
||||
"name": "m_texture"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "useTextureMap",
|
||||
"type": "Bool",
|
||||
"connection": [
|
||||
{
|
||||
"type": "ShaderOption",
|
||||
"name": "o_useTexture"
|
||||
},
|
||||
{
|
||||
"type": "ShaderOption",
|
||||
"name": "o_useTextureAlt",
|
||||
"shaderIndex": 0 // Having a specific shaderIndex traverses a different code path
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"functors": [
|
||||
{
|
||||
"type": "SaveNameContext"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"shaders": [
|
||||
{
|
||||
"file": "NestedGroupNameContext.shader"
|
||||
}
|
||||
]
|
||||
}
|
||||
)";
|
||||
|
||||
MaterialTypeSourceData materialTypeSourceData;
|
||||
JsonTestResult loadResult = LoadTestDataFromJson(materialTypeSourceData, materialTypeJson);
|
||||
|
||||
auto materialTypeAssetOutcome = materialTypeSourceData.CreateMaterialTypeAsset(Uuid::CreateRandom());
|
||||
EXPECT_TRUE(materialTypeAssetOutcome.IsSuccess());
|
||||
|
||||
Data::Asset<MaterialTypeAsset> materialTypeAsset = materialTypeAssetOutcome.TakeValue();
|
||||
const MaterialPropertiesLayout* propertiesLayout = materialTypeAsset->GetMaterialPropertiesLayout();
|
||||
|
||||
EXPECT_EQ(3, propertiesLayout->GetPropertyCount());
|
||||
|
||||
EXPECT_EQ(0, propertiesLayout->FindPropertyIndex(Name("groupA.groupB.number")).GetIndex());
|
||||
EXPECT_EQ(1, propertiesLayout->FindPropertyIndex(Name("groupA.groupB.groupC.textureMap")).GetIndex());
|
||||
EXPECT_EQ(2, propertiesLayout->FindPropertyIndex(Name("groupA.groupB.groupC.useTextureMap")).GetIndex());
|
||||
|
||||
// groupA.groupB.number has a connection to m_groupA_m_groupB_m_number
|
||||
MaterialPropertyIndex numberPropertyIndex{0};
|
||||
EXPECT_EQ(1, propertiesLayout->GetPropertyDescriptor(numberPropertyIndex)->GetOutputConnections().size());
|
||||
EXPECT_EQ(materialSrgLayout->FindShaderInputConstantIndex(Name("m_groupA_m_groupB_m_number")).GetIndex(),
|
||||
propertiesLayout->GetPropertyDescriptor(numberPropertyIndex)->GetOutputConnections()[0].m_itemIndex.GetIndex());
|
||||
|
||||
// groupA.gropuB.groupC.textureMap has a connection to m_groupA_m_groupB_m_texture
|
||||
MaterialPropertyIndex texturePropertyIndex{1};
|
||||
EXPECT_EQ(1, propertiesLayout->GetPropertyDescriptor(texturePropertyIndex)->GetOutputConnections().size());
|
||||
EXPECT_EQ(materialSrgLayout->FindShaderInputImageIndex(Name("m_groupA_m_groupB_m_texture")).GetIndex(),
|
||||
propertiesLayout->GetPropertyDescriptor(texturePropertyIndex)->GetOutputConnections()[0].m_itemIndex.GetIndex());
|
||||
|
||||
// groupA.gropuB.groupC.useTextureMap has a connection to o_groupA_o_groupB_o_useTexture and o_groupA_o_groupB_o_useTextureAlt
|
||||
MaterialPropertyIndex useTexturePropertyIndex{2};
|
||||
EXPECT_EQ(2, propertiesLayout->GetPropertyDescriptor(useTexturePropertyIndex)->GetOutputConnections().size());
|
||||
EXPECT_EQ(shaderOptions->FindShaderOptionIndex(Name("o_groupA_o_groupB_o_useTexture")).GetIndex(),
|
||||
propertiesLayout->GetPropertyDescriptor(useTexturePropertyIndex)->GetOutputConnections()[0].m_itemIndex.GetIndex());
|
||||
EXPECT_EQ(shaderOptions->FindShaderOptionIndex(Name("o_groupA_o_groupB_o_useTextureAlt")).GetIndex(),
|
||||
propertiesLayout->GetPropertyDescriptor(useTexturePropertyIndex)->GetOutputConnections()[1].m_itemIndex.GetIndex());
|
||||
|
||||
// There should be one functor, which processes useTextureMap, and it should have the appropriate name context for constructing the correct full names.
|
||||
EXPECT_EQ(1, materialTypeAsset->GetMaterialFunctors().size());
|
||||
|
||||
EXPECT_TRUE(azrtti_istypeof<SaveNameContextTestFunctor>(materialTypeAsset->GetMaterialFunctors()[0].get()));
|
||||
|
||||
auto saveNameContextFunctor = azrtti_cast<SaveNameContextTestFunctor*>(materialTypeAsset->GetMaterialFunctors()[0].get());
|
||||
const MaterialNameContext& nameContext = saveNameContextFunctor->m_nameContext;
|
||||
|
||||
Name textureMapProperty{"textureMap"};
|
||||
Name textureMapShaderInput{"m_texture"};
|
||||
Name useTextureMapProperty{"useTextureMap"};
|
||||
Name useTextureShaderOption{"o_useTexture"};
|
||||
|
||||
nameContext.ContextualizeProperty(textureMapProperty);
|
||||
nameContext.ContextualizeProperty(useTextureMapProperty);
|
||||
nameContext.ContextualizeSrgInput(textureMapShaderInput);
|
||||
nameContext.ContextualizeShaderOption(useTextureShaderOption);
|
||||
|
||||
EXPECT_EQ("groupA.groupB.groupC.useTextureMap", useTextureMapProperty.GetStringView());
|
||||
EXPECT_EQ("o_groupA_o_groupB_o_useTexture", useTextureShaderOption.GetStringView());
|
||||
EXPECT_EQ("groupA.groupB.groupC.textureMap", textureMapProperty.GetStringView());
|
||||
EXPECT_EQ("m_groupA_m_groupB_m_texture", textureMapShaderInput.GetStringView());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ set(FILES
|
||||
Include/Atom/RPI.Edit/Common/AssetAliasesSourceData.h
|
||||
Include/Atom/RPI.Edit/Common/ColorUtils.h
|
||||
Include/Atom/RPI.Edit/Common/ConvertibleSource.h
|
||||
Include/Atom/RPI.Edit/Common/JsonFileLoadContext.h
|
||||
Include/Atom/RPI.Edit/Common/JsonReportingHelper.h
|
||||
Include/Atom/RPI.Edit/Common/JsonUtils.h
|
||||
Include/Atom/RPI.Edit/Material/LuaMaterialFunctorSourceData.h
|
||||
@@ -56,7 +55,6 @@ set(FILES
|
||||
Source/RPI.Edit/Common/AssetAliasesSourceData.cpp
|
||||
Source/RPI.Edit/Common/ColorUtils.cpp
|
||||
Source/RPI.Edit/Common/ConvertibleSource.cpp
|
||||
Source/RPI.Edit/Common/JsonFileLoadContext.cpp
|
||||
Source/RPI.Edit/Common/JsonReportingHelper.cpp
|
||||
Source/RPI.Edit/Common/JsonUtils.cpp
|
||||
)
|
||||
|
||||
@@ -53,6 +53,7 @@ set(FILES
|
||||
Include/Atom/RPI.Reflect/Material/MaterialAsset.h
|
||||
Include/Atom/RPI.Reflect/Material/MaterialAssetCreator.h
|
||||
Include/Atom/RPI.Reflect/Material/MaterialDynamicMetadata.h
|
||||
Include/Atom/RPI.Reflect/Material/MaterialNameContext.h
|
||||
Include/Atom/RPI.Reflect/Material/MaterialPropertyDescriptor.h
|
||||
Include/Atom/RPI.Reflect/Material/MaterialPropertiesLayout.h
|
||||
Include/Atom/RPI.Reflect/Material/MaterialPropertyValue.h
|
||||
@@ -133,6 +134,7 @@ set(FILES
|
||||
Source/RPI.Reflect/Material/MaterialPropertyValue.cpp
|
||||
Source/RPI.Reflect/Material/MaterialAsset.cpp
|
||||
Source/RPI.Reflect/Material/MaterialAssetCreator.cpp
|
||||
Source/RPI.Reflect/Material/MaterialNameContext.cpp
|
||||
Source/RPI.Reflect/Material/LuaMaterialFunctor.cpp
|
||||
Source/RPI.Reflect/Material/MaterialDynamicMetadata.cpp
|
||||
Source/RPI.Reflect/Material/MaterialPropertyDescriptor.cpp
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <Atom/RPI.Public/Material/Material.h>
|
||||
#include <Atom/RPI.Reflect/Material/MaterialFunctor.h>
|
||||
#include <Atom/RPI.Reflect/Material/MaterialPropertiesLayout.h>
|
||||
#include <Atom/RPI.Reflect/Material/MaterialNameContext.h>
|
||||
#include <AtomCore/Instance/Instance.h>
|
||||
#include <AtomToolsFramework/Document/AtomToolsDocumentNotificationBus.h>
|
||||
#include <AtomToolsFramework/Util/MaterialPropertyUtil.h>
|
||||
@@ -335,9 +336,10 @@ namespace MaterialEditor
|
||||
bool addPropertiesResult = true;
|
||||
|
||||
// populate sourceData with properties that meet the filter
|
||||
m_materialTypeSourceData.EnumerateProperties([&, this](const AZStd::string& propertyIdContext, const auto& propertyDefinition) {
|
||||
m_materialTypeSourceData.EnumerateProperties([&](const auto& propertyDefinition, const AZ::RPI::MaterialNameContext& nameContext) {
|
||||
|
||||
AZ::Name propertyId{propertyIdContext + propertyDefinition->GetName()};
|
||||
AZ::Name propertyId{propertyDefinition->GetName()};
|
||||
nameContext.ContextualizeProperty(propertyId);
|
||||
|
||||
const auto property = FindProperty(propertyId);
|
||||
if (property && propertyFilter(*property))
|
||||
@@ -352,9 +354,7 @@ namespace MaterialEditor
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: Support populating the Material Editor with nested property groups, not just the top level.
|
||||
AZStd::string_view groupName = propertyId.GetStringView().substr(0, propertyId.GetStringView().size() - propertyDefinition->GetName().size() - 1);
|
||||
sourceData.SetPropertyValue(AZ::RPI::MaterialPropertyId{groupName, propertyDefinition->GetName()}, propertyValue);
|
||||
sourceData.SetPropertyValue(propertyId, propertyValue);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@@ -551,25 +551,43 @@ namespace MaterialEditor
|
||||
// Assets must still be used for now because they contain the final accumulated value after all other materials
|
||||
// in the hierarchy are applied
|
||||
bool enumerateResult = m_materialTypeSourceData.EnumeratePropertyGroups(
|
||||
[this, &parentPropertyValues](
|
||||
const AZStd::string& propertyIdContext, const AZ::RPI::MaterialTypeSourceData::PropertyGroup* propertyGroup)
|
||||
[this, &parentPropertyValues](const AZ::RPI::MaterialTypeSourceData::PropertyGroupStack& propertyGroupStack)
|
||||
{
|
||||
// Add any material functors that are located inside each property group.
|
||||
if (!AddEditorMaterialFunctors(propertyGroup->GetFunctors()))
|
||||
using namespace AZ::RPI;
|
||||
|
||||
const MaterialTypeSourceData::PropertyGroup* propertyGroup = propertyGroupStack.back();
|
||||
|
||||
MaterialNameContext groupNameContext = MaterialTypeSourceData::MakeMaterialNameContext(propertyGroupStack);
|
||||
|
||||
if (!AddEditorMaterialFunctors(propertyGroup->GetFunctors(), groupNameContext))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
AZStd::vector<AZStd::string> groupNameVector;
|
||||
AZStd::vector<AZStd::string> groupDisplayNameVector;
|
||||
|
||||
groupNameVector.reserve(propertyGroupStack.size());
|
||||
groupDisplayNameVector.reserve(propertyGroupStack.size());
|
||||
|
||||
for (auto& group : propertyGroupStack)
|
||||
{
|
||||
groupNameVector.push_back(group->GetName());
|
||||
groupDisplayNameVector.push_back(group->GetDisplayName());
|
||||
}
|
||||
|
||||
m_groups.emplace_back(aznew AtomToolsFramework::DynamicPropertyGroup);
|
||||
m_groups.back()->m_name = propertyIdContext + propertyGroup->GetName();
|
||||
m_groups.back()->m_displayName = propertyGroup->GetDisplayName();
|
||||
m_groups.back()->m_description = propertyGroup->GetDescription();
|
||||
AzFramework::StringFunc::Join(m_groups.back()->m_name, groupNameVector.begin(), groupNameVector.end(), ".");
|
||||
AzFramework::StringFunc::Join(m_groups.back()->m_displayName, groupDisplayNameVector.begin(), groupDisplayNameVector.end(), " | ");
|
||||
|
||||
for (const auto& propertyDefinition : propertyGroup->GetProperties())
|
||||
{
|
||||
// Assign id before conversion so it can be used in dynamic description
|
||||
AtomToolsFramework::DynamicPropertyConfig propertyConfig;
|
||||
propertyConfig.m_id = m_groups.back()->m_name + "." + propertyDefinition->GetName();
|
||||
|
||||
// Assign id before conversion so it can be used in dynamic description
|
||||
propertyConfig.m_id = propertyDefinition->GetName();
|
||||
groupNameContext.ContextualizeProperty(propertyConfig.m_id);
|
||||
|
||||
const auto& propertyIndex = m_materialAsset->GetMaterialPropertiesLayout()->FindPropertyIndex(propertyConfig.m_id);
|
||||
const bool propertyIndexInBounds =
|
||||
@@ -581,9 +599,8 @@ namespace MaterialEditor
|
||||
if (propertyIndexInBounds)
|
||||
{
|
||||
AtomToolsFramework::ConvertToPropertyConfig(propertyConfig, *propertyDefinition);
|
||||
|
||||
// TODO: Support populating the Material Editor with nested property groups, not just the top level.
|
||||
// (Does DynamicPropertyConfig really even need m_groupDisplayName?)
|
||||
|
||||
// (Does DynamicPropertyConfig really even need m_groupName? It doesn't seem to be used anywhere)
|
||||
propertyConfig.m_groupName = m_groups.back()->m_name;
|
||||
propertyConfig.m_groupDisplayName = m_groups.back()->m_displayName;
|
||||
propertyConfig.m_showThumbnail = true;
|
||||
@@ -611,7 +628,8 @@ namespace MaterialEditor
|
||||
}
|
||||
|
||||
// Add material functors that are in the top-level functors list.
|
||||
if (!AddEditorMaterialFunctors(m_materialTypeSourceData.m_materialFunctorSourceData))
|
||||
AZ::RPI::MaterialNameContext materialNameContext; // There is no name context for top-level functors, only functors inside PropertyGroups
|
||||
if (!AddEditorMaterialFunctors(m_materialTypeSourceData.m_materialFunctorSourceData, materialNameContext))
|
||||
{
|
||||
return OpenFailed();
|
||||
}
|
||||
@@ -739,10 +757,11 @@ namespace MaterialEditor
|
||||
}
|
||||
|
||||
bool MaterialDocument::AddEditorMaterialFunctors(
|
||||
const AZStd::vector<AZ::RPI::Ptr<AZ::RPI::MaterialFunctorSourceDataHolder>>& functorSourceDataHolders)
|
||||
const AZStd::vector<AZ::RPI::Ptr<AZ::RPI::MaterialFunctorSourceDataHolder>>& functorSourceDataHolders,
|
||||
const AZ::RPI::MaterialNameContext& nameContext)
|
||||
{
|
||||
const AZ::RPI::MaterialFunctorSourceData::EditorContext editorContext = AZ::RPI::MaterialFunctorSourceData::EditorContext(
|
||||
m_materialSourceData.m_materialType, m_materialAsset->GetMaterialPropertiesLayout());
|
||||
m_materialSourceData.m_materialType, m_materialAsset->GetMaterialPropertiesLayout(), &nameContext);
|
||||
|
||||
for (AZ::RPI::Ptr<AZ::RPI::MaterialFunctorSourceDataHolder> functorData : functorSourceDataHolders)
|
||||
{
|
||||
|
||||
@@ -82,7 +82,8 @@ namespace MaterialEditor
|
||||
void RestorePropertyValues(const PropertyValueMap& propertyValues);
|
||||
|
||||
bool AddEditorMaterialFunctors(
|
||||
const AZStd::vector<AZ::RPI::Ptr<AZ::RPI::MaterialFunctorSourceDataHolder>>& functorSourceDataHolders);
|
||||
const AZStd::vector<AZ::RPI::Ptr<AZ::RPI::MaterialFunctorSourceDataHolder>>& functorSourceDataHolders,
|
||||
const AZ::RPI::MaterialNameContext& nameContext);
|
||||
|
||||
// Run editor material functor to update editor metadata.
|
||||
// @param dirtyFlags indicates which properties have changed, and thus which MaterialFunctors need to be run.
|
||||
|
||||
+103
-60
@@ -15,6 +15,7 @@
|
||||
#include <Atom/RPI.Edit/Material/MaterialUtils.h>
|
||||
#include <Atom/RPI.Reflect/Material/MaterialFunctor.h>
|
||||
#include <Atom/RPI.Reflect/Material/MaterialPropertiesLayout.h>
|
||||
#include <Atom/RPI.Reflect/Material/MaterialNameContext.h>
|
||||
#include <AtomToolsFramework/Inspector/InspectorPropertyGroupWidget.h>
|
||||
#include <AtomToolsFramework/Util/MaterialPropertyUtil.h>
|
||||
#include <AtomToolsFramework/Util/Util.h>
|
||||
@@ -80,7 +81,7 @@ namespace AZ
|
||||
m_materialAssignmentId);
|
||||
}
|
||||
|
||||
if (!materialAssetId.IsValid())
|
||||
if (!materialAssetId.IsValid())
|
||||
{
|
||||
UnloadMaterial();
|
||||
return false;
|
||||
@@ -101,28 +102,10 @@ namespace AZ
|
||||
UnloadMaterial();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add material functors that are in the top-level functors list. Other functors are also added per-property-group elsewhere.
|
||||
AddEditorMaterialFunctors(m_editData.m_materialTypeSourceData.m_materialFunctorSourceData, AZ::RPI::MaterialNameContext{});
|
||||
|
||||
// Get a list of all the editor functors to be used for property editor states
|
||||
auto propertyLayout = m_editData.m_materialAsset->GetMaterialPropertiesLayout();
|
||||
const AZ::RPI::MaterialFunctorSourceData::EditorContext editorContext =
|
||||
AZ::RPI::MaterialFunctorSourceData::EditorContext(m_editData.m_materialTypeSourcePath, propertyLayout);
|
||||
for (AZ::RPI::Ptr<AZ::RPI::MaterialFunctorSourceDataHolder> functorData : m_editData.m_materialTypeSourceData.m_materialFunctorSourceData)
|
||||
{
|
||||
AZ::RPI::MaterialFunctorSourceData::FunctorResult createResult = functorData->CreateFunctor(editorContext);
|
||||
|
||||
if (createResult.IsSuccess())
|
||||
{
|
||||
AZ::RPI::Ptr<AZ::RPI::MaterialFunctor>& functor = createResult.GetValue();
|
||||
if (functor != nullptr)
|
||||
{
|
||||
m_editorFunctors.push_back(functor);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Error("AZ::Render::EditorMaterialComponentInspector", false, "Material functors were not created: '%s'.", m_editData.m_materialTypeSourcePath.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
Populate();
|
||||
LoadOverridesFromEntity();
|
||||
@@ -292,48 +275,77 @@ 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 groups, not just the top level.
|
||||
for (const AZStd::unique_ptr<AZ::RPI::MaterialTypeSourceData::PropertyGroup>& propertyGroup : m_editData.m_materialTypeSourceData.GetPropertyLayout().m_propertyGroups)
|
||||
{
|
||||
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(propertyGroup->GetProperties().size());
|
||||
for (const auto& propertyDefinition : propertyGroup->GetProperties())
|
||||
// Copy all of the properties from the material asset to the populate the inspector
|
||||
m_editData.m_materialTypeSourceData.EnumeratePropertyGroups(
|
||||
[this](const AZ::RPI::MaterialTypeSourceData::PropertyGroupStack& propertyGroupStack)
|
||||
{
|
||||
AtomToolsFramework::DynamicPropertyConfig propertyConfig;
|
||||
using namespace AZ::RPI;
|
||||
|
||||
// Assign id before conversion so it can be used in dynamic description
|
||||
propertyConfig.m_id = AZ::RPI::MaterialPropertyId(groupName, propertyDefinition->GetName());
|
||||
|
||||
AtomToolsFramework::ConvertToPropertyConfig(propertyConfig, *propertyDefinition.get());
|
||||
|
||||
const auto& propertyIndex =
|
||||
m_editData.m_materialAsset->GetMaterialPropertiesLayout()->FindPropertyIndex(propertyConfig.m_id);
|
||||
const MaterialTypeSourceData::PropertyGroup* propertyGroupDefinition = propertyGroupStack.back();
|
||||
|
||||
MaterialNameContext groupNameContext = MaterialTypeSourceData::MakeMaterialNameContext(propertyGroupStack);
|
||||
|
||||
propertyConfig.m_groupName = groupDisplayName;
|
||||
propertyConfig.m_showThumbnail = true;
|
||||
propertyConfig.m_defaultValue = AtomToolsFramework::ConvertToEditableType(
|
||||
m_editData.m_materialTypeAsset->GetDefaultPropertyValues()[propertyIndex.GetIndex()]);
|
||||
|
||||
// There is no explicit parent material here. Material instance property overrides replace the values from the
|
||||
// assigned material asset. Its values should be treated as parent, for comparison, in this case.
|
||||
propertyConfig.m_parentValue = AtomToolsFramework::ConvertToEditableType(
|
||||
m_editData.m_materialTypeAsset->GetDefaultPropertyValues()[propertyIndex.GetIndex()]);
|
||||
propertyConfig.m_originalValue = AtomToolsFramework::ConvertToEditableType(
|
||||
m_editData.m_materialAsset->GetPropertyValues()[propertyIndex.GetIndex()]);
|
||||
group.m_properties.emplace_back(propertyConfig);
|
||||
}
|
||||
AddEditorMaterialFunctors(propertyGroupDefinition->GetFunctors(), groupNameContext);
|
||||
|
||||
// Passing in same group as main and comparison instance to enable custom value comparison for highlighting modified properties
|
||||
auto propertyGroupWidget = new AtomToolsFramework::InspectorPropertyGroupWidget(
|
||||
&group, &group, group.TYPEINFO_Uuid(), this, this, GetGroupSaveStateKey(groupName), {},
|
||||
[this](const auto node) { return GetInstanceNodePropertyIndicator(node); }, 0);
|
||||
AddGroup(groupName, groupDisplayName, groupDescription, propertyGroupWidget);
|
||||
}
|
||||
AZStd::vector<AZStd::string> groupNameVector;
|
||||
AZStd::vector<AZStd::string> groupDisplayNameVector;
|
||||
|
||||
groupNameVector.reserve(propertyGroupStack.size());
|
||||
groupDisplayNameVector.reserve(propertyGroupStack.size());
|
||||
|
||||
for (auto& nextGroup : propertyGroupStack)
|
||||
{
|
||||
groupNameVector.push_back(nextGroup->GetName());
|
||||
groupDisplayNameVector.push_back(!nextGroup->GetDisplayName().empty() ? nextGroup->GetDisplayName() : nextGroup->GetName());
|
||||
}
|
||||
|
||||
AZStd::string groupId;
|
||||
AzFramework::StringFunc::Join(groupId, groupNameVector.begin(), groupNameVector.end(), ".");
|
||||
|
||||
auto& group = m_groups[groupId];
|
||||
group.m_name = groupId;
|
||||
AzFramework::StringFunc::Join(group.m_displayName, groupDisplayNameVector.begin(), groupDisplayNameVector.end(), " | ");
|
||||
group.m_description = !propertyGroupDefinition->GetDescription().empty() ? propertyGroupDefinition->GetDescription() : group.m_displayName;
|
||||
|
||||
group.m_properties.reserve(propertyGroupDefinition->GetProperties().size());
|
||||
for (const auto& propertyDefinition : propertyGroupDefinition->GetProperties())
|
||||
{
|
||||
AtomToolsFramework::DynamicPropertyConfig propertyConfig;
|
||||
|
||||
// Assign id before conversion so it can be used in dynamic description
|
||||
propertyConfig.m_id = propertyDefinition->GetName();
|
||||
groupNameContext.ContextualizeProperty(propertyConfig.m_id);
|
||||
|
||||
AtomToolsFramework::ConvertToPropertyConfig(propertyConfig, *propertyDefinition);
|
||||
|
||||
const auto& propertyIndex =
|
||||
m_editData.m_materialAsset->GetMaterialPropertiesLayout()->FindPropertyIndex(propertyConfig.m_id);
|
||||
|
||||
// (Does DynamicPropertyConfig really even need m_groupName? It doesn't seem to be used anywhere)
|
||||
propertyConfig.m_groupName = group.m_name;
|
||||
propertyConfig.m_groupDisplayName = group.m_displayName;
|
||||
propertyConfig.m_showThumbnail = true;
|
||||
|
||||
propertyConfig.m_defaultValue = AtomToolsFramework::ConvertToEditableType(
|
||||
m_editData.m_materialTypeAsset->GetDefaultPropertyValues()[propertyIndex.GetIndex()]);
|
||||
|
||||
// There is no explicit parent material here. Material instance property overrides replace the values from the
|
||||
// assigned material asset. Its values should be treated as parent, for comparison, in this case.
|
||||
propertyConfig.m_parentValue = AtomToolsFramework::ConvertToEditableType(
|
||||
m_editData.m_materialTypeAsset->GetDefaultPropertyValues()[propertyIndex.GetIndex()]);
|
||||
propertyConfig.m_originalValue = AtomToolsFramework::ConvertToEditableType(
|
||||
m_editData.m_materialAsset->GetPropertyValues()[propertyIndex.GetIndex()]);
|
||||
group.m_properties.emplace_back(propertyConfig);
|
||||
}
|
||||
|
||||
// Passing in same group as main and comparison instance to enable custom value comparison for highlighting modified properties
|
||||
auto propertyGroupWidget = new AtomToolsFramework::InspectorPropertyGroupWidget(
|
||||
&group, &group, group.TYPEINFO_Uuid(), this, this, GetGroupSaveStateKey(group.m_name), {},
|
||||
[this](const auto node) { return GetInstanceNodePropertyIndicator(node); }, 0);
|
||||
AddGroup(group.m_name, group.m_displayName, group.m_description, propertyGroupWidget);
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void MaterialPropertyInspector::Populate()
|
||||
@@ -433,6 +445,37 @@ namespace AZ
|
||||
// m_updatePreview should be set to true here for continuous preview updates as slider/color properties change but needs
|
||||
// throttling
|
||||
}
|
||||
|
||||
bool MaterialPropertyInspector::AddEditorMaterialFunctors(
|
||||
const AZStd::vector<AZ::RPI::Ptr<AZ::RPI::MaterialFunctorSourceDataHolder>>& functorSourceDataHolders,
|
||||
const AZ::RPI::MaterialNameContext& nameContext)
|
||||
{
|
||||
// Copied from MaterialDocument::AddEditorMaterialFunctors, should be refactored at some point
|
||||
|
||||
const AZ::RPI::MaterialFunctorSourceData::EditorContext editorContext = AZ::RPI::MaterialFunctorSourceData::EditorContext(
|
||||
m_editData.m_materialTypeSourcePath, m_editData.m_materialAsset->GetMaterialPropertiesLayout(), &nameContext);
|
||||
|
||||
for (AZ::RPI::Ptr<AZ::RPI::MaterialFunctorSourceDataHolder> functorData : functorSourceDataHolders)
|
||||
{
|
||||
AZ::RPI::MaterialFunctorSourceData::FunctorResult result = functorData->CreateFunctor(editorContext);
|
||||
|
||||
if (result.IsSuccess())
|
||||
{
|
||||
AZ::RPI::Ptr<AZ::RPI::MaterialFunctor>& functor = result.GetValue();
|
||||
if (functor != nullptr)
|
||||
{
|
||||
m_editorFunctors.push_back(functor);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Error("MaterialDocument", false, "Material functors were not created: '%s'.", m_editData.m_materialTypeSourcePath.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MaterialPropertyInspector::RunEditorMaterialFunctors()
|
||||
{
|
||||
|
||||
+4
@@ -108,6 +108,10 @@ namespace AZ
|
||||
void RunEditorMaterialFunctors();
|
||||
void UpdateMaterialInstanceProperty(const AtomToolsFramework::DynamicProperty& property);
|
||||
|
||||
bool AddEditorMaterialFunctors(
|
||||
const AZStd::vector<AZ::RPI::Ptr<AZ::RPI::MaterialFunctorSourceDataHolder>>& functorSourceDataHolders,
|
||||
const AZ::RPI::MaterialNameContext& nameContext);
|
||||
|
||||
AZ::Crc32 GetGroupSaveStateKey(const AZStd::string& groupName) const;
|
||||
bool IsInstanceNodePropertyModifed(const AzToolsFramework::InstanceDataNode* node) const;
|
||||
const char* GetInstanceNodePropertyIndicator(const AzToolsFramework::InstanceDataNode* node) const;
|
||||
|
||||
+6
-5
@@ -17,6 +17,7 @@
|
||||
#include <Atom/RPI.Reflect/Material/MaterialAsset.h>
|
||||
#include <Atom/RPI.Reflect/Material/MaterialPropertiesLayout.h>
|
||||
#include <Atom/RPI.Reflect/Material/MaterialTypeAsset.h>
|
||||
#include <Atom/RPI.Reflect/Material/MaterialNameContext.h>
|
||||
#include <AtomToolsFramework/Util/MaterialPropertyUtil.h>
|
||||
#include <AzFramework/API/ApplicationAPI.h>
|
||||
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
|
||||
@@ -113,9 +114,11 @@ namespace AZ
|
||||
|
||||
// Copy all of the properties from the material asset to the source data that will be exported
|
||||
bool result = true;
|
||||
editData.m_materialTypeSourceData.EnumerateProperties([&](const AZStd::string& propertyIdContext, const AZ::RPI::MaterialTypeSourceData::PropertyDefinition* propertyDefinition)
|
||||
editData.m_materialTypeSourceData.EnumerateProperties([&](const AZ::RPI::MaterialTypeSourceData::PropertyDefinition* propertyDefinition, const AZ::RPI::MaterialNameContext& nameContext)
|
||||
{
|
||||
AZ::Name propertyId(propertyIdContext + propertyDefinition->GetName());
|
||||
AZ::Name propertyId{propertyDefinition->GetName()};
|
||||
nameContext.ContextualizeProperty(propertyId);
|
||||
|
||||
const AZ::RPI::MaterialPropertyIndex propertyIndex =
|
||||
editData.m_materialAsset->GetMaterialPropertiesLayout()->FindPropertyIndex(propertyId);
|
||||
|
||||
@@ -148,9 +151,7 @@ namespace AZ
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: Support populating the Material Editor with nested property groups, not just the top level.
|
||||
AZStd::string_view groupName = propertyId.GetStringView().substr(0, propertyId.GetStringView().size() - propertyDefinition->GetName().size() - 1);
|
||||
exportData.SetPropertyValue(RPI::MaterialPropertyId{groupName, propertyDefinition->GetName()}, propertyValue);
|
||||
exportData.SetPropertyValue(propertyId, propertyValue);
|
||||
return true;
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user