Made StandardMultilayerPBR hide a layer's property groups when that layer is disabled.

ATOM-14688 Disable Individual Layers

- Added new SetMaterialPropertyGroupVisibility functions to the material functors.
- Updated the MaterialFunctor::EditorContext to include parameters for handling material property group metadata.
- Updated the material inspector(s) to apply the property group visiblity changes from the material functor, to hide or show the property groups.
- Moved some code from MaterialPropertyDescriptor.h/cpp to a new MaterialDynamicMetadata.h/cpp, since these aren't really related to the MaterialPropertyDescriptor code. It's more for material functors to use.
- Also fixed the casing for the "GetMaterialPropertyValue_Image" lua function, since I was already in this code (ATOM-14793 "Fix Inconsistent Casing For LuaMaterialFunctorRuntimeContext")

Tested in MaterialEditor and in in the main Editor's MaterialComponent property override inspector.
main
Chris Santora 5 years ago
parent 275bb1bfec
commit 53188a12da

@ -35,16 +35,16 @@ end
function Process(context)
local isFeatureEnabled = context:GetMaterialPropertyValue_bool("detailLayerGroup.enableDetailLayer")
local blendMaskTexture = context:GetMaterialPropertyValue_image("detailLayerGroup.blendDetailMask")
local blendMaskTexture = context:GetMaterialPropertyValue_Image("detailLayerGroup.blendDetailMask")
local blendMaskTextureEnabled = context:GetMaterialPropertyValue_bool("detailLayerGroup.enableDetailMaskTexture")
context:SetShaderOptionValue_bool("o_detail_blendMask_useTexture", isFeatureEnabled and blendMaskTextureEnabled and blendMaskTexture ~= nil)
local baseColorDetailEnabled = context:GetMaterialPropertyValue_bool("detailLayerGroup.enableBaseColor")
local baseColorDetailTexture = context:GetMaterialPropertyValue_image("detailLayerGroup.baseColorDetailMap")
local baseColorDetailTexture = context:GetMaterialPropertyValue_Image("detailLayerGroup.baseColorDetailMap")
context:SetShaderOptionValue_bool("o_detail_baseColor_useTexture", isFeatureEnabled and baseColorDetailEnabled and baseColorDetailTexture ~= nil)
local normalDetailEnabled = context:GetMaterialPropertyValue_bool("detailLayerGroup.enableNormals")
local normalDetailTexture = context:GetMaterialPropertyValue_image("detailLayerGroup.normalDetailMap")
local normalDetailTexture = context:GetMaterialPropertyValue_Image("detailLayerGroup.normalDetailMap")
context:SetShaderOptionValue_bool("o_detail_normal_useTexture", isFeatureEnabled and normalDetailEnabled and normalDetailTexture ~= nil)
end
@ -78,7 +78,7 @@ function ProcessEditor(context)
context:SetMaterialPropertyVisibility("detailUV.rotateDegrees", mainVisibility)
context:SetMaterialPropertyVisibility("detailUV.scale", mainVisibility)
local blendMaskTexture = context:GetMaterialPropertyValue_image("detailLayerGroup.blendDetailMask")
local blendMaskTexture = context:GetMaterialPropertyValue_Image("detailLayerGroup.blendDetailMask")
if(nil == blendMaskTexture) then
context:SetMaterialPropertyVisibility("detailLayerGroup.enableDetailMaskTexture", MaterialPropertyVisibility_Hidden)
context:SetMaterialPropertyVisibility("detailLayerGroup.blendDetailMaskUv", MaterialPropertyVisibility_Hidden)

@ -65,8 +65,8 @@ function Process(context)
for i=1,MAX_WRINKLE_LAYER_COUNT do
if(i <= count) then
isBaseColorTextureMissing = isBaseColorEnabled and nil == context:GetMaterialPropertyValue_image("wrinkleLayers.baseColorMap" .. i)
isNormalTextureMissing = isNormalEnabled and nil == context:GetMaterialPropertyValue_image("wrinkleLayers.normalMap" .. i)
isBaseColorTextureMissing = isBaseColorEnabled and nil == context:GetMaterialPropertyValue_Image("wrinkleLayers.baseColorMap" .. i)
isNormalTextureMissing = isNormalEnabled and nil == context:GetMaterialPropertyValue_Image("wrinkleLayers.normalMap" .. i)
context:SetShaderOptionValue_bool("o_wrinkleLayers_baseColor_useTexture" .. i, not isBaseColorTextureMissing)
context:SetShaderOptionValue_bool("o_wrinkleLayers_normal_useTexture" .. i, not isNormalTextureMissing)
else

