From ac13551dc032a57e726b19cfd28de19f8a4dfea4 Mon Sep 17 00:00:00 2001 From: Ken Pruiksma Date: Thu, 24 Jun 2021 20:14:28 -0500 Subject: [PATCH] Cherry picking a034500a10a1e0704efe6cb831d02a028cfc28d1 [a034500] (#1580) Adding a factor for alpha affecting specular in the standard and enhanced pbr materials (#1474) * Adding a factor for how much alpha should affect specular to standard and enhanced pbr. Currently blended and tinted transparency always assume that the geometry represents the surface, and the surface may just be transparent like glass. In this model, specular is unnaffected by alpha - perfectly clear glass still reflects light and obeys the Fresnel factor. However alpha may also represent the absence of a surface entirely for mateirals where cut-out alpha is a bad fit because of subpixel detail, like hair or cob webs. This change addresses that by allowing the alpha to also affect specular reflection if desired. * Adding material for ASV test. --- .../Materials/Types/EnhancedPBR.materialtype | 13 ++++++++++ .../Materials/Types/EnhancedPBR_Common.azsli | 1 + .../Types/EnhancedPBR_ForwardPass.azsl | 18 ++++++++++---- .../Materials/Types/StandardPBR.materialtype | 13 ++++++++++ .../Materials/Types/StandardPBR_Common.azsli | 1 + .../Types/StandardPBR_ForwardPass.azsl | 17 ++++++++++--- ...ty_Blended_Alpha_Affects_Specular.material | 24 +++++++++++++++++++ 7 files changed, 80 insertions(+), 7 deletions(-) create mode 100644 Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/009_Opacity_Blended_Alpha_Affects_Specular.material diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR.materialtype b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR.materialtype index a71fc65e2a..9b2c465352 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR.materialtype +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR.materialtype @@ -714,6 +714,19 @@ "displayName": "Double-sided", "description": "Whether to render back-faces or just front-faces.", "type": "Bool" + }, + { + "id": "alphaAffectsSpecular", + "displayName": "Alpha affects specular", + "description": "How much the alpha value should also affect specular reflection. This should be 0.0 for materials where light can transmit through their physical surface (like glass), but 1.0 when alpha determines the very presence of a surface (like hair or grass)", + "type": "float", + "min": 0.0, + "max": 1.0, + "defaultValue": 0.0, + "connection": { + "type": "ShaderInput", + "id": "m_opacityAffectsSpecularFactor" + } } ], "uv": [ diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_Common.azsli b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_Common.azsli index dbd36735b8..cf699228c2 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_Common.azsli +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_Common.azsli @@ -50,6 +50,7 @@ ShaderResourceGroup MaterialSrg : SRG_PerMaterial float m_anisotropicFactor; // Base layer anisotropic strength of deviation: negative = Bi-Normal direction, positive = Tangent direction float m_opacityFactor; + float m_opacityAffectsSpecularFactor; Texture2D m_opacityMap; uint m_opacityMapUvIndex; diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_ForwardPass.azsl b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_ForwardPass.azsl index f4269d9320..8e9b75e2ad 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_ForwardPass.azsl +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_ForwardPass.azsl @@ -326,7 +326,8 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float if (o_opacity_mode == OpacityMode::Blended || o_opacity_mode == OpacityMode::TintedTransparent) { - alpha = FresnelSchlickWithRoughness(lightingData.NdotV, alpha, surface.roughnessLinear).x; // Increase opacity at grazing angles. + float fresnelAlpha = FresnelSchlickWithRoughness(lightingData.NdotV, alpha, surface.roughnessLinear).x; // Increase opacity at grazing angles. + alpha = lerp(fresnelAlpha, alpha, MaterialSrg::m_opacityAffectsSpecularFactor); } PbrLightingOutput lightingOutput = GetPbrLightingOutput(surface, lightingData, alpha); @@ -344,8 +345,13 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float // For blended mode, we do (dest * alpha) + (source * 1.0). This allows the specular // to be added on top of the diffuse, but then the diffuse must be pre-multiplied. // It's done this way because surface transparency doesn't really change specular response (eg, glass). + lightingOutput.m_diffuseColor.rgb *= lightingOutput.m_diffuseColor.w; // pre-multiply diffuse - lightingOutput.m_diffuseColor.rgb += lightingOutput.m_specularColor.rgb; // add specular + + // Add specular. m_opacityAffectsSpecularFactor controls how much the alpha masks out specular contribution. + float3 specular = lightingOutput.m_specularColor.rgb; + specular = lerp(specular, specular * lightingOutput.m_diffuseColor.w, MaterialSrg::m_opacityAffectsSpecularFactor); + lightingOutput.m_diffuseColor.rgb += specular; } else if (o_opacity_mode == OpacityMode::TintedTransparent) { @@ -362,7 +368,12 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float // m_diffuseColor.rgb (source) is added to that, and the final result is stored in render target 0. lightingOutput.m_diffuseColor.rgb *= lightingOutput.m_diffuseColor.w; // pre-multiply diffuse - lightingOutput.m_diffuseColor.rgb += lightingOutput.m_specularColor.rgb; // add specular + + // Add specular. m_opacityAffectsSpecularFactor controls how much the alpha masks out specular contribution. + float3 specular = lightingOutput.m_specularColor.rgb; + specular = lerp(specular, specular * lightingOutput.m_diffuseColor.w, MaterialSrg::m_opacityAffectsSpecularFactor); + lightingOutput.m_diffuseColor.rgb += specular; + lightingOutput.m_specularColor.rgb = baseColor * (1.0 - lightingOutput.m_diffuseColor.w); } else @@ -410,4 +421,3 @@ ForwardPassOutput EnhancedPbr_ForwardPassPS_EDS(VSOutput IN, bool isFrontFace : return OUT; } - diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR.materialtype b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR.materialtype index 93220973df..8b7e4b1c7e 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR.materialtype +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR.materialtype @@ -655,6 +655,19 @@ "displayName": "Double-sided", "description": "Whether to render back-faces or just front-faces.", "type": "Bool" + }, + { + "id": "alphaAffectsSpecular", + "displayName": "Alpha affects specular", + "description": "How much the alpha value should also affect specular reflection. This should be 0.0 for materials where light can transmit through their physical surface (like glass), but 1.0 when alpha determines the very presence of a surface (like hair or grass)", + "type": "float", + "min": 0.0, + "max": 1.0, + "defaultValue": 0.0, + "connection": { + "type": "ShaderInput", + "id": "m_opacityAffectsSpecularFactor" + } } ], "uv": [ diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_Common.azsli b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_Common.azsli index d4f4e905b1..f0637c6675 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_Common.azsli +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_Common.azsli @@ -45,6 +45,7 @@ ShaderResourceGroup MaterialSrg : SRG_PerMaterial float4 m_pad2; // [GFX TODO][ATOM-14595] This is a workaround for a data stomping bug. Remove once it's fixed. float m_opacityFactor; + float m_opacityAffectsSpecularFactor; Texture2D m_opacityMap; uint m_opacityMapUvIndex; diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ForwardPass.azsl b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ForwardPass.azsl index b2262a65de..2dfdd3681f 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ForwardPass.azsl +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ForwardPass.azsl @@ -254,7 +254,8 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float if (o_opacity_mode == OpacityMode::Blended || o_opacity_mode == OpacityMode::TintedTransparent) { - alpha = FresnelSchlickWithRoughness(lightingData.NdotV, alpha, surface.roughnessLinear).x; // Increase opacity at grazing angles. + float fresnelAlpha = FresnelSchlickWithRoughness(lightingData.NdotV, alpha, surface.roughnessLinear).x; // Increase opacity at grazing angles. + alpha = lerp(fresnelAlpha, alpha, MaterialSrg::m_opacityAffectsSpecularFactor); } PbrLightingOutput lightingOutput = GetPbrLightingOutput(surface, lightingData, alpha); @@ -269,8 +270,13 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float // For blended mode, we do (dest * alpha) + (source * 1.0). This allows the specular // to be added on top of the diffuse, but then the diffuse must be pre-multiplied. // It's done this way because surface transparency doesn't really change specular response (eg, glass). + lightingOutput.m_diffuseColor.rgb *= lightingOutput.m_diffuseColor.w; // pre-multiply diffuse - lightingOutput.m_diffuseColor.rgb += lightingOutput.m_specularColor.rgb; // add specular + + // Add specular. m_opacityAffectsSpecularFactor controls how much the alpha masks out specular contribution. + float3 specular = lightingOutput.m_specularColor.rgb; + specular = lerp(specular, specular * lightingOutput.m_diffuseColor.w, MaterialSrg::m_opacityAffectsSpecularFactor); + lightingOutput.m_diffuseColor.rgb += specular; } else if (o_opacity_mode == OpacityMode::TintedTransparent) { @@ -287,7 +293,12 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float // m_diffuseColor.rgb (source) is added to that, and the final result is stored in render target 0. lightingOutput.m_diffuseColor.rgb *= lightingOutput.m_diffuseColor.w; // pre-multiply diffuse - lightingOutput.m_diffuseColor.rgb += lightingOutput.m_specularColor.rgb; // add specular + + // Add specular. m_opacityAffectsSpecularFactor controls how much the alpha masks out specular contribution. + float3 specular = lightingOutput.m_specularColor.rgb; + specular = lerp(specular, specular * lightingOutput.m_diffuseColor.w, MaterialSrg::m_opacityAffectsSpecularFactor); + lightingOutput.m_diffuseColor.rgb += specular; + lightingOutput.m_specularColor.rgb = baseColor * (1.0 - lightingOutput.m_diffuseColor.w); } else diff --git a/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/009_Opacity_Blended_Alpha_Affects_Specular.material b/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/009_Opacity_Blended_Alpha_Affects_Specular.material new file mode 100644 index 0000000000..dbaec36136 --- /dev/null +++ b/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/009_Opacity_Blended_Alpha_Affects_Specular.material @@ -0,0 +1,24 @@ +{ + "description": "", + "materialType": "Materials/Types/StandardPBR.materialtype", + "parentMaterial": "", + "propertyLayoutVersion": 3, + "properties": { + "baseColor": { + "color": [ + 0.5906767249107361, + 1.0, + 0.11703670024871826, + 1.0 + ], + "textureMap": "Textures/Default/default_basecolor.tif" + }, + "opacity": { + "alphaSource": "Split", + "factor": 0.75, + "mode": "Blended", + "textureMap": "TestData/Textures/checker8x8_gray_512.png", + "alphaAffectsSpecular": 1.0 + } + } +}