Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions com.unity.render-pipelines.high-definition/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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)
{
Expand All @@ -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;
}
Expand Down Expand Up @@ -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
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand Down Expand Up @@ -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:
//
Expand Down Expand Up @@ -4185,7 +4189,7 @@ DirectLighting EvaluateBSDF_Area(LightLoopContext lightLoopContext,
// ----------------------------------------------------------------------------

IndirectLighting EvaluateBSDF_ScreenSpaceReflection(PositionInputs posInput,
PreLightData preLightData,
inout PreLightData preLightData,
BSDFData bsdfData,
inout float reflectionHierarchyWeight)
{
Expand Down Expand Up @@ -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
{
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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;
}

Expand Down