@ -2684,6 +2684,12 @@
"file": "StandardMultilayerPBR_ShaderEnable.lua"
}
},
{
"type": "Lua",
"args": {
"file": "StandardMultilayerPBR_LayerEnable.lua"
}
},
{
"type": "Lua",
"args": {

@ -0,0 +1,49 @@
--------------------------------------------------------------------------------------
--
-- All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
-- its licensors.
--
-- For complete copyright and license terms please see the LICENSE at the root of this
-- distribution (the "License"). All use of this software is governed by the License,
-- or, if provided, by the license below or the license accompanying this file. Do not
-- remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
--
--
----------------------------------------------------------------------------------------------------
-- This functor hides the properties for disabled material layers.
function GetMaterialPropertyDependencies()
return {
"blend.enableLayer2",
"blend.enableLayer3"
}
end
function SetLayerVisibility(context, layerNamePrefix, isVisible)
local visibility = MaterialPropertyGroupVisibility_Enabled
if(not isVisible) then
visibility = MaterialPropertyGroupVisibility_Hidden
end
context:SetMaterialPropertyGroupVisibility(layerNamePrefix .. "baseColor", visibility)
context:SetMaterialPropertyGroupVisibility(layerNamePrefix .. "metallic", visibility)
context:SetMaterialPropertyGroupVisibility(layerNamePrefix .. "roughness", visibility)
context:SetMaterialPropertyGroupVisibility(layerNamePrefix .. "specularF0", visibility)
context:SetMaterialPropertyGroupVisibility(layerNamePrefix .. "normal", visibility)
context:SetMaterialPropertyGroupVisibility(layerNamePrefix .. "clearCoat", visibility)
context:SetMaterialPropertyGroupVisibility(layerNamePrefix .. "occlusion", visibility)
context:SetMaterialPropertyGroupVisibility(layerNamePrefix .. "emissive", visibility)
context:SetMaterialPropertyGroupVisibility(layerNamePrefix .. "parallax", visibility)
context:SetMaterialPropertyGroupVisibility(layerNamePrefix .. "uv", visibility)
end
function ProcessEditor(context)
local enableLayer2 = context:GetMaterialPropertyValue_bool("blend.enableLayer2")
local enableLayer3 = context:GetMaterialPropertyValue_bool("blend.enableLayer3")
SetLayerVisibility(context, "layer2_", context:GetMaterialPropertyValue_bool("blend.enableLayer2"))
SetLayerVisibility(context, "layer3_", context:GetMaterialPropertyValue_bool("blend.enableLayer3"))
end

@ -24,7 +24,7 @@ end
function Process(context)
local enable = context:GetMaterialPropertyValue_bool("parallax.enable")
local textureMap = context:GetMaterialPropertyValue_image("parallax.textureMap")
local textureMap = context:GetMaterialPropertyValue_Image("parallax.textureMap")
context:SetShaderOptionValue_bool("o_useDepthMap", enable and textureMap ~= nil)
end
@ -37,7 +37,7 @@ function ProcessEditor(context)
context:SetMaterialPropertyVisibility("parallax.textureMap", MaterialPropertyVisibility_Hidden)
end
local textureMap = context:GetMaterialPropertyValue_image("parallax.textureMap")
local textureMap = context:GetMaterialPropertyValue_Image("parallax.textureMap")
local visibility = MaterialPropertyVisibility_Enabled
if(not enable or textureMap == nil) then
visibility = MaterialPropertyVisibility_Hidden

@ -34,7 +34,7 @@ function GetShaderOptionDependencies()
end
function UpdateUseTextureState(context, clearCoatEnabled, textureMapPropertyName, useTexturePropertyName, shaderOptionName)
local textureMap = context:GetMaterialPropertyValue_image(textureMapPropertyName)
local textureMap = context:GetMaterialPropertyValue_Image(textureMapPropertyName)
local useTextureMap = context:GetMaterialPropertyValue_bool(useTexturePropertyName)
context:SetShaderOptionValue_bool(shaderOptionName, clearCoatEnabled and useTextureMap and textureMap ~= nil)
end
@ -50,7 +50,7 @@ end
-- Note this logic matches that of the UseTextureFunctor class.
function UpdateTextureDependentPropertyVisibility(context, textureMapPropertyName, useTexturePropertyName, uvPropertyName)
local textureMap = context:GetMaterialPropertyValue_image(textureMapPropertyName)
local textureMap = context:GetMaterialPropertyValue_Image(textureMapPropertyName)
local useTexture = context:GetMaterialPropertyValue_bool(useTexturePropertyName)
if(textureMap == nil) then

@ -22,7 +22,7 @@ end
function Process(context)
local enable = context:GetMaterialPropertyValue_bool("emissive.enable")
local textureMap = context:GetMaterialPropertyValue_image("emissive.textureMap")
local textureMap = context:GetMaterialPropertyValue_Image("emissive.textureMap")
local useTextureMap = context:GetMaterialPropertyValue_bool("emissive.useTexture")
context:SetShaderOptionValue_bool("o_emissiveEnabled", enable)
@ -47,7 +47,7 @@ function ProcessEditor(context)
context:SetMaterialPropertyVisibility("emissive.textureMapUv", mainVisibility)
if(enable) then
local textureMap = context:GetMaterialPropertyValue_image("emissive.textureMap")
local textureMap = context:GetMaterialPropertyValue_Image("emissive.textureMap")
local useTextureMap = context:GetMaterialPropertyValue_bool("emissive.useTexture")
if(textureMap == nil) then

@ -90,7 +90,7 @@ function ProcessEditor(context)
context:SetMaterialPropertyVisibility("opacity.textureMap", MaterialPropertyVisibility_Hidden)
context:SetMaterialPropertyVisibility("opacity.textureMapUv", MaterialPropertyVisibility_Hidden)
else
local textureMap = context:GetMaterialPropertyValue_image("opacity.textureMap")
local textureMap = context:GetMaterialPropertyValue_Image("opacity.textureMap")
if(nil == textureMap) then
context:SetMaterialPropertyVisibility("opacity.textureMapUv", MaterialPropertyVisibility_Disabled)

@ -22,7 +22,7 @@ end
function Process(context)
local enable = context:GetMaterialPropertyValue_bool("parallax.enable")
local textureMap = context:GetMaterialPropertyValue_image("parallax.textureMap")
local textureMap = context:GetMaterialPropertyValue_Image("parallax.textureMap")
context:SetShaderOptionValue_bool("o_parallax_feature_enabled", enable)
context:SetShaderOptionValue_bool("o_useDepthMap", enable and textureMap ~= nil)
end
@ -36,7 +36,7 @@ function ProcessEditor(context)
context:SetMaterialPropertyVisibility("parallax.textureMap", MaterialPropertyVisibility_Hidden)
end
local textureMap = context:GetMaterialPropertyValue_image("parallax.textureMap")
local textureMap = context:GetMaterialPropertyValue_Image("parallax.textureMap")
local visibility = MaterialPropertyVisibility_Enabled
if(not enable or textureMap == nil) then
visibility = MaterialPropertyVisibility_Hidden

@ -21,13 +21,13 @@ function GetShaderOptionDependencies()
end
function Process(context)
local textureMap = context:GetMaterialPropertyValue_image("roughness.textureMap")
local textureMap = context:GetMaterialPropertyValue_Image("roughness.textureMap")
local useTexture = context:GetMaterialPropertyValue_bool("roughness.useTexture")
context:SetShaderOptionValue_bool("o_roughness_useTexture", useTexture and textureMap ~= nil)
end
function ProcessEditor(context)
local textureMap = context:GetMaterialPropertyValue_image("roughness.textureMap")
local textureMap = context:GetMaterialPropertyValue_Image("roughness.textureMap")
local useTexture = context:GetMaterialPropertyValue_bool("roughness.useTexture")
if(nil == textureMap) then

@ -35,7 +35,7 @@ TransmissionMode_ThickObject = 1
TransmissionMode_ThinObject = 2
function UpdateUseTextureState(context, subsurfaceScatteringEnabled, textureMapPropertyName, useTexturePropertyName, shaderOptionName)
local textureMap = context:GetMaterialPropertyValue_image(textureMapPropertyName)
local textureMap = context:GetMaterialPropertyValue_Image(textureMapPropertyName)
local useTextureMap = context:GetMaterialPropertyValue_bool(useTexturePropertyName)
context:SetShaderOptionValue_bool(shaderOptionName, subsurfaceScatteringEnabled and useTextureMap and textureMap ~= nil)
end
@ -53,7 +53,7 @@ function UpdateTextureDependentPropertyVisibility(context, featureEnabled, textu
context:SetMaterialPropertyVisibility(useTexturePropertyName, MaterialPropertyVisibility_Hidden)
context:SetMaterialPropertyVisibility(uvPropertyName, MaterialPropertyVisibility_Hidden)
else
local textureMap = context:GetMaterialPropertyValue_image(textureMapPropertyName)
local textureMap = context:GetMaterialPropertyValue_Image(textureMapPropertyName)
local useTextureMap = context:GetMaterialPropertyValue_bool(useTexturePropertyName)
if(textureMap == nil) then

@ -329,6 +329,8 @@ namespace AZ
bool SetMaterialPropertySoftMaxValue(const char* name, Type value);
bool SetMaterialPropertyDescription(const char* name, const char* description);
bool SetMaterialPropertyGroupVisibility(const char* name, MaterialPropertyGroupVisibility visibility);
private:

@ -0,0 +1,100 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzCore/RTTI/TypeInfo.h>
#include <AzCore/RTTI/ReflectContext.h>
#include <Atom/RPI.Reflect/Material/MaterialPropertyValue.h>
namespace AZ
{
namespace RPI
{
// Normally we wouldn't want editor-related code mixed in with runtime code, but
// since this data can be modified dynamically, keeping it in the runtime makes
// the overall material functor design simpler and more user-friendly.
//! Visibility for each material property.
//! If the data field is empty, use default as editable.
enum class MaterialPropertyVisibility : uint32_t
{
Enabled, //!< The property is visible and editable
Disabled, //!< The property is visible but non-editable
Hidden, //!< The property is invisible
Default = Enabled
};
struct MaterialPropertyRange
{
MaterialPropertyRange() = default;
MaterialPropertyRange(
const MaterialPropertyValue& max,
const MaterialPropertyValue& min,
const MaterialPropertyValue& softMax,
const MaterialPropertyValue& softMin
)
: m_max(max)
, m_min(min)
, m_softMax(softMax)
, m_softMin(softMin)
{}
MaterialPropertyValue m_max;
MaterialPropertyValue m_min;
MaterialPropertyValue m_softMax;
MaterialPropertyValue m_softMin;
};
//! Used by material functors to dynamically control property metadata in tools.
//! For example, show/hide a property based on some other 'enable' flag property.
struct MaterialPropertyDynamicMetadata
{
AZ_TYPE_INFO(MaterialPropertyDynamicMetadata, "{A89F215F-3235-499F-896C-9E63ACC1D657}");
AZ::RPI::MaterialPropertyVisibility m_visibility;
AZStd::string m_description;
AZ::RPI::MaterialPropertyRange m_propertyRange;
};
//! Visibility for each material property group.
enum class MaterialPropertyGroupVisibility : uint32_t
{
// Note it's helpful to keep these values aligned with MaterialPropertyVisibility in part because in lua it would be easy to accidentally use
// MaterialPropertyVisibility instead of MaterialPropertyGroupVisibility resulting in sneaky bugs. Also, if the enums end up being the same in
// the future, we could just merge them into one.
Enabled, //!< The property is visible and editable
//Disabled, //!< The property is visible but non-editable (reserved for possible future use, to match MaterialPropertyVisibility)
Hidden=2, //!< The property is invisible
Default = Enabled
};
//! Used by material functors to dynamically control property group metadata in tools.
//! For example, show/hide an entire property group based on some 'enable' flag property.
struct MaterialPropertyGroupDynamicMetadata
{
AZ_TYPE_INFO(MaterialPropertyGroupDynamicMetadata, "{F94009F7-48A3-4CE0-AF64-D5A86890ACD4}");
AZ::RPI::MaterialPropertyGroupVisibility m_visibility;
};
void ReflectMaterialDynamicMetadata(ReflectContext* context);
} // namespace RPI
AZ_TYPE_INFO_SPECIALIZE(RPI::MaterialPropertyVisibility, "{318B43A2-79E3-4502-8FD0-5815209EA123}");
AZ_TYPE_INFO_SPECIALIZE(RPI::MaterialPropertyGroupVisibility, "{B803958B-DE64-4FBF-AC00-CF781611BE37}");
} // namespace AZ

@ -18,6 +18,7 @@
#include <Atom/RPI.Reflect/Material/ShaderCollection.h>
#include <Atom/RPI.Reflect/Material/MaterialPropertyDescriptor.h>
#include <Atom/RPI.Reflect/Material/MaterialPropertyValue.h>
#include <Atom/RPI.Reflect/Material/MaterialDynamicMetadata.h>
namespace AZ
{
@ -147,6 +148,8 @@ namespace AZ
public:
const MaterialPropertyDynamicMetadata* GetMaterialPropertyMetadata(const Name& propertyName) const;
const MaterialPropertyDynamicMetadata* GetMaterialPropertyMetadata(const MaterialPropertyIndex& index) const;
const MaterialPropertyGroupDynamicMetadata* GetMaterialPropertyGroupMetadata(const Name& propertyName) const;
//! Get the property value. The type must be one of those in MaterialPropertyValue.
//! Otherwise, a compile error will be reported.
@ -178,6 +181,8 @@ namespace AZ
bool SetMaterialPropertySoftMaxValue(const Name& propertyName, const MaterialPropertyValue& max);
bool SetMaterialPropertySoftMaxValue(const MaterialPropertyIndex& index, const MaterialPropertyValue& max);
bool SetMaterialPropertyGroupVisibility(const Name& propertyGroupName, MaterialPropertyGroupVisibility visibility);
// [GFX TODO][ATOM-4168] Replace the workaround for unlink-able RPI.Public classes in MaterialFunctor
// const AZStd::vector<AZStd::any>&, AZStd::unordered_map<MaterialPropertyIndex, Image*>&, RHI::ConstPtr<MaterialPropertiesLayout>
@ -185,18 +190,23 @@ namespace AZ
EditorContext(
const AZStd::vector<MaterialPropertyValue>& propertyValues,
RHI::ConstPtr<MaterialPropertiesLayout> materialPropertiesLayout,
AZStd::unordered_map<Name, MaterialPropertyDynamicMetadata>& metadata,
AZStd::unordered_set<Name>& outChangedProperties,
AZStd::unordered_map<Name, MaterialPropertyDynamicMetadata>& propertyMetadata,
AZStd::unordered_map<Name, MaterialPropertyGroupDynamicMetadata>& propertyGroupMetadata,
AZStd::unordered_set<Name>& updatedPropertiesOut,
AZStd::unordered_set<Name>& updatedPropertyGroupsOut,
const MaterialPropertyFlags* materialPropertyDependencies
);
private:
AZStd::list_iterator<AZStd::pair<AZ::Name, AZ::RPI::MaterialPropertyDynamicMetadata>> QueryMaterialMetadata(const Name& propertyName) const;
AZStd::list_iterator<AZStd::pair<AZ::Name, AZ::RPI::MaterialPropertyDynamicMetadata>> QueryMaterialPropertyMetadata(const Name& propertyName) const;
AZStd::list_iterator<AZStd::pair<AZ::Name, AZ::RPI::MaterialPropertyGroupDynamicMetadata>> QueryMaterialPropertyGroupMetadata(const Name& propertyGroupName) const;
const AZStd::vector<MaterialPropertyValue>& m_materialPropertyValues;
RHI::ConstPtr<MaterialPropertiesLayout> m_materialPropertiesLayout;
AZStd::unordered_map<Name, MaterialPropertyDynamicMetadata>& m_metadata;
AZStd::unordered_set<Name>& m_outChangedProperties;
AZStd::unordered_map<Name, MaterialPropertyDynamicMetadata>& m_propertyMetadata;
AZStd::unordered_map<Name, MaterialPropertyGroupDynamicMetadata>& m_propertyGroupMetadata;
AZStd::unordered_set<Name>& m_updatedPropertiesOut;
AZStd::unordered_set<Name>& m_updatedPropertyGroupsOut;
const MaterialPropertyFlags* m_materialPropertyDependencies = nullptr;
};

@ -81,52 +81,6 @@ namespace AZ
AZStd::string GetMaterialPropertyDataTypeString(AZ::TypeId typeId);
//! Visibility for each material property.
//! If the data field is empty, use default as editable.
enum class MaterialPropertyVisibility : uint32_t
{
Enabled, //< The property is visible and editable
Disabled, //< The property is visible but non-editable
Hidden, //< The property is invisible
Default = Enabled
};
struct MaterialPropertyRange
{
MaterialPropertyRange() = default;
MaterialPropertyRange(
const MaterialPropertyValue& max,
const MaterialPropertyValue& min,
const MaterialPropertyValue& softMax,
const MaterialPropertyValue& softMin
)
: m_max(max)
, m_min(min)
, m_softMax(softMax)
, m_softMin(softMin)
{}
MaterialPropertyValue m_max;
MaterialPropertyValue m_min;
MaterialPropertyValue m_softMax;
MaterialPropertyValue m_softMin;
};
//! Used by material functors to dynamically control property metadata in tools.
//! For example, show/hide a property based on some other 'enable' flag property.
//! Normally we wouldn't want editor-related code mixed in with runtime code, but
//! since this data can be modified dynamically, keeping it in the runtime makes
//! the overall material functor design simpler and more user-friendly.
struct MaterialPropertyDynamicMetadata
{
AZ_TYPE_INFO(MaterialPropertyDynamicMetadata, "{A89F215F-3235-499F-896C-9E63ACC1D657}");
AZ::RPI::MaterialPropertyVisibility m_visibility;
AZStd::string m_description;
AZ::RPI::MaterialPropertyRange m_propertyRange;
};
//! A material property is any data input to a material, like a bool, float, Vector, Image, Buffer, etc.
//! This descriptor defines a single input property, including it's name ID, and how it maps
//! to the shader system.
@ -171,7 +125,6 @@ namespace AZ
} // namespace RPI
AZ_TYPE_INFO_SPECIALIZE(RPI::MaterialPropertyOutputType, "{42A6E5E8-0FE6-4D7B-884A-1F478E4ADD97}");
AZ_TYPE_INFO_SPECIALIZE(RPI::MaterialPropertyVisibility, "{318B43A2-79E3-4502-8FD0-5815209EA123}");
AZ_TYPE_INFO_SPECIALIZE(RPI::MaterialPropertyDataType, "{3D903D5C-C6AA-452E-A2F8-8948D30833FF}");
} // namespace AZ

@ -32,6 +32,7 @@ namespace AZ
MaterialPropertiesLayout::Reflect(context);
MaterialFunctor::Reflect(context);
LuaMaterialFunctor::Reflect(context);
ReflectMaterialDynamicMetadata(context);
}
void MaterialSystem::GetAssetHandlers(AssetHandlerPtrList& assetHandlers)

