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"