Merge pull request #736 from aws-lumberyard-dev/Atom/santorac/NewLayeringWorkflow
Updated StandardMultilayerPBR To Use New Layering Model ATOM-15518 "Change Multilayer PBR To Use Lerp Base Blending" ATOM-14688 "Disable Individual Layers" ATOM-14793 "Fix Inconsistent Casing For LuaMaterialFunctorRuntimeContext" ATOM-4120 "Stabilize Standard PBR Regarding Subsurface and Translucency" (partial) Changed to lerp-based blending, with an implicit base layer. Refactored the shader code to collate all the code for each layer into a couple structs and utility functions. This makes the code easier to maintain, and in particular will make it easy for me to add Enable flags for the layers in a subsequent commit. Added support for disabling individual layers, so you can easily make a 2-layer material instead of a 3-layer material. Added support to the material system and MaterialEditor for hiding entire property groups. This is used to hide the disabled layers. Added and updated test data to reflect the new blend model. Removed subsurface scattering and translucency from StandardMultilayerPBR. Note to reviewers: There are a lot of changes here, but they are broken down into separate commits. I recommend going through each commit individually rather than doing one comprehensive review. ASV changes are here: aws-lumberyard/o3de-atom-sampleviewer#55
This commit is contained in:
+4
-4
@@ -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
|
||||
|
||||
+25
-204
@@ -23,11 +23,6 @@
|
||||
"displayName": "UVs",
|
||||
"description": "Properties for configuring UV transforms for the entire material, including the blend masks."
|
||||
},
|
||||
{
|
||||
"id": "subsurfaceScattering",
|
||||
"displayName": "Subsurface Scattering",
|
||||
"description": "Properties for configuring subsurface scattering effects."
|
||||
},
|
||||
{
|
||||
// Note: this property group is used in the DiffuseGlobalIllumination pass, it is not read by the StandardPBR shader
|
||||
"id": "irradiance",
|
||||
@@ -204,7 +199,7 @@
|
||||
"displayName": "Debug Draw Mode",
|
||||
"description": "Enables various debug view features.",
|
||||
"type": "Enum",
|
||||
"enumValues": [ "None", "BlendMaskValues", "DepthMaps" ],
|
||||
"enumValues": [ "None", "BlendSource", "DepthMaps" ],
|
||||
"defaultValue": "None",
|
||||
"connection": {
|
||||
"type": "ShaderOption",
|
||||
@@ -300,6 +295,28 @@
|
||||
}
|
||||
],
|
||||
"blend": [
|
||||
{
|
||||
"id": "enableLayer2",
|
||||
"displayName": "Enable Layer 2",
|
||||
"description": "Whether to enable layer 2.",
|
||||
"type": "Bool",
|
||||
"defaultValue": false,
|
||||
"connection": {
|
||||
"type": "ShaderOption",
|
||||
"id": "o_layer2_enabled"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "enableLayer3",
|
||||
"displayName": "Enable Layer 3",
|
||||
"description": "Whether to enable layer 3.",
|
||||
"type": "Bool",
|
||||
"defaultValue": false,
|
||||
"connection": {
|
||||
"type": "ShaderOption",
|
||||
"id": "o_layer3_enabled"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "blendSource",
|
||||
"displayName": "Blend Source",
|
||||
@@ -467,183 +484,6 @@
|
||||
"step": 0.1
|
||||
}
|
||||
],
|
||||
"subsurfaceScattering": [
|
||||
{
|
||||
"id": "enableSubsurfaceScattering",
|
||||
"displayName": "Subsurface Scattering",
|
||||
"description": "Enable subsurface scattering feature, this will disable metallic and parallax mapping property due to incompatibility",
|
||||
"type": "Bool",
|
||||
"defaultValue": false,
|
||||
"connection": {
|
||||
"type": "ShaderOption",
|
||||
"id": "o_enableSubsurfaceScattering"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "subsurfaceScatterFactor",
|
||||
"displayName": " Factor",
|
||||
"description": "Strength factor for scaling percentage of subsurface scattering effect applied",
|
||||
"type": "float",
|
||||
"defaultValue": 1.0,
|
||||
"min": 0.0,
|
||||
"max": 1.0,
|
||||
"connection": {
|
||||
"type": "ShaderInput",
|
||||
"id": "m_subsurfaceScatteringFactor"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "influenceMap",
|
||||
"displayName": " Influence Map",
|
||||
"description": "Use texture map to control the strength of subsurface scattering",
|
||||
"type": "Image",
|
||||
"connection": {
|
||||
"type": "ShaderInput",
|
||||
"id": "m_subsurfaceScatteringInfluenceMap"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "useInfluenceMap",
|
||||
"displayName": " Use Influence Map",
|
||||
"description": "Whether to use the texture map as influence mask.",
|
||||
"type": "Bool",
|
||||
"defaultValue": true
|
||||
},
|
||||
{
|
||||
"id": "influenceMapUv",
|
||||
"displayName": " UV",
|
||||
"description": "Influence map UV set",
|
||||
"type": "Enum",
|
||||
"enumIsUv": true,
|
||||
"defaultValue": "Tiled",
|
||||
"connection": {
|
||||
"type": "ShaderInput",
|
||||
"id": "m_subsurfaceScatteringInfluenceMapUvIndex"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "scatterColor",
|
||||
"displayName": " Scatter color",
|
||||
"description": "Color of volume light traveled through",
|
||||
"type": "Color",
|
||||
"defaultValue": [ 1.0, 0.27, 0.13 ]
|
||||
},
|
||||
{
|
||||
"id": "scatterDistance",
|
||||
"displayName": " Scatter distance",
|
||||
"description": "How far light traveled inside the volume",
|
||||
"type": "float",
|
||||
"defaultValue": 8,
|
||||
"min": 0.0,
|
||||
"softMax": 20.0
|
||||
},
|
||||
{
|
||||
"id": "quality",
|
||||
"displayName": " Quality",
|
||||
"description": "How much percent of sample will be used for each pixel, more samples improve quality and reduce artifacts, especially when the scatter distance is relatively large, but slow down computation time, 1.0 = full set 200 samples per pixel",
|
||||
"type": "float",
|
||||
"defaultValue": 0.4,
|
||||
"min": 0.2,
|
||||
"max": 1.0,
|
||||
"connection": {
|
||||
"type": "ShaderInput",
|
||||
"id": "m_subsurfaceScatteringQuality"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "transmissionMode",
|
||||
"displayName": "Transmission",
|
||||
"description": "Algorithm used for calculating transmission",
|
||||
"type": "Enum",
|
||||
"enumValues": [ "None", "ThickObject", "ThinObject" ],
|
||||
"defaultValue": "None",
|
||||
"connection": {
|
||||
"type": "ShaderOption",
|
||||
"id": "o_transmission_mode"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "thickness",
|
||||
"displayName": " Thickness",
|
||||
"description": "Normalized global thickness, the maxima between this value (multiplied by thickness map if enabled) and thickness from shadow map (if applicable) will be used as final thickness of pixel",
|
||||
"type": "float",
|
||||
"defaultValue": 0.5,
|
||||
"min": 0.0,
|
||||
"max": 1.0
|
||||
},
|
||||
{
|
||||
"id": "thicknessMap",
|
||||
"displayName": " Thickness Map",
|
||||
"description": "Use a greyscale texture for per pixel thickness",
|
||||
"type": "Image",
|
||||
"connection": {
|
||||
"type": "ShaderInput",
|
||||
"id": "m_transmissionThicknessMap"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "useThicknessMap",
|
||||
"displayName": " Use Thickness Map",
|
||||
"description": "Whether to use the thickness map",
|
||||
"type": "Bool",
|
||||
"defaultValue": true
|
||||
},
|
||||
{
|
||||
"id": "thicknessMapUv",
|
||||
"displayName": " UV",
|
||||
"description": "Thickness map UV set",
|
||||
"type": "Enum",
|
||||
"enumIsUv": true,
|
||||
"defaultValue": "Tiled",
|
||||
"connection": {
|
||||
"type": "ShaderInput",
|
||||
"id": "m_transmissionThicknessMapUvIndex"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "transmissionTint",
|
||||
"displayName": " Transmission Tint",
|
||||
"description": "Color of the volume light travelling through",
|
||||
"type": "Color",
|
||||
"defaultValue": [ 1.0, 0.8, 0.6 ]
|
||||
},
|
||||
{
|
||||
"id": "transmissionPower",
|
||||
"displayName": " Power",
|
||||
"description": "How much transmitted light scatter radially ",
|
||||
"type": "float",
|
||||
"defaultValue": 6.0,
|
||||
"min": 0.0,
|
||||
"softMax": 20.0
|
||||
},
|
||||
{
|
||||
"id": "transmissionDistortion",
|
||||
"displayName": " Distortion",
|
||||
"description": "How much light direction distorted towards surface normal",
|
||||
"type": "float",
|
||||
"defaultValue": 0.1,
|
||||
"min": 0.0,
|
||||
"max": 1.0
|
||||
},
|
||||
{
|
||||
"id": "transmissionAttenuation",
|
||||
"displayName": " Attenuation",
|
||||
"description": "How fast transmitted light fade with thickness",
|
||||
"type": "float",
|
||||
"defaultValue": 4.0,
|
||||
"min": 0.0,
|
||||
"softMax": 20.0
|
||||
},
|
||||
{
|
||||
"id": "transmissionScale",
|
||||
"displayName": " Scale",
|
||||
"description": "Strength of transmission",
|
||||
"type": "float",
|
||||
"defaultValue": 3.0,
|
||||
"min": 0.0,
|
||||
"softMax": 20.0
|
||||
}
|
||||
],
|
||||
"irradiance": [
|
||||
// Note: this property group is used in the DiffuseGlobalIllumination pass, it is not read by the StandardPBR shader
|
||||
{
|
||||
@@ -2845,22 +2685,9 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
// Preprocess & build parameter set for subsurface scattering and translucency
|
||||
"type": "HandleSubsurfaceScatteringParameters",
|
||||
"type": "Lua",
|
||||
"args": {
|
||||
"mode": "subsurfaceScattering.transmissionMode",
|
||||
"scale" : "subsurfaceScattering.transmissionScale",
|
||||
"power" : "subsurfaceScattering.transmissionPower",
|
||||
"distortion" : "subsurfaceScattering.transmissionDistortion",
|
||||
"attenuation" : "subsurfaceScattering.transmissionAttenuation",
|
||||
"tintColor" : "subsurfaceScattering.transmissionTint",
|
||||
"thickness" : "subsurfaceScattering.thickness",
|
||||
"enabled": "subsurfaceScattering.enableSubsurfaceScattering",
|
||||
"scatterDistanceColor" : "subsurfaceScattering.scatterColor",
|
||||
"scatterDistanceIntensity" : "subsurfaceScattering.scatterDistance",
|
||||
"scatterDistanceShaderInput" : "m_scatterDistance",
|
||||
"parametersShaderInput" : "m_transmissionParams",
|
||||
"tintThickenssShaderInput" : "m_transmissionTintThickness"
|
||||
"file": "StandardMultilayerPBR_LayerEnable.lua"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -2875,12 +2702,6 @@
|
||||
"file": "StandardMultilayerPBR_Parallax.lua"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Lua",
|
||||
"args": {
|
||||
"file": "StandardPBR_SubsurfaceState.lua"
|
||||
}
|
||||
},
|
||||
//##############################################################################################
|
||||
// Layer 1 Functors
|
||||
//##############################################################################################
|
||||
|
||||
+79
-56
@@ -42,7 +42,7 @@ COMMON_SRG_INPUTS_PARALLAX(prefix)
|
||||
|
||||
ShaderResourceGroup MaterialSrg : SRG_PerMaterial
|
||||
{
|
||||
Texture2D m_blendMaskTexture;
|
||||
Texture2D m_blendMaskTexture;
|
||||
uint m_blendMaskUvIndex;
|
||||
|
||||
// Auto-generate material SRG fields for common inputs for each layer
|
||||
@@ -91,29 +91,14 @@ ShaderResourceGroup MaterialSrg : SRG_PerMaterial
|
||||
MipFilter = Linear;
|
||||
};
|
||||
|
||||
// Parameters for subsurface scattering
|
||||
float m_subsurfaceScatteringFactor;
|
||||
float m_subsurfaceScatteringQuality;
|
||||
float3 m_scatterDistance;
|
||||
Texture2D m_subsurfaceScatteringInfluenceMap;
|
||||
uint m_subsurfaceScatteringInfluenceMapUvIndex;
|
||||
|
||||
// Parameters for transmission
|
||||
|
||||
// Elements of m_transmissionParams:
|
||||
// Thick object mode: (attenuation coefficient, power, distortion, scale)
|
||||
// Thin object mode: (float3 scatter distance, scale)
|
||||
float4 m_transmissionParams;
|
||||
|
||||
// (float3 TintColor, thickness)
|
||||
float4 m_transmissionTintThickness;
|
||||
Texture2D m_transmissionThicknessMap;
|
||||
uint m_transmissionThicknessMapUvIndex;
|
||||
}
|
||||
|
||||
// ------ Shader Options ----------------------------------------
|
||||
|
||||
enum class DebugDrawMode { None, BlendMaskValues, DepthMaps };
|
||||
option bool o_layer2_enabled;
|
||||
option bool o_layer3_enabled;
|
||||
|
||||
enum class DebugDrawMode { None, BlendSource, DepthMaps };
|
||||
option DebugDrawMode o_debugDrawMode;
|
||||
|
||||
enum class BlendMaskSource { TextureMap, VertexColors, Fallback };
|
||||
@@ -127,6 +112,10 @@ option bool o_blendMask_isBound;
|
||||
|
||||
// ------ Blend Utilities ----------------------------------------
|
||||
|
||||
// This is mainly used to pass extra data to the GetDepth callback function during the parallax depth search.
|
||||
// But since we have it, we use it in some other functions as well rather than passing it around.
|
||||
static float3 s_blendMaskFromVertexStream;
|
||||
|
||||
//! Returns the BlendMaskSource that will actually be used when rendering (not necessarily the same BlendMaskSource specified by the user)
|
||||
BlendMaskSource GetFinalBlendMaskSource()
|
||||
{
|
||||
@@ -151,40 +140,84 @@ BlendMaskSource GetFinalBlendMaskSource()
|
||||
}
|
||||
}
|
||||
|
||||
//! Return the final blend mask values to be used for rendering, based on the available data and configuration.
|
||||
float3 GetBlendMaskValues(float2 uv, float3 vertexBlendMask)
|
||||
//! Return the raw blend source values directly from the blend mask or vertex colors, depending on the available data and configuration.
|
||||
//! layer1 is an implicit base layer
|
||||
//! layer2 is weighted by r
|
||||
//! layer3 is weighted by g
|
||||
//! b is reserved for perhaps a dedicated puddle layer
|
||||
float3 GetBlendSourceValues(float2 uv)
|
||||
{
|
||||
float3 blendMaskValues;
|
||||
float3 blendSourceValues = float3(0,0,0);
|
||||
|
||||
switch(GetFinalBlendMaskSource())
|
||||
if(o_layer2_enabled || o_layer3_enabled)
|
||||
{
|
||||
case BlendMaskSource::TextureMap:
|
||||
blendMaskValues = MaterialSrg::m_blendMaskTexture.Sample(MaterialSrg::m_sampler, uv).rgb;
|
||||
break;
|
||||
case BlendMaskSource::VertexColors:
|
||||
blendMaskValues = vertexBlendMask;
|
||||
break;
|
||||
case BlendMaskSource::Fallback:
|
||||
blendMaskValues = float3(1,1,1);
|
||||
break;
|
||||
switch(GetFinalBlendMaskSource())
|
||||
{
|
||||
case BlendMaskSource::TextureMap:
|
||||
blendSourceValues = MaterialSrg::m_blendMaskTexture.Sample(MaterialSrg::m_sampler, uv).rgb;
|
||||
break;
|
||||
case BlendMaskSource::VertexColors:
|
||||
blendSourceValues = s_blendMaskFromVertexStream;
|
||||
break;
|
||||
}
|
||||
|
||||
if(!o_layer2_enabled)
|
||||
{
|
||||
blendSourceValues.r = 0.0;
|
||||
}
|
||||
|
||||
if(!o_layer3_enabled)
|
||||
{
|
||||
blendSourceValues.g = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
blendMaskValues = blendMaskValues / (blendMaskValues.r + blendMaskValues.g + blendMaskValues.b);
|
||||
|
||||
return blendMaskValues;
|
||||
return blendSourceValues;
|
||||
}
|
||||
|
||||
float BlendLayers(float layer1, float layer2, float layer3, float3 blendMaskValues)
|
||||
//! Return the final blend mask values to be used for rendering, based on the available data and configuration.
|
||||
//! @return The blend weights for each layer.
|
||||
//! Even though layer1 not explicitly specified in the blend source data, it is explicitly included with the returned values.
|
||||
//! layer1 = r
|
||||
//! layer2 = g
|
||||
//! layer3 = b
|
||||
float3 GetBlendWeights(float2 uv)
|
||||
{
|
||||
return dot(float3(layer1, layer2, layer3), blendMaskValues);
|
||||
float3 blendWeights;
|
||||
|
||||
if(o_layer2_enabled || o_layer3_enabled)
|
||||
{
|
||||
float3 blendSourceValues = GetBlendSourceValues(uv);
|
||||
|
||||
// Calculate blend weights such that multiplying and adding them with layer data is equivalent
|
||||
// to lerping between each layer.
|
||||
// final = lerp(final, layer1, blendWeights.r)
|
||||
// final = lerp(final, layer2, blendWeights.g)
|
||||
// final = lerp(final, layer3, blendWeights.b)
|
||||
|
||||
blendWeights.b = blendSourceValues.g;
|
||||
blendWeights.g = (1.0 - blendSourceValues.g) * blendSourceValues.r;
|
||||
blendWeights.r = (1.0 - blendSourceValues.g) * (1.0 - blendSourceValues.r);
|
||||
}
|
||||
else
|
||||
{
|
||||
blendWeights = float3(1,0,0);
|
||||
}
|
||||
|
||||
return blendWeights;
|
||||
}
|
||||
float2 BlendLayers(float2 layer1, float2 layer2, float2 layer3, float3 blendMaskValues)
|
||||
|
||||
float BlendLayers(float layer1, float layer2, float layer3, float3 blendWeights)
|
||||
{
|
||||
return layer1 * blendMaskValues.r + layer2 * blendMaskValues.g + layer3 * blendMaskValues.b;
|
||||
return dot(float3(layer1, layer2, layer3), blendWeights);
|
||||
}
|
||||
float3 BlendLayers(float3 layer1, float3 layer2, float3 layer3, float3 blendMaskValues)
|
||||
float2 BlendLayers(float2 layer1, float2 layer2, float2 layer3, float3 blendWeights)
|
||||
{
|
||||
return layer1 * blendMaskValues.r + layer2 * blendMaskValues.g + layer3 * blendMaskValues.b;
|
||||
return layer1 * blendWeights.r + layer2 * blendWeights.g + layer3 * blendWeights.b;
|
||||
}
|
||||
float3 BlendLayers(float3 layer1, float3 layer2, float3 layer3, float3 blendWeights)
|
||||
{
|
||||
return layer1 * blendWeights.r + layer2 * blendWeights.g + layer3 * blendWeights.b;
|
||||
}
|
||||
|
||||
// ------ Parallax Utilities ----------------------------------------
|
||||
@@ -203,16 +236,6 @@ bool ShouldHandleParallaxInDepthShaders()
|
||||
return ShouldHandleParallax() && o_parallax_enablePixelDepthOffset;
|
||||
}
|
||||
|
||||
// These static values are used to pass extra data to the GetDepth callback function during the parallax depth search.
|
||||
static float3 s_blendMaskFromVertexStream;
|
||||
|
||||
//! Setup static variables that are needed by the GetDepth callback function
|
||||
//! @param vertexBlendMask the blend mask values from the vertex input stream.
|
||||
void GetDepth_Setup(float3 vertexBlendMask)
|
||||
{
|
||||
s_blendMaskFromVertexStream = vertexBlendMask;
|
||||
}
|
||||
|
||||
// Callback function for ParallaxMapping.azsli
|
||||
DepthResult GetDepth(float2 uv, float2 uv_ddx, float2 uv_ddy)
|
||||
{
|
||||
@@ -231,7 +254,7 @@ DepthResult GetDepth(float2 uv, float2 uv_ddx, float2 uv_ddy)
|
||||
layerDepthValues.r -= MaterialSrg::m_layer1_m_depthOffset;
|
||||
}
|
||||
|
||||
if(o_layer2_o_useDepthMap)
|
||||
if(o_layer2_enabled && o_layer2_o_useDepthMap)
|
||||
{
|
||||
float2 layerUv = uv;
|
||||
if(MaterialSrg::m_parallaxUvIndex == 0)
|
||||
@@ -244,7 +267,7 @@ DepthResult GetDepth(float2 uv, float2 uv_ddx, float2 uv_ddy)
|
||||
layerDepthValues.g -= MaterialSrg::m_layer2_m_depthOffset;
|
||||
}
|
||||
|
||||
if(o_layer3_o_useDepthMap)
|
||||
if(o_layer3_enabled && o_layer3_o_useDepthMap)
|
||||
{
|
||||
float2 layerUv = uv;
|
||||
if(MaterialSrg::m_parallaxUvIndex == 0)
|
||||
@@ -260,8 +283,8 @@ DepthResult GetDepth(float2 uv, float2 uv_ddx, float2 uv_ddy)
|
||||
// Note, when the blend source is BlendMaskSource::VertexColors, parallax will not be able to blend correctly between layers. It will end up using the same blend mask values
|
||||
// for every UV position when searching for the intersection. This leads to smearing artifacts at the transition point, but these won't be so noticeable as long as
|
||||
// you have a small depth factor relative to the size of the blend transition.
|
||||
float3 blendMaskValues = GetBlendMaskValues(uv, s_blendMaskFromVertexStream);
|
||||
float3 blendWeights = GetBlendWeights(uv);
|
||||
|
||||
float depth = BlendLayers(layerDepthValues.r, layerDepthValues.g, layerDepthValues.b, blendMaskValues);
|
||||
float depth = BlendLayers(layerDepthValues.r, layerDepthValues.g, layerDepthValues.b, blendWeights);
|
||||
return DepthResultAbsolute(depth);
|
||||
}
|
||||
|
||||
+1
-1
@@ -108,7 +108,7 @@ PSDepthOutput MainPS(VSDepthOutput IN, bool isFrontFace : SV_IsFrontFace)
|
||||
float3 bitangents[UvSetCount] = { IN.m_bitangent.xyz, float3(0, 0, 0) };
|
||||
PrepareGeneratedTangent(IN.m_normal, IN.m_worldPosition, isFrontFace, IN.m_uv, UvSetCount, tangents, bitangents, 1);
|
||||
|
||||
GetDepth_Setup(IN.m_blendMask);
|
||||
s_blendMaskFromVertexStream = IN.m_blendMask;
|
||||
|
||||
float depth;
|
||||
|
||||
|
||||
+252
-175
@@ -55,7 +55,6 @@ DEFINE_LAYER_OPTIONS(o_layer1_)
|
||||
DEFINE_LAYER_OPTIONS(o_layer2_)
|
||||
DEFINE_LAYER_OPTIONS(o_layer3_)
|
||||
|
||||
#include "MaterialInputs/SubsurfaceInput.azsli"
|
||||
#include "MaterialInputs/TransmissionInput.azsli"
|
||||
#include "StandardMultilayerPBR_Common.azsli"
|
||||
|
||||
@@ -127,6 +126,181 @@ VSOutput ForwardPassVS(VSInput IN)
|
||||
return OUT;
|
||||
}
|
||||
|
||||
//! Collects all the raw Standard material inputs for a single layer. See ProcessStandardMaterialInputs().
|
||||
struct StandardMaterialInputs
|
||||
{
|
||||
COMMON_SRG_INPUTS_BASE_COLOR()
|
||||
COMMON_SRG_INPUTS_ROUGHNESS()
|
||||
COMMON_SRG_INPUTS_METALLIC()
|
||||
COMMON_SRG_INPUTS_SPECULAR_F0()
|
||||
COMMON_SRG_INPUTS_NORMAL()
|
||||
COMMON_SRG_INPUTS_CLEAR_COAT()
|
||||
COMMON_SRG_INPUTS_OCCLUSION()
|
||||
COMMON_SRG_INPUTS_EMISSIVE()
|
||||
// Note parallax is omitted here because that requires special handling.
|
||||
|
||||
bool m_normal_useTexture;
|
||||
bool m_baseColor_useTexture;
|
||||
bool m_metallic_useTexture;
|
||||
bool m_specularF0_useTexture;
|
||||
bool m_roughness_useTexture;
|
||||
bool m_emissiveEnabled;
|
||||
bool m_emissive_useTexture;
|
||||
bool m_diffuseOcclusion_useTexture;
|
||||
bool m_specularOcclusion_useTexture;
|
||||
bool m_clearCoatEnabled;
|
||||
bool m_clearCoat_factor_useTexture;
|
||||
bool m_clearCoat_roughness_useTexture;
|
||||
bool m_clearCoat_normal_useTexture;
|
||||
|
||||
TextureBlendMode m_baseColorTextureBlendMode;
|
||||
|
||||
float2 m_vertexUv[UvSetCount];
|
||||
float3x3 m_uvMatrix;
|
||||
float m_normal;
|
||||
float3 m_tangents[UvSetCount];
|
||||
float3 m_bitangents[UvSetCount];
|
||||
|
||||
sampler m_sampler;
|
||||
|
||||
bool m_isFrontFace;
|
||||
};
|
||||
|
||||
//! Holds the final processed material inputs, after all flags have been checked, textures have been sampled, factors have been applied, etc.
|
||||
//! This data is ready to be copied into a Surface and/or LightingData struct for the lighting system to consume.
|
||||
class ProcessedMaterialInputs
|
||||
{
|
||||
float3 m_normalTS; //!< Normal in tangent-space
|
||||
float3 m_baseColor;
|
||||
float3 m_specularF0Factor;
|
||||
float m_metallic;
|
||||
float m_roughness;
|
||||
float3 m_emissiveLighting;
|
||||
float m_diffuseAmbientOcclusion;
|
||||
float m_specularOcclusion;
|
||||
ClearCoatSurfaceData m_clearCoat;
|
||||
|
||||
void InitializeToZero()
|
||||
{
|
||||
m_normalTS = float3(0,0,0);
|
||||
m_baseColor = float3(0,0,0);
|
||||
m_specularF0Factor = float3(0,0,0);
|
||||
m_metallic = 0.0f;
|
||||
m_roughness = 0.0f;
|
||||
m_emissiveLighting = float3(0,0,0);
|
||||
m_diffuseAmbientOcclusion = 0;
|
||||
m_specularOcclusion = 0;
|
||||
m_clearCoat.InitializeToZero();
|
||||
}
|
||||
};
|
||||
|
||||
//! Processes the set of Standard material inputs for a single layer.
|
||||
//! The FILL_STANDARD_MATERIAL_INPUTS() macro below can be used to fill the StandardMaterialInputs struct.
|
||||
ProcessedMaterialInputs ProcessStandardMaterialInputs(StandardMaterialInputs inputs)
|
||||
{
|
||||
ProcessedMaterialInputs result;
|
||||
|
||||
float2 transformedUv[UvSetCount];
|
||||
transformedUv[0] = mul(inputs.m_uvMatrix, float3(inputs.m_vertexUv[0], 1.0)).xy;
|
||||
transformedUv[1] = inputs.m_vertexUv[1];
|
||||
|
||||
float3x3 normalUvMatrix = inputs.m_normalMapUvIndex == 0 ? inputs.m_uvMatrix : CreateIdentity3x3();
|
||||
result.m_normalTS = GetNormalInputTS(inputs.m_normalMap, inputs.m_sampler, transformedUv[inputs.m_normalMapUvIndex], inputs.m_flipNormalX, inputs.m_flipNormalY, normalUvMatrix, inputs.m_normal_useTexture, inputs.m_normalFactor);
|
||||
|
||||
float3 sampledBaseColor = GetBaseColorInput(inputs.m_baseColorMap, inputs.m_sampler, transformedUv[inputs.m_baseColorMapUvIndex], inputs.m_baseColor.rgb, inputs.m_baseColor_useTexture);
|
||||
result.m_baseColor = BlendBaseColor(sampledBaseColor, inputs.m_baseColor.rgb, inputs.m_baseColorFactor, inputs.m_baseColorTextureBlendMode, inputs.m_baseColor_useTexture);
|
||||
result.m_specularF0Factor = GetSpecularInput(inputs.m_specularF0Map, inputs.m_sampler, transformedUv[inputs.m_specularF0MapUvIndex], inputs.m_specularF0Factor, inputs.m_specularF0_useTexture);
|
||||
result.m_metallic = GetMetallicInput(inputs.m_metallicMap, inputs.m_sampler, transformedUv[inputs.m_metallicMapUvIndex], inputs.m_metallicFactor, inputs.m_metallic_useTexture);
|
||||
result.m_roughness = GetRoughnessInput(inputs.m_roughnessMap, MaterialSrg::m_sampler, transformedUv[inputs.m_roughnessMapUvIndex], inputs.m_roughnessFactor, inputs.m_roughnessLowerBound, inputs.m_roughnessUpperBound, inputs.m_roughness_useTexture);
|
||||
|
||||
result.m_emissiveLighting = GetEmissiveInput(inputs.m_emissiveMap, inputs.m_sampler, transformedUv[inputs.m_emissiveMapUvIndex], inputs.m_emissiveIntensity, inputs.m_emissiveColor.rgb, inputs.m_emissiveEnabled, inputs.m_emissive_useTexture);
|
||||
result.m_diffuseAmbientOcclusion = GetOcclusionInput(inputs.m_diffuseOcclusionMap, inputs.m_sampler, transformedUv[inputs.m_diffuseOcclusionMapUvIndex], inputs.m_diffuseOcclusionFactor, inputs.m_diffuseOcclusion_useTexture);
|
||||
result.m_specularOcclusion = GetOcclusionInput(inputs.m_specularOcclusionMap, MaterialSrg::m_sampler, transformedUv[inputs.m_specularOcclusionMapUvIndex], inputs.m_specularOcclusionFactor, inputs.m_specularOcclusion_useTexture);
|
||||
|
||||
result.m_clearCoat.InitializeToZero();
|
||||
if(inputs.m_clearCoatEnabled)
|
||||
{
|
||||
float3x3 clearCoatUvMatrix = inputs.m_clearCoatNormalMapUvIndex == 0 ? inputs.m_uvMatrix : CreateIdentity3x3();
|
||||
|
||||
GetClearCoatInputs(inputs.m_clearCoatInfluenceMap, transformedUv[inputs.m_clearCoatInfluenceMapUvIndex], inputs.m_clearCoatFactor, inputs.m_clearCoat_factor_useTexture,
|
||||
inputs.m_clearCoatRoughnessMap, transformedUv[inputs.m_clearCoatRoughnessMapUvIndex], inputs.m_clearCoatRoughness, inputs.m_clearCoat_roughness_useTexture,
|
||||
inputs.m_clearCoatNormalMap, transformedUv[inputs.m_clearCoatNormalMapUvIndex], inputs.m_normal, inputs.m_clearCoat_normal_useTexture, inputs.m_clearCoatNormalStrength,
|
||||
clearCoatUvMatrix, inputs.m_tangents[inputs.m_clearCoatNormalMapUvIndex], inputs.m_bitangents[inputs.m_clearCoatNormalMapUvIndex],
|
||||
inputs.m_sampler, inputs.m_isFrontFace,
|
||||
result.m_clearCoat.factor, result.m_clearCoat.roughness, result.m_clearCoat.normal);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//! Fills a StandardMaterialInputs struct with data from the MaterialSrg, shader options, and local vertex data.
|
||||
#define FILL_STANDARD_MATERIAL_INPUTS(inputs, srgLayerPrefix, optionsLayerPrefix, blendWeight) \
|
||||
inputs.m_sampler = MaterialSrg::m_sampler; \
|
||||
inputs.m_vertexUv = IN.m_uv; \
|
||||
inputs.m_uvMatrix = srgLayerPrefix##m_uvMatrix; \
|
||||
inputs.m_normal = IN.m_normal; \
|
||||
inputs.m_tangents = tangents; \
|
||||
inputs.m_bitangents = bitangents; \
|
||||
inputs.m_isFrontFace = isFrontFace; \
|
||||
\
|
||||
inputs.m_normalMapUvIndex = srgLayerPrefix##m_normalMapUvIndex; \
|
||||
inputs.m_normalMap = srgLayerPrefix##m_normalMap; \
|
||||
inputs.m_flipNormalX = srgLayerPrefix##m_flipNormalX; \
|
||||
inputs.m_flipNormalY = srgLayerPrefix##m_flipNormalY; \
|
||||
inputs.m_normal_useTexture = optionsLayerPrefix##o_normal_useTexture; \
|
||||
inputs.m_normalFactor = srgLayerPrefix##m_normalFactor * blendWeight; \
|
||||
inputs.m_baseColorMap = srgLayerPrefix##m_baseColorMap; \
|
||||
inputs.m_baseColorMapUvIndex = srgLayerPrefix##m_baseColorMapUvIndex; \
|
||||
inputs.m_baseColor = srgLayerPrefix##m_baseColor; \
|
||||
inputs.m_baseColor_useTexture = optionsLayerPrefix##o_baseColor_useTexture; \
|
||||
inputs.m_baseColorFactor = srgLayerPrefix##m_baseColorFactor; \
|
||||
inputs.m_baseColorTextureBlendMode = optionsLayerPrefix##o_baseColorTextureBlendMode; \
|
||||
inputs.m_metallicMap = srgLayerPrefix##m_metallicMap; \
|
||||
inputs.m_metallicMapUvIndex = srgLayerPrefix##m_metallicMapUvIndex; \
|
||||
inputs.m_metallicFactor = srgLayerPrefix##m_metallicFactor; \
|
||||
inputs.m_metallic_useTexture = optionsLayerPrefix##o_metallic_useTexture; \
|
||||
inputs.m_specularF0Map = srgLayerPrefix##m_specularF0Map; \
|
||||
inputs.m_specularF0MapUvIndex = srgLayerPrefix##m_specularF0MapUvIndex; \
|
||||
inputs.m_specularF0Factor = srgLayerPrefix##m_specularF0Factor; \
|
||||
inputs.m_specularF0_useTexture = optionsLayerPrefix##o_specularF0_useTexture; \
|
||||
inputs.m_roughnessMap = srgLayerPrefix##m_roughnessMap; \
|
||||
inputs.m_roughnessMapUvIndex = srgLayerPrefix##m_roughnessMapUvIndex; \
|
||||
inputs.m_roughnessFactor = srgLayerPrefix##m_roughnessFactor; \
|
||||
inputs.m_roughnessLowerBound = srgLayerPrefix##m_roughnessLowerBound; \
|
||||
inputs.m_roughnessUpperBound = srgLayerPrefix##m_roughnessUpperBound; \
|
||||
inputs.m_roughness_useTexture = optionsLayerPrefix##o_roughness_useTexture; \
|
||||
\
|
||||
inputs.m_emissiveMap = srgLayerPrefix##m_emissiveMap; \
|
||||
inputs.m_emissiveMapUvIndex = srgLayerPrefix##m_emissiveMapUvIndex; \
|
||||
inputs.m_emissiveIntensity = srgLayerPrefix##m_emissiveIntensity; \
|
||||
inputs.m_emissiveColor = srgLayerPrefix##m_emissiveColor; \
|
||||
inputs.m_emissiveEnabled = optionsLayerPrefix##o_emissiveEnabled; \
|
||||
inputs.m_emissive_useTexture = optionsLayerPrefix##o_emissive_useTexture; \
|
||||
\
|
||||
inputs.m_diffuseOcclusionMap = srgLayerPrefix##m_diffuseOcclusionMap; \
|
||||
inputs.m_diffuseOcclusionMapUvIndex = srgLayerPrefix##m_diffuseOcclusionMapUvIndex; \
|
||||
inputs.m_diffuseOcclusionFactor = srgLayerPrefix##m_diffuseOcclusionFactor; \
|
||||
inputs.m_diffuseOcclusion_useTexture = optionsLayerPrefix##o_diffuseOcclusion_useTexture; \
|
||||
\
|
||||
inputs.m_specularOcclusionMap = srgLayerPrefix##m_specularOcclusionMap; \
|
||||
inputs.m_specularOcclusionMapUvIndex = srgLayerPrefix##m_specularOcclusionMapUvIndex; \
|
||||
inputs.m_specularOcclusionFactor = srgLayerPrefix##m_specularOcclusionFactor; \
|
||||
inputs.m_specularOcclusion_useTexture = optionsLayerPrefix##o_specularOcclusion_useTexture; \
|
||||
\
|
||||
inputs.m_clearCoatEnabled = o_clearCoat_feature_enabled && optionsLayerPrefix##o_clearCoat_enabled; \
|
||||
inputs.m_clearCoatInfluenceMap = srgLayerPrefix##m_clearCoatInfluenceMap; \
|
||||
inputs.m_clearCoatInfluenceMapUvIndex = srgLayerPrefix##m_clearCoatInfluenceMapUvIndex; \
|
||||
inputs.m_clearCoatFactor = srgLayerPrefix##m_clearCoatFactor; \
|
||||
inputs.m_clearCoat_factor_useTexture = optionsLayerPrefix##o_clearCoat_factor_useTexture; \
|
||||
inputs.m_clearCoatRoughnessMap = srgLayerPrefix##m_clearCoatRoughnessMap; \
|
||||
inputs.m_clearCoatRoughnessMapUvIndex = srgLayerPrefix##m_clearCoatRoughnessMapUvIndex; \
|
||||
inputs.m_clearCoatRoughness = srgLayerPrefix##m_clearCoatRoughness; \
|
||||
inputs.m_clearCoat_roughness_useTexture = optionsLayerPrefix##o_clearCoat_roughness_useTexture; \
|
||||
inputs.m_clearCoatNormalMap = srgLayerPrefix##m_clearCoatNormalMap; \
|
||||
inputs.m_clearCoatNormalMapUvIndex = srgLayerPrefix##m_clearCoatNormalMapUvIndex; \
|
||||
inputs.m_clearCoat_normal_useTexture = optionsLayerPrefix##o_clearCoat_normal_useTexture; \
|
||||
inputs.m_clearCoatNormalStrength = srgLayerPrefix##m_clearCoatNormalStrength;
|
||||
|
||||
|
||||
// ---------- Pixel Shader ----------
|
||||
|
||||
@@ -134,6 +308,8 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
|
||||
{
|
||||
depthNDC = IN.m_position.z;
|
||||
|
||||
s_blendMaskFromVertexStream = IN.m_blendMask;
|
||||
|
||||
// ------- Tangents & Bitangets -------
|
||||
|
||||
// We support two UV streams, but only a single stream of tangent/bitangent. So for UV[1+] we generated the tangent/bitangent in screen-space.
|
||||
@@ -156,15 +332,14 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
|
||||
|
||||
// ------- Debug Modes -------
|
||||
|
||||
if(o_debugDrawMode == DebugDrawMode::BlendMaskValues)
|
||||
if(o_debugDrawMode == DebugDrawMode::BlendSource)
|
||||
{
|
||||
float3 blendMaskValues = GetBlendMaskValues(IN.m_uv[MaterialSrg::m_blendMaskUvIndex], IN.m_blendMask);
|
||||
return DebugOutput(blendMaskValues);
|
||||
float3 blendSource = GetBlendSourceValues(IN.m_uv[MaterialSrg::m_blendMaskUvIndex]);
|
||||
return DebugOutput(blendSource);
|
||||
}
|
||||
|
||||
if(o_debugDrawMode == DebugDrawMode::DepthMaps)
|
||||
{
|
||||
GetDepth_Setup(IN.m_blendMask);
|
||||
float depth = GetNormalizedDepth(-MaterialSrg::m_displacementMax, -MaterialSrg::m_displacementMin, IN.m_uv[MaterialSrg::m_parallaxUvIndex], float2(0,0), float2(0,0));
|
||||
return DebugOutput(float3(depth,depth,depth));
|
||||
}
|
||||
@@ -173,11 +348,8 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
|
||||
|
||||
bool displacementIsClipped = false;
|
||||
|
||||
// Parallax mapping's non uniform uv transformations break screen space subsurface scattering, disable it when subsurface scatteirng is enabled
|
||||
if(ShouldHandleParallax())
|
||||
{
|
||||
GetDepth_Setup(IN.m_blendMask);
|
||||
|
||||
float3x3 uvMatrix = MaterialSrg::m_parallaxUvIndex == 0 ? MaterialSrg::m_uvMatrix : CreateIdentity3x3();
|
||||
float3x3 uvMatrixInverse = MaterialSrg::m_parallaxUvIndex == 0 ? MaterialSrg::m_uvMatrixInverse : CreateIdentity3x3();
|
||||
|
||||
@@ -198,108 +370,86 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
|
||||
}
|
||||
}
|
||||
|
||||
Surface surface;
|
||||
surface.position = IN.m_worldPosition;
|
||||
|
||||
// ------- Setup the per-layer UV transforms -------
|
||||
|
||||
float2 uvLayer1[UvSetCount];
|
||||
float2 uvLayer2[UvSetCount];
|
||||
float2 uvLayer3[UvSetCount];
|
||||
|
||||
// Only UV0 will be applied transforms from each layer.
|
||||
uvLayer1[0] = mul(MaterialSrg::m_layer1_m_uvMatrix, float3(IN.m_uv[0], 1.0)).xy;
|
||||
uvLayer2[0] = mul(MaterialSrg::m_layer2_m_uvMatrix, float3(IN.m_uv[0], 1.0)).xy;
|
||||
uvLayer3[0] = mul(MaterialSrg::m_layer3_m_uvMatrix, float3(IN.m_uv[0], 1.0)).xy;
|
||||
uvLayer1[1] = IN.m_uv[1];
|
||||
uvLayer2[1] = IN.m_uv[1];
|
||||
uvLayer3[1] = IN.m_uv[1];
|
||||
|
||||
// ------- Calculate Layer Blend Mask Values -------
|
||||
|
||||
// Now that any parallax has been calculated, we calculate the blend factors for any layers that are impacted by the parallax.
|
||||
float3 blendMaskValues = GetBlendMaskValues(IN.m_uv[MaterialSrg::m_blendMaskUvIndex], IN.m_blendMask);
|
||||
float3 blendWeights = GetBlendWeights(IN.m_uv[MaterialSrg::m_blendMaskUvIndex]);
|
||||
|
||||
// ------- Normal -------
|
||||
// ------- Layer 1 (base layer) -----------
|
||||
|
||||
ProcessedMaterialInputs lightingInputLayer1;
|
||||
{
|
||||
StandardMaterialInputs inputs;
|
||||
FILL_STANDARD_MATERIAL_INPUTS(inputs, MaterialSrg::m_layer1_, o_layer1_, blendWeights.r)
|
||||
lightingInputLayer1 = ProcessStandardMaterialInputs(inputs);
|
||||
}
|
||||
|
||||
float3 layer1_normalFactor = MaterialSrg::m_layer1_m_normalFactor * blendMaskValues.r;
|
||||
float3 layer2_normalFactor = MaterialSrg::m_layer2_m_normalFactor * blendMaskValues.g;
|
||||
float3 layer3_normalFactor = MaterialSrg::m_layer3_m_normalFactor * blendMaskValues.b;
|
||||
float3x3 layer1_uvMatrix = MaterialSrg::m_layer1_m_normalMapUvIndex == 0 ? MaterialSrg::m_layer1_m_uvMatrix : CreateIdentity3x3();
|
||||
float3x3 layer2_uvMatrix = MaterialSrg::m_layer2_m_normalMapUvIndex == 0 ? MaterialSrg::m_layer2_m_uvMatrix : CreateIdentity3x3();
|
||||
float3x3 layer3_uvMatrix = MaterialSrg::m_layer3_m_normalMapUvIndex == 0 ? MaterialSrg::m_layer3_m_uvMatrix : CreateIdentity3x3();
|
||||
float3 layer1_normalTS = GetNormalInputTS(MaterialSrg::m_layer1_m_normalMap, MaterialSrg::m_sampler, uvLayer1[MaterialSrg::m_layer1_m_normalMapUvIndex], MaterialSrg::m_layer1_m_flipNormalX, MaterialSrg::m_layer1_m_flipNormalY, layer1_uvMatrix, o_layer1_o_normal_useTexture, layer1_normalFactor);
|
||||
float3 layer2_normalTS = GetNormalInputTS(MaterialSrg::m_layer2_m_normalMap, MaterialSrg::m_sampler, uvLayer2[MaterialSrg::m_layer2_m_normalMapUvIndex], MaterialSrg::m_layer2_m_flipNormalX, MaterialSrg::m_layer2_m_flipNormalY, layer2_uvMatrix, o_layer2_o_normal_useTexture, layer2_normalFactor);
|
||||
float3 layer3_normalTS = GetNormalInputTS(MaterialSrg::m_layer3_m_normalMap, MaterialSrg::m_sampler, uvLayer3[MaterialSrg::m_layer3_m_normalMapUvIndex], MaterialSrg::m_layer3_m_flipNormalX, MaterialSrg::m_layer3_m_flipNormalY, layer3_uvMatrix, o_layer3_o_normal_useTexture, layer3_normalFactor);
|
||||
// ----------- Layer 2 -----------
|
||||
|
||||
ProcessedMaterialInputs lightingInputLayer2;
|
||||
if(o_layer2_enabled)
|
||||
{
|
||||
StandardMaterialInputs inputs;
|
||||
FILL_STANDARD_MATERIAL_INPUTS(inputs, MaterialSrg::m_layer2_, o_layer2_, blendWeights.g)
|
||||
lightingInputLayer2 = ProcessStandardMaterialInputs(inputs);
|
||||
}
|
||||
else
|
||||
{
|
||||
lightingInputLayer2.InitializeToZero();
|
||||
}
|
||||
|
||||
float3 normalTS = ReorientTangentSpaceNormal(layer1_normalTS, layer2_normalTS);
|
||||
normalTS = ReorientTangentSpaceNormal(normalTS, layer3_normalTS);
|
||||
// ----------- Layer 3 -----------
|
||||
|
||||
ProcessedMaterialInputs lightingInputLayer3;
|
||||
if(o_layer3_enabled)
|
||||
{
|
||||
StandardMaterialInputs inputs;
|
||||
FILL_STANDARD_MATERIAL_INPUTS(inputs, MaterialSrg::m_layer3_, o_layer3_, blendWeights.b)
|
||||
lightingInputLayer3 = ProcessStandardMaterialInputs(inputs);
|
||||
}
|
||||
else
|
||||
{
|
||||
lightingInputLayer3.InitializeToZero();
|
||||
}
|
||||
|
||||
// ------- Combine all layers ---------
|
||||
|
||||
Surface surface;
|
||||
surface.position = IN.m_worldPosition;
|
||||
surface.transmission.InitializeToZero();
|
||||
|
||||
// ------- Combine Normals ---------
|
||||
|
||||
float3 normalTS = lightingInputLayer1.m_normalTS;
|
||||
if(o_layer2_enabled)
|
||||
{
|
||||
normalTS = ReorientTangentSpaceNormal(normalTS, lightingInputLayer2.m_normalTS);
|
||||
}
|
||||
if(o_layer3_enabled)
|
||||
{
|
||||
normalTS = ReorientTangentSpaceNormal(normalTS, lightingInputLayer3.m_normalTS);
|
||||
}
|
||||
// [GFX TODO][ATOM-14591]: This will only work if the normal maps all use the same UV stream. We would need to add support for having them in different UV streams.
|
||||
surface.normal = normalize(TangentSpaceToWorld(normalTS, IN.m_normal, tangents[MaterialSrg::m_parallaxUvIndex], bitangents[MaterialSrg::m_parallaxUvIndex]));
|
||||
|
||||
// ------- Base Color -------
|
||||
|
||||
float2 layer1_baseColorUv = uvLayer1[MaterialSrg::m_layer1_m_baseColorMapUvIndex];
|
||||
float2 layer2_baseColorUv = uvLayer2[MaterialSrg::m_layer2_m_baseColorMapUvIndex];
|
||||
float2 layer3_baseColorUv = uvLayer3[MaterialSrg::m_layer3_m_baseColorMapUvIndex];
|
||||
|
||||
// ------- Combine Albedo, roughness, specular, roughness ---------
|
||||
|
||||
float3 layer1_sampledColor = GetBaseColorInput(MaterialSrg::m_layer1_m_baseColorMap, MaterialSrg::m_sampler, layer1_baseColorUv, MaterialSrg::m_layer1_m_baseColor.rgb, o_layer1_o_baseColor_useTexture);
|
||||
float3 layer2_sampledColor = GetBaseColorInput(MaterialSrg::m_layer2_m_baseColorMap, MaterialSrg::m_sampler, layer2_baseColorUv, MaterialSrg::m_layer2_m_baseColor.rgb, o_layer2_o_baseColor_useTexture);
|
||||
float3 layer3_sampledColor = GetBaseColorInput(MaterialSrg::m_layer3_m_baseColorMap, MaterialSrg::m_sampler, layer3_baseColorUv, MaterialSrg::m_layer3_m_baseColor.rgb, o_layer3_o_baseColor_useTexture);
|
||||
float3 layer1_baseColor = BlendBaseColor(layer1_sampledColor, MaterialSrg::m_layer1_m_baseColor.rgb, MaterialSrg::m_layer1_m_baseColorFactor, o_layer1_o_baseColorTextureBlendMode, o_layer1_o_baseColor_useTexture);
|
||||
float3 layer2_baseColor = BlendBaseColor(layer2_sampledColor, MaterialSrg::m_layer2_m_baseColor.rgb, MaterialSrg::m_layer2_m_baseColorFactor, o_layer2_o_baseColorTextureBlendMode, o_layer2_o_baseColor_useTexture);
|
||||
float3 layer3_baseColor = BlendBaseColor(layer3_sampledColor, MaterialSrg::m_layer3_m_baseColor.rgb, MaterialSrg::m_layer3_m_baseColorFactor, o_layer3_o_baseColorTextureBlendMode, o_layer3_o_baseColor_useTexture);
|
||||
float3 baseColor = BlendLayers(layer1_baseColor, layer2_baseColor, layer3_baseColor, blendMaskValues);
|
||||
float3 baseColor = BlendLayers(lightingInputLayer1.m_baseColor, lightingInputLayer2.m_baseColor, lightingInputLayer3.m_baseColor, blendWeights);
|
||||
float3 specularF0Factor = BlendLayers(lightingInputLayer1.m_specularF0Factor, lightingInputLayer2.m_specularF0Factor, lightingInputLayer3.m_specularF0Factor, blendWeights);
|
||||
float3 metallic = BlendLayers(lightingInputLayer1.m_metallic, lightingInputLayer2.m_metallic, lightingInputLayer3.m_metallic, blendWeights);
|
||||
|
||||
if(o_parallax_highlightClipping && displacementIsClipped)
|
||||
{
|
||||
ApplyParallaxClippingHighlight(baseColor);
|
||||
}
|
||||
|
||||
// ------- Metallic -------
|
||||
|
||||
float metallic = 0;
|
||||
if(!o_enableSubsurfaceScattering) // If subsurface scattering is enabled skip texture lookup for metallic, as this quantity won't be used anyway
|
||||
{
|
||||
float layer1_metallic = GetMetallicInput(MaterialSrg::m_layer1_m_metallicMap, MaterialSrg::m_sampler, uvLayer1[MaterialSrg::m_layer1_m_metallicMapUvIndex], MaterialSrg::m_layer1_m_metallicFactor, o_layer1_o_metallic_useTexture);
|
||||
float layer2_metallic = GetMetallicInput(MaterialSrg::m_layer2_m_metallicMap, MaterialSrg::m_sampler, uvLayer2[MaterialSrg::m_layer2_m_metallicMapUvIndex], MaterialSrg::m_layer2_m_metallicFactor, o_layer2_o_metallic_useTexture);
|
||||
float layer3_metallic = GetMetallicInput(MaterialSrg::m_layer3_m_metallicMap, MaterialSrg::m_sampler, uvLayer3[MaterialSrg::m_layer3_m_metallicMapUvIndex], MaterialSrg::m_layer3_m_metallicFactor, o_layer3_o_metallic_useTexture);
|
||||
metallic = BlendLayers(layer1_metallic, layer2_metallic, layer3_metallic, blendMaskValues);
|
||||
}
|
||||
|
||||
// ------- Specular -------
|
||||
|
||||
float layer1_specularF0Factor = GetSpecularInput(MaterialSrg::m_layer1_m_specularF0Map, MaterialSrg::m_sampler, uvLayer1[MaterialSrg::m_layer1_m_specularF0MapUvIndex], MaterialSrg::m_layer1_m_specularF0Factor, o_layer1_o_specularF0_useTexture);
|
||||
float layer2_specularF0Factor = GetSpecularInput(MaterialSrg::m_layer2_m_specularF0Map, MaterialSrg::m_sampler, uvLayer2[MaterialSrg::m_layer2_m_specularF0MapUvIndex], MaterialSrg::m_layer2_m_specularF0Factor, o_layer2_o_specularF0_useTexture);
|
||||
float layer3_specularF0Factor = GetSpecularInput(MaterialSrg::m_layer3_m_specularF0Map, MaterialSrg::m_sampler, uvLayer3[MaterialSrg::m_layer3_m_specularF0MapUvIndex], MaterialSrg::m_layer3_m_specularF0Factor, o_layer3_o_specularF0_useTexture);
|
||||
float specularF0Factor = BlendLayers(layer1_specularF0Factor, layer2_specularF0Factor, layer3_specularF0Factor, blendMaskValues);
|
||||
|
||||
surface.SetAlbedoAndSpecularF0(baseColor, specularF0Factor, metallic);
|
||||
|
||||
// ------- Roughness -------
|
||||
|
||||
float layer1_roughness = GetRoughnessInput(MaterialSrg::m_layer1_m_roughnessMap, MaterialSrg::m_sampler, uvLayer1[MaterialSrg::m_layer1_m_roughnessMapUvIndex], MaterialSrg::m_layer1_m_roughnessFactor, MaterialSrg::m_layer1_m_roughnessLowerBound, MaterialSrg::m_layer1_m_roughnessUpperBound, o_layer1_o_roughness_useTexture);
|
||||
float layer2_roughness = GetRoughnessInput(MaterialSrg::m_layer2_m_roughnessMap, MaterialSrg::m_sampler, uvLayer2[MaterialSrg::m_layer2_m_roughnessMapUvIndex], MaterialSrg::m_layer2_m_roughnessFactor, MaterialSrg::m_layer2_m_roughnessLowerBound, MaterialSrg::m_layer2_m_roughnessUpperBound, o_layer2_o_roughness_useTexture);
|
||||
float layer3_roughness = GetRoughnessInput(MaterialSrg::m_layer3_m_roughnessMap, MaterialSrg::m_sampler, uvLayer3[MaterialSrg::m_layer3_m_roughnessMapUvIndex], MaterialSrg::m_layer3_m_roughnessFactor, MaterialSrg::m_layer3_m_roughnessLowerBound, MaterialSrg::m_layer3_m_roughnessUpperBound, o_layer3_o_roughness_useTexture);
|
||||
surface.roughnessLinear = BlendLayers(layer1_roughness, layer2_roughness, layer3_roughness, blendMaskValues);
|
||||
|
||||
surface.roughnessLinear = BlendLayers(lightingInputLayer1.m_roughness, lightingInputLayer2.m_roughness, lightingInputLayer3.m_roughness, blendWeights);
|
||||
surface.CalculateRoughnessA();
|
||||
|
||||
// ------- Subsurface -------
|
||||
|
||||
float2 subsurfaceUv = IN.m_uv[MaterialSrg::m_subsurfaceScatteringInfluenceMapUvIndex];
|
||||
float surfaceScatteringFactor = GetSubsurfaceInput(MaterialSrg::m_subsurfaceScatteringInfluenceMap, MaterialSrg::m_sampler, subsurfaceUv, MaterialSrg::m_subsurfaceScatteringFactor);
|
||||
|
||||
// ------- Transmission -------
|
||||
|
||||
float2 transmissionUv = IN.m_uv[MaterialSrg::m_transmissionThicknessMapUvIndex];
|
||||
float4 transmissionTintThickness = GeTransmissionInput(MaterialSrg::m_transmissionThicknessMap, MaterialSrg::m_sampler, transmissionUv, MaterialSrg::m_transmissionTintThickness);
|
||||
surface.transmission.tint = transmissionTintThickness.rgb;
|
||||
surface.transmission.thickness = transmissionTintThickness.w;
|
||||
surface.transmission.transmissionParams = MaterialSrg::m_transmissionParams;
|
||||
|
||||
// ------- Lighting Data -------
|
||||
|
||||
// ------- Init and Combine Lighting Data -------
|
||||
|
||||
LightingData lightingData;
|
||||
|
||||
// Light iterator
|
||||
@@ -308,88 +458,22 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
|
||||
|
||||
// Directional light shadow coordinates
|
||||
lightingData.shadowCoords = IN.m_shadowCoords;
|
||||
|
||||
// ------- Emissive -------
|
||||
|
||||
float3 layer1_emissive = GetEmissiveInput(MaterialSrg::m_layer1_m_emissiveMap, MaterialSrg::m_sampler, uvLayer1[MaterialSrg::m_layer1_m_emissiveMapUvIndex], MaterialSrg::m_layer1_m_emissiveIntensity, MaterialSrg::m_layer1_m_emissiveColor.rgb, o_layer1_o_emissiveEnabled, o_layer1_o_emissive_useTexture);
|
||||
float3 layer2_emissive = GetEmissiveInput(MaterialSrg::m_layer2_m_emissiveMap, MaterialSrg::m_sampler, uvLayer2[MaterialSrg::m_layer2_m_emissiveMapUvIndex], MaterialSrg::m_layer2_m_emissiveIntensity, MaterialSrg::m_layer2_m_emissiveColor.rgb, o_layer2_o_emissiveEnabled, o_layer2_o_emissive_useTexture);
|
||||
float3 layer3_emissive = GetEmissiveInput(MaterialSrg::m_layer3_m_emissiveMap, MaterialSrg::m_sampler, uvLayer3[MaterialSrg::m_layer3_m_emissiveMapUvIndex], MaterialSrg::m_layer3_m_emissiveIntensity, MaterialSrg::m_layer3_m_emissiveColor.rgb, o_layer3_o_emissiveEnabled, o_layer3_o_emissive_useTexture);
|
||||
lightingData.emissiveLighting = BlendLayers(layer1_emissive, layer2_emissive, layer3_emissive, blendMaskValues);
|
||||
lightingData.emissiveLighting = BlendLayers(lightingInputLayer1.m_emissiveLighting, lightingInputLayer2.m_emissiveLighting, lightingInputLayer3.m_emissiveLighting, blendWeights);
|
||||
lightingData.specularOcclusion = BlendLayers(lightingInputLayer1.m_specularOcclusion, lightingInputLayer2.m_specularOcclusion, lightingInputLayer3.m_specularOcclusion, blendWeights);
|
||||
lightingData.diffuseAmbientOcclusion = BlendLayers(lightingInputLayer1.m_diffuseAmbientOcclusion, lightingInputLayer2.m_diffuseAmbientOcclusion, lightingInputLayer3.m_diffuseAmbientOcclusion, blendWeights);
|
||||
|
||||
// ------- Occlusion -------
|
||||
|
||||
float layer1_diffuseAmbientOcclusion = GetOcclusionInput(MaterialSrg::m_layer1_m_diffuseOcclusionMap, MaterialSrg::m_sampler, uvLayer1[MaterialSrg::m_layer1_m_diffuseOcclusionMapUvIndex], MaterialSrg::m_layer1_m_diffuseOcclusionFactor, o_layer1_o_diffuseOcclusion_useTexture);
|
||||
float layer2_diffuseAmbientOcclusion = GetOcclusionInput(MaterialSrg::m_layer2_m_diffuseOcclusionMap, MaterialSrg::m_sampler, uvLayer2[MaterialSrg::m_layer2_m_diffuseOcclusionMapUvIndex], MaterialSrg::m_layer2_m_diffuseOcclusionFactor, o_layer2_o_diffuseOcclusion_useTexture);
|
||||
float layer3_diffuseAmbientOcclusion = GetOcclusionInput(MaterialSrg::m_layer3_m_diffuseOcclusionMap, MaterialSrg::m_sampler, uvLayer3[MaterialSrg::m_layer3_m_diffuseOcclusionMapUvIndex], MaterialSrg::m_layer3_m_diffuseOcclusionFactor, o_layer3_o_diffuseOcclusion_useTexture);
|
||||
lightingData.diffuseAmbientOcclusion = BlendLayers(layer1_diffuseAmbientOcclusion, layer2_diffuseAmbientOcclusion, layer3_diffuseAmbientOcclusion, blendMaskValues);
|
||||
lightingData.CalculateMultiscatterCompensation(surface.specularF0, o_specularF0_enableMultiScatterCompensation);
|
||||
|
||||
float layer1_specularOcclusion = GetOcclusionInput(MaterialSrg::m_layer1_m_specularOcclusionMap, MaterialSrg::m_sampler, uvLayer1[MaterialSrg::m_layer1_m_specularOcclusionMapUvIndex], MaterialSrg::m_layer1_m_specularOcclusionFactor, o_layer1_o_specularOcclusion_useTexture);
|
||||
float layer2_specularOcclusion = GetOcclusionInput(MaterialSrg::m_layer2_m_specularOcclusionMap, MaterialSrg::m_sampler, uvLayer2[MaterialSrg::m_layer2_m_specularOcclusionMapUvIndex], MaterialSrg::m_layer2_m_specularOcclusionFactor, o_layer2_o_specularOcclusion_useTexture);
|
||||
float layer3_specularOcclusion = GetOcclusionInput(MaterialSrg::m_layer3_m_specularOcclusionMap, MaterialSrg::m_sampler, uvLayer3[MaterialSrg::m_layer3_m_specularOcclusionMapUvIndex], MaterialSrg::m_layer3_m_specularOcclusionFactor, o_layer3_o_specularOcclusion_useTexture);
|
||||
lightingData.specularOcclusion = BlendLayers(layer1_specularOcclusion, layer2_specularOcclusion, layer3_specularOcclusion, blendMaskValues);
|
||||
|
||||
// ------- Clearcoat -------
|
||||
// ------- Combine Clearcoat -------
|
||||
|
||||
if(o_clearCoat_feature_enabled)
|
||||
{
|
||||
// --- Layer 1 ---
|
||||
|
||||
float layer1_clearCoatFactor = 0.0f;
|
||||
float layer1_clearCoatRoughness = 0.0f;
|
||||
float3 layer1_clearCoatNormal = float3(0.0, 0.0, 0.0);
|
||||
if(o_layer1_o_clearCoat_enabled)
|
||||
{
|
||||
float3x3 layer1_uvMatrix = MaterialSrg::m_layer1_m_clearCoatNormalMapUvIndex == 0 ? MaterialSrg::m_layer1_m_uvMatrix : CreateIdentity3x3();
|
||||
|
||||
GetClearCoatInputs(MaterialSrg::m_layer1_m_clearCoatInfluenceMap, uvLayer1[MaterialSrg::m_layer1_m_clearCoatInfluenceMapUvIndex], MaterialSrg::m_layer1_m_clearCoatFactor, o_layer1_o_clearCoat_factor_useTexture,
|
||||
MaterialSrg::m_layer1_m_clearCoatRoughnessMap, uvLayer1[MaterialSrg::m_layer1_m_clearCoatRoughnessMapUvIndex], MaterialSrg::m_layer1_m_clearCoatRoughness, o_layer1_o_clearCoat_roughness_useTexture,
|
||||
MaterialSrg::m_layer1_m_clearCoatNormalMap, uvLayer1[MaterialSrg::m_layer1_m_clearCoatNormalMapUvIndex], IN.m_normal, o_layer1_o_clearCoat_normal_useTexture, MaterialSrg::m_layer1_m_clearCoatNormalStrength,
|
||||
layer1_uvMatrix, tangents[MaterialSrg::m_layer1_m_clearCoatNormalMapUvIndex], bitangents[MaterialSrg::m_layer1_m_clearCoatNormalMapUvIndex],
|
||||
MaterialSrg::m_sampler, isFrontFace,
|
||||
layer1_clearCoatFactor, layer1_clearCoatRoughness, layer1_clearCoatNormal);
|
||||
}
|
||||
|
||||
// --- Layer 2 ---
|
||||
|
||||
float layer2_clearCoatFactor = 0.0f;
|
||||
float layer2_clearCoatRoughness = 0.0f;
|
||||
float3 layer2_clearCoatNormal = float3(0.0, 0.0, 0.0);
|
||||
if(o_layer2_o_clearCoat_enabled)
|
||||
{
|
||||
float3x3 layer2_uvMatrix = MaterialSrg::m_layer2_m_clearCoatNormalMapUvIndex == 0 ? MaterialSrg::m_layer2_m_uvMatrix : CreateIdentity3x3();
|
||||
|
||||
GetClearCoatInputs(MaterialSrg::m_layer2_m_clearCoatInfluenceMap, uvLayer2[MaterialSrg::m_layer2_m_clearCoatInfluenceMapUvIndex], MaterialSrg::m_layer2_m_clearCoatFactor, o_layer2_o_clearCoat_factor_useTexture,
|
||||
MaterialSrg::m_layer2_m_clearCoatRoughnessMap, uvLayer2[MaterialSrg::m_layer2_m_clearCoatRoughnessMapUvIndex], MaterialSrg::m_layer2_m_clearCoatRoughness, o_layer2_o_clearCoat_roughness_useTexture,
|
||||
MaterialSrg::m_layer2_m_clearCoatNormalMap, uvLayer2[MaterialSrg::m_layer2_m_clearCoatNormalMapUvIndex], IN.m_normal, o_layer2_o_clearCoat_normal_useTexture, MaterialSrg::m_layer2_m_clearCoatNormalStrength,
|
||||
layer2_uvMatrix, tangents[MaterialSrg::m_layer2_m_clearCoatNormalMapUvIndex], bitangents[MaterialSrg::m_layer2_m_clearCoatNormalMapUvIndex],
|
||||
MaterialSrg::m_sampler, isFrontFace,
|
||||
layer2_clearCoatFactor, layer2_clearCoatRoughness, layer2_clearCoatNormal);
|
||||
}
|
||||
|
||||
// --- Layer 3 ---
|
||||
|
||||
float layer3_clearCoatFactor = 0.0f;
|
||||
float layer3_clearCoatRoughness = 0.0f;
|
||||
float3 layer3_clearCoatNormal = float3(0.0, 0.0, 0.0);
|
||||
if(o_layer3_o_clearCoat_enabled)
|
||||
{
|
||||
float3x3 layer3_uvMatrix = MaterialSrg::m_layer3_m_clearCoatNormalMapUvIndex == 0 ? MaterialSrg::m_layer3_m_uvMatrix : CreateIdentity3x3();
|
||||
|
||||
GetClearCoatInputs(MaterialSrg::m_layer3_m_clearCoatInfluenceMap, uvLayer3[MaterialSrg::m_layer3_m_clearCoatInfluenceMapUvIndex], MaterialSrg::m_layer3_m_clearCoatFactor, o_layer3_o_clearCoat_factor_useTexture,
|
||||
MaterialSrg::m_layer3_m_clearCoatRoughnessMap, uvLayer3[MaterialSrg::m_layer3_m_clearCoatRoughnessMapUvIndex], MaterialSrg::m_layer3_m_clearCoatRoughness, o_layer3_o_clearCoat_roughness_useTexture,
|
||||
MaterialSrg::m_layer3_m_clearCoatNormalMap, uvLayer3[MaterialSrg::m_layer3_m_clearCoatNormalMapUvIndex], IN.m_normal, o_layer3_o_clearCoat_normal_useTexture, MaterialSrg::m_layer3_m_clearCoatNormalStrength,
|
||||
layer3_uvMatrix, tangents[MaterialSrg::m_layer3_m_clearCoatNormalMapUvIndex], bitangents[MaterialSrg::m_layer3_m_clearCoatNormalMapUvIndex],
|
||||
MaterialSrg::m_sampler, isFrontFace,
|
||||
layer3_clearCoatFactor, layer3_clearCoatRoughness, layer3_clearCoatNormal);
|
||||
}
|
||||
|
||||
// --- Blend Layers ---
|
||||
|
||||
surface.clearCoat.factor = BlendLayers(layer1_clearCoatFactor, layer2_clearCoatFactor, layer3_clearCoatFactor, blendMaskValues);
|
||||
surface.clearCoat.roughness = BlendLayers(layer1_clearCoatRoughness, layer2_clearCoatRoughness, layer3_clearCoatRoughness, blendMaskValues);
|
||||
surface.clearCoat.factor = BlendLayers(lightingInputLayer1.m_clearCoat.factor, lightingInputLayer2.m_clearCoat.factor, lightingInputLayer3.m_clearCoat.factor, blendWeights);
|
||||
surface.clearCoat.roughness = BlendLayers(lightingInputLayer1.m_clearCoat.roughness, lightingInputLayer2.m_clearCoat.roughness, lightingInputLayer3.m_clearCoat.roughness, blendWeights);
|
||||
|
||||
// [GFX TODO][ATOM-14592] This is not the right way to blend the normals. We need to use ReorientTangentSpaceNormal(), and that requires GetClearCoatInputs() to return the normal in TS instead of WS.
|
||||
surface.clearCoat.normal = BlendLayers(layer1_clearCoatNormal, layer2_clearCoatNormal, layer3_clearCoatNormal, blendMaskValues);
|
||||
surface.clearCoat.normal = BlendLayers(lightingInputLayer1.m_clearCoat.normal, lightingInputLayer2.m_clearCoat.normal, lightingInputLayer3.m_clearCoat.normal, blendWeights);
|
||||
surface.clearCoat.normal = normalize(surface.clearCoat.normal);
|
||||
|
||||
// manipulate base layer f0 if clear coat is enabled
|
||||
@@ -409,11 +493,7 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
|
||||
// Clear coat layer has fixed IOR = 1.5 and transparent => F0 = (1.5 - 1)^2 / (1.5 + 1)^2 = 0.04
|
||||
lightingData.diffuseResponse *= 1.0 - (FresnelSchlickWithRoughness(lightingData.NdotV, float3(0.04, 0.04, 0.04), surface.clearCoat.roughness) * surface.clearCoat.factor);
|
||||
}
|
||||
|
||||
// ------- Multiscatter -------
|
||||
|
||||
lightingData.CalculateMultiscatterCompensation(surface.specularF0, o_specularF0_enableMultiScatterCompensation);
|
||||
|
||||
|
||||
// ------- Lighting Calculation -------
|
||||
|
||||
// Apply Decals
|
||||
@@ -426,17 +506,14 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
|
||||
ApplyIBL(surface, lightingData);
|
||||
|
||||
// Finalize Lighting
|
||||
lightingData.FinalizeLighting(surface.transmission.tint);
|
||||
lightingData.FinalizeLighting(0);
|
||||
|
||||
|
||||
const float alpha = 1.0;
|
||||
|
||||
PbrLightingOutput lightingOutput = GetPbrLightingOutput(surface, lightingData, alpha);
|
||||
|
||||
// Pack factor and quality, drawback: because of precision limit of float16 cannot represent exact 1, maximum representable value is 0.9961
|
||||
uint factorAndQuality = dot(round(float2(saturate(surfaceScatteringFactor), MaterialSrg::m_subsurfaceScatteringQuality) * 255), float2(256, 1));
|
||||
lightingOutput.m_diffuseColor.w = factorAndQuality * (o_enableSubsurfaceScattering ? 1.0 : -1.0);
|
||||
|
||||
lightingOutput.m_diffuseColor.w = -1; // Disable subsurface scattering
|
||||
|
||||
return lightingOutput;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
+2
-2
@@ -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
|
||||
|
||||
+1
-1
@@ -107,7 +107,7 @@ PSDepthOutput MainPS(VertexOutput IN, bool isFrontFace : SV_IsFrontFace)
|
||||
float3 bitangents[UvSetCount] = { IN.m_bitangent.xyz, float3(0, 0, 0) };
|
||||
PrepareGeneratedTangent(IN.m_normal, IN.m_worldPosition, isFrontFace, IN.m_uv, UvSetCount, tangents, bitangents, 1);
|
||||
|
||||
GetDepth_Setup(IN.m_blendMask);
|
||||
s_blendMaskFromVertexStream = IN.m_blendMask;
|
||||
|
||||
float depthNDC;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
-1
@@ -43,7 +43,6 @@ class Surface
|
||||
|
||||
};
|
||||
|
||||
|
||||
// Specular Anti-Aliasing technique from this paper:
|
||||
// http://www.jp.square-enix.com/tech/library/pdf/ImprovedGeometricSpecularAA.pdf
|
||||
void Surface::ApplySpecularAA()
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:f74ffab6ee15906158d27cbd2e5556e8fcdfd7820c0d0fd4b403de8a7af81662
|
||||
size 5651
|
||||
oid sha256:6660fa05dbf1e90298472fb41d99fff80a80de64ee88d17af4d0df3bdafb1ff6
|
||||
size 52877
|
||||
|
||||
@@ -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;
|
||||
MaterialPropertyDynamicMetadata* QueryMaterialPropertyMetadata(const Name& propertyName) const;
|
||||
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,25 +142,24 @@ 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())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return &(it->second);
|
||||
return QueryMaterialPropertyMetadata(propertyName);
|
||||
}
|
||||
|
||||
const MaterialPropertyDynamicMetadata* MaterialFunctor::EditorContext::GetMaterialPropertyMetadata(const MaterialPropertyIndex& index) const
|
||||
@@ -168,19 +167,41 @@ namespace AZ
|
||||
const Name& name = m_materialPropertiesLayout->GetPropertyDescriptor(index)->GetName();
|
||||
return GetMaterialPropertyMetadata(name);
|
||||
}
|
||||
|
||||
bool MaterialFunctor::EditorContext::SetMaterialPropertyVisibility(const Name& propertyName, MaterialPropertyVisibility visibility)
|
||||
|
||||
const MaterialPropertyGroupDynamicMetadata* MaterialFunctor::EditorContext::GetMaterialPropertyGroupMetadata(const Name& propertyName) const
|
||||
{
|
||||
auto it = QueryMaterialMetadata(propertyName);
|
||||
if (it == m_metadata.end())
|
||||
return QueryMaterialPropertyGroupMetadata(propertyName);
|
||||
}
|
||||
|
||||
bool MaterialFunctor::EditorContext::SetMaterialPropertyGroupVisibility(const Name& propertyGroupName, MaterialPropertyGroupVisibility visibility)
|
||||
{
|
||||
MaterialPropertyGroupDynamicMetadata* metadata = QueryMaterialPropertyGroupMetadata(propertyGroupName);
|
||||
if (!metadata)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
MaterialPropertyVisibility originValue = it->second.m_visibility;
|
||||
it->second.m_visibility = visibility;
|
||||
if (originValue != visibility)
|
||||
|
||||
if (metadata->m_visibility != visibility)
|
||||
{
|
||||
m_outChangedProperties.insert(propertyName);
|
||||
metadata->m_visibility = visibility;
|
||||
m_updatedPropertyGroupsOut.insert(propertyGroupName);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MaterialFunctor::EditorContext::SetMaterialPropertyVisibility(const Name& propertyName, MaterialPropertyVisibility visibility)
|
||||
{
|
||||
MaterialPropertyDynamicMetadata* metadata = QueryMaterialPropertyMetadata(propertyName);
|
||||
if (!metadata)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (metadata->m_visibility != visibility)
|
||||
{
|
||||
metadata->m_visibility = visibility;
|
||||
m_updatedPropertiesOut.insert(propertyName);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -194,17 +215,16 @@ namespace AZ
|
||||
|
||||
bool MaterialFunctor::EditorContext::SetMaterialPropertyDescription(const Name& propertyName, AZStd::string description)
|
||||
{
|
||||
auto it = QueryMaterialMetadata(propertyName);
|
||||
if (it == m_metadata.end())
|
||||
MaterialPropertyDynamicMetadata* metadata = QueryMaterialPropertyMetadata(propertyName);
|
||||
if (!metadata)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
AZStd::string origin = it->second.m_description;
|
||||
it->second.m_description = description;
|
||||
if (origin != description)
|
||||
if (metadata->m_description != description)
|
||||
{
|
||||
m_outChangedProperties.insert(propertyName);
|
||||
metadata->m_description = description;
|
||||
m_updatedPropertiesOut.insert(propertyName);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -218,18 +238,16 @@ namespace AZ
|
||||
|
||||
bool MaterialFunctor::EditorContext::SetMaterialPropertyMinValue(const Name& propertyName, const MaterialPropertyValue& min)
|
||||
{
|
||||
auto it = QueryMaterialMetadata(propertyName);
|
||||
if (it == m_metadata.end())
|
||||
MaterialPropertyDynamicMetadata* metadata = QueryMaterialPropertyMetadata(propertyName);
|
||||
if (!metadata)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
MaterialPropertyValue origin = it->second.m_propertyRange.m_min;
|
||||
it->second.m_propertyRange.m_min = min;
|
||||
|
||||
if(origin != min)
|
||||
if(metadata->m_propertyRange.m_min != min)
|
||||
{
|
||||
m_outChangedProperties.insert(propertyName);
|
||||
metadata->m_propertyRange.m_min = min;
|
||||
m_updatedPropertiesOut.insert(propertyName);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -243,18 +261,16 @@ namespace AZ
|
||||
|
||||
bool MaterialFunctor::EditorContext::SetMaterialPropertyMaxValue(const Name& propertyName, const MaterialPropertyValue& max)
|
||||
{
|
||||
auto it = QueryMaterialMetadata(propertyName);
|
||||
if (it == m_metadata.end())
|
||||
MaterialPropertyDynamicMetadata* metadata = QueryMaterialPropertyMetadata(propertyName);
|
||||
if (!metadata)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
MaterialPropertyValue origin = it->second.m_propertyRange.m_max;
|
||||
it->second.m_propertyRange.m_max = max;
|
||||
|
||||
if (origin != max)
|
||||
if (metadata->m_propertyRange.m_max != max)
|
||||
{
|
||||
m_outChangedProperties.insert(propertyName);
|
||||
metadata->m_propertyRange.m_max = max;
|
||||
m_updatedPropertiesOut.insert(propertyName);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -268,18 +284,16 @@ namespace AZ
|
||||
|
||||
bool MaterialFunctor::EditorContext::SetMaterialPropertySoftMinValue(const Name& propertyName, const MaterialPropertyValue& min)
|
||||
{
|
||||
auto it = QueryMaterialMetadata(propertyName);
|
||||
if (it == m_metadata.end())
|
||||
MaterialPropertyDynamicMetadata* metadata = QueryMaterialPropertyMetadata(propertyName);
|
||||
if (!metadata)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
MaterialPropertyValue origin = it->second.m_propertyRange.m_softMin;
|
||||
it->second.m_propertyRange.m_softMin = min;
|
||||
|
||||
if (origin != min)
|
||||
if (metadata->m_propertyRange.m_softMin != min)
|
||||
{
|
||||
m_outChangedProperties.insert(propertyName);
|
||||
metadata->m_propertyRange.m_softMin = min;
|
||||
m_updatedPropertiesOut.insert(propertyName);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -293,18 +307,16 @@ namespace AZ
|
||||
|
||||
bool MaterialFunctor::EditorContext::SetMaterialPropertySoftMaxValue(const Name& propertyName, const MaterialPropertyValue& max)
|
||||
{
|
||||
auto it = QueryMaterialMetadata(propertyName);
|
||||
if (it == m_metadata.end())
|
||||
MaterialPropertyDynamicMetadata* metadata = QueryMaterialPropertyMetadata(propertyName);
|
||||
if (!metadata)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
MaterialPropertyValue origin = it->second.m_propertyRange.m_softMax;
|
||||
it->second.m_propertyRange.m_softMax = max;
|
||||
|
||||
if (origin != max)
|
||||
if (metadata->m_propertyRange.m_softMax != max)
|
||||
{
|
||||
m_outChangedProperties.insert(propertyName);
|
||||
metadata->m_propertyRange.m_softMax = max;
|
||||
m_updatedPropertiesOut.insert(propertyName);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -316,15 +328,26 @@ namespace AZ
|
||||
return SetMaterialPropertySoftMaxValue(name, max);
|
||||
}
|
||||
|
||||
AZStd::list_iterator<AZStd::pair<AZ::Name, AZ::RPI::MaterialPropertyDynamicMetadata>> MaterialFunctor::EditorContext::QueryMaterialMetadata(const Name& propertyName) const
|
||||
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;
|
||||
return &it->second;
|
||||
}
|
||||
|
||||
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->second;
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
|
||||
@@ -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
|
||||
@@ -140,6 +141,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
|
||||
|
||||
+13
-3
@@ -4,6 +4,10 @@
|
||||
"parentMaterial": "",
|
||||
"propertyLayoutVersion": 3,
|
||||
"properties": {
|
||||
"blend": {
|
||||
"enableLayer2": true,
|
||||
"enableLayer3": true
|
||||
},
|
||||
"layer1_baseColor": {
|
||||
"color": [
|
||||
0.3495536744594574,
|
||||
@@ -134,8 +138,14 @@
|
||||
"enable": true
|
||||
},
|
||||
"uv": {
|
||||
"offsetU": -0.2800000011920929,
|
||||
"rotateDegrees": 39.599998474121097
|
||||
"center": [
|
||||
0.10000000149011612,
|
||||
0.20000000298023225
|
||||
],
|
||||
"offsetU": 0.23000000417232514,
|
||||
"offsetV": -0.23999999463558198,
|
||||
"rotateDegrees": 39.599998474121097,
|
||||
"scale": 1.100000023841858
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"description": "",
|
||||
"materialType": "Materials/Types/StandardMultilayerPBR.materialtype",
|
||||
"parentMaterial": "TestData/Materials/StandardMultilayerPbrTestCases/001_ManyFeatures.material",
|
||||
"propertyLayoutVersion": 3,
|
||||
"properties": {
|
||||
"blend": {
|
||||
"enableLayer2": false
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"description": "",
|
||||
"materialType": "Materials/Types/StandardMultilayerPBR.materialtype",
|
||||
"parentMaterial": "TestData/Materials/StandardMultilayerPbrTestCases/001_ManyFeatures.material",
|
||||
"propertyLayoutVersion": 3,
|
||||
"properties": {
|
||||
"blend": {
|
||||
"enableLayer3": false
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
-1
@@ -4,6 +4,10 @@
|
||||
"parentMaterial": "",
|
||||
"propertyLayoutVersion": 3,
|
||||
"properties": {
|
||||
"blend": {
|
||||
"enableLayer2": true,
|
||||
"enableLayer3": true
|
||||
},
|
||||
"layer1_baseColor": {
|
||||
"textureMap": "TestData/Textures/cc0/bark1_col.jpg"
|
||||
},
|
||||
@@ -30,6 +34,7 @@
|
||||
"layer2_parallax": {
|
||||
"enable": true,
|
||||
"factor": 0.05299999937415123,
|
||||
"offset": -0.024000000208616258,
|
||||
"textureMap": "TestData/Textures/cc0/Rock030_2K_Displacement.jpg"
|
||||
},
|
||||
"layer2_roughness": {
|
||||
@@ -49,4 +54,4 @@
|
||||
"pdo": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
"propertyLayoutVersion": 3,
|
||||
"properties": {
|
||||
"general": {
|
||||
"debugDrawMode": "BlendMaskValues"
|
||||
"debugDrawMode": "BlendSource"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:053a7cd73b37c815900f87abd524830e6f23eee75d3b72fb866e86498d528159
|
||||
size 36156
|
||||
+3
-3
@@ -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.
|
||||
|
||||
+11
@@ -44,6 +44,17 @@ 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 whether a specific property is visible.
|
||||
//! Note this follows the same rules as QWidget::isVisible(), meaning a group could be not visible due to the widget's parents being not visible.
|
||||
virtual bool IsGroupVisible(const AZStd::string& groupNameId) const = 0;
|
||||
|
||||
//! Returns whether a specific property is explicitly hidden.
|
||||
//! Note this follows the same rules as QWidget::isHidden(), meaning a group that is hidden will not become visible automatically when the parent becomes visible.
|
||||
virtual bool IsGroupHidden(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;
|
||||
|
||||
|
||||
+12
-1
@@ -57,6 +57,10 @@ 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;
|
||||
bool IsGroupHidden(const AZStd::string& groupNameId) const override;
|
||||
|
||||
void RefreshGroup(const AZStd::string& groupNameId) override;
|
||||
void RebuildGroup(const AZStd::string& groupNameId) override;
|
||||
|
||||
@@ -79,6 +83,13 @@ namespace AtomToolsFramework
|
||||
private:
|
||||
QVBoxLayout* m_layout = nullptr;
|
||||
QScopedPointer<Ui::InspectorWidget> m_ui;
|
||||
AZStd::unordered_map<AZStd::string, AZStd::pair<InspectorGroupHeaderWidget*, QWidget*>> m_groups;
|
||||
|
||||
struct GroupWidgetPair
|
||||
{
|
||||
InspectorGroupHeaderWidget* m_header;
|
||||
QWidget* m_panel;
|
||||
};
|
||||
|
||||
AZStd::unordered_map<AZStd::string, GroupWidgetPair> m_groups;
|
||||
};
|
||||
} // namespace AtomToolsFramework
|
||||
|
||||
@@ -74,7 +74,7 @@ namespace AtomToolsFramework
|
||||
groupWidget->setParent(m_ui->m_propertyContent);
|
||||
m_layout->addWidget(groupWidget);
|
||||
|
||||
m_groups[groupNameId] = AZStd::make_pair(groupHeader, groupWidget);
|
||||
m_groups[groupNameId] = {groupHeader, groupWidget};
|
||||
|
||||
connect(groupHeader, &InspectorGroupHeaderWidget::clicked, this, [this, groupNameId](QMouseEvent* event) {
|
||||
OnHeaderClicked(groupNameId, event);
|
||||
@@ -91,6 +91,38 @@ namespace AtomToolsFramework
|
||||
CollapseGroup(groupNameId);
|
||||
}
|
||||
}
|
||||
|
||||
void InspectorWidget::SetGroupVisible(const AZStd::string& groupNameId, bool visible)
|
||||
{
|
||||
auto groupItr = m_groups.find(groupNameId);
|
||||
if (groupItr != m_groups.end())
|
||||
{
|
||||
groupItr->second.m_header->setVisible(visible);
|
||||
groupItr->second.m_panel->setVisible(visible && groupItr->second.m_header->IsExpanded());
|
||||
}
|
||||
}
|
||||
|
||||
bool InspectorWidget::IsGroupVisible(const AZStd::string& groupNameId) const
|
||||
{
|
||||
auto groupItr = m_groups.find(groupNameId);
|
||||
if (groupItr != m_groups.end())
|
||||
{
|
||||
return groupItr->second.m_header->isVisible();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool InspectorWidget::IsGroupHidden(const AZStd::string& groupNameId) const
|
||||
{
|
||||
auto groupItr = m_groups.find(groupNameId);
|
||||
if (groupItr != m_groups.end())
|
||||
{
|
||||
return groupItr->second.m_header->isHidden();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void InspectorWidget::RefreshGroup(const AZStd::string& groupNameId)
|
||||
{
|
||||
@@ -129,8 +161,8 @@ namespace AtomToolsFramework
|
||||
auto groupItr = m_groups.find(groupNameId);
|
||||
if (groupItr != m_groups.end())
|
||||
{
|
||||
groupItr->second.first->SetExpanded(true);
|
||||
groupItr->second.second->setVisible(true);
|
||||
groupItr->second.m_header->SetExpanded(true);
|
||||
groupItr->second.m_panel->setVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,23 +171,23 @@ namespace AtomToolsFramework
|
||||
auto groupItr = m_groups.find(groupNameId);
|
||||
if (groupItr != m_groups.end())
|
||||
{
|
||||
groupItr->second.first->SetExpanded(false);
|
||||
groupItr->second.second->setVisible(false);
|
||||
groupItr->second.m_header->SetExpanded(false);
|
||||
groupItr->second.m_panel->setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
bool InspectorWidget::IsGroupExpanded(const AZStd::string& groupNameId) const
|
||||
{
|
||||
auto groupItr = m_groups.find(groupNameId);
|
||||
return groupItr != m_groups.end() ? groupItr->second.first->IsExpanded() : false;
|
||||
return groupItr != m_groups.end() ? groupItr->second.m_header->IsExpanded() : false;
|
||||
}
|
||||
|
||||
void InspectorWidget::ExpandAll()
|
||||
{
|
||||
for (auto& groupPair : m_groups)
|
||||
{
|
||||
groupPair.second.first->SetExpanded(true);
|
||||
groupPair.second.second->setVisible(true);
|
||||
groupPair.second.m_header->SetExpanded(true);
|
||||
groupPair.second.m_panel->setVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,8 +195,8 @@ namespace AtomToolsFramework
|
||||
{
|
||||
for (auto& groupPair : m_groups)
|
||||
{
|
||||
groupPair.second.first->SetExpanded(false);
|
||||
groupPair.second.second->setVisible(false);
|
||||
groupPair.second.m_header->SetExpanded(false);
|
||||
groupPair.second.m_panel->setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+7
@@ -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
|
||||
|
||||
+13
-6
@@ -198,6 +198,11 @@ namespace MaterialEditor
|
||||
&group, &group, group.TYPEINFO_Uuid(), this, this, GetGroupSaveStateKey(groupNameId),
|
||||
[this](const auto source, const auto target) { return CompareInstanceNodeProperties(source, target); });
|
||||
AddGroup(groupNameId, groupDisplayName, groupDescription, propertyGroupWidget);
|
||||
|
||||
bool isGroupVisible = false;
|
||||
MaterialDocumentRequestBus::EventResult(
|
||||
isGroupVisible, m_documentId, &MaterialDocumentRequestBus::Events::IsPropertyGroupVisible, AZ::Name{groupNameId});
|
||||
SetGroupVisible(groupNameId, isGroupVisible);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,8 +226,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)
|
||||
{
|
||||
@@ -234,20 +238,23 @@ 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)
|
||||
{
|
||||
SetGroupVisible(groupId.GetStringView(), visible);
|
||||
}
|
||||
|
||||
void MaterialInspector::BeforePropertyModified(AzToolsFramework::InstanceDataNode* pNode)
|
||||
{
|
||||
|
||||
+1
@@ -60,6 +60,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;
|
||||
|
||||
+21
-7
@@ -296,15 +296,20 @@ 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}];
|
||||
|
||||
// It's significant that we check IsGroupHidden rather than IsGroupVisisble, because it follows the same rules as QWidget::isHidden().
|
||||
// We don't care whether the widget and all its parents are visible, we only care about whether the group was hidden within the context
|
||||
// of the material property inspector.
|
||||
metadata.m_visibility = IsGroupHidden(groupPair.first) ?
|
||||
AZ::RPI::MaterialPropertyGroupVisibility::Hidden : AZ::RPI::MaterialPropertyGroupVisibility::Enabled;
|
||||
}
|
||||
|
||||
for (AZ::RPI::Ptr<AZ::RPI::MaterialFunctor>& functor : m_editorFunctors)
|
||||
@@ -318,7 +323,9 @@ namespace AZ
|
||||
m_materialInstance->GetPropertyValues(),
|
||||
m_materialInstance->GetMaterialPropertiesLayout(),
|
||||
propertyDynamicMetadata,
|
||||
propertyGroupDynamicMetadata,
|
||||
changedPropertyNames,
|
||||
changedPropertyGroupNames,
|
||||
&materialPropertyDependencies
|
||||
);
|
||||
functor->Process(context);
|
||||
@@ -327,9 +334,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();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user