From 9dafc54fc08bd66ef4159171cb7a5c08af9613b6 Mon Sep 17 00:00:00 2001 From: Chris Santora Date: Thu, 13 May 2021 14:57:16 -0700 Subject: [PATCH] Got things working again after merging my depth-based-blend changes together with the new layering model. Updated the terminology (yet again) to hopefully be a bit more clear and consistent. "Blend mask" means the R and G channels that mask layers 2-3. These can come from multipls source, including a "blend mask texture" or "blend mask vertex colors". "Blend weights" are the final RGB channels that are multiplied and added with layer properties to do the final blend. "Blend source" is the combination of data that is used to produce the blend weights, which could be a combination of displacement maps, blend mask texture, vertex colors, or others in the future. Added another debug render mode, so now we can show either the blend mask and the final blend weights. --- .../Types/StandardMultilayerPBR.materialtype | 8 +- .../StandardMultilayerPBR.materialtype.orig | 3126 +++++++++++++++++ .../Types/StandardMultilayerPBR_Common.azsli | 102 +- .../StandardMultilayerPBR_Common.azsli.orig | 401 +++ ...tandardMultilayerPBR_DepthPass_WithPS.azsl | 6 +- ...rdMultilayerPBR_DepthPass_WithPS.azsl.orig | 132 + .../StandardMultilayerPBR_ForwardPass.azsl | 24 +- ...tandardMultilayerPBR_ForwardPass.azsl.orig | 710 ++++ ...tandardMultilayerPBR_Shadowmap_WithPS.azsl | 6 +- ...rdMultilayerPBR_Shadowmap_WithPS.azsl.orig | 131 + ....material => 003_Debug_BlendMask.material} | 2 +- .../003_Debug_BlendWeights.material | 11 + ...terial => 003_Debug_Displacement.material} | 2 +- .../005_UseDisplacement.material | 4 +- 14 files changed, 4608 insertions(+), 57 deletions(-) create mode 100644 Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR.materialtype.orig create mode 100644 Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_Common.azsli.orig create mode 100644 Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_DepthPass_WithPS.azsl.orig create mode 100644 Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_ForwardPass.azsl.orig create mode 100644 Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_Shadowmap_WithPS.azsl.orig rename Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/{003_Debug_BlendSource.material => 003_Debug_BlendMask.material} (86%) create mode 100644 Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/003_Debug_BlendWeights.material rename Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/{003_Debug_DisplacementMaps.material => 003_Debug_Displacement.material} (85%) diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR.materialtype b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR.materialtype index 96fb4eeea8..f6c0cc3ad3 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR.materialtype +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR.materialtype @@ -199,7 +199,7 @@ "displayName": "Debug Draw Mode", "description": "Enables various debug view features.", "type": "Enum", - "enumValues": [ "None", "BlendSource", "DisplacementMaps" ], + "enumValues": [ "None", "BlendMask", "Displacement", "FinalBlendWeights" ], "defaultValue": "None", "connection": { "type": "ShaderOption", @@ -322,8 +322,8 @@ "displayName": "Blend Source", "description": "The source to use for defining the blend mask. Note VertexColors mode will still use the texture as a fallback if the mesh does not have a COLOR0 stream.", "type": "Enum", - "enumValues": ["BlendMask", "VertexColors", "Displacement"], - "defaultValue": "BlendMask", + "enumValues": ["TextureMap", "VertexColors", "Displacement"], + "defaultValue": "TextureMap", "connection": { "type": "ShaderOption", "id": "o_layerBlendSource" @@ -331,7 +331,7 @@ }, { "id": "textureMap", - "displayName": "Blend Mask", + "displayName": "Blend Mask Texture", "description": "RGB image where each channel is the blend mask for one of the three available layers.", "type": "Image", "defaultValue": "Textures/DefaultBlendMask_layers.png", diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR.materialtype.orig b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR.materialtype.orig new file mode 100644 index 0000000000..d185eecddf --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR.materialtype.orig @@ -0,0 +1,3126 @@ +{ + "description": "Similar to StandardPBR but supports multiple layers blended together.", + "propertyLayout": { + "version": 3, + "groups": [ + { + "id": "general", + "displayName": "General", + "description": "General settings." + }, + { + "id": "blend", + "displayName": "Blend Settings", + "description": "Properties for configuring how layers are blended together." + }, + { + "id": "parallax", + "displayName": "Parallax Settings", + "description": "Properties for configuring the parallax effect, applied to all layers." + }, + { + "id": "uv", + "displayName": "UVs", + "description": "Properties for configuring UV transforms for the entire material, including the blend masks." + }, + { + // Note: this property group is used in the DiffuseGlobalIllumination pass, it is not read by the StandardPBR shader + "id": "irradiance", + "displayName": "Irradiance", + "description": "Properties for configuring the irradiance used in global illumination." + }, + //############################################################################################## + // Layer 1 Groups + //############################################################################################## + { + "id": "layer1_baseColor", + "displayName": "Layer 1: Base Color", + "description": "Properties for configuring the surface reflected color for dielectrics or reflectance values for metals." + }, + { + "id": "layer1_metallic", + "displayName": "Layer 1: Metallic", + "description": "Properties for configuring whether the surface is metallic or not." + }, + { + "id": "layer1_roughness", + "displayName": "Layer 1: Roughness", + "description": "Properties for configuring how rough the surface appears." + }, + { + "id": "layer1_specularF0", + "displayName": "Layer 1: Specular Reflectance f0", + "description": "The constant f0 represents the specular reflectance at normal incidence (Fresnel 0 Angle). Used to adjust reflectance of non-metal surfaces." + }, + { + "id": "layer1_normal", + "displayName": "Layer 1: Normal", + "description": "Properties related to configuring surface normal." + }, + { + "id": "layer1_clearCoat", + "displayName": "Layer 1: Clear Coat", + "description": "Properties for configuring gloss clear coat" + }, + { + "id": "layer1_occlusion", + "displayName": "Layer 1: Occlusion", + "description": "Properties for baked textures for diffuse and specular occlusion of ambient lighting." + }, + { + "id": "layer1_emissive", + "displayName": "Layer 1: Emissive", + "description": "Properties to add light emission, independent of other lights in the scene." + }, + { + "id": "layer1_parallax", + "displayName": "Layer 1: Parallax Mapping", + "description": "Properties for parallax effect produced by depthmap." + }, + { + "id": "layer1_uv", + "displayName": "Layer 1: UVs", + "description": "Properties for configuring UV transforms." + }, + //############################################################################################## + // Layer 2 Groups + //############################################################################################## + { + "id": "layer2_baseColor", + "displayName": "Layer 2: Base Color", + "description": "Properties for configuring the surface reflected color for dielectrics or reflectance values for metals." + }, + { + "id": "layer2_metallic", + "displayName": "Layer 2: Metallic", + "description": "Properties for configuring whether the surface is metallic or not." + }, + { + "id": "layer2_roughness", + "displayName": "Layer 2: Roughness", + "description": "Properties for configuring how rough the surface appears." + }, + { + "id": "layer2_specularF0", + "displayName": "Layer 2: Specular Reflectance f0", + "description": "The constant f0 represents the specular reflectance at normal incidence (Fresnel 0 Angle). Used to adjust reflectance of non-metal surfaces." + }, + { + "id": "layer2_normal", + "displayName": "Layer 2: Normal", + "description": "Properties related to configuring surface normal." + }, + { + "id": "layer2_clearCoat", + "displayName": "Layer 2: Clear Coat", + "description": "Properties for configuring gloss clear coat" + }, + { + "id": "layer2_occlusion", + "displayName": "Layer 2: Occlusion", + "description": "Properties for baked textures for diffuse and specular occlusion of ambient lighting." + }, + { + "id": "layer2_emissive", + "displayName": "Layer 2: Emissive", + "description": "Properties to add light emission, independent of other lights in the scene." + }, + { + "id": "layer2_parallax", + "displayName": "Layer 2: Parallax Mapping", + "description": "Properties for parallax effect produced by depthmap." + }, + { + "id": "layer2_uv", + "displayName": "Layer 2: UVs", + "description": "Properties for configuring UV transforms." + }, + //############################################################################################## + // Layer 3 Groups + //############################################################################################## + { + "id": "layer3_baseColor", + "displayName": "Layer 3: Base Color", + "description": "Properties for configuring the surface reflected color for dielectrics or reflectance values for metals." + }, + { + "id": "layer3_metallic", + "displayName": "Layer 3: Metallic", + "description": "Properties for configuring whether the surface is metallic or not." + }, + { + "id": "layer3_roughness", + "displayName": "Layer 3: Roughness", + "description": "Properties for configuring how rough the surface appears." + }, + { + "id": "layer3_specularF0", + "displayName": "Layer 3: Specular Reflectance f0", + "description": "The constant f0 represents the specular reflectance at normal incidence (Fresnel 0 Angle). Used to adjust reflectance of non-metal surfaces." + }, + { + "id": "layer3_normal", + "displayName": "Layer 3: Normal", + "description": "Properties related to configuring surface normal." + }, + { + "id": "layer3_clearCoat", + "displayName": "Layer 3: Clear Coat", + "description": "Properties for configuring gloss clear coat" + }, + { + "id": "layer3_occlusion", + "displayName": "Layer 3: Occlusion", + "description": "Properties for baked textures for diffuse and specular occlusion of ambient lighting." + }, + { + "id": "layer3_emissive", + "displayName": "Layer 3: Emissive", + "description": "Properties to add light emission, independent of other lights in the scene." + }, + { + "id": "layer3_parallax", + "displayName": "Layer 3: Parallax Mapping", + "description": "Properties for parallax effect produced by depthmap." + }, + { + "id": "layer3_uv", + "displayName": "Layer 3: UVs", + "description": "Properties for configuring UV transforms." + } + ], + "properties": { + //############################################################################################## + // General Properties + //############################################################################################## + "general": [ + { + "id": "debugDrawMode", + "displayName": "Debug Draw Mode", + "description": "Enables various debug view features.", + "type": "Enum", +<<<<<<< HEAD + "enumValues": [ "None", "BlendSource", "DepthMaps" ], +======= + "enumValues": [ "None", "BlendWeights", "DisplacementMaps" ], +>>>>>>> Atom/santorac/MultilayerPbrImprovements + "defaultValue": "None", + "connection": { + "type": "ShaderOption", + "id": "o_debugDrawMode" + } + }, + { + "id": "applySpecularAA", + "displayName": "Apply Specular AA", + "description": "Whether to apply specular anti-aliasing in the shader.", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderOption", + "id": "o_applySpecularAA" + } + }, + { + "id": "enableMultiScatterCompensation", + "displayName": "Multiscattering Compensation", + "description": "Whether to enable multiple scattering compensation.", + "type": "Bool", + "connection": { + "type": "ShaderOption", + "id": "o_specularF0_enableMultiScatterCompensation" + } + }, + { + "id": "enableShadows", + "displayName": "Enable Shadows", + "description": "Whether to use the shadow maps.", + "type": "Bool", + "defaultValue": true, + "connection": { + "type": "ShaderOption", + "id": "o_enableShadows" + } + }, + { + "id": "enableDirectionalLights", + "displayName": "Enable Directional Lights", + "description": "Whether to use directional lights.", + "type": "Bool", + "defaultValue": true, + "connection": { + "type": "ShaderOption", + "id": "o_enableDirectionalLights" + } + }, + { + "id": "enablePunctualLights", + "displayName": "Enable Punctual Lights", + "description": "Whether to use punctual lights.", + "type": "Bool", + "defaultValue": true, + "connection": { + "type": "ShaderOption", + "id": "o_enablePunctualLights" + } + }, + { + "id": "enableAreaLights", + "displayName": "Enable Area Lights", + "description": "Whether to use area lights.", + "type": "Bool", + "defaultValue": true, + "connection": { + "type": "ShaderOption", + "id": "o_enableAreaLights" + } + }, + { + "id": "enableIBL", + "displayName": "Enable IBL", + "description": "Whether to use Image Based Lighting (IBL).", + "type": "Bool", + "defaultValue": true, + "connection": { + "type": "ShaderOption", + "id": "o_enableIBL" + } + }, + { + "id": "forwardPassIBLSpecular", + "displayName": "Forward Pass IBL Specular", + "description": "Whether to apply IBL specular in the forward pass.", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderOption", + "id": "o_materialUseForwardPassIBLSpecular" + } + } + ], + "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", + "description": "The source to use for defining the blend mask. Note VertexColors mode will still use the texture as a fallback if the mesh does not have a COLOR0 stream.", + "type": "Enum", + "enumValues": ["TextureMap", "VertexColors", "Displacement"], + "defaultValue": "TextureMap", + "connection": { + "type": "ShaderOption", + "id": "o_layerBlendSource" + } + }, + { + "id": "textureMap", + "displayName": "Blend Mask", + "description": "RGB image where each channel is the blend mask for one of the three available layers.", + "type": "Image", + "defaultValue": "Textures/DefaultBlendMask_layers.png", + "connection": { + "type": "ShaderInput", + "id": "m_blendMaskTexture" + } + }, + { + "id": "textureMapUv", + "displayName": "Blend Mask UV", + "description": "Blend Mask UV set.", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "id": "m_blendMaskUvIndex" + } + } + ], + "parallax": [ + { + "id": "enable", + "displayName": "Enable", + "description": "Whether to enable the parallax feature for this material.", + "type": "Bool", + "defaultValue": false + }, + { + "id": "parallaxUv", + "displayName": "UV", + "description": "UV set that supports parallax mapping.", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "id": "m_parallaxUvIndex" + } + }, + { + "id": "algorithm", + "displayName": "Algorithm", + "description": "Select the algorithm to use for parallax mapping.", + "type": "Enum", + "enumValues": [ "Basic", "Steep", "POM", "Relief", "ContactRefinement" ], + "defaultValue": "POM", + "connection": { + "type": "ShaderOption", + "id": "o_parallax_algorithm" + } + }, + { + "id": "quality", + "displayName": "Quality", + "description": "Quality of parallax mapping.", + "type": "Enum", + "enumValues": [ "Low", "Medium", "High", "Ultra" ], + "defaultValue": "Medium", + "connection": { + "type": "ShaderOption", + "id": "o_parallax_quality" + } + }, + { + "id": "pdo", + "displayName": "Pixel Depth Offset", + "description": "Whether to enable the pixel depth offset feature.", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderOption", + "id": "o_parallax_enablePixelDepthOffset" + } + }, + { + "id": "showClipping", + "displayName": "Show Clipping", + "description": "Highlight areas where the heightmap is clipped by the mesh surface.", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderOption", + "id": "o_parallax_highlightClipping" + } + } + ], + "uv": [ + { + "id": "center", + "displayName": "Center", + "description": "Center point for scaling and rotation transformations.", + "type": "vector2", + "vectorLabels": [ "U", "V" ], + "defaultValue": [ 0.0, 0.0 ] + }, + { + "id": "tileU", + "displayName": "Tile U", + "description": "Scales texture coordinates in V.", + "type": "float", + "defaultValue": 1.0, + "step": 0.1 + }, + { + "id": "tileV", + "displayName": "Tile V", + "description": "Scales texture coordinates in V.", + "type": "float", + "defaultValue": 1.0, + "step": 0.1 + }, + { + "id": "offsetU", + "displayName": "Offset U", + "description": "Offsets texture coordinates in the U direction.", + "type": "float", + "defaultValue": 0.0, + "min": -1.0, + "max": 1.0, + "step": 0.001 + }, + { + "id": "offsetV", + "displayName": "Offset V", + "description": "Offsets texture coordinates in the V direction.", + "type": "float", + "defaultValue": 0.0, + "min": -1.0, + "max": 1.0, + "step": 0.001 + }, + { + "id": "rotateDegrees", + "displayName": "Rotate", + "description": "Rotates the texture coordinates (degrees).", + "type": "float", + "defaultValue": 0.0, + "min": -180.0, + "max": 180.0, + "step": 1.0 + }, + { + "id": "scale", + "displayName": "Scale", + "description": "Scales texture coordinates in both U and V.", + "type": "float", + "defaultValue": 1.0, + "step": 0.1 + } + ], + "irradiance": [ + // Note: this property group is used in the DiffuseGlobalIllumination pass, it is not read by the StandardPBR shader + { + "id": "color", + "displayName": "Color", + "description": "Color is displayed as sRGB but the values are stored as linear color.", + "type": "Color", + "defaultValue": [ 1.0, 1.0, 1.0 ] + }, + { + "id": "factor", + "displayName": "Factor", + "description": "Strength factor for scaling the irradiance color values. Zero (0.0) is black, white (1.0) is full color.", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 1.0 + } + ], + //############################################################################################## + // Layer 1 Properties + //############################################################################################## + "layer1_baseColor": [ + { + "id": "color", + "displayName": "Color", + "description": "Color is displayed as sRGB but the values are stored as linear color.", + "type": "Color", + "defaultValue": [ 1.0, 1.0, 1.0 ], + "connection": { + "type": "ShaderInput", + "id": "m_layer1_m_baseColor" + } + }, + { + "id": "factor", + "displayName": "Factor", + "description": "Strength factor for scaling the base color values. Zero (0.0) is black, white (1.0) is full color.", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "id": "m_layer1_m_baseColorFactor" + } + }, + { + "id": "textureMap", + "displayName": "Texture Map", + "description": "Base color texture map", + "type": "Image", + "connection": { + "type": "ShaderInput", + "id": "m_layer1_m_baseColorMap" + } + }, + { + "id": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture map.", + "type": "Bool", + "defaultValue": true + }, + { + "id": "textureMapUv", + "displayName": "UV", + "description": "Base color texture map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "id": "m_layer1_m_baseColorMapUvIndex" + } + }, + { + "id": "textureBlendMode", + "displayName": "Texture Blend Mode", + "description": "Selects the equation to use when combining Color, Factor, and Texture Map.", + "type": "Enum", + "enumValues": [ "Multiply", "LinearLight", "Lerp", "Overlay" ], + "defaultValue": "Multiply", + "connection": { + "type": "ShaderOption", + "id": "o_layer1_o_baseColorTextureBlendMode" + } + } + ], + "layer1_metallic": [ + { + "id": "factor", + "displayName": "Factor", + "description": "This value is linear, black is non-metal and white means raw metal.", + "type": "Float", + "defaultValue": 0.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "id": "m_layer1_m_metallicFactor" + } + }, + { + "id": "textureMap", + "displayName": "Texture Map", + "description": "", + "type": "Image", + "connection": { + "type": "ShaderInput", + "id": "m_layer1_m_metallicMap" + } + }, + { + "id": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture map, or just default to the Factor value.", + "type": "Bool", + "defaultValue": true + }, + { + "id": "textureMapUv", + "displayName": "UV", + "description": "Metallic texture map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "id": "m_layer1_m_metallicMapUvIndex" + } + } + ], + "layer1_roughness": [ + { + "id": "textureMap", + "displayName": "Texture Map", + "description": "Texture map for defining surface roughness.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "id": "m_layer1_m_roughnessMap" + } + }, + { + "id": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture map, or just default to the Factor value.", + "type": "Bool", + "defaultValue": true + }, + { + "id": "textureMapUv", + "displayName": "UV", + "description": "Roughness texture map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "id": "m_layer1_m_roughnessMapUvIndex" + } + }, + { + // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. + "id": "lowerBound", + "displayName": "Lower Bound", + "description": "The roughness value that corresponds to black in the texture map.", + "type": "Float", + "defaultValue": 0.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "id": "m_layer1_m_roughnessLowerBound" + } + }, + { + // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. + "id": "upperBound", + "displayName": "Upper Bound", + "description": "The roughness value that corresponds to white in the texture map.", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "id": "m_layer1_m_roughnessUpperBound" + } + }, + { + // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. + "id": "factor", + "displayName": "Factor", + "description": "Controls the roughness value", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "id": "m_layer1_m_roughnessFactor" + } + } + ], + "layer1_specularF0": [ + { + "id": "factor", + "displayName": "Factor", + "description": "The default IOR is 1.5, which gives you 0.04 (4% of light reflected at 0 degree angle for dielectric materials). F0 values lie in the range 0-0.08, so that is why the default F0 slider is set on 0.5.", + "type": "Float", + "defaultValue": 0.5, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "id": "m_layer1_m_specularF0Factor" + } + }, + { + "id": "textureMap", + "displayName": "Texture Map", + "description": "Texture map for defining surface reflectance.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "id": "m_layer1_m_specularF0Map" + } + }, + { + "id": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture map, or just default to the Factor value.", + "type": "Bool", + "defaultValue": true + }, + { + "id": "textureMapUv", + "displayName": "UV", + "description": "Specular reflection texture map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "id": "m_layer1_m_specularF0MapUvIndex" + } + } + ], + "layer1_normal": [ + { + "id": "textureMap", + "displayName": "Texture Map", + "description": "Texture map for defining surface normal direction.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "id": "m_layer1_m_normalMap" + } + }, + { + "id": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture map, or just rely on vertex normals.", + "type": "Bool", + "defaultValue": true + }, + { + "id": "textureMapUv", + "displayName": "UV", + "description": "Normal texture map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "id": "m_layer1_m_normalMapUvIndex" + } + }, + { + "id": "flipX", + "displayName": "Flip X Channel", + "description": "Flip tangent direction for this normal map.", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderInput", + "id": "m_layer1_m_flipNormalX" + } + }, + { + "id": "flipY", + "displayName": "Flip Y Channel", + "description": "Flip bitangent direction for this normal map.", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderInput", + "id": "m_layer1_m_flipNormalY" + } + }, + { + "id": "factor", + "displayName": "Factor", + "description": "Strength factor for scaling the values", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "softMax": 2.0, + "connection": { + "type": "ShaderInput", + "id": "m_layer1_m_normalFactor" + } + } + ], + "layer1_clearCoat": [ + { + "id": "enable", + "displayName": "Enable", + "description": "Enable clear coat", + "type": "Bool", + "defaultValue": false + }, + { + "id": "factor", + "displayName": "Factor", + "description": "Strength factor for scaling the percentage of effect applied", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "id": "m_layer1_m_clearCoatFactor" + } + }, + { + "id": "influenceMap", + "displayName": " Influence Map", + "description": "Strength factor texture map", + "type": "Image", + "connection": { + "type": "ShaderInput", + "id": "m_layer1_m_clearCoatInfluenceMap" + } + }, + { + "id": "useInfluenceMap", + "displayName": " Use Texture", + "description": "Whether to use the texture map, or just default to the Factor value.", + "type": "Bool", + "defaultValue": true + }, + { + "id": "influenceMapUv", + "displayName": " UV", + "description": "Strength factor texture map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "id": "m_layer1_m_clearCoatInfluenceMapUvIndex" + } + }, + { + "id": "roughness", + "displayName": "Roughness", + "description": "Clear coat layer roughness", + "type": "Float", + "defaultValue": 0.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "id": "m_layer1_m_clearCoatRoughness" + } + }, + { + "id": "roughnessMap", + "displayName": " Roughness Map", + "description": "Roughness texture map", + "type": "Image", + "connection": { + "type": "ShaderInput", + "id": "m_layer1_m_clearCoatRoughnessMap" + } + }, + { + "id": "useRoughnessMap", + "displayName": " Use Texture", + "description": "Whether to use the texture map, or just default to the roughness value.", + "type": "Bool", + "defaultValue": true + }, + { + "id": "roughnessMapUv", + "displayName": " UV", + "description": "Roughness texture map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "id": "m_layer1_m_clearCoatRoughnessMapUvIndex" + } + }, + { + "id": "normalStrength", + "displayName": "Normal Strength", + "description": "Scales the impact of the clear coat normal map", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 2.0, + "connection": { + "type": "ShaderInput", + "id": "m_layer1_m_clearCoatNormalStrength" + } + }, + { + "id": "normalMap", + "displayName": "Normal Map", + "description": "Normal map for clear coat layer, as top layer material clear coat doesn't affect by base layer normal map", + "type": "Image", + "connection": { + "type": "ShaderInput", + "id": "m_layer1_m_clearCoatNormalMap" + } + }, + { + "id": "useNormalMap", + "displayName": " Use Texture", + "description": "Whether to use the normal map", + "type": "Bool", + "defaultValue": true + }, + { + "id": "normalMapUv", + "displayName": " UV", + "description": "Normal texture map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "id": "m_layer1_m_clearCoatNormalMapUvIndex" + } + } + ], + "layer1_occlusion": [ + { + "id": "diffuseTextureMap", + "displayName": "Diffuse AO", + "description": "Texture map for defining occlusion area for diffuse ambient lighting.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "id": "m_layer1_m_diffuseOcclusionMap" + } + }, + { + "id": "diffuseUseTexture", + "displayName": " Use Texture", + "description": "Whether to use the Diffuse AO texture map.", + "type": "Bool", + "defaultValue": true + }, + { + "id": "diffuseTextureMapUv", + "displayName": " UV", + "description": "Diffuse AO texture map UV set.", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "id": "m_layer1_m_diffuseOcclusionMapUvIndex" + } + }, + { + "id": "diffuseFactor", + "displayName": " Factor", + "description": "Strength factor for scaling the values of Diffuse AO", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "softMax": 2.0, + "connection": { + "type": "ShaderInput", + "id": "m_layer1_m_diffuseOcclusionFactor" + } + }, + { + "id": "specularTextureMap", + "displayName": "Specular Cavity", + "description": "Texture map for defining occlusion area for specular lighting.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "id": "m_layer1_m_specularOcclusionMap" + } + }, + { + "id": "specularUseTexture", + "displayName": " Use Texture", + "description": "Whether to use the Specular Cavity texture map.", + "type": "Bool", + "defaultValue": true + }, + { + "id": "specularTextureMapUv", + "displayName": " UV", + "description": "Specular Cavity texture map UV set.", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "id": "m_layer1_m_specularOcclusionMapUvIndex" + } + }, + { + "id": "specularFactor", + "displayName": " Factor", + "description": "Strength factor for scaling the values of Specular Cavity", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "softMax": 2.0, + "connection": { + "type": "ShaderInput", + "id": "m_layer1_m_specularOcclusionFactor" + } + } + ], + "layer1_emissive": [ + { + "id": "enable", + "displayName": "Enable", + "description": "Enable the emissive group", + "type": "Bool", + "defaultValue": false + }, + { + "id": "unit", + "displayName": "Units", + "description": "The photometric units of the Intensity property.", + "type": "Enum", + "enumValues": ["Ev100"], + "defaultValue": "Ev100" + }, + { + "id": "color", + "displayName": "Color", + "description": "Color is displayed as sRGB but the values are stored as linear color.", + "type": "Color", + "defaultValue": [ 1.0, 1.0, 1.0 ], + "connection": { + "type": "ShaderInput", + "id": "m_layer1_m_emissiveColor" + } + }, + { + "id": "intensity", + "displayName": "Intensity", + "description": "The amount of energy emitted.", + "type": "Float", + "defaultValue": 4, + "min": -10, + "max": 20, + "softMin": -6, + "softMax": 16 + }, + { + "id": "textureMap", + "displayName": "Texture Map", + "description": "Texture map for defining emissive area.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "id": "m_layer1_m_emissiveMap" + } + }, + { + "id": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture map.", + "type": "Bool", + "defaultValue": true + }, + { + "id": "textureMapUv", + "displayName": "UV", + "description": "Emissive texture map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "id": "m_layer1_m_emissiveMapUvIndex" + } + } + ], + "layer1_parallax": [ + { + "id": "enable", + "displayName": "Enable", + "description": "Whether to enable the parallax feature.", + "type": "Bool", + "defaultValue": false + }, + { + "id": "textureMap", + "displayName": "Texture Map", + "description": "Depthmap to create parallax effect.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "id": "m_layer1_m_depthMap" + } + }, + { + "id": "factor", + "displayName": "Heightmap Scale", + "description": "The total height of the heightmap in local model units.", + "type": "Float", + "defaultValue": 0.0, + "min": 0.0, + "softMax": 0.1, + "connection": { + "type": "ShaderInput", + "id": "m_layer1_m_depthFactor" + } + }, + { + "id": "offset", + "displayName": "Offset", + "description": "Adjusts the overall displacement amount in local model units.", + "type": "Float", + "defaultValue": 0.0, + "softMin": -0.1, + "softMax": 0.1, + "connection": { + "type": "ShaderInput", + "id": "m_layer1_m_depthOffset" + } + }, + { + "id": "invert", + "displayName": "Invert", + "description": "Invert to depthmap if the texture is heightmap", + "type": "Bool", + "defaultValue": true, + "connection": { + "type": "ShaderInput", + "id": "m_layer1_m_depthInverted" + } + } + ], + "layer1_uv": [ + { + "id": "center", + "displayName": "Center", + "description": "Center point for scaling and rotation transformations.", + "type": "vector2", + "vectorLabels": [ "U", "V" ], + "defaultValue": [ 0.0, 0.0 ] + }, + { + "id": "tileU", + "displayName": "Tile U", + "description": "Scales texture coordinates in V.", + "type": "float", + "defaultValue": 1.0, + "step": 0.1 + }, + { + "id": "tileV", + "displayName": "Tile V", + "description": "Scales texture coordinates in V.", + "type": "float", + "defaultValue": 1.0, + "step": 0.1 + }, + { + "id": "offsetU", + "displayName": "Offset U", + "description": "Offsets texture coordinates in the U direction.", + "type": "float", + "defaultValue": 0.0, + "min": -1.0, + "max": 1.0, + "step": 0.001 + }, + { + "id": "offsetV", + "displayName": "Offset V", + "description": "Offsets texture coordinates in the V direction.", + "type": "float", + "defaultValue": 0.0, + "min": -1.0, + "max": 1.0, + "step": 0.001 + }, + { + "id": "rotateDegrees", + "displayName": "Rotate", + "description": "Rotates the texture coordinates (degrees).", + "type": "float", + "defaultValue": 0.0, + "min": -180.0, + "max": 180.0, + "step": 1.0 + }, + { + "id": "scale", + "displayName": "Scale", + "description": "Scales texture coordinates in both U and V.", + "type": "float", + "defaultValue": 1.0, + "step": 0.1 + } + ], + //############################################################################################## + // Layer 2 Properties + //############################################################################################## + "layer2_baseColor": [ + { + "id": "color", + "displayName": "Color", + "description": "Color is displayed as sRGB but the values are stored as linear color.", + "type": "Color", + "defaultValue": [ 1.0, 1.0, 1.0 ], + "connection": { + "type": "ShaderInput", + "id": "m_layer2_m_baseColor" + } + }, + { + "id": "factor", + "displayName": "Factor", + "description": "Strength factor for scaling the base color values. Zero (0.0) is black, white (1.0) is full color.", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "id": "m_layer2_m_baseColorFactor" + } + }, + { + "id": "textureMap", + "displayName": "Texture Map", + "description": "Base color texture map", + "type": "Image", + "connection": { + "type": "ShaderInput", + "id": "m_layer2_m_baseColorMap" + } + }, + { + "id": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture map.", + "type": "Bool", + "defaultValue": true + }, + { + "id": "textureMapUv", + "displayName": "UV", + "description": "Base color texture map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "id": "m_layer2_m_baseColorMapUvIndex" + } + }, + { + "id": "textureBlendMode", + "displayName": "Texture Blend Mode", + "description": "Selects the equation to use when combining Color, Factor, and Texture Map.", + "type": "Enum", + "enumValues": [ "Multiply", "LinearLight", "Lerp", "Overlay" ], + "defaultValue": "Multiply", + "connection": { + "type": "ShaderOption", + "id": "o_layer2_o_baseColorTextureBlendMode" + } + } + ], + "layer2_metallic": [ + { + "id": "factor", + "displayName": "Factor", + "description": "This value is linear, black is non-metal and white means raw metal.", + "type": "Float", + "defaultValue": 0.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "id": "m_layer2_m_metallicFactor" + } + }, + { + "id": "textureMap", + "displayName": "Texture Map", + "description": "", + "type": "Image", + "connection": { + "type": "ShaderInput", + "id": "m_layer2_m_metallicMap" + } + }, + { + "id": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture map, or just default to the Factor value.", + "type": "Bool", + "defaultValue": true + }, + { + "id": "textureMapUv", + "displayName": "UV", + "description": "Metallic texture map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "id": "m_layer2_m_metallicMapUvIndex" + } + } + ], + "layer2_roughness": [ + { + "id": "textureMap", + "displayName": "Texture Map", + "description": "Texture map for defining surface roughness.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "id": "m_layer2_m_roughnessMap" + } + }, + { + "id": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture map, or just default to the Factor value.", + "type": "Bool", + "defaultValue": true + }, + { + "id": "textureMapUv", + "displayName": "UV", + "description": "Roughness texture map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "id": "m_layer2_m_roughnessMapUvIndex" + } + }, + { + // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. + "id": "lowerBound", + "displayName": "Lower Bound", + "description": "The roughness value that corresponds to black in the texture map.", + "type": "Float", + "defaultValue": 0.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "id": "m_layer2_m_roughnessLowerBound" + } + }, + { + // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. + "id": "upperBound", + "displayName": "Upper Bound", + "description": "The roughness value that corresponds to white in the texture map.", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "id": "m_layer2_m_roughnessUpperBound" + } + }, + { + // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. + "id": "factor", + "displayName": "Factor", + "description": "Controls the roughness value", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "id": "m_layer2_m_roughnessFactor" + } + } + ], + "layer2_specularF0": [ + { + "id": "factor", + "displayName": "Factor", + "description": "The default IOR is 1.5, which gives you 0.04 (4% of light reflected at 0 degree angle for dielectric materials). F0 values lie in the range 0-0.08, so that is why the default F0 slider is set on 0.5.", + "type": "Float", + "defaultValue": 0.5, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "id": "m_layer2_m_specularF0Factor" + } + }, + { + "id": "textureMap", + "displayName": "Texture Map", + "description": "Texture map for defining surface reflectance.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "id": "m_layer2_m_specularF0Map" + } + }, + { + "id": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture map, or just default to the Factor value.", + "type": "Bool", + "defaultValue": true + }, + { + "id": "textureMapUv", + "displayName": "UV", + "description": "Specular reflection texture map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "id": "m_layer2_m_specularF0MapUvIndex" + } + } + ], + "layer2_normal": [ + { + "id": "textureMap", + "displayName": "Texture Map", + "description": "Texture map for defining surface normal direction.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "id": "m_layer2_m_normalMap" + } + }, + { + "id": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture map, or just rely on vertex normals.", + "type": "Bool", + "defaultValue": true + }, + { + "id": "textureMapUv", + "displayName": "UV", + "description": "Normal texture map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "id": "m_layer2_m_normalMapUvIndex" + } + }, + { + "id": "flipX", + "displayName": "Flip X Channel", + "description": "Flip tangent direction for this normal map.", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderInput", + "id": "m_layer2_m_flipNormalX" + } + }, + { + "id": "flipY", + "displayName": "Flip Y Channel", + "description": "Flip bitangent direction for this normal map.", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderInput", + "id": "m_layer2_m_flipNormalY" + } + }, + { + "id": "factor", + "displayName": "Factor", + "description": "Strength factor for scaling the values", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "softMax": 2.0, + "connection": { + "type": "ShaderInput", + "id": "m_layer2_m_normalFactor" + } + } + ], + "layer2_clearCoat": [ + { + "id": "enable", + "displayName": "Enable", + "description": "Enable clear coat", + "type": "Bool", + "defaultValue": false + }, + { + "id": "factor", + "displayName": "Factor", + "description": "Strength factor for scaling the percentage of effect applied", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "id": "m_layer2_m_clearCoatFactor" + } + }, + { + "id": "influenceMap", + "displayName": " Influence Map", + "description": "Strength factor texture map", + "type": "Image", + "connection": { + "type": "ShaderInput", + "id": "m_layer2_m_clearCoatInfluenceMap" + } + }, + { + "id": "useInfluenceMap", + "displayName": " Use Texture", + "description": "Whether to use the texture map, or just default to the Factor value.", + "type": "Bool", + "defaultValue": true + }, + { + "id": "influenceMapUv", + "displayName": " UV", + "description": "Strength factor texture map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "id": "m_layer2_m_clearCoatInfluenceMapUvIndex" + } + }, + { + "id": "roughness", + "displayName": "Roughness", + "description": "Clear coat layer roughness", + "type": "Float", + "defaultValue": 0.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "id": "m_layer2_m_clearCoatRoughness" + } + }, + { + "id": "roughnessMap", + "displayName": " Roughness Map", + "description": "Roughness texture map", + "type": "Image", + "connection": { + "type": "ShaderInput", + "id": "m_layer2_m_clearCoatRoughnessMap" + } + }, + { + "id": "useRoughnessMap", + "displayName": " Use Texture", + "description": "Whether to use the texture map, or just default to the roughness value.", + "type": "Bool", + "defaultValue": true + }, + { + "id": "roughnessMapUv", + "displayName": " UV", + "description": "Roughness texture map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "id": "m_layer2_m_clearCoatRoughnessMapUvIndex" + } + }, + { + "id": "normalStrength", + "displayName": "Normal Strength", + "description": "Scales the impact of the clear coat normal map", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 2.0, + "connection": { + "type": "ShaderInput", + "id": "m_layer2_m_clearCoatNormalStrength" + } + }, + { + "id": "normalMap", + "displayName": "Normal Map", + "description": "Normal map for clear coat layer, as top layer material clear coat doesn't affect by base layer normal map", + "type": "Image", + "connection": { + "type": "ShaderInput", + "id": "m_layer2_m_clearCoatNormalMap" + } + }, + { + "id": "useNormalMap", + "displayName": " Use Texture", + "description": "Whether to use the normal map", + "type": "Bool", + "defaultValue": true + }, + { + "id": "normalMapUv", + "displayName": " UV", + "description": "Normal texture map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "id": "m_layer2_m_clearCoatNormalMapUvIndex" + } + } + ], + "layer2_occlusion": [ + { + "id": "diffuseTextureMap", + "displayName": "Diffuse AO", + "description": "Texture map for defining occlusion area for diffuse ambient lighting.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "id": "m_layer2_m_diffuseOcclusionMap" + } + }, + { + "id": "diffuseUseTexture", + "displayName": " Use Texture", + "description": "Whether to use the Diffuse AO texture map.", + "type": "Bool", + "defaultValue": true + }, + { + "id": "diffuseTextureMapUv", + "displayName": " UV", + "description": "Diffuse AO texture map UV set.", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "id": "m_layer2_m_diffuseOcclusionMapUvIndex" + } + }, + { + "id": "diffuseFactor", + "displayName": " Factor", + "description": "Strength factor for scaling the values of Diffuse AO", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "softMax": 2.0, + "connection": { + "type": "ShaderInput", + "id": "m_layer2_m_diffuseOcclusionFactor" + } + }, + { + "id": "specularTextureMap", + "displayName": "Specular Cavity", + "description": "Texture map for defining occlusion area for specular lighting.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "id": "m_layer2_m_specularOcclusionMap" + } + }, + { + "id": "specularUseTexture", + "displayName": " Use Texture", + "description": "Whether to use the Specular Cavity texture map.", + "type": "Bool", + "defaultValue": true + }, + { + "id": "specularTextureMapUv", + "displayName": " UV", + "description": "Specular Cavity texture map UV set.", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "id": "m_layer2_m_specularOcclusionMapUvIndex" + } + }, + { + "id": "specularFactor", + "displayName": " Factor", + "description": "Strength factor for scaling the values of Specular Cavity", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "softMax": 2.0, + "connection": { + "type": "ShaderInput", + "id": "m_layer2_m_specularOcclusionFactor" + } + } + ], + "layer2_emissive": [ + { + "id": "enable", + "displayName": "Enable", + "description": "Enable the emissive group", + "type": "Bool", + "defaultValue": false + }, + { + "id": "unit", + "displayName": "Units", + "description": "The photometric units of the Intensity property.", + "type": "Enum", + "enumValues": ["Ev100"], + "defaultValue": "Ev100" + }, + { + "id": "color", + "displayName": "Color", + "description": "Color is displayed as sRGB but the values are stored as linear color.", + "type": "Color", + "defaultValue": [ 1.0, 1.0, 1.0 ], + "connection": { + "type": "ShaderInput", + "id": "m_layer2_m_emissiveColor" + } + }, + { + "id": "intensity", + "displayName": "Intensity", + "description": "The amount of energy emitted.", + "type": "Float", + "defaultValue": 4, + "min": -10, + "max": 20, + "softMin": -6, + "softMax": 16 + }, + { + "id": "textureMap", + "displayName": "Texture Map", + "description": "Texture map for defining emissive area.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "id": "m_layer2_m_emissiveMap" + } + }, + { + "id": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture map.", + "type": "Bool", + "defaultValue": true + }, + { + "id": "textureMapUv", + "displayName": "UV", + "description": "Emissive texture map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "id": "m_layer2_m_emissiveMapUvIndex" + } + } + ], + "layer2_parallax": [ + { + "id": "enable", + "displayName": "Enable", + "description": "Whether to enable the parallax feature.", + "type": "Bool", + "defaultValue": false + }, + { + "id": "textureMap", + "displayName": "Texture Map", + "description": "Depthmap to create parallax effect.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "id": "m_layer2_m_depthMap" + } + }, + { + "id": "factor", + "displayName": "Heightmap Scale", + "description": "The total height of the heightmap in local model units.", + "type": "Float", + "defaultValue": 0.0, + "min": 0.0, + "softMax": 0.1, + "connection": { + "type": "ShaderInput", + "id": "m_layer2_m_depthFactor" + } + }, + { + "id": "offset", + "displayName": "Offset", + "description": "Adjusts the overall displacement amount in local model units.", + "type": "Float", + "defaultValue": 0.0, + "softMin": -0.1, + "softMax": 0.1, + "connection": { + "type": "ShaderInput", + "id": "m_layer2_m_depthOffset" + } + }, + { + "id": "invert", + "displayName": "Invert", + "description": "Invert to depthmap if the texture is heightmap", + "type": "Bool", + "defaultValue": true, + "connection": { + "type": "ShaderInput", + "id": "m_layer2_m_depthInverted" + } + } + ], + "layer2_uv": [ + { + "id": "center", + "displayName": "Center", + "description": "Center point for scaling and rotation transformations.", + "type": "vector2", + "vectorLabels": [ "U", "V" ], + "defaultValue": [ 0.0, 0.0 ] + }, + { + "id": "tileU", + "displayName": "Tile U", + "description": "Scales texture coordinates in V.", + "type": "float", + "defaultValue": 1.0, + "step": 0.1 + }, + { + "id": "tileV", + "displayName": "Tile V", + "description": "Scales texture coordinates in V.", + "type": "float", + "defaultValue": 1.0, + "step": 0.1 + }, + { + "id": "offsetU", + "displayName": "Offset U", + "description": "Offsets texture coordinates in the U direction.", + "type": "float", + "defaultValue": 0.0, + "min": -1.0, + "max": 1.0, + "step": 0.001 + }, + { + "id": "offsetV", + "displayName": "Offset V", + "description": "Offsets texture coordinates in the V direction.", + "type": "float", + "defaultValue": 0.0, + "min": -1.0, + "max": 1.0, + "step": 0.001 + }, + { + "id": "rotateDegrees", + "displayName": "Rotate", + "description": "Rotates the texture coordinates (degrees).", + "type": "float", + "defaultValue": 0.0, + "min": -180.0, + "max": 180.0, + "step": 1.0 + }, + { + "id": "scale", + "displayName": "Scale", + "description": "Scales texture coordinates in both U and V.", + "type": "float", + "defaultValue": 1.0, + "step": 0.1 + } + ], + //############################################################################################## + // Layer 3 Properties + //############################################################################################## + "layer3_baseColor": [ + { + "id": "color", + "displayName": "Color", + "description": "Color is displayed as sRGB but the values are stored as linear color.", + "type": "Color", + "defaultValue": [ 1.0, 1.0, 1.0 ], + "connection": { + "type": "ShaderInput", + "id": "m_layer3_m_baseColor" + } + }, + { + "id": "factor", + "displayName": "Factor", + "description": "Strength factor for scaling the base color values. Zero (0.0) is black, white (1.0) is full color.", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "id": "m_layer3_m_baseColorFactor" + } + }, + { + "id": "textureMap", + "displayName": "Texture Map", + "description": "Base color texture map", + "type": "Image", + "connection": { + "type": "ShaderInput", + "id": "m_layer3_m_baseColorMap" + } + }, + { + "id": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture map.", + "type": "Bool", + "defaultValue": true + }, + { + "id": "textureMapUv", + "displayName": "UV", + "description": "Base color texture map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "id": "m_layer3_m_baseColorMapUvIndex" + } + }, + { + "id": "textureBlendMode", + "displayName": "Texture Blend Mode", + "description": "Selects the equation to use when combining Color, Factor, and Texture Map.", + "type": "Enum", + "enumValues": [ "Multiply", "LinearLight", "Lerp", "Overlay" ], + "defaultValue": "Multiply", + "connection": { + "type": "ShaderOption", + "id": "o_layer3_o_baseColorTextureBlendMode" + } + } + ], + "layer3_metallic": [ + { + "id": "factor", + "displayName": "Factor", + "description": "This value is linear, black is non-metal and white means raw metal.", + "type": "Float", + "defaultValue": 0.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "id": "m_layer3_m_metallicFactor" + } + }, + { + "id": "textureMap", + "displayName": "Texture Map", + "description": "", + "type": "Image", + "connection": { + "type": "ShaderInput", + "id": "m_layer3_m_metallicMap" + } + }, + { + "id": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture map, or just default to the Factor value.", + "type": "Bool", + "defaultValue": true + }, + { + "id": "textureMapUv", + "displayName": "UV", + "description": "Metallic texture map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "id": "m_layer3_m_metallicMapUvIndex" + } + } + ], + "layer3_roughness": [ + { + "id": "textureMap", + "displayName": "Texture Map", + "description": "Texture map for defining surface roughness.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "id": "m_layer3_m_roughnessMap" + } + }, + { + "id": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture map, or just default to the Factor value.", + "type": "Bool", + "defaultValue": true + }, + { + "id": "textureMapUv", + "displayName": "UV", + "description": "Roughness texture map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "id": "m_layer3_m_roughnessMapUvIndex" + } + }, + { + // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. + "id": "lowerBound", + "displayName": "Lower Bound", + "description": "The roughness value that corresponds to black in the texture map.", + "type": "Float", + "defaultValue": 0.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "id": "m_layer3_m_roughnessLowerBound" + } + }, + { + // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. + "id": "upperBound", + "displayName": "Upper Bound", + "description": "The roughness value that corresponds to white in the texture map.", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "id": "m_layer3_m_roughnessUpperBound" + } + }, + { + // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. + "id": "factor", + "displayName": "Factor", + "description": "Controls the roughness value", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "id": "m_layer3_m_roughnessFactor" + } + } + ], + "layer3_specularF0": [ + { + "id": "factor", + "displayName": "Factor", + "description": "The default IOR is 1.5, which gives you 0.04 (4% of light reflected at 0 degree angle for dielectric materials). F0 values lie in the range 0-0.08, so that is why the default F0 slider is set on 0.5.", + "type": "Float", + "defaultValue": 0.5, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "id": "m_layer3_m_specularF0Factor" + } + }, + { + "id": "textureMap", + "displayName": "Texture Map", + "description": "Texture map for defining surface reflectance.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "id": "m_layer3_m_specularF0Map" + } + }, + { + "id": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture map, or just default to the Factor value.", + "type": "Bool", + "defaultValue": true + }, + { + "id": "textureMapUv", + "displayName": "UV", + "description": "Specular reflection texture map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "id": "m_layer3_m_specularF0MapUvIndex" + } + } + ], + "layer3_normal": [ + { + "id": "textureMap", + "displayName": "Texture Map", + "description": "Texture map for defining surface normal direction.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "id": "m_layer3_m_normalMap" + } + }, + { + "id": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture map, or just rely on vertex normals.", + "type": "Bool", + "defaultValue": true + }, + { + "id": "textureMapUv", + "displayName": "UV", + "description": "Normal texture map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "id": "m_layer3_m_normalMapUvIndex" + } + }, + { + "id": "flipX", + "displayName": "Flip X Channel", + "description": "Flip tangent direction for this normal map.", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderInput", + "id": "m_layer3_m_flipNormalX" + } + }, + { + "id": "flipY", + "displayName": "Flip Y Channel", + "description": "Flip bitangent direction for this normal map.", + "type": "Bool", + "defaultValue": false, + "connection": { + "type": "ShaderInput", + "id": "m_layer3_m_flipNormalY" + } + }, + { + "id": "factor", + "displayName": "Factor", + "description": "Strength factor for scaling the values", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "softMax": 2.0, + "connection": { + "type": "ShaderInput", + "id": "m_layer3_m_normalFactor" + } + } + ], + "layer3_clearCoat": [ + { + "id": "enable", + "displayName": "Enable", + "description": "Enable clear coat", + "type": "Bool", + "defaultValue": false + }, + { + "id": "factor", + "displayName": "Factor", + "description": "Strength factor for scaling the percentage of effect applied", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "id": "m_layer3_m_clearCoatFactor" + } + }, + { + "id": "influenceMap", + "displayName": " Influence Map", + "description": "Strength factor texture map", + "type": "Image", + "connection": { + "type": "ShaderInput", + "id": "m_layer3_m_clearCoatInfluenceMap" + } + }, + { + "id": "useInfluenceMap", + "displayName": " Use Texture", + "description": "Whether to use the texture map, or just default to the Factor value.", + "type": "Bool", + "defaultValue": true + }, + { + "id": "influenceMapUv", + "displayName": " UV", + "description": "Strength factor texture map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "id": "m_layer3_m_clearCoatInfluenceMapUvIndex" + } + }, + { + "id": "roughness", + "displayName": "Roughness", + "description": "Clear coat layer roughness", + "type": "Float", + "defaultValue": 0.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "id": "m_layer3_m_clearCoatRoughness" + } + }, + { + "id": "roughnessMap", + "displayName": " Roughness Map", + "description": "Roughness texture map", + "type": "Image", + "connection": { + "type": "ShaderInput", + "id": "m_layer3_m_clearCoatRoughnessMap" + } + }, + { + "id": "useRoughnessMap", + "displayName": " Use Texture", + "description": "Whether to use the texture map, or just default to the roughness value.", + "type": "Bool", + "defaultValue": true + }, + { + "id": "roughnessMapUv", + "displayName": " UV", + "description": "Roughness texture map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "id": "m_layer3_m_clearCoatRoughnessMapUvIndex" + } + }, + { + "id": "normalStrength", + "displayName": "Normal Strength", + "description": "Scales the impact of the clear coat normal map", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 2.0, + "connection": { + "type": "ShaderInput", + "id": "m_layer3_m_clearCoatNormalStrength" + } + }, + { + "id": "normalMap", + "displayName": "Normal Map", + "description": "Normal map for clear coat layer, as top layer material clear coat doesn't affect by base layer normal map", + "type": "Image", + "connection": { + "type": "ShaderInput", + "id": "m_layer3_m_clearCoatNormalMap" + } + }, + { + "id": "useNormalMap", + "displayName": " Use Texture", + "description": "Whether to use the normal map", + "type": "Bool", + "defaultValue": true + }, + { + "id": "normalMapUv", + "displayName": " UV", + "description": "Normal texture map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "id": "m_layer3_m_clearCoatNormalMapUvIndex" + } + } + ], + "layer3_occlusion": [ + { + "id": "diffuseTextureMap", + "displayName": "Diffuse AO", + "description": "Texture map for defining occlusion area for diffuse ambient lighting.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "id": "m_layer3_m_diffuseOcclusionMap" + } + }, + { + "id": "diffuseUseTexture", + "displayName": " Use Texture", + "description": "Whether to use the Diffuse AO texture map.", + "type": "Bool", + "defaultValue": true + }, + { + "id": "diffuseTextureMapUv", + "displayName": " UV", + "description": "Diffuse AO texture map UV set.", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "id": "m_layer3_m_diffuseOcclusionMapUvIndex" + } + }, + { + "id": "diffuseFactor", + "displayName": " Factor", + "description": "Strength factor for scaling the values of Diffuse AO", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "softMax": 2.0, + "connection": { + "type": "ShaderInput", + "id": "m_layer3_m_diffuseOcclusionFactor" + } + }, + { + "id": "specularTextureMap", + "displayName": "Specular Cavity", + "description": "Texture map for defining occlusion area for specular lighting.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "id": "m_layer3_m_specularOcclusionMap" + } + }, + { + "id": "specularUseTexture", + "displayName": " Use Texture", + "description": "Whether to use the Specular Cavity texture map.", + "type": "Bool", + "defaultValue": true + }, + { + "id": "specularTextureMapUv", + "displayName": " UV", + "description": "Specular Cavity texture map UV set.", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "id": "m_layer3_m_specularOcclusionMapUvIndex" + } + }, + { + "id": "specularFactor", + "displayName": " Factor", + "description": "Strength factor for scaling the values of Specular Cavity", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "softMax": 2.0, + "connection": { + "type": "ShaderInput", + "id": "m_layer3_m_specularOcclusionFactor" + } + } + ], + "layer3_emissive": [ + { + "id": "enable", + "displayName": "Enable", + "description": "Enable the emissive group", + "type": "Bool", + "defaultValue": false + }, + { + "id": "unit", + "displayName": "Units", + "description": "The photometric units of the Intensity property.", + "type": "Enum", + "enumValues": ["Ev100"], + "defaultValue": "Ev100" + }, + { + "id": "color", + "displayName": "Color", + "description": "Color is displayed as sRGB but the values are stored as linear color.", + "type": "Color", + "defaultValue": [ 1.0, 1.0, 1.0 ], + "connection": { + "type": "ShaderInput", + "id": "m_layer3_m_emissiveColor" + } + }, + { + "id": "intensity", + "displayName": "Intensity", + "description": "The amount of energy emitted.", + "type": "Float", + "defaultValue": 4, + "min": -10, + "max": 20, + "softMin": -6, + "softMax": 16 + }, + { + "id": "textureMap", + "displayName": "Texture Map", + "description": "Texture map for defining emissive area.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "id": "m_layer3_m_emissiveMap" + } + }, + { + "id": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture map.", + "type": "Bool", + "defaultValue": true + }, + { + "id": "textureMapUv", + "displayName": "UV", + "description": "Emissive texture map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "id": "m_layer3_m_emissiveMapUvIndex" + } + } + ], + "layer3_parallax": [ + { + "id": "enable", + "displayName": "Enable", + "description": "Whether to enable the parallax feature.", + "type": "Bool", + "defaultValue": false + }, + { + "id": "textureMap", + "displayName": "Texture Map", + "description": "Depthmap to create parallax effect.", + "type": "Image", + "connection": { + "type": "ShaderInput", + "id": "m_layer3_m_depthMap" + } + }, + { + "id": "factor", + "displayName": "Heightmap Scale", + "description": "The total height of the heightmap in local model units.", + "type": "Float", + "defaultValue": 0.0, + "min": 0.0, + "softMax": 0.1, + "connection": { + "type": "ShaderInput", + "id": "m_layer3_m_depthFactor" + } + }, + { + "id": "offset", + "displayName": "Offset", + "description": "Adjusts the overall displacement amount in local model units.", + "type": "Float", + "defaultValue": 0.0, + "softMin": -0.1, + "softMax": 0.1, + "connection": { + "type": "ShaderInput", + "id": "m_layer3_m_depthOffset" + } + }, + { + "id": "invert", + "displayName": "Invert", + "description": "Invert to depthmap if the texture is heightmap", + "type": "Bool", + "defaultValue": true, + "connection": { + "type": "ShaderInput", + "id": "m_layer3_m_depthInverted" + } + } + ], + "layer3_uv": [ + { + "id": "center", + "displayName": "Center", + "description": "Center point for scaling and rotation transformations.", + "type": "vector2", + "vectorLabels": [ "U", "V" ], + "defaultValue": [ 0.0, 0.0 ] + }, + { + "id": "tileU", + "displayName": "Tile U", + "description": "Scales texture coordinates in V.", + "type": "float", + "defaultValue": 1.0, + "step": 0.1 + }, + { + "id": "tileV", + "displayName": "Tile V", + "description": "Scales texture coordinates in V.", + "type": "float", + "defaultValue": 1.0, + "step": 0.1 + }, + { + "id": "offsetU", + "displayName": "Offset U", + "description": "Offsets texture coordinates in the U direction.", + "type": "float", + "defaultValue": 0.0, + "min": -1.0, + "max": 1.0, + "step": 0.001 + }, + { + "id": "offsetV", + "displayName": "Offset V", + "description": "Offsets texture coordinates in the V direction.", + "type": "float", + "defaultValue": 0.0, + "min": -1.0, + "max": 1.0, + "step": 0.001 + }, + { + "id": "rotateDegrees", + "displayName": "Rotate", + "description": "Rotates the texture coordinates (degrees).", + "type": "float", + "defaultValue": 0.0, + "min": -180.0, + "max": 180.0, + "step": 1.0 + }, + { + "id": "scale", + "displayName": "Scale", + "description": "Scales texture coordinates in both U and V.", + "type": "float", + "defaultValue": 1.0, + "step": 0.1 + } + ] + } + }, + "shaders": [ + { + "file": "./StandardMultilayerPBR_ForwardPass.shader", + "tag": "ForwardPass" + }, + { + "file": "./StandardMultilayerPBR_ForwardPass_EDS.shader", + "tag": "ForwardPass_EDS" + }, + { + "file": "Shaders/Shadow/Shadowmap.shader", + "tag": "Shadowmap" + }, + { + "file": "./StandardMultilayerPBR_Shadowmap_WithPS.shader", + "tag": "Shadowmap_WithPS" + }, + { + "file": "Shaders/Depth/DepthPass.shader", + "tag": "DepthPass" + }, + { + "file": "./StandardMultilayerPBR_DepthPass_WithPS.shader", + "tag": "DepthPass_WithPS" + }, + // [GFX TODO][ATOM-4726] Use an "isSkinnedMesh" external material property and a functor that enables/disables the appropriate motion-vector shader + { + "file": "Shaders/MotionVector/StaticMeshMotionVector.shader", + "tag": "StaticMeshMotionVector" + }, + { + "file": "Shaders/MotionVector/SkinnedMeshMotionVector.shader", + "tag": "SkinnedMeshMotionVector" + } + ], + "functors": [ + //############################################################################################## + // General Functors + //############################################################################################## + { + // Maps 2D scale, offset, and rotate properties into a float3x3 transform matrix. + "type": "Transform2D", + "args": { + "transformOrder": [ "Rotate", "Translate", "Scale" ], + "centerProperty": "uv.center", + "scaleProperty": "uv.scale", + "scaleXProperty": "uv.tileU", + "scaleYProperty": "uv.tileV", + "translateXProperty": "uv.offsetU", + "translateYProperty": "uv.offsetV", + "rotateDegreesProperty": "uv.rotateDegrees", + "float3x3ShaderInput": "m_uvMatrix", + "float3x3InverseShaderInput": "m_uvMatrixInverse" + } + }, + { + "type": "Lua", + "args": { + "file": "StandardMultilayerPBR_ShaderEnable.lua" + } + }, + { + "type": "Lua", + "args": { + "file": "StandardMultilayerPBR_LayerEnable.lua" + } + }, + { + "type": "Lua", + "args": { + "file": "StandardMultilayerPBR_ClearCoatEnableFeature.lua" + } + }, + { + "type": "Lua", + "args": { + "file": "StandardMultilayerPBR_Parallax.lua" + } + }, + //############################################################################################## + // Layer 1 Functors + //############################################################################################## + { + "type": "UseTexture", + "args": { + "textureProperty": "layer1_baseColor.textureMap", + "useTextureProperty": "layer1_baseColor.useTexture", + "dependentProperties": ["layer1_baseColor.textureMapUv", "layer1_baseColor.textureBlendMode"], + "shaderTags": [ + "ForwardPass", + "ForwardPass_EDS" + ], + "shaderOption": "o_layer1_o_baseColor_useTexture" + } + }, + { + "type": "UseTexture", + "args": { + "textureProperty": "layer1_metallic.textureMap", + "useTextureProperty": "layer1_metallic.useTexture", + "dependentProperties": ["layer1_metallic.textureMapUv"], + "shaderTags": [ + "ForwardPass", + "ForwardPass_EDS" + ], + "shaderOption": "o_layer1_o_metallic_useTexture" + } + }, + { + "type": "Lua", + "args": { + "file": "StandardPBR_Roughness.lua", + "propertyNamePrefix": "layer1_", + "srgNamePrefix": "m_layer1_", + "optionsNamePrefix": "o_layer1_" + } + }, + { + "type": "UseTexture", + "args": { + "textureProperty": "layer1_specularF0.textureMap", + "useTextureProperty": "layer1_specularF0.useTexture", + "dependentProperties": ["layer1_specularF0.textureMapUv"], + "shaderTags": [ + "ForwardPass", + "ForwardPass_EDS" + ], + "shaderOption": "o_layer1_o_specularF0_useTexture" + } + }, + { + "type": "UseTexture", + "args": { + "textureProperty": "layer1_normal.textureMap", + "useTextureProperty": "layer1_normal.useTexture", + "dependentProperties": ["layer1_normal.textureMapUv", "layer1_normal.factor", "layer1_normal.flipX", "layer1_normal.flipY"], + "shaderTags": [ + "ForwardPass", + "ForwardPass_EDS" + ], + "shaderOption": "o_layer1_o_normal_useTexture" + } + }, + { + "type": "Lua", + "args": { + "file": "StandardPBR_ClearCoatState.lua", + "propertyNamePrefix": "layer1_", + "srgNamePrefix": "m_layer1_", + "optionsNamePrefix": "o_layer1_" + } + }, + { + "type": "UseTexture", + "args": { + "textureProperty": "layer1_occlusion.diffuseTextureMap", + "useTextureProperty": "layer1_occlusion.diffuseUseTexture", + "dependentProperties": ["layer1_occlusion.diffuseTextureMapUv", "layer1_occlusion.diffuseFactor"], + "shaderOption": "o_layer1_o_diffuseOcclusion_useTexture" + } + }, + { + "type": "UseTexture", + "args": { + "textureProperty": "layer1_occlusion.specularTextureMap", + "useTextureProperty": "layer1_occlusion.specularUseTexture", + "dependentProperties": ["layer1_occlusion.specularTextureMapUv", "layer1_occlusion.specularFactor"], + "shaderOption": "o_layer1_o_specularOcclusion_useTexture" + } + }, + { + "type": "Lua", + "args": { + "file": "StandardPBR_EmissiveState.lua", + "propertyNamePrefix": "layer1_", + "srgNamePrefix": "m_layer1_", + "optionsNamePrefix": "o_layer1_" + } + }, + { + // Convert emissive unit. + "type": "ConvertEmissiveUnit", + "args": { + "intensityProperty": "layer1_emissive.intensity", + "lightUnitProperty": "layer1_emissive.unit", + "shaderInput": "m_layer1_m_emissiveIntensity", + "ev100Index": 0, + "nitIndex" : 1, + "ev100MinMax": [-10, 20], + "nitMinMax": [0.001, 100000.0] + } + }, + { + "type": "Lua", + "args": { + "file": "StandardMultilayerPBR_ParallaxPerLayer.lua", + "propertyNamePrefix": "layer1_", + "srgNamePrefix": "m_layer1_", + "optionsNamePrefix": "o_layer1_" + } + }, + { + // Maps 2D scale, offset, and rotate properties into a float3x3 transform matrix. + "type": "Transform2D", + "args": { + "transformOrder": [ "Rotate", "Translate", "Scale" ], + "centerProperty": "layer1_uv.center", + "scaleProperty": "layer1_uv.scale", + "scaleXProperty": "layer1_uv.tileU", + "scaleYProperty": "layer1_uv.tileV", + "translateXProperty": "layer1_uv.offsetU", + "translateYProperty": "layer1_uv.offsetV", + "rotateDegreesProperty": "layer1_uv.rotateDegrees", + "float3x3ShaderInput": "m_layer1_m_uvMatrix" + } + }, + //############################################################################################## + // Layer 2 Functors + //############################################################################################## + { + "type": "UseTexture", + "args": { + "textureProperty": "layer2_baseColor.textureMap", + "useTextureProperty": "layer2_baseColor.useTexture", + "dependentProperties": ["layer2_baseColor.textureMapUv", "layer2_baseColor.textureBlendMode"], + "shaderTags": [ + "ForwardPass", + "ForwardPass_EDS" + ], + "shaderOption": "o_layer2_o_baseColor_useTexture" + } + }, + { + "type": "UseTexture", + "args": { + "textureProperty": "layer2_metallic.textureMap", + "useTextureProperty": "layer2_metallic.useTexture", + "dependentProperties": ["layer2_metallic.textureMapUv"], + "shaderTags": [ + "ForwardPass", + "ForwardPass_EDS" + ], + "shaderOption": "o_layer2_o_metallic_useTexture" + } + }, + { + "type": "Lua", + "args": { + "file": "StandardPBR_Roughness.lua", + "propertyNamePrefix": "layer2_", + "srgNamePrefix": "m_layer2_", + "optionsNamePrefix": "o_layer2_" + } + }, + { + "type": "UseTexture", + "args": { + "textureProperty": "layer2_specularF0.textureMap", + "useTextureProperty": "layer2_specularF0.useTexture", + "dependentProperties": ["layer2_specularF0.textureMapUv"], + "shaderTags": [ + "ForwardPass", + "ForwardPass_EDS" + ], + "shaderOption": "o_layer2_o_specularF0_useTexture" + } + }, + { + "type": "UseTexture", + "args": { + "textureProperty": "layer2_normal.textureMap", + "useTextureProperty": "layer2_normal.useTexture", + "dependentProperties": ["layer2_normal.textureMapUv", "layer2_normal.factor", "layer2_normal.flipX", "layer2_normal.flipY"], + "shaderTags": [ + "ForwardPass", + "ForwardPass_EDS" + ], + "shaderOption": "o_layer2_o_normal_useTexture" + } + }, + { + "type": "Lua", + "args": { + "file": "StandardPBR_ClearCoatState.lua", + "propertyNamePrefix": "layer2_", + "srgNamePrefix": "m_layer2_", + "optionsNamePrefix": "o_layer2_" + } + }, + { + "type": "UseTexture", + "args": { + "textureProperty": "layer2_occlusion.diffuseTextureMap", + "useTextureProperty": "layer2_occlusion.diffuseUseTexture", + "dependentProperties": ["layer2_occlusion.diffuseTextureMapUv", "layer2_occlusion.diffuseFactor"], + "shaderOption": "o_layer2_o_diffuseOcclusion_useTexture" + } + }, + { + "type": "UseTexture", + "args": { + "textureProperty": "layer2_occlusion.specularTextureMap", + "useTextureProperty": "layer2_occlusion.specularUseTexture", + "dependentProperties": ["layer2_occlusion.specularTextureMapUv", "layer2_occlusion.specularFactor"], + "shaderOption": "o_layer2_o_specularOcclusion_useTexture" + } + }, + { + "type": "Lua", + "args": { + "file": "StandardPBR_EmissiveState.lua", + "propertyNamePrefix": "layer2_", + "srgNamePrefix": "m_layer2_", + "optionsNamePrefix": "o_layer2_" + } + }, + { + // Convert emissive unit. + "type": "ConvertEmissiveUnit", + "args": { + "intensityProperty": "layer2_emissive.intensity", + "lightUnitProperty": "layer2_emissive.unit", + "shaderInput": "m_layer2_m_emissiveIntensity", + "ev100Index": 0, + "nitIndex" : 1, + "ev100MinMax": [-10, 20], + "nitMinMax": [0.001, 100000.0] + } + }, + { + "type": "Lua", + "args": { + "file": "StandardMultilayerPBR_ParallaxPerLayer.lua", + "propertyNamePrefix": "layer2_", + "srgNamePrefix": "m_layer2_", + "optionsNamePrefix": "o_layer2_" + } + }, + { + // Maps 2D scale, offset, and rotate properties into a float3x3 transform matrix. + "type": "Transform2D", + "args": { + "transformOrder": [ "Rotate", "Translate", "Scale" ], + "centerProperty": "layer2_uv.center", + "scaleProperty": "layer2_uv.scale", + "scaleXProperty": "layer2_uv.tileU", + "scaleYProperty": "layer2_uv.tileV", + "translateXProperty": "layer2_uv.offsetU", + "translateYProperty": "layer2_uv.offsetV", + "rotateDegreesProperty": "layer2_uv.rotateDegrees", + "float3x3ShaderInput": "m_layer2_m_uvMatrix" + } + }, + //############################################################################################## + // Layer 3 Functors + //############################################################################################## + { + "type": "UseTexture", + "args": { + "textureProperty": "layer3_baseColor.textureMap", + "useTextureProperty": "layer3_baseColor.useTexture", + "dependentProperties": ["layer3_baseColor.textureMapUv", "layer3_baseColor.textureBlendMode"], + "shaderTags": [ + "ForwardPass", + "ForwardPass_EDS" + ], + "shaderOption": "o_layer3_o_baseColor_useTexture" + } + }, + { + "type": "UseTexture", + "args": { + "textureProperty": "layer3_metallic.textureMap", + "useTextureProperty": "layer3_metallic.useTexture", + "dependentProperties": ["layer3_metallic.textureMapUv"], + "shaderTags": [ + "ForwardPass", + "ForwardPass_EDS" + ], + "shaderOption": "o_layer3_o_metallic_useTexture" + } + }, + { + "type": "Lua", + "args": { + "file": "StandardPBR_Roughness.lua", + "propertyNamePrefix": "layer3_", + "srgNamePrefix": "m_layer3_", + "optionsNamePrefix": "o_layer3_" + } + }, + { + "type": "UseTexture", + "args": { + "textureProperty": "layer3_specularF0.textureMap", + "useTextureProperty": "layer3_specularF0.useTexture", + "dependentProperties": ["layer3_specularF0.textureMapUv"], + "shaderTags": [ + "ForwardPass", + "ForwardPass_EDS" + ], + "shaderOption": "o_layer3_o_specularF0_useTexture" + } + }, + { + "type": "UseTexture", + "args": { + "textureProperty": "layer3_normal.textureMap", + "useTextureProperty": "layer3_normal.useTexture", + "dependentProperties": ["layer3_normal.textureMapUv", "layer3_normal.factor", "layer3_normal.flipX", "layer3_normal.flipY"], + "shaderTags": [ + "ForwardPass", + "ForwardPass_EDS" + ], + "shaderOption": "o_layer3_o_normal_useTexture" + } + }, + { + "type": "Lua", + "args": { + "file": "StandardPBR_ClearCoatState.lua", + "propertyNamePrefix": "layer3_", + "srgNamePrefix": "m_layer3_", + "optionsNamePrefix": "o_layer3_" + } + }, + { + "type": "UseTexture", + "args": { + "textureProperty": "layer3_occlusion.diffuseTextureMap", + "useTextureProperty": "layer3_occlusion.diffuseUseTexture", + "dependentProperties": ["layer3_occlusion.diffuseTextureMapUv", "layer3_occlusion.diffuseFactor"], + "shaderOption": "o_layer3_o_diffuseOcclusion_useTexture" + } + }, + { + "type": "UseTexture", + "args": { + "textureProperty": "layer3_occlusion.specularTextureMap", + "useTextureProperty": "layer3_occlusion.specularUseTexture", + "dependentProperties": ["layer3_occlusion.specularTextureMapUv", "layer3_occlusion.specularFactor"], + "shaderOption": "o_layer3_o_specularOcclusion_useTexture" + } + }, + { + "type": "Lua", + "args": { + "file": "StandardPBR_EmissiveState.lua", + "propertyNamePrefix": "layer3_", + "srgNamePrefix": "m_layer3_", + "optionsNamePrefix": "o_layer3_" + } + }, + { + // Convert emissive unit. + "type": "ConvertEmissiveUnit", + "args": { + "intensityProperty": "layer3_emissive.intensity", + "lightUnitProperty": "layer3_emissive.unit", + "shaderInput": "m_layer3_m_emissiveIntensity", + "ev100Index": 0, + "nitIndex" : 1, + "ev100MinMax": [-10, 20], + "nitMinMax": [0.001, 100000.0] + } + }, + { + "type": "Lua", + "args": { + "file": "StandardMultilayerPBR_ParallaxPerLayer.lua", + "propertyNamePrefix": "layer3_", + "srgNamePrefix": "m_layer3_", + "optionsNamePrefix": "o_layer3_" + } + }, + { + // Maps 2D scale, offset, and rotate properties into a float3x3 transform matrix. + "type": "Transform2D", + "args": { + "transformOrder": [ "Rotate", "Translate", "Scale" ], + "centerProperty": "layer3_uv.center", + "scaleProperty": "layer3_uv.scale", + "scaleXProperty": "layer3_uv.tileU", + "scaleYProperty": "layer3_uv.tileV", + "translateXProperty": "layer3_uv.offsetU", + "translateYProperty": "layer3_uv.offsetV", + "rotateDegreesProperty": "layer3_uv.rotateDegrees", + "float3x3ShaderInput": "m_layer3_m_uvMatrix" + } + } + ], + "uvNameMap": { + "UV0": "Tiled", + "UV1": "Unwrapped" + } +} + diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_Common.azsli b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_Common.azsli index 776999f3ff..dc1b627d29 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_Common.azsli +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_Common.azsli @@ -95,10 +95,13 @@ ShaderResourceGroup MaterialSrg : SRG_PerMaterial // ------ Shader Options ---------------------------------------- -enum class DebugDrawMode { None, BlendSource, DisplacementMaps }; +option bool o_layer2_enabled; +option bool o_layer3_enabled; + +enum class DebugDrawMode { None, BlendMask, Displacement, FinalBlendWeights }; option DebugDrawMode o_debugDrawMode; -enum class LayerBlendSource { BlendMask, VertexColors, Displacement, Fallback }; +enum class LayerBlendSource { TextureMap, VertexColors, Displacement, Fallback }; option LayerBlendSource o_layerBlendSource; // Indicates whether the vertex input struct's "m_optional_blendMask" is bound. If false, it is not safe to read from m_optional_blendMask. @@ -112,12 +115,14 @@ option bool o_blendMask_isBound; // But since we have it, we use it in some other functions as well rather than passing it around. static float3 s_blendMaskFromVertexStream; +// TODO: Consider storing the result of GetFinalLayerBlendSource() in a static similar to s_blendMaskFromVertexStream. That might give better performance when variants aren't used. + //! Returns the LayerBlendSource that will actually be used when rendering (not necessarily the same LayerBlendSource specified by the user) LayerBlendSource GetFinalLayerBlendSource() { - if(o_layerBlendSource == LayerBlendSource::BlendMask) + if(o_layerBlendSource == LayerBlendSource::TextureMap) { - return LayerBlendSource::BlendMask; + return LayerBlendSource::TextureMap; } else if(o_layerBlendSource == LayerBlendSource::VertexColors) { @@ -127,7 +132,7 @@ LayerBlendSource GetFinalLayerBlendSource() } else { - return LayerBlendSource::BlendMask; + return LayerBlendSource::TextureMap; } } else if(o_layerBlendSource == LayerBlendSource::Displacement) @@ -140,24 +145,28 @@ LayerBlendSource GetFinalLayerBlendSource() } } -//! Return the raw blend source values directly from the blend mask or vertex colors, depending on the available data and configuration. +//! Return the applicable blend mask values from the blend mask texture or vertex colors, and filters out any that don't apply. //! layer1 is an implicit base layer -//! layer2 is weighted by r -//! layer3 is weighted by g +//! layer2 mask is in the r channel +//! layer3 mask is in the g channel //! b is reserved for perhaps a dedicated puddle layer -float3 GetBlendSourceValues(float2 uv) +//! @param blendSource indicates where to get the blend mask from +//! @param blendMaskUv for sampling a blend mask texture, if that's the blend source +//! @param blendMaskVertexColors the vertex color values to use for the blend mask, if that's the blend source +//! @return the blend mask values, or 0 if there is no blend mask +float3 GetApplicableBlendMaskValues(LayerBlendSource blendSource, float2 blendMaskUv, float3 blendMaskVertexColors) { float3 blendSourceValues = float3(0,0,0); if(o_layer2_enabled || o_layer3_enabled) { - switch(GetFinalBlendMaskSource()) + switch(blendSource) { - case BlendMaskSource::TextureMap: - blendSourceValues = MaterialSrg::m_blendMaskTexture.Sample(MaterialSrg::m_sampler, uv).rgb; + case LayerBlendSource::TextureMap: + blendSourceValues = MaterialSrg::m_blendMaskTexture.Sample(MaterialSrg::m_sampler, blendMaskUv).rgb; break; - case BlendMaskSource::VertexColors: - blendSourceValues = s_blendMaskFromVertexStream; + case LayerBlendSource::VertexColors: + blendSourceValues = blendMaskVertexColors; break; } @@ -179,38 +188,57 @@ float3 GetBlendSourceValues(float2 uv) //! @param layerDepthValues - the per-layer depth values as provided by GetLayerDepthValues() float3 GetBlendWeightsFromLayerDepthValues(float3 layerDepthValues) { - float highestPoint = min(layerDepthValues.x, min(layerDepthValues.y, layerDepthValues.z)); + float highestPoint = layerDepthValues.x; + if(o_layer2_enabled) + { + highestPoint = min(highestPoint, layerDepthValues.y); + } + if(o_layer3_enabled) + { + highestPoint = min(highestPoint, layerDepthValues.z); + } + float3 blendWeights = float3(layerDepthValues.x <= highestPoint ? 1.0 : 0.0, - layerDepthValues.y <= highestPoint ? 1.0 : 0.0, - layerDepthValues.z <= highestPoint ? 1.0 : 0.0); + o_layer2_enabled && layerDepthValues.y <= highestPoint ? 1.0 : 0.0, + o_layer3_enabled && layerDepthValues.z <= highestPoint ? 1.0 : 0.0); return blendWeights; } -float3 GetLayerDepthValues(float2 uv, float2 uv_ddx, float2 uv_ddy); - -//! Return the final blend mask values to be used for rendering, based on the available data and configuration. +//! Return the final blend weights to be used for rendering, based on the available data and configuration. +//! @param blendSource indicates where to get the blend mask from +//! @param blendMaskUv for sampling a blend mask texture, if that's the blend source +//! @param blendMaskVertexColors the vertex color values to use for the blend mask, if that's the blend source +//! @param layerDepthValues the depth values for each layer, use if the blend source includes displacement //! @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) +float3 GetBlendWeights(LayerBlendSource blendSource, float2 blendMaskUv, float3 blendMaskVertexColors, float3 layerDepthValues) { float3 blendWeights; if(o_layer2_enabled || o_layer3_enabled) { - float3 blendSourceValues = GetBlendSourceValues(uv); + if(LayerBlendSource::Displacement == blendSource) + { + blendWeights = GetBlendWeightsFromLayerDepthValues(layerDepthValues); + } + else + { + float3 blendMaskValues = GetApplicableBlendMaskValues(blendSource, blendMaskUv, blendMaskVertexColors); - // 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) + // 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 = blendMaskValues.g; + blendWeights.g = (1.0 - blendMaskValues.g) * blendMaskValues.r; + blendWeights.r = (1.0 - blendMaskValues.g) * (1.0 - blendMaskValues.r); + } - blendWeights.b = blendSourceValues.g; - blendWeights.g = (1.0 - blendSourceValues.g) * blendSourceValues.r; - blendWeights.r = (1.0 - blendSourceValues.g) * (1.0 - blendSourceValues.r); } else { @@ -220,19 +248,21 @@ float3 GetBlendWeights(float2 uv) return blendWeights; } -//! Return the final blend mask values to be used for rendering, based on the available data and configuration. +float3 GetLayerDepthValues(float2 uv, float2 uv_ddx, float2 uv_ddy); + +//! Return the final blend weights to be used for rendering, based on the available data and configuration. //! Note this will sample the displacement maps in the case of LayerBlendSource::Displacement. If you have already -//! called GetLayerDepthValues(), use the GetBlendWeights() overlad that takes layerDepthValues instead. -float3 GetBlendWeights(float2 uv, float3 vertexBlendWeights) +//! called GetLayerDepthValues(), use the GetBlendWeights() overload that takes layerDepthValues instead. +float3 GetBlendWeights(LayerBlendSource blendSource, float2 uv, float3 blendMaskVertexColors) { float3 layerDepthValues = float3(0,0,0); - if(GetFinalLayerBlendSource() == LayerBlendSource::Displacement) + if(blendSource == LayerBlendSource::Displacement) { layerDepthValues = GetLayerDepthValues(uv, ddx_fine(uv), ddy_fine(uv)); } - return GetBlendWeights(uv, vertexBlendWeights, layerDepthValues); + return GetBlendWeights(blendSource, uv, blendMaskVertexColors, layerDepthValues); } float BlendLayers(float layer1, float layer2, float layer3, float3 blendWeights) @@ -319,7 +349,7 @@ DepthResult GetDepth(float2 uv, float2 uv_ddx, float2 uv_ddy) // Note, when the blend source is LayerBlendSource::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 blendWeightValues = GetBlendWeights(uv, s_blendWeightsFromVertexStream, layerDepthValues); + float3 blendWeightValues = GetBlendWeights(GetFinalLayerBlendSource(), uv, s_blendMaskFromVertexStream, layerDepthValues); float depth = BlendLayers(layerDepthValues.r, layerDepthValues.g, layerDepthValues.b, blendWeightValues); return DepthResultAbsolute(depth); diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_Common.azsli.orig b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_Common.azsli.orig new file mode 100644 index 0000000000..471fab991d --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_Common.azsli.orig @@ -0,0 +1,401 @@ +/* +* 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 +#include +#include + +#include "MaterialInputs/BaseColorInput.azsli" +#include "MaterialInputs/RoughnessInput.azsli" +#include "MaterialInputs/MetallicInput.azsli" +#include "MaterialInputs/SpecularInput.azsli" +#include "MaterialInputs/NormalInput.azsli" +#include "MaterialInputs/ClearCoatInput.azsli" +#include "MaterialInputs/OcclusionInput.azsli" +#include "MaterialInputs/EmissiveInput.azsli" +#include "MaterialInputs/ParallaxInput.azsli" +#include "MaterialInputs/UvSetCount.azsli" + +// ------ ShaderResourceGroup ---------------------------------------- + +#define DEFINE_LAYER_SRG_INPUTS(prefix) \ +COMMON_SRG_INPUTS_BASE_COLOR(prefix) \ +COMMON_SRG_INPUTS_ROUGHNESS(prefix) \ +COMMON_SRG_INPUTS_METALLIC(prefix) \ +COMMON_SRG_INPUTS_SPECULAR_F0(prefix) \ +COMMON_SRG_INPUTS_NORMAL(prefix) \ +COMMON_SRG_INPUTS_CLEAR_COAT(prefix) \ +COMMON_SRG_INPUTS_OCCLUSION(prefix) \ +COMMON_SRG_INPUTS_EMISSIVE(prefix) \ +COMMON_SRG_INPUTS_PARALLAX(prefix) + +ShaderResourceGroup MaterialSrg : SRG_PerMaterial +{ + Texture2D m_blendMaskTexture; + uint m_blendMaskUvIndex; + + // Auto-generate material SRG fields for common inputs for each layer + DEFINE_LAYER_SRG_INPUTS(m_layer1_) + DEFINE_LAYER_SRG_INPUTS(m_layer2_) + DEFINE_LAYER_SRG_INPUTS(m_layer3_) + + float3x3 m_layer1_m_uvMatrix; + float4 m_pad1; // [GFX TODO][ATOM-14595] This is a workaround for a data stomping bug. Remove once it's fixed. + + float3x3 m_layer2_m_uvMatrix; + float4 m_pad2; // [GFX TODO][ATOM-14595] This is a workaround for a data stomping bug. Remove once it's fixed. + + float3x3 m_layer3_m_uvMatrix; + float4 m_pad3; // [GFX TODO][ATOM-14595] This is a workaround for a data stomping bug. Remove once it's fixed. + + uint m_parallaxUvIndex; + + // These are used to limit the heightmap intersection search range to the narrowest band possible, to give the best quality result. + float m_displacementMin; // The lowest displacement value possible from all layers combined (negative values are below the surface) + float m_displacementMax; // The highest displacement value possible from all layers combined (negative values are below the surface) + + float3x3 m_uvMatrix; + float4 m_pad4; // [GFX TODO][ATOM-14595] This is a workaround for a data stomping bug. Remove once it's fixed. + float3x3 m_uvMatrixInverse; + float4 m_pad5; // [GFX TODO][ATOM-14595] This is a workaround for a data stomping bug. Remove once it's fixed. + + Sampler m_sampler + { + AddressU = Wrap; + AddressV = Wrap; + MinFilter = Linear; + MagFilter = Linear; + MipFilter = Linear; + MaxAnisotropy = 16; + }; + + Texture2D m_brdfMap; + + Sampler m_samplerBrdf + { + AddressU = Clamp; + AddressV = Clamp; + MinFilter = Linear; + MagFilter = Linear; + MipFilter = Linear; + }; + +} + +// ------ Shader Options ---------------------------------------- + +<<<<<<< HEAD +option bool o_layer2_enabled; +option bool o_layer3_enabled; + +enum class DebugDrawMode { None, BlendSource, DepthMaps }; +======= +enum class DebugDrawMode { None, BlendWeights, DisplacementMaps }; +>>>>>>> Atom/santorac/MultilayerPbrImprovements +option DebugDrawMode o_debugDrawMode; + +enum class LayerBlendSource { BlendMask, VertexColors, Displacement, Fallback }; +option LayerBlendSource o_layerBlendSource; + +// Indicates whether the vertex input struct's "m_optional_blendMask" is bound. If false, it is not safe to read from m_optional_blendMask. +// This option gets set automatically by the system at runtime; there is a soft naming convention that associates it with m_optional_blendMask. +// (search "m_optional_" in ShaderVariantAssetBuilder for details on the naming convention). +// [GFX TODO][ATOM-14475]: Come up with a more elegant way to associate the isBound flag with the input stream. +option bool o_blendMask_isBound; + +// ------ Blend Utilities ---------------------------------------- + +<<<<<<< HEAD +// 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() +======= +//! Returns the LayerBlendSource that will actually be used when rendering (not necessarily the same LayerBlendSource specified by the user) +LayerBlendSource GetFinalLayerBlendSource() +>>>>>>> Atom/santorac/MultilayerPbrImprovements +{ + if(o_layerBlendSource == LayerBlendSource::BlendMask) + { + return LayerBlendSource::BlendMask; + } + else if(o_layerBlendSource == LayerBlendSource::VertexColors) + { + if(o_blendMask_isBound) + { + return LayerBlendSource::VertexColors; + } + else + { + return LayerBlendSource::BlendMask; + } + } + else if(o_layerBlendSource == LayerBlendSource::Displacement) + { + return LayerBlendSource::Displacement; + } + else + { + return LayerBlendSource::Fallback; + } +} + +<<<<<<< HEAD +//! 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 blendSourceValues = float3(0,0,0); + + if(o_layer2_enabled || o_layer3_enabled) + { + 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; + } + } + + return blendSourceValues; +} + +//! 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) +{ + 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; +} + +float BlendLayers(float layer1, float layer2, float layer3, float3 blendWeights) +{ + return dot(float3(layer1, layer2, layer3), blendWeights); +} +float2 BlendLayers(float2 layer1, float2 layer2, float2 layer3, float3 blendWeights) +{ + 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; +======= +//! Returns blend weights given the depth values for each layer +float3 GetBlendWeightsFromLayerDepthValues(float3 layerDepthValues) +{ + float highestPoint = min(layerDepthValues.x, min(layerDepthValues.y, layerDepthValues.z)); + float3 blendWeights = float3(layerDepthValues.x <= highestPoint ? 1.0 : 0.0, + layerDepthValues.y <= highestPoint ? 1.0 : 0.0, + layerDepthValues.z <= highestPoint ? 1.0 : 0.0); + return blendWeights; +} + +float3 GetLayerDepthValues(float2 uv, float2 uv_ddx, float2 uv_ddy); + +//! Return the final blend mask values to be used for rendering, based on the available data and configuration. +//! @param vertexBlendWeights - the blend weights that came from the vertex input, relevant for LayerBlendSource::VertexColors +//! @param layerDepthValues - the per-layer depth values as provided by GetLayerDepthValues() +float3 GetBlendWeights(float2 uv, float3 vertexBlendWeights, float3 layerDepthValues) +{ + float3 blendWeightValues; + + switch(GetFinalLayerBlendSource()) + { + case LayerBlendSource::BlendMask: + blendWeightValues = MaterialSrg::m_blendMaskTexture.Sample(MaterialSrg::m_sampler, uv).rgb; + break; + case LayerBlendSource::VertexColors: + blendWeightValues = vertexBlendWeights; + break; + case LayerBlendSource::Displacement: + blendWeightValues = GetBlendWeightsFromLayerDepthValues(layerDepthValues); + break; + case LayerBlendSource::Fallback: + blendWeightValues = float3(1,1,1); + break; + } + + blendWeightValues = blendWeightValues / (blendWeightValues.r + blendWeightValues.g + blendWeightValues.b); + + return blendWeightValues; +} + +//! Return the final blend mask values to be used for rendering, based on the available data and configuration. +//! Note this will sample the displacement maps in the case of LayerBlendSource::Displacement. If you have already +//! called GetLayerDepthValues(), use the GetBlendWeights() overlad that takes layerDepthValues instead. +float3 GetBlendWeights(float2 uv, float3 vertexBlendWeights) +{ + float3 layerDepthValues = float3(0,0,0); + + if(GetFinalLayerBlendSource() == LayerBlendSource::Displacement) + { + layerDepthValues = GetLayerDepthValues(uv, ddx_fine(uv), ddy_fine(uv)); + } + + return GetBlendWeights(uv, vertexBlendWeights, layerDepthValues); +} + +float BlendLayers(float layer1, float layer2, float layer3, float3 blendWeightValues) +{ + return dot(float3(layer1, layer2, layer3), blendWeightValues); +} +float2 BlendLayers(float2 layer1, float2 layer2, float2 layer3, float3 blendWeightValues) +{ + return layer1 * blendWeightValues.r + layer2 * blendWeightValues.g + layer3 * blendWeightValues.b; +} +float3 BlendLayers(float3 layer1, float3 layer2, float3 layer3, float3 blendWeightValues) +{ + return layer1 * blendWeightValues.r + layer2 * blendWeightValues.g + layer3 * blendWeightValues.b; +>>>>>>> Atom/santorac/MultilayerPbrImprovements +} + +// ------ Parallax Utilities ---------------------------------------- + +bool ShouldHandleParallax() +{ + // Parallax mapping's non uniform uv transformations break screen space subsurface scattering, disable it when subsurface scattering is enabled. + // Also, all the debug draw modes avoid parallax (they early-return before parallax code actually) so you can see exactly where the various maps appear on the surface UV space. + return !o_enableSubsurfaceScattering && o_parallax_feature_enabled && o_debugDrawMode == DebugDrawMode::None; +} + +bool ShouldHandleParallaxInDepthShaders() +{ + // The depth pass shaders need to calculate parallax when the result could affect the depth buffer (or when + // parallax could affect texel clipping but we don't have alpha/clipping support in multilayer PBR). + return ShouldHandleParallax() && o_parallax_enablePixelDepthOffset; +} + +<<<<<<< HEAD +// Callback function for ParallaxMapping.azsli +DepthResult GetDepth(float2 uv, float2 uv_ddx, float2 uv_ddy) +======= +// These static values are used to pass extra data to the GetDepth callback function during the parallax depth search. +static float3 s_blendWeightsFromVertexStream; + +//! Setup static variables that are needed by the GetDepth callback function +//! @param vertexBlendWeights - the blend weights from the vertex input stream. +void GetDepth_Setup(float3 vertexBlendWeights) +{ + s_blendWeightsFromVertexStream = vertexBlendWeights; +} + +//! Returns the depth values for each layer +float3 GetLayerDepthValues(float2 uv, float2 uv_ddx, float2 uv_ddy) +>>>>>>> Atom/santorac/MultilayerPbrImprovements +{ + float3 layerDepthValues = float3(0,0,0); + + if(o_layer1_o_useDepthMap) + { + float2 layerUv = uv; + if(MaterialSrg::m_parallaxUvIndex == 0) + { + layerUv = mul(MaterialSrg::m_layer1_m_uvMatrix, float3(uv, 1.0)).xy; + } + + layerDepthValues.r = SampleDepthOrHeightMap(MaterialSrg::m_layer1_m_depthInverted, MaterialSrg::m_layer1_m_depthMap, MaterialSrg::m_sampler, layerUv, uv_ddx, uv_ddy).m_depth; + layerDepthValues.r *= MaterialSrg::m_layer1_m_depthFactor; + layerDepthValues.r -= MaterialSrg::m_layer1_m_depthOffset; + } + + if(o_layer2_enabled && o_layer2_o_useDepthMap) + { + float2 layerUv = uv; + if(MaterialSrg::m_parallaxUvIndex == 0) + { + layerUv = mul(MaterialSrg::m_layer2_m_uvMatrix, float3(uv, 1.0)).xy; + } + + layerDepthValues.g = SampleDepthOrHeightMap(MaterialSrg::m_layer2_m_depthInverted, MaterialSrg::m_layer2_m_depthMap, MaterialSrg::m_sampler, layerUv, uv_ddx, uv_ddy).m_depth; + layerDepthValues.g *= MaterialSrg::m_layer2_m_depthFactor; + layerDepthValues.g -= MaterialSrg::m_layer2_m_depthOffset; + } + + if(o_layer3_enabled && o_layer3_o_useDepthMap) + { + float2 layerUv = uv; + if(MaterialSrg::m_parallaxUvIndex == 0) + { + layerUv = mul(MaterialSrg::m_layer3_m_uvMatrix, float3(uv, 1.0)).xy; + } + + layerDepthValues.b = SampleDepthOrHeightMap(MaterialSrg::m_layer3_m_depthInverted, MaterialSrg::m_layer3_m_depthMap, MaterialSrg::m_sampler, layerUv, uv_ddx, uv_ddy).m_depth; + layerDepthValues.b *= MaterialSrg::m_layer3_m_depthFactor; + layerDepthValues.b -= MaterialSrg::m_layer3_m_depthOffset; + } + + return layerDepthValues; +} + +//! Callback function for ParallaxMapping.azsli +DepthResult GetDepth(float2 uv, float2 uv_ddx, float2 uv_ddy) +{ + float3 layerDepthValues = GetLayerDepthValues(uv, uv_ddx, uv_ddy); + + // Note, when the blend source is LayerBlendSource::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. +<<<<<<< HEAD + float3 blendWeights = GetBlendWeights(uv); + + float depth = BlendLayers(layerDepthValues.r, layerDepthValues.g, layerDepthValues.b, blendWeights); +======= + float3 blendWeightValues = GetBlendWeights(uv, s_blendWeightsFromVertexStream, layerDepthValues); + + float depth = BlendLayers(layerDepthValues.r, layerDepthValues.g, layerDepthValues.b, blendWeightValues); +>>>>>>> Atom/santorac/MultilayerPbrImprovements + return DepthResultAbsolute(depth); +} diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_DepthPass_WithPS.azsl b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_DepthPass_WithPS.azsl index e274945e30..255ba60762 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_DepthPass_WithPS.azsl +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_DepthPass_WithPS.azsl @@ -53,7 +53,7 @@ struct VSDepthOutput float3 m_tangent : TANGENT; float3 m_bitangent : BITANGENT; float3 m_worldPosition : UV0; - float3 m_blendWeights : UV3; + float3 m_blendMask : UV3; }; VSDepthOutput MainVS(VSInput IN) @@ -80,11 +80,11 @@ VSDepthOutput MainVS(VSInput IN) if(o_blendMask_isBound) { - OUT.m_blendWeights = IN.m_optional_blendMask.rgb; + OUT.m_blendMask = IN.m_optional_blendMask.rgb; } else { - OUT.m_blendWeights = float3(1,1,1); + OUT.m_blendMask = float3(0,0,0); } return OUT; diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_DepthPass_WithPS.azsl.orig b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_DepthPass_WithPS.azsl.orig new file mode 100644 index 0000000000..489bd87037 --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_DepthPass_WithPS.azsl.orig @@ -0,0 +1,132 @@ +/* +* 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 +#include +#include +#include + +#include "MaterialInputs/ParallaxInput.azsli" + + +#include "MaterialInputs/ParallaxInput.azsli" +COMMON_OPTIONS_PARALLAX(o_layer1_) +COMMON_OPTIONS_PARALLAX(o_layer2_) +COMMON_OPTIONS_PARALLAX(o_layer3_) + +#include "./StandardMultilayerPBR_Common.azsli" + +struct VSInput +{ + float3 m_position : POSITION; + float2 m_uv0 : UV0; + float2 m_uv1 : UV1; + + // only used for parallax depth calculation + float3 m_normal : NORMAL; + float4 m_tangent : TANGENT; + float3 m_bitangent : BITANGENT; + + // This gets set automatically by the system at runtime only if it's available. + // There is a soft naming convention that associates this with o_blendMask_isBound, which will be set to true whenever m_optional_blendMask is available. + // (search "m_optional_" in ShaderVariantAssetBuilder for details on the naming convention). + // [GFX TODO][ATOM-14475]: Come up with a more elegant way to associate the isBound flag with the input stream. + float4 m_optional_blendMask : COLOR0; +}; + +struct VSDepthOutput +{ + float4 m_position : SV_Position; + float2 m_uv[UvSetCount] : UV1; + + // only used for parallax depth calculation + float3 m_normal : NORMAL; + float3 m_tangent : TANGENT; + float3 m_bitangent : BITANGENT; + float3 m_worldPosition : UV0; + float3 m_blendWeights : UV3; +}; + +VSDepthOutput MainVS(VSInput IN) +{ + VSDepthOutput OUT; + + float4x4 objectToWorld = ObjectSrg::GetWorldMatrix(); + float4 worldPosition = mul(objectToWorld, float4(IN.m_position, 1.0)); + + OUT.m_position = mul(ViewSrg::m_viewProjectionMatrix, worldPosition); + + // By design, only UV0 is allowed to apply transforms. + // Note there are additional UV transforms that happen for each layer, but we defer that step to the pixel shader to avoid bloating the vertex output buffer. + OUT.m_uv[0] = mul(MaterialSrg::m_uvMatrix, float3(IN.m_uv0, 1.0)).xy; + OUT.m_uv[1] = IN.m_uv1; + + if(ShouldHandleParallaxInDepthShaders()) + { + OUT.m_worldPosition = worldPosition.xyz; + + float3x3 objectToWorldIT = ObjectSrg::GetWorldMatrixInverseTranspose(); + ConstructTBN(IN.m_normal, IN.m_tangent, IN.m_bitangent, objectToWorld, objectToWorldIT, OUT.m_normal, OUT.m_tangent, OUT.m_bitangent); + } + + if(o_blendMask_isBound) + { + OUT.m_blendWeights = IN.m_optional_blendMask.rgb; + } + else + { + OUT.m_blendWeights = float3(1,1,1); + } + + return OUT; +} + +struct PSDepthOutput +{ + float m_depth : SV_Depth; +}; + +PSDepthOutput MainPS(VSDepthOutput IN, bool isFrontFace : SV_IsFrontFace) +{ + PSDepthOutput OUT; + + OUT.m_depth = IN.m_position.z; + + if(ShouldHandleParallaxInDepthShaders()) + { + // 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. + float3 tangents[UvSetCount] = { IN.m_tangent.xyz, float3(0, 0, 0) }; + 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); + +<<<<<<< HEAD + s_blendMaskFromVertexStream = IN.m_blendMask; +======= + GetDepth_Setup(IN.m_blendWeights); +>>>>>>> Atom/santorac/MultilayerPbrImprovements + + float depth; + + float3x3 uvMatrix = MaterialSrg::m_parallaxUvIndex == 0 ? MaterialSrg::m_uvMatrix : CreateIdentity3x3(); + float3x3 uvMatrixInverse = MaterialSrg::m_parallaxUvIndex == 0 ? MaterialSrg::m_uvMatrixInverse : CreateIdentity3x3(); + + float parallaxOverallOffset = MaterialSrg::m_displacementMax; + float parallaxOverallFactor = MaterialSrg::m_displacementMax - MaterialSrg::m_displacementMin; + GetParallaxInput(IN.m_normal, tangents[MaterialSrg::m_parallaxUvIndex], bitangents[MaterialSrg::m_parallaxUvIndex], parallaxOverallFactor, parallaxOverallOffset, + ObjectSrg::GetWorldMatrix(), uvMatrix, uvMatrixInverse, + IN.m_uv[MaterialSrg::m_parallaxUvIndex], IN.m_worldPosition, depth); + + OUT.m_depth = depth; + } + + return OUT; +} diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_ForwardPass.azsl b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_ForwardPass.azsl index b6d9e545d7..1fed3acbee 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_ForwardPass.azsl +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_ForwardPass.azsl @@ -94,7 +94,7 @@ struct VSOutput // Extended fields (only referenced in this azsl file)... float2 m_uv[UvSetCount] : UV1; - float3 m_blendWeights : UV7; + float3 m_blendMask : UV7; }; #include @@ -112,11 +112,11 @@ VSOutput ForwardPassVS(VSInput IN) if(o_blendMask_isBound) { - OUT.m_blendWeights = IN.m_optional_blendMask.rgb; + OUT.m_blendMask = IN.m_optional_blendMask.rgb; } else { - OUT.m_blendWeights = float3(1,1,1); + OUT.m_blendMask = float3(0,0,0); } // Shadow coords will be calculated in the pixel shader in this case @@ -310,6 +310,8 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float s_blendMaskFromVertexStream = IN.m_blendMask; + LayerBlendSource blendSource = GetFinalLayerBlendSource(); + // ------- 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. @@ -332,17 +334,23 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float // ------- Debug Modes ------- - if(o_debugDrawMode == DebugDrawMode::BlendMaskValues) + if(o_debugDrawMode == DebugDrawMode::BlendMask) { - float3 blendMaskValues = GetBlendMaskValues(IN.m_uv[MaterialSrg::m_blendMaskUvIndex]); + float3 blendMaskValues = GetApplicableBlendMaskValues(blendSource, IN.m_uv[MaterialSrg::m_blendMaskUvIndex], IN.m_blendMask); return DebugOutput(blendMaskValues); } - if(o_debugDrawMode == DebugDrawMode::DisplacementMaps) + if(o_debugDrawMode == DebugDrawMode::Displacement) { 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)); } + + if(o_debugDrawMode == DebugDrawMode::FinalBlendWeights) + { + float3 blendWeights = GetBlendWeights(blendSource, IN.m_uv[MaterialSrg::m_blendMaskUvIndex], IN.m_blendMask); + return DebugOutput(blendWeights); + } // ------- Parallax ------- @@ -373,7 +381,7 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float // ------- 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 blendWeights = GetBlendWeights(IN.m_uv[MaterialSrg::m_blendMaskUvIndex]); + float3 blendWeights = GetBlendWeights(blendSource, IN.m_uv[MaterialSrg::m_blendMaskUvIndex], IN.m_blendMask); // ------- Layer 1 (base layer) ----------- @@ -434,7 +442,7 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float // ------- Combine Albedo, roughness, specular, roughness --------- - 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); diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_ForwardPass.azsl.orig b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_ForwardPass.azsl.orig new file mode 100644 index 0000000000..4ddea9b0cf --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_ForwardPass.azsl.orig @@ -0,0 +1,710 @@ +/* +* 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. +* +*/ + +// SRGs +#include +#include +#include + +// Pass Output +#include + +// Utility +#include +#include + +// Custom Surface & Lighting +#include + +// Decals +#include + +// ---------- Material Parameters ---------- + +#include "MaterialInputs/BaseColorInput.azsli" +#include "MaterialInputs/RoughnessInput.azsli" +#include "MaterialInputs/MetallicInput.azsli" +#include "MaterialInputs/SpecularInput.azsli" +#include "MaterialInputs/NormalInput.azsli" +#include "MaterialInputs/ClearCoatInput.azsli" +#include "MaterialInputs/OcclusionInput.azsli" +#include "MaterialInputs/EmissiveInput.azsli" +#include "MaterialInputs/ParallaxInput.azsli" + +#define DEFINE_LAYER_OPTIONS(prefix) \ +COMMON_OPTIONS_BASE_COLOR(prefix) \ +COMMON_OPTIONS_ROUGHNESS(prefix) \ +COMMON_OPTIONS_METALLIC(prefix) \ +COMMON_OPTIONS_SPECULAR_F0(prefix) \ +COMMON_OPTIONS_NORMAL(prefix) \ +COMMON_OPTIONS_CLEAR_COAT(prefix) \ +COMMON_OPTIONS_OCCLUSION(prefix) \ +COMMON_OPTIONS_EMISSIVE(prefix) \ +COMMON_OPTIONS_PARALLAX(prefix) + +DEFINE_LAYER_OPTIONS(o_layer1_) +DEFINE_LAYER_OPTIONS(o_layer2_) +DEFINE_LAYER_OPTIONS(o_layer3_) + +#include "MaterialInputs/TransmissionInput.azsli" +#include "StandardMultilayerPBR_Common.azsli" + + +// ---------- Vertex Shader ---------- + +struct VSInput +{ + // Base fields (required by the template azsli file)... + float3 m_position : POSITION; + float3 m_normal : NORMAL; + float4 m_tangent : TANGENT; + float3 m_bitangent : BITANGENT; + + // Extended fields (only referenced in this azsl file)... + float2 m_uv0 : UV0; + float2 m_uv1 : UV1; + + // This gets set automatically by the system at runtime only if it's available. + // There is a soft naming convention that associates this with o_blendMask_isBound, which will be set to true whenever m_optional_blendMask is available. + // (search "m_optional_" in ShaderVariantAssetBuilder for details on the naming convention). + // [GFX TODO][ATOM-14475]: Come up with a more elegant way to associate the isBound flag with the input stream. + float4 m_optional_blendMask : COLOR0; +}; + + +struct VSOutput +{ + // Base fields (required by the template azsli file)... + float4 m_position : SV_Position; + float3 m_normal: NORMAL; + float3 m_tangent : TANGENT; + float3 m_bitangent : BITANGENT; + float3 m_worldPosition : UV0; + float3 m_shadowCoords[ViewSrg::MaxCascadeCount] : UV3; + + // Extended fields (only referenced in this azsl file)... + float2 m_uv[UvSetCount] : UV1; + + float3 m_blendWeights : UV7; +}; + +#include + +VSOutput ForwardPassVS(VSInput IN) +{ + VSOutput OUT; + + float3 worldPosition = mul(ObjectSrg::GetWorldMatrix(), float4(IN.m_position, 1.0)).xyz; + + // By design, only UV0 is allowed to apply transforms. + // Note there are additional UV transforms that happen for each layer, but we defer that step to the pixel shader to avoid bloating the vertex output buffer. + OUT.m_uv[0] = mul(MaterialSrg::m_uvMatrix, float3(IN.m_uv0, 1.0)).xy; + OUT.m_uv[1] = IN.m_uv1; + + if(o_blendMask_isBound) + { + OUT.m_blendWeights = IN.m_optional_blendMask.rgb; + } + else + { + OUT.m_blendWeights = float3(1,1,1); + } + + // Shadow coords will be calculated in the pixel shader in this case + bool skipShadowCoords = ShouldHandleParallax() && o_parallax_enablePixelDepthOffset; + VertexHelper(IN, OUT, worldPosition, skipShadowCoords); + + 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 ---------- + +PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float depthNDC) +{ + 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. + float3 tangents[UvSetCount] = { IN.m_tangent.xyz, float3(0, 0, 0) }; + float3 bitangents[UvSetCount] = { IN.m_bitangent.xyz, float3(0, 0, 0) }; + + if ((o_parallax_feature_enabled && !o_enableSubsurfaceScattering && MaterialSrg::m_parallaxUvIndex != 0) + || (o_layer1_o_normal_useTexture && MaterialSrg::m_layer1_m_normalMapUvIndex != 0) + || (o_layer2_o_normal_useTexture && MaterialSrg::m_layer2_m_normalMapUvIndex != 0) + || (o_layer3_o_normal_useTexture && MaterialSrg::m_layer3_m_normalMapUvIndex != 0) + || (o_layer1_o_clearCoat_normal_useTexture && MaterialSrg::m_layer1_m_clearCoatNormalMapUvIndex != 0) + || (o_layer2_o_clearCoat_normal_useTexture && MaterialSrg::m_layer2_m_clearCoatNormalMapUvIndex != 0) + || (o_layer3_o_clearCoat_normal_useTexture && MaterialSrg::m_layer3_m_clearCoatNormalMapUvIndex != 0) + ) + { + // Generate the tangent/bitangent for UV[1+] + const int startIndex = 1; + PrepareGeneratedTangent(IN.m_normal, IN.m_worldPosition, isFrontFace, IN.m_uv, UvSetCount, tangents, bitangents, startIndex); + } + + // ------- Debug Modes ------- + +<<<<<<< HEAD + if(o_debugDrawMode == DebugDrawMode::BlendSource) + { + float3 blendSource = GetBlendSourceValues(IN.m_uv[MaterialSrg::m_blendMaskUvIndex]); + return DebugOutput(blendSource); +======= + if(o_debugDrawMode == DebugDrawMode::BlendWeights) + { + float3 blendWeights = GetBlendWeights(IN.m_uv[MaterialSrg::m_blendMaskUvIndex], IN.m_blendWeights); + return DebugOutput(blendWeights); +>>>>>>> Atom/santorac/MultilayerPbrImprovements + } + + if(o_debugDrawMode == DebugDrawMode::DisplacementMaps) + { +<<<<<<< HEAD +======= + GetDepth_Setup(IN.m_blendWeights); +>>>>>>> Atom/santorac/MultilayerPbrImprovements + 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)); + } + + // ------- Parallax ------- + + bool displacementIsClipped = false; + + if(ShouldHandleParallax()) + { +<<<<<<< HEAD +======= + GetDepth_Setup(IN.m_blendWeights); + +>>>>>>> Atom/santorac/MultilayerPbrImprovements + float3x3 uvMatrix = MaterialSrg::m_parallaxUvIndex == 0 ? MaterialSrg::m_uvMatrix : CreateIdentity3x3(); + float3x3 uvMatrixInverse = MaterialSrg::m_parallaxUvIndex == 0 ? MaterialSrg::m_uvMatrixInverse : CreateIdentity3x3(); + + float parallaxOverallOffset = MaterialSrg::m_displacementMax; + float parallaxOverallFactor = MaterialSrg::m_displacementMax - MaterialSrg::m_displacementMin; + GetParallaxInput(IN.m_normal, tangents[MaterialSrg::m_parallaxUvIndex], bitangents[MaterialSrg::m_parallaxUvIndex], parallaxOverallFactor, parallaxOverallOffset, + ObjectSrg::GetWorldMatrix(), uvMatrix, uvMatrixInverse, + IN.m_uv[MaterialSrg::m_parallaxUvIndex], IN.m_worldPosition, depthNDC, IN.m_position.w, displacementIsClipped); + + // Adjust directional light shadow coorinates for parallax correction + if(o_parallax_enablePixelDepthOffset) + { + const uint shadowIndex = ViewSrg::m_shadowIndexDirectionalLight; + if (o_enableShadows && shadowIndex < SceneSrg::m_directionalLightCount) + { + DirectionalLightShadow::GetShadowCoords(shadowIndex, IN.m_worldPosition, IN.m_shadowCoords); + } + } + } + + // ------- 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. +<<<<<<< HEAD + float3 blendWeights = GetBlendWeights(IN.m_uv[MaterialSrg::m_blendMaskUvIndex]); + + // ------- Layer 1 (base layer) ----------- + + ProcessedMaterialInputs lightingInputLayer1; +======= + float3 blendWeights = GetBlendWeights(IN.m_uv[MaterialSrg::m_blendMaskUvIndex], IN.m_blendWeights); + + // ------- Normal ------- + + float3 layer1_normalFactor = MaterialSrg::m_layer1_m_normalFactor * blendWeights.r; + float3 layer2_normalFactor = MaterialSrg::m_layer2_m_normalFactor * blendWeights.g; + float3 layer3_normalFactor = MaterialSrg::m_layer3_m_normalFactor * blendWeights.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); + + float3 normalTS = ReorientTangentSpaceNormal(layer1_normalTS, layer2_normalTS); + normalTS = ReorientTangentSpaceNormal(normalTS, layer3_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]; + + 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, blendWeights); + + if(o_parallax_highlightClipping && displacementIsClipped) +>>>>>>> Atom/santorac/MultilayerPbrImprovements + { + StandardMaterialInputs inputs; + FILL_STANDARD_MATERIAL_INPUTS(inputs, MaterialSrg::m_layer1_, o_layer1_, blendWeights.r) + lightingInputLayer1 = ProcessStandardMaterialInputs(inputs); + } + + // ----------- Layer 2 ----------- + + ProcessedMaterialInputs lightingInputLayer2; + if(o_layer2_enabled) + { +<<<<<<< HEAD + StandardMaterialInputs inputs; + FILL_STANDARD_MATERIAL_INPUTS(inputs, MaterialSrg::m_layer2_, o_layer2_, blendWeights.g) + lightingInputLayer2 = ProcessStandardMaterialInputs(inputs); + } + else + { + lightingInputLayer2.InitializeToZero(); + } + + // ----------- Layer 3 ----------- +======= + 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, blendWeights); + } + + // ------- 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, blendWeights); + + surface.SetAlbedoAndSpecularF0(baseColor, specularF0Factor, metallic); +>>>>>>> Atom/santorac/MultilayerPbrImprovements + + 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(); + } + +<<<<<<< HEAD + // ------- Combine all layers --------- + + Surface surface; + surface.position = IN.m_worldPosition; + surface.transmission.InitializeToZero(); +======= + 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, blendWeights); +>>>>>>> Atom/santorac/MultilayerPbrImprovements + + // ------- 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])); + + // ------- Combine Albedo, roughness, specular, roughness --------- + + 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); + } + + surface.SetAlbedoAndSpecularF0(baseColor, specularF0Factor, metallic); + + surface.roughnessLinear = BlendLayers(lightingInputLayer1.m_roughness, lightingInputLayer2.m_roughness, lightingInputLayer3.m_roughness, blendWeights); + surface.CalculateRoughnessA(); + + // ------- Init and Combine Lighting Data ------- + + LightingData lightingData; + + // Light iterator + lightingData.tileIterator.Init(IN.m_position, PassSrg::m_lightListRemapped, PassSrg::m_tileLightData); + lightingData.Init(surface.position, surface.normal, surface.roughnessLinear); + + // Directional light shadow coordinates + lightingData.shadowCoords = IN.m_shadowCoords; + +<<<<<<< HEAD + 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); + + lightingData.CalculateMultiscatterCompensation(surface.specularF0, o_specularF0_enableMultiScatterCompensation); +======= + 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, 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, blendWeights); + + 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, blendWeights); +>>>>>>> Atom/santorac/MultilayerPbrImprovements + + // ------- Combine Clearcoat ------- + + if(o_clearCoat_feature_enabled) + { +<<<<<<< HEAD + 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(lightingInputLayer1.m_clearCoat.normal, lightingInputLayer2.m_clearCoat.normal, lightingInputLayer3.m_clearCoat.normal, blendWeights); +======= + // --- 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, blendWeights); + surface.clearCoat.roughness = BlendLayers(layer1_clearCoatRoughness, layer2_clearCoatRoughness, layer3_clearCoatRoughness, 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, blendWeights); +>>>>>>> Atom/santorac/MultilayerPbrImprovements + surface.clearCoat.normal = normalize(surface.clearCoat.normal); + + // manipulate base layer f0 if clear coat is enabled + // modify base layer's normal incidence reflectance + // for the derivation of the following equation please refer to: + // https://google.github.io/filament/Filament.md.html#materialsystem/clearcoatmodel/baselayermodification + float3 f0 = (1.0 - 5.0 * sqrt(surface.specularF0)) / (5.0 - sqrt(surface.specularF0)); + surface.specularF0 = lerp(surface.specularF0, f0 * f0, surface.clearCoat.factor); + } + + // Diffuse and Specular response (used in IBL calculations) + lightingData.specularResponse = FresnelSchlickWithRoughness(lightingData.NdotV, surface.specularF0, surface.roughnessLinear); + lightingData.diffuseResponse = 1.0 - lightingData.specularResponse; + + if(o_clearCoat_feature_enabled) + { + // 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); + } + + // ------- Lighting Calculation ------- + + // Apply Decals + ApplyDecals(lightingData.tileIterator, surface); + + // Apply Direct Lighting + ApplyDirectLighting(surface, lightingData); + + // Apply Image Based Lighting (IBL) + ApplyIBL(surface, lightingData); + + // Finalize Lighting + lightingData.FinalizeLighting(0); + + + const float alpha = 1.0; + + PbrLightingOutput lightingOutput = GetPbrLightingOutput(surface, lightingData, alpha); + + lightingOutput.m_diffuseColor.w = -1; // Disable subsurface scattering + + return lightingOutput; +} + +ForwardPassOutputWithDepth ForwardPassPS(VSOutput IN, bool isFrontFace : SV_IsFrontFace) +{ + ForwardPassOutputWithDepth OUT; + float depth; + + PbrLightingOutput lightingOutput = ForwardPassPS_Common(IN, isFrontFace, depth); + + OUT.m_diffuseColor = lightingOutput.m_diffuseColor; + OUT.m_specularColor = lightingOutput.m_specularColor; + OUT.m_specularF0 = lightingOutput.m_specularF0; + OUT.m_albedo = lightingOutput.m_albedo; + OUT.m_normal = lightingOutput.m_normal; + OUT.m_depth = depth; + return OUT; +} + +[earlydepthstencil] +ForwardPassOutput ForwardPassPS_EDS(VSOutput IN, bool isFrontFace : SV_IsFrontFace) +{ + ForwardPassOutput OUT; + float depth; + + PbrLightingOutput lightingOutput = ForwardPassPS_Common(IN, isFrontFace, depth); + + OUT.m_diffuseColor = lightingOutput.m_diffuseColor; + OUT.m_specularColor = lightingOutput.m_specularColor; + OUT.m_specularF0 = lightingOutput.m_specularF0; + OUT.m_albedo = lightingOutput.m_albedo; + OUT.m_normal = lightingOutput.m_normal; + + return OUT; +} + diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_Shadowmap_WithPS.azsl b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_Shadowmap_WithPS.azsl index a4e8bb3c0a..e06fc67be7 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_Shadowmap_WithPS.azsl +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_Shadowmap_WithPS.azsl @@ -53,7 +53,7 @@ struct VertexOutput float3 m_tangent : TANGENT; float3 m_bitangent : BITANGENT; float3 m_worldPosition : UV0; - float3 m_blendWeights : UV3; + float3 m_blendMask : UV3; }; VertexOutput MainVS(VertexInput IN) @@ -79,11 +79,11 @@ VertexOutput MainVS(VertexInput IN) if(o_blendMask_isBound) { - OUT.m_blendWeights = IN.m_optional_blendMask.rgb; + OUT.m_blendMask = IN.m_optional_blendMask.rgb; } else { - OUT.m_blendWeights = float3(1,1,1); + OUT.m_blendMask = float3(0,0,0); } return OUT; diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_Shadowmap_WithPS.azsl.orig b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_Shadowmap_WithPS.azsl.orig new file mode 100644 index 0000000000..a9be92b7a5 --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_Shadowmap_WithPS.azsl.orig @@ -0,0 +1,131 @@ +/* +* 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 +#include +#include +#include +#include + +#include "MaterialInputs/ParallaxInput.azsli" + +#include "MaterialInputs/ParallaxInput.azsli" +COMMON_OPTIONS_PARALLAX(o_layer1_) +COMMON_OPTIONS_PARALLAX(o_layer2_) +COMMON_OPTIONS_PARALLAX(o_layer3_) + +#include "StandardMultilayerPBR_Common.azsli" + +struct VertexInput +{ + float3 m_position : POSITION; + float2 m_uv0 : UV0; + float2 m_uv1 : UV1; + + // only used for parallax depth calculation + float3 m_normal : NORMAL; + float4 m_tangent : TANGENT; + float3 m_bitangent : BITANGENT; + + // This gets set automatically by the system at runtime only if it's available. + // There is a soft naming convention that associates this with o_blendMask_isBound, which will be set to true whenever m_optional_blendMask is available. + // (search "m_optional_" in ShaderVariantAssetBuilder for details on the naming convention). + // [GFX TODO][ATOM-14475]: Come up with a more elegant way to associate the isBound flag with the input stream. + float4 m_optional_blendMask : COLOR0; +}; + +struct VertexOutput +{ + float4 m_position : SV_Position; + float2 m_uv[UvSetCount] : UV1; + + // only used for parallax depth calculation + float3 m_normal : NORMAL; + float3 m_tangent : TANGENT; + float3 m_bitangent : BITANGENT; + float3 m_worldPosition : UV0; + float3 m_blendWeights : UV3; +}; + +VertexOutput MainVS(VertexInput IN) +{ + const float4x4 objectToWorld = ObjectSrg::GetWorldMatrix(); + VertexOutput OUT; + + const float3 worldPosition = mul(objectToWorld, float4(IN.m_position, 1.0)).xyz; + OUT.m_position = mul(ViewSrg::m_viewProjectionMatrix, float4(worldPosition, 1.0)); + + // By design, only UV0 is allowed to apply transforms. + // Note there are additional UV transforms that happen for each layer, but we defer that step to the pixel shader to avoid bloating the vertex output buffer. + OUT.m_uv[0] = mul(MaterialSrg::m_uvMatrix, float3(IN.m_uv0, 1.0)).xy; + OUT.m_uv[1] = IN.m_uv1; + + if(ShouldHandleParallaxInDepthShaders()) + { + OUT.m_worldPosition = worldPosition.xyz; + + float3x3 objectToWorldIT = ObjectSrg::GetWorldMatrixInverseTranspose(); + ConstructTBN(IN.m_normal, IN.m_tangent, IN.m_bitangent, objectToWorld, objectToWorldIT, OUT.m_normal, OUT.m_tangent, OUT.m_bitangent); + } + + if(o_blendMask_isBound) + { + OUT.m_blendWeights = IN.m_optional_blendMask.rgb; + } + else + { + OUT.m_blendWeights = float3(1,1,1); + } + + return OUT; +} + +struct PSDepthOutput +{ + float m_depth : SV_Depth; +}; + +PSDepthOutput MainPS(VertexOutput IN, bool isFrontFace : SV_IsFrontFace) +{ + PSDepthOutput OUT; + + OUT.m_depth = IN.m_position.z; + + if(ShouldHandleParallaxInDepthShaders()) + { + // 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. + float3 tangents[UvSetCount] = { IN.m_tangent.xyz, float3(0, 0, 0) }; + 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); + +<<<<<<< HEAD + s_blendMaskFromVertexStream = IN.m_blendMask; +======= + GetDepth_Setup(IN.m_blendWeights); +>>>>>>> Atom/santorac/MultilayerPbrImprovements + + float depthNDC; + + float3x3 uvMatrix = MaterialSrg::m_parallaxUvIndex == 0 ? MaterialSrg::m_uvMatrix : CreateIdentity3x3(); + float3x3 uvMatrixInverse = MaterialSrg::m_parallaxUvIndex == 0 ? MaterialSrg::m_uvMatrixInverse : CreateIdentity3x3(); + + float parallaxOverallOffset = MaterialSrg::m_displacementMax; + float parallaxOverallFactor = MaterialSrg::m_displacementMax - MaterialSrg::m_displacementMin; + GetParallaxInput(IN.m_normal, tangents[MaterialSrg::m_parallaxUvIndex], bitangents[MaterialSrg::m_parallaxUvIndex], parallaxOverallFactor, parallaxOverallOffset, + ObjectSrg::GetWorldMatrix(), uvMatrix, uvMatrixInverse, + IN.m_uv[MaterialSrg::m_parallaxUvIndex], IN.m_worldPosition, depthNDC); + + OUT.m_depth = depthNDC; + } + + return OUT; +} diff --git a/Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/003_Debug_BlendSource.material b/Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/003_Debug_BlendMask.material similarity index 86% rename from Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/003_Debug_BlendSource.material rename to Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/003_Debug_BlendMask.material index 94a1ec6a30..df81b9b25a 100644 --- a/Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/003_Debug_BlendSource.material +++ b/Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/003_Debug_BlendMask.material @@ -5,7 +5,7 @@ "propertyLayoutVersion": 3, "properties": { "general": { - "debugDrawMode": "BlendMaskValues" + "debugDrawMode": "BlendMask" } } } diff --git a/Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/003_Debug_BlendWeights.material b/Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/003_Debug_BlendWeights.material new file mode 100644 index 0000000000..4cd6546028 --- /dev/null +++ b/Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/003_Debug_BlendWeights.material @@ -0,0 +1,11 @@ +{ + "description": "", + "materialType": "Materials/Types/StandardMultilayerPBR.materialtype", + "parentMaterial": "TestData/Materials/StandardMultilayerPbrTestCases/002_ParallaxPdo.material", + "propertyLayoutVersion": 3, + "properties": { + "general": { + "debugDrawMode": "FinalBlendWeights" + } + } +} diff --git a/Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/003_Debug_DisplacementMaps.material b/Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/003_Debug_Displacement.material similarity index 85% rename from Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/003_Debug_DisplacementMaps.material rename to Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/003_Debug_Displacement.material index eb2d01cef2..fb4db87c2c 100644 --- a/Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/003_Debug_DisplacementMaps.material +++ b/Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/003_Debug_Displacement.material @@ -5,7 +5,7 @@ "propertyLayoutVersion": 3, "properties": { "general": { - "debugDrawMode": "DisplacementMaps" + "debugDrawMode": "Displacement" } } } diff --git a/Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/005_UseDisplacement.material b/Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/005_UseDisplacement.material index c29dddc623..477d62737c 100644 --- a/Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/005_UseDisplacement.material +++ b/Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/005_UseDisplacement.material @@ -5,7 +5,9 @@ "propertyLayoutVersion": 3, "properties": { "blend": { - "blendSource": "Displacement" + "blendSource": "Displacement", + "enableLayer2": true, + "enableLayer3": true }, "layer1_baseColor": { "textureMap": "TestData/Textures/cc0/Rock030_2K_Color.jpg"