@ -63,6 +63,7 @@ namespace AZ
behaviorContext->Class<Image>();
MaterialPropertyDescriptor::Reflect(behaviorContext);
ReflectMaterialDynamicMetadata(behaviorContext);
LuaMaterialFunctorRenderStates::Reflect(behaviorContext);
LuaMaterialFunctorShaderItem::Reflect(behaviorContext);
@ -255,7 +256,7 @@ namespace AZ
// Specialize for type Image* because that will be more intuitive within Lua.
// The script can then check the result for nil without calling "get()".
// For example, "GetMaterialPropertyValue_image(name) == nil" rather than "GetMaterialPropertyValue_image(name):get() == nil"
// For example, "GetMaterialPropertyValue_Image(name) == nil" rather than "GetMaterialPropertyValue_Image(name):get() == nil"
template<>
Image* LuaMaterialFunctorCommonContext::GetMaterialPropertyValue(const char* name) const
{
@ -278,7 +279,7 @@ namespace AZ
->Method("GetMaterialPropertyValue_Vector3", &LuaMaterialFunctorRuntimeContext::GetMaterialPropertyValue<Vector3>)
->Method("GetMaterialPropertyValue_Vector4", &LuaMaterialFunctorRuntimeContext::GetMaterialPropertyValue<Vector4>)
->Method("GetMaterialPropertyValue_Color", &LuaMaterialFunctorRuntimeContext::GetMaterialPropertyValue<Color>)
->Method("GetMaterialPropertyValue_image", &LuaMaterialFunctorRuntimeContext::GetMaterialPropertyValue<Image*>)
->Method("GetMaterialPropertyValue_Image", &LuaMaterialFunctorRuntimeContext::GetMaterialPropertyValue<Image*>)
->Method("SetShaderConstant_bool", &LuaMaterialFunctorRuntimeContext::SetShaderConstant<bool>)
->Method("SetShaderConstant_int", &LuaMaterialFunctorRuntimeContext::SetShaderConstant<int32_t>)
->Method("SetShaderConstant_uint", &LuaMaterialFunctorRuntimeContext::SetShaderConstant<uint32_t>)
@ -436,7 +437,7 @@ namespace AZ
->Method("GetMaterialPropertyValue_Vector3", &LuaMaterialFunctorEditorContext::GetMaterialPropertyValue<Vector3>)
->Method("GetMaterialPropertyValue_Vector4", &LuaMaterialFunctorEditorContext::GetMaterialPropertyValue<Vector4>)
->Method("GetMaterialPropertyValue_Color", &LuaMaterialFunctorEditorContext::GetMaterialPropertyValue<Color>)
->Method("GetMaterialPropertyValue_image", &LuaMaterialFunctorEditorContext::GetMaterialPropertyValue<Image*>)
->Method("GetMaterialPropertyValue_Image", &LuaMaterialFunctorEditorContext::GetMaterialPropertyValue<Image*>)
->Method("SetMaterialPropertyVisibility", &LuaMaterialFunctorEditorContext::SetMaterialPropertyVisibility)
->Method("SetMaterialPropertyDescription", &LuaMaterialFunctorEditorContext::SetMaterialPropertyDescription)
->Method("SetMaterialPropertyMinValue_int", &LuaMaterialFunctorEditorContext::SetMaterialPropertyMinValue<int32_t>)
@ -451,6 +452,7 @@ namespace AZ
->Method("SetMaterialPropertySoftMaxValue_int", &LuaMaterialFunctorEditorContext::SetMaterialPropertySoftMaxValue<int32_t>)
->Method("SetMaterialPropertySoftMaxValue_uint", &LuaMaterialFunctorEditorContext::SetMaterialPropertySoftMaxValue<uint32_t>)
->Method("SetMaterialPropertySoftMaxValue_float", &LuaMaterialFunctorEditorContext::SetMaterialPropertySoftMaxValue<float>)
->Method("SetMaterialPropertyGroupVisibility", &LuaMaterialFunctorEditorContext::SetMaterialPropertyGroupVisibility)
;
}
@ -524,6 +526,15 @@ namespace AZ
return m_editorContextImpl->SetMaterialPropertySoftMaxValue(index, value);
}
bool LuaMaterialFunctorEditorContext::SetMaterialPropertyGroupVisibility(const char* name, MaterialPropertyGroupVisibility visibility)
{
if (m_editorContextImpl)
{
return m_editorContextImpl->SetMaterialPropertyGroupVisibility(Name{m_propertyNamePrefix + name}, visibility);
}
return false;
}
bool LuaMaterialFunctorEditorContext::SetMaterialPropertyVisibility(const char* name, MaterialPropertyVisibility visibility)
{

@ -0,0 +1,50 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <Atom/RPI.Reflect/Material/MaterialDynamicMetadata.h>
#include <AzCore/RTTI/BehaviorContext.h>
namespace AZ
{
namespace RPI
{
void ReflectMaterialDynamicMetadata(ReflectContext* context)
{
if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
{
serializeContext->Enum<MaterialPropertyVisibility>()
->Value("Enabled", MaterialPropertyVisibility::Enabled)
->Value("Disabled", MaterialPropertyVisibility::Disabled)
->Value("Hidden", MaterialPropertyVisibility::Hidden)
;
serializeContext->Enum<MaterialPropertyGroupVisibility>()
->Value("Enabled", MaterialPropertyGroupVisibility::Enabled)
->Value("Hidden", MaterialPropertyGroupVisibility::Hidden)
;
}
if (auto* behaviorContext = azrtti_cast<BehaviorContext*>(context))
{
behaviorContext
->Enum<(int)MaterialPropertyVisibility::Enabled>("MaterialPropertyVisibility_Enabled")
->Enum<(int)MaterialPropertyVisibility::Disabled>("MaterialPropertyVisibility_Disabled")
->Enum<(int)MaterialPropertyVisibility::Hidden>("MaterialPropertyVisibility_Hidden");
behaviorContext
->Enum<(int)MaterialPropertyGroupVisibility::Enabled>("MaterialPropertyGroupVisibility_Enabled")
->Enum<(int)MaterialPropertyGroupVisibility::Hidden>("MaterialPropertyGroupVisibility_Hidden");
}
}
} // namespace RPI
} // namespace AZ

@ -142,21 +142,25 @@ namespace AZ
MaterialFunctor::EditorContext::EditorContext(
const AZStd::vector<MaterialPropertyValue>& propertyValues,
RHI::ConstPtr<MaterialPropertiesLayout> materialPropertiesLayout,
AZStd::unordered_map<Name, MaterialPropertyDynamicMetadata>& metadata,
AZStd::unordered_set<Name>& outChangedProperties,
AZStd::unordered_map<Name, MaterialPropertyDynamicMetadata>& propertyMetadata,
AZStd::unordered_map<Name, MaterialPropertyGroupDynamicMetadata>& propertyGroupMetadata,
AZStd::unordered_set<Name>& updatedPropertiesOut,
AZStd::unordered_set<Name>& updatedPropertyGroupsOut,
const MaterialPropertyFlags* materialPropertyDependencies
)
: m_materialPropertyValues(propertyValues)
, m_materialPropertiesLayout(materialPropertiesLayout)
, m_metadata(metadata)
, m_outChangedProperties(outChangedProperties)
, m_propertyMetadata(propertyMetadata)
, m_propertyGroupMetadata(propertyGroupMetadata)
, m_updatedPropertiesOut(updatedPropertiesOut)
, m_updatedPropertyGroupsOut(updatedPropertyGroupsOut)
, m_materialPropertyDependencies(materialPropertyDependencies)
{}
const MaterialPropertyDynamicMetadata* MaterialFunctor::EditorContext::GetMaterialPropertyMetadata(const Name& propertyName) const
{
auto it = QueryMaterialMetadata(propertyName);
if (it == m_metadata.end())
auto it = QueryMaterialPropertyMetadata(propertyName);
if (it == m_propertyMetadata.end())
{
return nullptr;
}
@ -168,11 +172,38 @@ namespace AZ
const Name& name = m_materialPropertiesLayout->GetPropertyDescriptor(index)->GetName();
return GetMaterialPropertyMetadata(name);
}
const MaterialPropertyGroupDynamicMetadata* MaterialFunctor::EditorContext::GetMaterialPropertyGroupMetadata(const Name& propertyName) const
{
auto it = QueryMaterialPropertyGroupMetadata(propertyName);
if (it == m_propertyGroupMetadata.end())
{
return nullptr;
}
return &(it->second);
}
bool MaterialFunctor::EditorContext::SetMaterialPropertyGroupVisibility(const Name& propertyGroupName, MaterialPropertyGroupVisibility visibility)
{
auto it = QueryMaterialPropertyGroupMetadata(propertyGroupName);
if (it == m_propertyGroupMetadata.end())
{
return false;
}
MaterialPropertyGroupVisibility originValue = it->second.m_visibility;
it->second.m_visibility = visibility;
if (originValue != visibility)
{
m_updatedPropertyGroupsOut.insert(propertyGroupName);
}
return true;
}
bool MaterialFunctor::EditorContext::SetMaterialPropertyVisibility(const Name& propertyName, MaterialPropertyVisibility visibility)
{
auto it = QueryMaterialMetadata(propertyName);
if (it == m_metadata.end())
auto it = QueryMaterialPropertyMetadata(propertyName);
if (it == m_propertyMetadata.end())
{
return false;
}
@ -180,7 +211,7 @@ namespace AZ
it->second.m_visibility = visibility;
if (originValue != visibility)
{
m_outChangedProperties.insert(propertyName);
m_updatedPropertiesOut.insert(propertyName);
}
return true;
@ -194,8 +225,8 @@ namespace AZ
bool MaterialFunctor::EditorContext::SetMaterialPropertyDescription(const Name& propertyName, AZStd::string description)
{
auto it = QueryMaterialMetadata(propertyName);
if (it == m_metadata.end())
auto it = QueryMaterialPropertyMetadata(propertyName);
if (it == m_propertyMetadata.end())
{
return false;
}
@ -204,7 +235,7 @@ namespace AZ
it->second.m_description = description;
if (origin != description)
{
m_outChangedProperties.insert(propertyName);
m_updatedPropertiesOut.insert(propertyName);
}
return true;
@ -218,8 +249,8 @@ namespace AZ
bool MaterialFunctor::EditorContext::SetMaterialPropertyMinValue(const Name& propertyName, const MaterialPropertyValue& min)
{
auto it = QueryMaterialMetadata(propertyName);
if (it == m_metadata.end())
auto it = QueryMaterialPropertyMetadata(propertyName);
if (it == m_propertyMetadata.end())
{
return false;
}
@ -229,7 +260,7 @@ namespace AZ
if(origin != min)
{
m_outChangedProperties.insert(propertyName);
m_updatedPropertiesOut.insert(propertyName);
}
return true;
@ -243,8 +274,8 @@ namespace AZ
bool MaterialFunctor::EditorContext::SetMaterialPropertyMaxValue(const Name& propertyName, const MaterialPropertyValue& max)
{
auto it = QueryMaterialMetadata(propertyName);
if (it == m_metadata.end())
auto it = QueryMaterialPropertyMetadata(propertyName);
if (it == m_propertyMetadata.end())
{
return false;
}
@ -254,7 +285,7 @@ namespace AZ
if (origin != max)
{
m_outChangedProperties.insert(propertyName);
m_updatedPropertiesOut.insert(propertyName);
}
return true;
@ -268,8 +299,8 @@ namespace AZ
bool MaterialFunctor::EditorContext::SetMaterialPropertySoftMinValue(const Name& propertyName, const MaterialPropertyValue& min)
{
auto it = QueryMaterialMetadata(propertyName);
if (it == m_metadata.end())
auto it = QueryMaterialPropertyMetadata(propertyName);
if (it == m_propertyMetadata.end())
{
return false;
}
@ -279,7 +310,7 @@ namespace AZ
if (origin != min)
{
m_outChangedProperties.insert(propertyName);
m_updatedPropertiesOut.insert(propertyName);
}
return true;
@ -293,8 +324,8 @@ namespace AZ
bool MaterialFunctor::EditorContext::SetMaterialPropertySoftMaxValue(const Name& propertyName, const MaterialPropertyValue& max)
{
auto it = QueryMaterialMetadata(propertyName);
if (it == m_metadata.end())
auto it = QueryMaterialPropertyMetadata(propertyName);
if (it == m_propertyMetadata.end())
{
return false;
}
@ -304,7 +335,7 @@ namespace AZ
if (origin != max)
{
m_outChangedProperties.insert(propertyName);
m_updatedPropertiesOut.insert(propertyName);
}
return true;
@ -316,16 +347,27 @@ namespace AZ
return SetMaterialPropertySoftMaxValue(name, max);
}
AZStd::list_iterator<AZStd::pair<AZ::Name, AZ::RPI::MaterialPropertyDynamicMetadata>> MaterialFunctor::EditorContext::QueryMaterialMetadata(const Name& propertyName) const
AZStd::list_iterator<AZStd::pair<AZ::Name, AZ::RPI::MaterialPropertyDynamicMetadata>> MaterialFunctor::EditorContext::QueryMaterialPropertyMetadata(const Name& propertyName) const
{
auto it = m_metadata.find(propertyName);
if (it == m_metadata.end())
auto it = m_propertyMetadata.find(propertyName);
if (it == m_propertyMetadata.end())
{
AZ_Error("MaterialFunctor", false, "Couldn't find metadata for material property: %s.", propertyName.GetCStr());
}
return it;
}
AZStd::list_iterator<AZStd::pair<AZ::Name, AZ::RPI::MaterialPropertyGroupDynamicMetadata>> MaterialFunctor::EditorContext::QueryMaterialPropertyGroupMetadata(const Name& propertyGroupName) const
{
auto it = m_propertyGroupMetadata.find(propertyGroupName);
if (it == m_propertyGroupMetadata.end())
{
AZ_Error("MaterialFunctor", false, "Couldn't find metadata for material property group: %s.", propertyGroupName.GetCStr());
}
return it;
}
template<typename Type>
const Type& MaterialFunctor::RuntimeContext::GetMaterialPropertyValue(const MaterialPropertyIndex& index) const

@ -124,12 +124,6 @@ namespace AZ
->Value(ToString(MaterialPropertyOutputType::ShaderOption), MaterialPropertyOutputType::ShaderOption)
;
serializeContext->Enum<MaterialPropertyVisibility>()
->Value("Enabled", MaterialPropertyVisibility::Enabled)
->Value("Disabled", MaterialPropertyVisibility::Disabled)
->Value("Hidden", MaterialPropertyVisibility::Hidden)
;
serializeContext->Enum<MaterialPropertyDataType>()
->Value(ToString(MaterialPropertyDataType::Invalid), MaterialPropertyDataType::Invalid)
->Value(ToString(MaterialPropertyDataType::Bool), MaterialPropertyDataType::Bool)
@ -153,14 +147,6 @@ namespace AZ
;
}
if (auto* behaviorContext = azrtti_cast<BehaviorContext*>(context))
{
behaviorContext
->Enum<(int)MaterialPropertyVisibility::Enabled>("MaterialPropertyVisibility_Enabled")
->Enum<(int)MaterialPropertyVisibility::Disabled>("MaterialPropertyVisibility_Disabled")
->Enum<(int)MaterialPropertyVisibility::Hidden>("MaterialPropertyVisibility_Hidden");
}
MaterialPropertyIndex::Reflect(context);
}

@ -748,12 +748,15 @@ namespace UnitTest
MaterialPropertyDataType::UInt, "general.mode",
MaterialPropertyDataType::Float, "general.value",
functorScript);
AZStd::unordered_set<AZ::Name> changedPropertyNames;
AZStd::unordered_map<Name, MaterialPropertyDynamicMetadata> propertyDynamicMetadata;
propertyDynamicMetadata[Name{"general.mode"}] = {};
propertyDynamicMetadata[Name{"general.value"}] = {};
AZStd::unordered_set<AZ::Name> changedPropertyGroupNames;
AZStd::unordered_map<Name, MaterialPropertyGroupDynamicMetadata> propertyGroupDynamicMetadata;
propertyGroupDynamicMetadata[Name{"general"}] = {};
Ptr<MaterialFunctor> functor = testData.GetMaterialTypeAsset()->GetMaterialFunctors()[0];
@ -761,7 +764,9 @@ namespace UnitTest
testData.GetMaterial()->GetPropertyValues(),
testData.GetMaterial()->GetMaterialPropertiesLayout(),
propertyDynamicMetadata,
propertyGroupDynamicMetadata,
changedPropertyNames,
changedPropertyGroupNames,
&functor->GetMaterialPropertyDependencies()
);
@ -814,10 +819,13 @@ namespace UnitTest
functorScript);
AZStd::unordered_set<AZ::Name> changedPropertyNames;
AZStd::unordered_map<Name, MaterialPropertyDynamicMetadata> propertyDynamicMetadata;
propertyDynamicMetadata[Name{"general.units"}] = {};
propertyDynamicMetadata[Name{"general.distance"}] = {};
AZStd::unordered_set<AZ::Name> changedPropertyGroupNames;
AZStd::unordered_map<Name, MaterialPropertyGroupDynamicMetadata> propertyGroupDynamicMetadata;
propertyGroupDynamicMetadata[Name{"general"}] = {};
Ptr<MaterialFunctor> functor = testData.GetMaterialTypeAsset()->GetMaterialFunctors()[0];
@ -825,7 +833,9 @@ namespace UnitTest
testData.GetMaterial()->GetPropertyValues(),
testData.GetMaterial()->GetMaterialPropertiesLayout(),
propertyDynamicMetadata,
propertyGroupDynamicMetadata,
changedPropertyNames,
changedPropertyGroupNames,
&functor->GetMaterialPropertyDependencies()
);
@ -845,6 +855,66 @@ namespace UnitTest
EXPECT_EQ(-100.0f, propertyDynamicMetadata[Name{"general.distance"}].m_propertyRange.m_softMin.GetValue<float>());
EXPECT_EQ(100.0f, propertyDynamicMetadata[Name{"general.distance"}].m_propertyRange.m_softMax.GetValue<float>());
}
TEST_F(LuaMaterialFunctorTests, LuaMaterialFunctor_EditorContext_SetMaterialPropertyGroupVisibility)
{
using namespace AZ::RPI;
const char* functorScript =
R"(
function GetMaterialPropertyDependencies()
return { "general.mode" }
end
function ProcessEditor(context)
local mode = context:GetMaterialPropertyValue_uint("general.mode")
if (mode == 1) then
context:SetMaterialPropertyGroupVisibility("otherGroup", MaterialPropertyGroupVisibility_Enabled)
else
context:SetMaterialPropertyGroupVisibility("otherGroup", MaterialPropertyGroupVisibility_Hidden)
end
end
)";
TestMaterialData testData;
testData.Setup(
MaterialPropertyDataType::UInt, "general.mode",
MaterialPropertyDataType::Float, "otherGroup.value",
functorScript);
AZStd::unordered_set<AZ::Name> changedPropertyNames;
AZStd::unordered_map<Name, MaterialPropertyDynamicMetadata> propertyDynamicMetadata;
propertyDynamicMetadata[Name{"general.mode"}] = {};
propertyDynamicMetadata[Name{"otherGroup.value"}] = {};
AZStd::unordered_set<AZ::Name> changedPropertyGroupNames;
AZStd::unordered_map<Name, MaterialPropertyGroupDynamicMetadata> propertyGroupDynamicMetadata;
propertyGroupDynamicMetadata[Name{"general"}] = {};
propertyGroupDynamicMetadata[Name{"otherGroup"}] = {};
Ptr<MaterialFunctor> functor = testData.GetMaterialTypeAsset()->GetMaterialFunctors()[0];
AZ::RPI::MaterialFunctor::EditorContext context = AZ::RPI::MaterialFunctor::EditorContext(
testData.GetMaterial()->GetPropertyValues(),
testData.GetMaterial()->GetMaterialPropertiesLayout(),
propertyDynamicMetadata,
propertyGroupDynamicMetadata,
changedPropertyNames,
changedPropertyGroupNames,
&functor->GetMaterialPropertyDependencies()
);
testData.GetMaterial()->SetPropertyValue(testData.GetMaterialPropertyIndex(), MaterialPropertyValue{0u});
functor->Process(context);
EXPECT_EQ(MaterialPropertyGroupVisibility::Enabled, propertyGroupDynamicMetadata[Name{"general"}].m_visibility);
EXPECT_EQ(MaterialPropertyGroupVisibility::Hidden, propertyGroupDynamicMetadata[Name{"otherGroup"}].m_visibility);
testData.GetMaterial()->SetPropertyValue(testData.GetMaterialPropertyIndex(), MaterialPropertyValue{1u});
functor->Process(context);
EXPECT_EQ(MaterialPropertyGroupVisibility::Enabled, propertyGroupDynamicMetadata[Name{"general"}].m_visibility);
EXPECT_EQ(MaterialPropertyGroupVisibility::Enabled, propertyGroupDynamicMetadata[Name{"otherGroup"}].m_visibility);
}
TEST_F(LuaMaterialFunctorTests, LuaMaterialFunctor_RuntimeContext_SetRenderStates)
{

@ -29,6 +29,7 @@ namespace JsonSerializationTests
{
AZ::RPI::MaterialTypeSourceData::Reflect(context.get());
AZ::RPI::MaterialPropertyDescriptor::Reflect(context.get());
AZ::RPI::ReflectMaterialDynamicMetadata(context.get());
}
void Reflect(AZStd::unique_ptr<AZ::JsonRegistrationContext>& context)

@ -55,6 +55,7 @@ set(FILES
Include/Atom/RPI.Reflect/Material/MaterialAsset.h
Include/Atom/RPI.Reflect/Material/MaterialAssetCreatorCommon.h
Include/Atom/RPI.Reflect/Material/MaterialAssetCreator.h
Include/Atom/RPI.Reflect/Material/MaterialDynamicMetadata.h
Include/Atom/RPI.Reflect/Material/MaterialPropertyDescriptor.h
Include/Atom/RPI.Reflect/Material/MaterialPropertiesLayout.h
Include/Atom/RPI.Reflect/Material/MaterialPropertyValue.h
@ -135,6 +136,7 @@ set(FILES
Source/RPI.Reflect/Material/MaterialAssetCreatorCommon.cpp
Source/RPI.Reflect/Material/MaterialAssetCreator.cpp
Source/RPI.Reflect/Material/LuaMaterialFunctor.cpp
Source/RPI.Reflect/Material/MaterialDynamicMetadata.cpp
Source/RPI.Reflect/Material/MaterialPropertyDescriptor.cpp
Source/RPI.Reflect/Material/MaterialPropertiesLayout.cpp
Source/RPI.Reflect/Material/MaterialTypeAsset.cpp

@ -38,8 +38,8 @@ namespace AtomToolsFramework
Count
};
// Configures the initial state, data type, attributes, and values that describe
// the dynamic property and how it is presented
//! Configures the initial state, data type, attributes, and values that describe
//! the dynamic property and how it is presented
struct DynamicPropertyConfig
{
AZ_TYPE_INFO(DynamicPropertyConfig, "{9CA40E92-7F03-42BE-B6AA-51F30EE5796C}");
@ -98,7 +98,7 @@ namespace AtomToolsFramework
//! Returns true if the property has a valid value.
bool IsValid() const;
//! Returns the ID of the property.
//! Returns the ID of the property.
const AZ::Name GetId() const;
//! Returns the current property visibility.

@ -44,6 +44,12 @@ namespace AtomToolsFramework
const AZStd::string& groupDescription,
QWidget* groupWidget) = 0;
//! Sets the visibility of a specific property group. This impacts both the header and the widget.
virtual void SetGroupVisible(const AZStd::string& groupNameId, bool visible) = 0;
//! Returns the visibility of a specific property group.
virtual bool IsGroupVisible(const AZStd::string& groupNameId) const = 0;
//! Calls Refresh for a specific InspectorGroupWidget, allowing for non-destructive UI changes
virtual void RefreshGroup(const AZStd::string& groupNameId) = 0;

@ -57,6 +57,9 @@ namespace AtomToolsFramework
const AZStd::string& groupDescription,
QWidget* groupWidget) override;
void SetGroupVisible(const AZStd::string& groupNameId, bool visible) override;
bool IsGroupVisible(const AZStd::string& groupNameId) const override;
void RefreshGroup(const AZStd::string& groupNameId) override;
void RebuildGroup(const AZStd::string& groupNameId) override;

@ -69,6 +69,7 @@ namespace AtomToolsFramework
InspectorGroupHeaderWidget* groupHeader = new InspectorGroupHeaderWidget(m_ui->m_propertyContent);
groupHeader->setText(groupDisplayName.c_str());
groupHeader->setToolTip(groupDescription.c_str());
groupHeader->setObjectName(groupNameId.c_str());
m_layout->addWidget(groupHeader);
m_headers.push_back(groupHeader);
@ -81,6 +82,32 @@ namespace AtomToolsFramework
OnHeaderClicked(event, groupHeader, groupWidget);
});
}
void InspectorWidget::SetGroupVisible(const AZStd::string& groupNameId, bool visible)
{
for (size_t i = 0; i < m_groups.size(); ++i)
{
if (m_groups[i]->objectName() == groupNameId.c_str())
{
m_headers[i]->setVisible(visible);
m_groups[i]->setVisible(visible && m_headers[i]->IsExpanded());
break;
}
}
}
bool InspectorWidget::IsGroupVisible(const AZStd::string& groupNameId) const
{
for (auto& header : m_headers)
{
if (header->objectName() == groupNameId.c_str())
{
return header->isVisible();
}
}
return false;
}
void InspectorWidget::RefreshGroup(const AZStd::string& groupNameId)
{

@ -18,6 +18,7 @@
#include <AzCore/std/any.h>
#include <AtomToolsFramework/DynamicProperty/DynamicProperty.h>
#include <AtomToolsFramework/DynamicProperty/DynamicPropertyGroup.h>
namespace MaterialEditor
{
@ -77,6 +78,12 @@ namespace MaterialEditor
//! @param documentId unique id of material document for which the notification is sent
//! @param property object containing the property value and configuration that was modified
virtual void OnDocumentPropertyConfigModified([[maybe_unused]] const AZ::Uuid& documentId, [[maybe_unused]] const AtomToolsFramework::DynamicProperty& property) {}
//! Signal that the property group visibility has been changed.
//! @param documentId unique id of material document for which the notification is sent
//! @param groupId id of the group that changed
//! @param visible whether the property group is visible
virtual void OnDocumentPropertyGroupVisibilityChanged([[maybe_unused]] const AZ::Uuid& documentId, [[maybe_unused]] const AZ::Name& groupId, [[maybe_unused]] bool visible) {}
};
using MaterialDocumentNotificationBus = AZ::EBus<MaterialDocumentNotifications>;

@ -19,6 +19,7 @@
#include <AzCore/std/any.h>
#include <AtomToolsFramework/DynamicProperty/DynamicProperty.h>
#include <AtomToolsFramework/DynamicProperty/DynamicPropertyGroup.h>
namespace AZ
{
@ -67,6 +68,10 @@ namespace MaterialEditor
//! Returns a property object
//! If the document is not open or the id can't be found, an invalid property is returned.
virtual const AtomToolsFramework::DynamicProperty& GetProperty(const AZ::Name& propertyFullName) const = 0;
//! Returns whether a property group is visible
//! If the document is not open or the id can't be found, returns false.
virtual bool IsPropertyGroupVisible(const AZ::Name& propertyGroupFullName) const = 0;
//! Modify material property value
virtual void SetPropertyValue(const AZ::Name& propertyFullName, const AZStd::any& value) = 0;

@ -117,6 +117,24 @@ namespace MaterialEditor
const AtomToolsFramework::DynamicProperty& property = it->second;
return property;
}
bool MaterialDocument::IsPropertyGroupVisible(const AZ::Name& propertyGroupFullName) const
{
if (!IsOpen())
{
AZ_Error("MaterialDocument", false, "Material document is not open.");
return false;
}
const auto it = m_propertyGroupVisibility.find(propertyGroupFullName);
if (it == m_propertyGroupVisibility.end())
{
AZ_Error("MaterialDocument", false, "Material document property group could not be found: '%s'.", propertyGroupFullName.GetCStr());
return false;
}
return it->second;
}
void MaterialDocument::SetPropertyValue(const AZ::Name& propertyFullName, const AZStd::any& value)
{
@ -153,8 +171,12 @@ namespace MaterialEditor
Recompile();
AZStd::unordered_set<Name> changedPropertyNames = RunEditorMaterialFunctors(dirtyFlags);
for (const Name& changedPropertyName : changedPropertyNames)
EditorMaterialFunctorResult result = RunEditorMaterialFunctors(dirtyFlags);
for (const Name& changedPropertyGroupName : result.m_updatedPropertyGroups)
{
MaterialDocumentNotificationBus::Broadcast(&MaterialDocumentNotificationBus::Events::OnDocumentPropertyGroupVisibilityChanged, m_id, changedPropertyGroupName, IsPropertyGroupVisible(changedPropertyGroupName));
}
for (const Name& changedPropertyName : result.m_updatedProperties)
{
MaterialDocumentNotificationBus::Broadcast(&MaterialDocumentNotificationBus::Events::OnDocumentPropertyConfigModified, m_id, GetProperty(changedPropertyName));
}
@ -782,6 +804,12 @@ namespace MaterialEditor
return true;
});
// Populate the property group visibility map
for (MaterialTypeSourceData::GroupDefinition& group : m_materialTypeSourceData.GetGroupDefinitionsInDisplayOrder())
{
m_propertyGroupVisibility[AZ::Name{group.m_nameId}] = true;
}
// Adding properties for material type and parent as part of making dynamic
// properties and the inspector more general purpose.
// This allows the read only properties to appear in the inspector like any
@ -914,16 +942,26 @@ namespace MaterialEditor
}
}
AZStd::unordered_set<AZ::Name> MaterialDocument::RunEditorMaterialFunctors(AZ::RPI::MaterialPropertyFlags dirtyFlags)
MaterialDocument::EditorMaterialFunctorResult MaterialDocument::RunEditorMaterialFunctors(AZ::RPI::MaterialPropertyFlags dirtyFlags)
{
AZStd::unordered_set<AZ::Name> changedPropertyNames;
EditorMaterialFunctorResult result;
AZStd::unordered_map<AZ::Name, AZ::RPI::MaterialPropertyDynamicMetadata> propertyDynamicMetadata;
AZStd::unordered_map<AZ::Name, AZ::RPI::MaterialPropertyGroupDynamicMetadata> propertyGroupDynamicMetadata;
for (auto& propertyPair : m_properties)
{
AtomToolsFramework::DynamicProperty& property = propertyPair.second;
AtomToolsFramework::ConvertToPropertyMetaData(propertyDynamicMetadata[property.GetId()], property.GetConfig());
}
for (auto& groupPair : m_propertyGroupVisibility)
{
AZ::RPI::MaterialPropertyGroupDynamicMetadata& metadata = propertyGroupDynamicMetadata[AZ::Name{groupPair.first}];
bool visible = groupPair.second;
metadata.m_visibility = visible ?
AZ::RPI::MaterialPropertyGroupVisibility::Enabled : AZ::RPI::MaterialPropertyGroupVisibility::Hidden;
}
for (AZ::RPI::Ptr<AZ::RPI::MaterialFunctor>& functor : m_editorFunctors)
{
const AZ::RPI::MaterialPropertyFlags& materialPropertyDependencies = functor->GetMaterialPropertyDependencies();
@ -935,7 +973,9 @@ namespace MaterialEditor
m_materialInstance->GetPropertyValues(),
m_materialInstance->GetMaterialPropertiesLayout(),
propertyDynamicMetadata,
changedPropertyNames,
propertyGroupDynamicMetadata,
result.m_updatedProperties,
result.m_updatedPropertyGroups,
&materialPropertyDependencies
);
functor->Process(context);
@ -950,7 +990,13 @@ namespace MaterialEditor
property.SetConfig(propertyConfig);
}
return changedPropertyNames;
for (auto& updatedPropertyGroup : result.m_updatedPropertyGroups)
{
bool visible = propertyGroupDynamicMetadata[updatedPropertyGroup].m_visibility == AZ::RPI::MaterialPropertyGroupVisibility::Enabled;
m_propertyGroupVisibility[updatedPropertyGroup] = visible;
}
return result;
}
} // namespace MaterialEditor

