diff --git a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/OSXEditor/Metal/None/1302_StackLitSG_PixarLM.png b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/OSXEditor/Metal/None/1302_StackLitSG_PixarLM.png index a0fe7329cdc..7c52eee5b9e 100644 --- a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/OSXEditor/Metal/None/1302_StackLitSG_PixarLM.png +++ b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/OSXEditor/Metal/None/1302_StackLitSG_PixarLM.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d9ac0db404cae70b6a83ccdd54f5744a50bbb17294538a44ed1467f6368c69a8 -size 212028 +oid sha256:1aa3a521dae784030a87e20cf347958162e24393d3fd2c85aab197f154e6fe7b +size 212504 diff --git a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/OSXEditor/Metal/None/2551_SSR.png b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/OSXEditor/Metal/None/2551_SSR.png index 6a5146f3c7e..772302cc72d 100644 --- a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/OSXEditor/Metal/None/2551_SSR.png +++ b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/OSXEditor/Metal/None/2551_SSR.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6e9ffbdaca14b58876d46568ffcdd2e723acdb6bf3008bc652cefd85ef10fce1 -size 142882 +oid sha256:93a55dee752a0bb596c16d6dc6dc59b8f7691622a402dfcac6f477b08c4fc4dc +size 143768 diff --git a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D11/None/1302_StackLitSG_PixarLM.png b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D11/None/1302_StackLitSG_PixarLM.png index 4af65a030f5..cdd2c338f3f 100644 --- a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D11/None/1302_StackLitSG_PixarLM.png +++ b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D11/None/1302_StackLitSG_PixarLM.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c024ddcf69509e7b895df1a640c57f4baee061c7814ba600f63408a7c8fa3ac0 -size 211399 +oid sha256:b08295918695965b6797de45177d16c02c5c955421b760094cc1380a3fc691d5 +size 211165 diff --git a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D11/None/2551_SSR.png b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D11/None/2551_SSR.png index 2c60f1ff108..9f3aeb7ebb1 100644 --- a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D11/None/2551_SSR.png +++ b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D11/None/2551_SSR.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:56c9383462eb4be6e6f5daeb5beb71ccac10086c01e6697d3e5847f411c342fa -size 146961 +oid sha256:efe6a76322ab84ce22ab15abe9a8b17470451f6322682e826dddf6df5cf73bda +size 147625 diff --git a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D12/None/1302_StackLitSG_PixarLM.png b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D12/None/1302_StackLitSG_PixarLM.png index c18a8f35c13..36ad7cd5fea 100644 --- a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D12/None/1302_StackLitSG_PixarLM.png +++ b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D12/None/1302_StackLitSG_PixarLM.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:94bd417f722ad25d9e00466ecab5c6a94651d4cc4e6fb82d05135bd34a85d949 -size 211597 +oid sha256:3fdc820d09792c28e33d2c5698ef77ea19e91eb89786f5304b0ff23a905583a6 +size 211311 diff --git a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D12/None/2551_SSR.png b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D12/None/2551_SSR.png index 97b7ca35706..1eaad192e15 100644 --- a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D12/None/2551_SSR.png +++ b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Direct3D12/None/2551_SSR.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b822a08740ddc63dc8dab665b4b5226af66e456e33ad4b45940cc66bbdc9cbd2 -size 146874 +oid sha256:79d6d18d8453b554b4af1a665236a66df28ded3c105b44fb9cab1a1ed5179d18 +size 147515 diff --git a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Vulkan/None/1302_StackLitSG_PixarLM.png b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Vulkan/None/1302_StackLitSG_PixarLM.png index 353e025eba5..9f13563b662 100644 --- a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Vulkan/None/1302_StackLitSG_PixarLM.png +++ b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Vulkan/None/1302_StackLitSG_PixarLM.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ea9c0b66eda079dde8aa3256fdacf1cf8006f560d01533721f395032c52ab342 -size 207569 +oid sha256:01fcf917577d5f34b672674f5f408229d462bf6bb16b668a0ad9c528316fed43 +size 207417 diff --git a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Vulkan/None/2551_SSR.png b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Vulkan/None/2551_SSR.png index 11cbddaf040..660e27b4426 100644 --- a/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Vulkan/None/2551_SSR.png +++ b/TestProjects/HDRP_Tests/Assets/ReferenceImages/Linear/WindowsEditor/Vulkan/None/2551_SSR.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1b0519cef96a71ddeb7adfe891a9ebab7c9ec6777ec9c6b582755a969b821cfa -size 147890 +oid sha256:21159c1f1e9ac49b8a6472a412e41989bff1e96dfa3f0b9e5f211da54fa9987d +size 148634 diff --git a/com.unity.render-pipelines.high-definition/CHANGELOG.md b/com.unity.render-pipelines.high-definition/CHANGELOG.md index e0c671ed1ed..22d5d7aa7eb 100644 --- a/com.unity.render-pipelines.high-definition/CHANGELOG.md +++ b/com.unity.render-pipelines.high-definition/CHANGELOG.md @@ -47,6 +47,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Fix recursive rendering transmittance over the sky (case 1323945). - Fixed specular anti aliasing for layeredlit shader. - Fixed lens flare occlusion issues with transparent depth. It had the wrong depth bound (1365098) +- Fixed double contribution from the clear coat when having SSR or RTR on the Lit and StackLit shaders (case 1352424). ### Changed - Visual Environment ambient mode is now Dynamic by default. diff --git a/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/Lit.hlsl b/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/Lit.hlsl index f391c7bf599..b76dac06b6d 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/Lit.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/Lit.hlsl @@ -1083,6 +1083,7 @@ struct PreLightData float coatPartLambdaV; float3 coatIblR; float coatIblF; // Fresnel term for view vector + float clearCoatIndirectSpec; // Weight used to support the clear coat's SSR/IBL blending float3x3 ltcTransformCoat; // Inverse transformation for GGX (4x VGPRs) #if HAS_REFRACTION @@ -1144,6 +1145,7 @@ PreLightData GetPreLightData(float3 V, PositionInputs posInput, inout BSDFData b preLightData.coatPartLambdaV = GetSmithJointGGXPartLambdaV(clampedNdotV, CLEAR_COAT_ROUGHNESS); preLightData.coatIblR = reflect(-V, N); preLightData.coatIblF = F_Schlick(CLEAR_COAT_F0, clampedNdotV) * bsdfData.coatMask; + preLightData.clearCoatIndirectSpec = 1.0; } // Handle IBL + area light + multiscattering. @@ -1803,7 +1805,8 @@ DirectLighting EvaluateBSDF_Area(LightLoopContext lightLoopContext, // ---------------------------------------------------------------------------- IndirectLighting EvaluateBSDF_ScreenSpaceReflection(PositionInputs posInput, - PreLightData preLightData, + // Note: We use inout here with PreLightData for a hack we do with clear coat to transfer value of clearCoatIndirectSpec but it should be avoided for other Material + inout PreLightData preLightData, BSDFData bsdfData, inout float reflectionHierarchyWeight) { @@ -1822,17 +1825,37 @@ IndirectLighting EvaluateBSDF_ScreenSpaceReflection(PositionInputs posInput, // of a materia feature and the coat mask. float clampedNdotV = ClampNdotV(preLightData.NdotV); float F = F_Schlick(CLEAR_COAT_F0, clampedNdotV); - lighting.specularReflected = ssrLighting.rgb * (HasFlag(bsdfData.materialFeatures, MATERIALFEATUREFLAGS_LIT_CLEAR_COAT) ? - lerp(preLightData.specularFGD, F, bsdfData.coatMask) - : preLightData.specularFGD); - // Set the default weight value - reflectionHierarchyWeight = ssrLighting.a; - // In case this is a clear coat material, we only need to add to the reflectionHierarchyWeight the amount of energy that the clear coat has already - // provided to the indirect specular lighting. That would be reflectionHierarchyWeight * F (if has a coat mask). In the environement lighting, - // we do something similar. The base layer coat is multiplied by (1-coatF)^2, but that we cannot do as we have no lighting to provid for the base layer. + // Set the default weight value + reflectionHierarchyWeight = ssrLighting.a; + + // If this material has a clear coat, the behavior is more complex + // For clear coat we change a bit how reflection hierarchy is handled + // With a regular Material, we do SSR to get lighting then fallback on other method based on reflectionHierarchyWeight + // but for clear coat Material we try to do this mechanism separately for each layer. So clear coat do SSR then fallback but with the weight of clearCoatIndirectSpec + // base layer will get reamining energy of coat layer via reflectionHierarchyWeight with the fallback (i.e the cubemap). + // On top of this above we also add an additional hack to limit the smoothness used on based layer depending on coat layer for SSR application (See below) if (HasFlag(bsdfData.materialFeatures, MATERIALFEATUREFLAGS_LIT_CLEAR_COAT)) - reflectionHierarchyWeight = lerp(reflectionHierarchyWeight, reflectionHierarchyWeight * F, bsdfData.coatMask); + { + // Because we do not want to have a double contribution, we need to keep track that the clear coat's indirect specular contribution was added + preLightData.clearCoatIndirectSpec = 1.0 - ssrLighting.a; + + // We have three possible behaviors in this case: + // - The smoothness is superior or equal to 0.9, we approximate the fact that the clear coat and base layer have the same roughness and use the SSR as the indirect specular signal. + // - The smoothness is inferior to 0.8. We cannot use the SSR for the base layer, but we use the fresnel to lerp between the two lobes. + // - The smooothness is between 0.8 and 0.9, we lerp between the two behaviors. + float blendingFactor = lerp(0.0, 1.0, saturate((bsdfData.perceptualRoughness - 0.1) / 0.2)); + + // Combine the three behaviors for the lighting signal + lighting.specularReflected = ssrLighting.rgb * lerp(preLightData.specularFGD, lerp(preLightData.specularFGD, F, bsdfData.coatMask), blendingFactor); + + // We only need to add to the reflectionHierarchyWeight the amount of energy that the clear coat has already + // provided to the indirect specular lighting. That would be reflectionHierarchyWeight * F (if has a coat mask). In the environement lighting, + // we do something similar. The base layer coat is multiplied by (1-coatF)^2, but that we cannot do as we have no lighting to provid for the base layer. + reflectionHierarchyWeight = lerp(reflectionHierarchyWeight, lerp(reflectionHierarchyWeight, reflectionHierarchyWeight * F, bsdfData.coatMask), blendingFactor); + } + else + lighting.specularReflected = ssrLighting.rgb * preLightData.specularFGD; return lighting; } @@ -2002,7 +2025,7 @@ IndirectLighting EvaluateBSDF_Env( LightLoopContext lightLoopContext, // Evaluate the Clear Coat color float4 preLD = SampleEnv(lightLoopContext, lightData.envIndex, coatR, 0.0, lightData.rangeCompressionFactorCompensation, posInput.positionNDC); - envLighting += preLightData.coatIblF * preLD.rgb; + envLighting += preLightData.coatIblF * preLD.rgb * preLightData.clearCoatIndirectSpec; // Can't attenuate diffuse lighting here, may try to apply something on bakeLighting in PostEvaluateBSDF } diff --git a/com.unity.render-pipelines.high-definition/Runtime/Material/StackLit/StackLit.hlsl b/com.unity.render-pipelines.high-definition/Runtime/Material/StackLit/StackLit.hlsl index de18a0d03f0..8db6e9b5612 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Material/StackLit/StackLit.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/Material/StackLit/StackLit.hlsl @@ -1046,6 +1046,9 @@ struct PreLightData float coatIeta; + // Weight used to support the clear coat's SSR/IBL blending + float clearCoatIndirectSpec; + // For IBLs (and analytical lights if approximation is used) float3 vLayerEnergyCoeff[NB_VLAYERS]; @@ -2627,6 +2630,7 @@ PreLightData GetPreLightData(float3 V, PositionInputs posInput, inout BSDFData b PreLightData_SetupNormals(bsdfData, preLightData, V, N, NdotV); preLightData.diffuseEnergy = float3(1.0, 1.0, 1.0); + preLightData.clearCoatIndirectSpec = 1.0; // For eval IBL lights, we need: // @@ -4185,7 +4189,7 @@ DirectLighting EvaluateBSDF_Area(LightLoopContext lightLoopContext, // ---------------------------------------------------------------------------- IndirectLighting EvaluateBSDF_ScreenSpaceReflection(PositionInputs posInput, - PreLightData preLightData, + inout PreLightData preLightData, BSDFData bsdfData, inout float reflectionHierarchyWeight) { @@ -4220,18 +4224,30 @@ IndirectLighting EvaluateBSDF_ScreenSpaceReflection(PositionInputs posInput, reflectanceFactorC *= preLightData.energyCompensationFactor[COAT_LOBE_IDX]; float3 reflectanceFactorB = (float3)0.0; - for(int i = 0; i < TOTAL_NB_LOBES; i++) + for(int i = 0; i < BASE_NB_LOBES; i++) { - float3 lobeFactor = preLightData.specularFGD[i]; // note: includes the lobeMix factor, see PreLightData. - lobeFactor *= preLightData.hemiSpecularOcclusion[i]; + float3 lobeFactor = preLightData.specularFGD[i + COAT_NB_LOBES]; // note: includes the lobeMix factor, see PreLightData. + lobeFactor *= preLightData.hemiSpecularOcclusion[i + COAT_NB_LOBES]; // TODOENERGY: If vlayered, should be done in ComputeAdding with FGD formulation for non dirac lights. // Incorrect, but for now: - lobeFactor *= preLightData.energyCompensationFactor[i]; + lobeFactor *= preLightData.energyCompensationFactor[i + COAT_NB_LOBES]; reflectanceFactorB += lobeFactor; } - lighting.specularReflected = ssrLighting.rgb * lerp(reflectanceFactorB, reflectanceFactorC, bsdfData.coatMask); - reflectionHierarchyWeight = lerp(ssrLighting.a, ssrLighting.a * reflectanceFactorC.x, bsdfData.coatMask); + // Given that we have two base lobes, we need to mix them for an appproximated roughness + float mixedPerceptualRougness = lerp(bsdfData.perceptualRoughnessA, bsdfData.perceptualRoughnessB, bsdfData.lobeMix); + + // We have three possible behaviors in this case: + // - The smoothness is superior or equal to 0.9, we approximate the fact that the clear coat and base layer have the same roughness and use the SSR as the indirect specular signal. + // - The smoothness is inferior to 0.8. We cannot use the SSR for the base layer, but we use the fresnel to lerp between the two lobes. + // - The smooothness is between 0.8 and 0.9, we lerp between the two behaviors. + float blendingFactor = lerp(0.0, 1.0, saturate((mixedPerceptualRougness - 0.1) / 0.2)); + + // Because we do not want to have a double contribution, we need to keep track that the clear coat's indirect specular contribution was added + preLightData.clearCoatIndirectSpec = 1.0 - ssrLighting.a; + + lighting.specularReflected = ssrLighting.rgb * lerp(reflectanceFactorB, lerp(reflectanceFactorB, reflectanceFactorC, bsdfData.coatMask), blendingFactor); + reflectionHierarchyWeight = lerp(ssrLighting.a, lerp(ssrLighting.a, ssrLighting.a * reflectanceFactorC.x, bsdfData.coatMask), blendingFactor); } else { @@ -4351,6 +4367,7 @@ IndirectLighting EvaluateBSDF_Env( LightLoopContext lightLoopContext, if( (i == (0 IF_FEATURE_COAT(+1))) && _DebugEnvLobeMask.y == 0.0) continue; if( (i == (1 IF_FEATURE_COAT(+1))) && _DebugEnvLobeMask.z == 0.0) continue; #endif + // Compiler will deal with all that: normal = (NB_NORMALS > 1 && i == COAT_NORMAL_IDX) ? bsdfData.coatNormalWS : bsdfData.normalWS; @@ -4384,6 +4401,9 @@ IndirectLighting EvaluateBSDF_Env( LightLoopContext lightLoopContext, // Incorrect, but just for now: L *= preLightData.energyCompensationFactor[i]; L *= preLightData.hemiSpecularOcclusion[i]; + + // If we are going to process the clear coat, we need to take into account the coat indirect spec factor + L *= (i == COAT_LOBE_IDX && COAT_NB_LOBES == 1) ? preLightData.clearCoatIndirectSpec : 1.0; envLighting += L; }