@ -56,6 +56,7 @@ namespace MaterialEditor
const AZ::RPI::MaterialTypeSourceData* GetMaterialTypeSourceData() const override;
const AZStd::any& GetPropertyValue(const AZ::Name& propertyFullName) const override;
const AtomToolsFramework::DynamicProperty& GetProperty(const AZ::Name& propertyFullName) const override;
bool IsPropertyGroupVisible(const AZ::Name& propertyGroupFullName) const override;
void SetPropertyValue(const AZ::Name& propertyFullName, const AZStd::any& value) override;
bool Open(AZStd::string_view loadPath) override;
bool Rebuild() override;
@ -79,11 +80,14 @@ namespace MaterialEditor
// Predicate for evaluating properties
using PropertyFilterFunction = AZStd::function<bool(const AtomToolsFramework::DynamicProperty&)>;
// Map of documenmt's property
// Map of document's properties
using PropertyMap = AZStd::unordered_map<AZ::Name, AtomToolsFramework::DynamicProperty>;
// Map of raw property values for undo/redo comparison and storage
using PropertyValueMap = AZStd::unordered_map<AZ::Name, AZStd::any>;
// Map of document's property group visibility flags
using PropertyGroupVisibilityMap = AZStd::unordered_map<AZ::Name, bool>;
// Function to be bound for undo and redo
using UndoRedoFunction = AZStd::function<void()>;
@ -119,10 +123,16 @@ namespace MaterialEditor
void RestorePropertyValues(const PropertyValueMap& propertyValues);
struct EditorMaterialFunctorResult
{
AZStd::unordered_set<AZ::Name> m_updatedProperties;
AZStd::unordered_set<AZ::Name> m_updatedPropertyGroups;
};
// Run editor material functor to update editor metadata.
// @param dirtyFlags indicates which properties have changed, and thus which MaterialFunctors need to be run.
// @return names for the set of properties that have been changed or need update.
AZStd::unordered_set<AZ::Name> RunEditorMaterialFunctors(AZ::RPI::MaterialPropertyFlags dirtyFlags);
// @return names for the set of properties and groups that have been changed or need update.
EditorMaterialFunctorResult RunEditorMaterialFunctors(AZ::RPI::MaterialPropertyFlags dirtyFlags);
// Unique id of this material document
AZ::Uuid m_id = AZ::Uuid::CreateRandom();
@ -153,6 +163,9 @@ namespace MaterialEditor
// Collection of all material's properties
PropertyMap m_properties;
// Collection of all material's property groups
PropertyGroupVisibilityMap m_propertyGroupVisibility;
// Material functors that run in editor. See MaterialFunctor.h for details.
AZStd::vector<AZ::RPI::Ptr<AZ::RPI::MaterialFunctor>> m_editorFunctors;
@ -175,7 +188,7 @@ namespace MaterialEditor
int m_undoHistoryIndex = 0;
AZStd::any m_invalidValue;
AtomToolsFramework::DynamicProperty m_invalidProperty;
};
} // namespace MaterialEditor

@ -185,7 +185,7 @@ namespace MaterialEditor
}
}
void MaterialInspector::OnDocumentPropertyConfigModified(const AZ::Uuid& documentId, const AtomToolsFramework::DynamicProperty& property)
void MaterialInspector::OnDocumentPropertyConfigModified(const AZ::Uuid&, const AtomToolsFramework::DynamicProperty& property)
{
for (auto& groupPair : m_groups)
{
@ -197,18 +197,28 @@ namespace MaterialEditor
if (reflectedProperty.GetVisibility() != property.GetVisibility())
{
reflectedProperty.SetConfig(property.GetConfig());
AtomToolsFramework::InspectorRequestBus::Event(documentId, &AtomToolsFramework::InspectorRequestBus::Events::RebuildGroup, groupPair.first);
RebuildGroup(groupPair.first);
}
else
{
reflectedProperty.SetConfig(property.GetConfig());
AtomToolsFramework::InspectorRequestBus::Event(documentId, &AtomToolsFramework::InspectorRequestBus::Events::RefreshGroup, groupPair.first);
RefreshGroup(groupPair.first);
}
return;
}
}
}
}
void MaterialInspector::OnDocumentPropertyGroupVisibilityChanged(const AZ::Uuid&, const AZ::Name& groupId, bool visible)
{
auto groupIter = m_groups.find(groupId.GetStringView());
if(groupIter != m_groups.end())
{
SetGroupVisible(groupIter->first, visible);
}
}
void MaterialInspector::BeforePropertyModified(AzToolsFramework::InstanceDataNode* pNode)
{

@ -50,6 +50,7 @@ namespace MaterialEditor
void OnDocumentOpened(const AZ::Uuid& documentId) override;
void OnDocumentPropertyValueModified(const AZ::Uuid& documentId, const AtomToolsFramework::DynamicProperty& property) override;
void OnDocumentPropertyConfigModified(const AZ::Uuid& documentId, const AtomToolsFramework::DynamicProperty& property) override;
void OnDocumentPropertyGroupVisibilityChanged(const AZ::Uuid& documentId, const AZ::Name& groupId, bool visible) override;
// AzToolsFramework::IPropertyEditorNotify overrides...
void BeforePropertyModified(AzToolsFramework::InstanceDataNode* pNode) override;

@ -288,15 +288,17 @@ namespace AZ
void MaterialPropertyInspector::RunEditorMaterialFunctors()
{
AZStd::unordered_set<AZ::Name> changedPropertyNames;
AZStd::unordered_set<AZ::Name> changedPropertyGroupNames;
// Convert editor property configuration data into material property meta data so that it can be used to execute functors
AZStd::unordered_map<AZ::Name, AZ::RPI::MaterialPropertyDynamicMetadata> propertyDynamicMetadata;
for (auto& group : m_groups)
AZStd::unordered_map<AZ::Name, AZ::RPI::MaterialPropertyGroupDynamicMetadata> propertyGroupDynamicMetadata;
for (auto& groupPair : m_groups)
{
for (auto& property : group.second.m_properties)
{
AtomToolsFramework::ConvertToPropertyMetaData(propertyDynamicMetadata[property.GetId()], property.GetConfig());
}
AZ::RPI::MaterialPropertyGroupDynamicMetadata& metadata = propertyGroupDynamicMetadata[AZ::Name{groupPair.first}];
metadata.m_visibility = IsGroupVisible(groupPair.first) ?
AZ::RPI::MaterialPropertyGroupVisibility::Enabled : AZ::RPI::MaterialPropertyGroupVisibility::Hidden;
}
for (AZ::RPI::Ptr<AZ::RPI::MaterialFunctor>& functor : m_editorFunctors)
@ -310,7 +312,9 @@ namespace AZ
m_materialInstance->GetPropertyValues(),
m_materialInstance->GetMaterialPropertiesLayout(),
propertyDynamicMetadata,
propertyGroupDynamicMetadata,
changedPropertyNames,
changedPropertyGroupNames,
&materialPropertyDependencies
);
functor->Process(context);
@ -319,9 +323,16 @@ namespace AZ
m_dirtyPropertyFlags.reset();
// Apply any changes to material property meta data back to the editor property configurations
for (auto& group : m_groups)
for (auto& groupPair : m_groups)
{
for (auto& property : group.second.m_properties)
AZ::Name groupName{groupPair.first};
if (changedPropertyGroupNames.find(groupName) != changedPropertyGroupNames.end())
{
SetGroupVisible(groupPair.first, propertyGroupDynamicMetadata[groupName].m_visibility == AZ::RPI::MaterialPropertyGroupVisibility::Enabled);
}
for (auto& property : groupPair.second.m_properties)
{
AtomToolsFramework::DynamicPropertyConfig propertyConfig = property.GetConfig();

Loading…
Cancel
Save