浏览代码

Add correct handling of Fresnel0 for interface

/feature-ReflectionProbeFit
Sebastien Lagarde 7 年前
当前提交
72d32af8
共有 3 个文件被更改,包括 54 次插入25 次删除
  1. 13
      ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/CommonLighting.hlsl
  2. 42
      ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/CommonMaterial.hlsl
  3. 24
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Lit/Lit.hlsl

13
ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/CommonLighting.hlsl


return real3x3(localX, localY, localZ);
}
// ior is a value between 1.0 and 2.5
real IORToFresnel0(real ior)
{
return Sq((ior - 1.0) / (ior + 1.0));
}
// same as regular refract except there is not the test for total internal reflection
real3 RefractNoTIR(real3 X, real3 N, real ieta)
{
real XdotN = saturate(dot(N, X));
return ieta * X + (sqrt(1 + ieta * ieta * (XdotN * XdotN - 1)) - ieta * XdotN) * N;
}
#endif // UNITY_COMMON_LIGHTING_INCLUDED

42
ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/CommonMaterial.hlsl


}
// Use with stack BRDF (clear coat / coat)
float roughnessToVariance(float roughness)
real roughnessToVariance(real roughness)
float roughnessPow = pow(roughness, 1.1);
float roughnessPow = PositivePow(roughness, 1.1);
float varianceToRoughness(float variance)
real varianceToRoughness(real variance)
{
return PositivePow(variance / (1.0 + variance), 1.0 / 1.1);
}
// ior is a value between 1.0 and 2.5
// Assume air interface for top
real IORToFresnel0(real ior)
return pow(variance / (1.0 + variance), 1.0 / 1.1);
return Sq((ior - 1.0) / (ior + 1.0));
}
real IORToFresnel0(real baseIor, real topIor)
{
return Sq((baseIor - topIor) / (baseIor + topIor));
}
// Assume air interface for top
real Fresnel0ToIor(real fresnel0)
{
real sqrtF0 = sqrt(fresnel0);
return (1.0 + sqrtF0) / (1.0 - sqrtF0);
}
// This function is equivalent to IORToFresnel0(Fresnel0ToIor(fresnel0), 1.5)
// This is a coarse approximation of computing fresnel0 for a different top than air (here clear coat of IOR 1.5) when we only have fresnel0 with air interface
real Fresnel0ReajustFor15(real fresnel0)
{
real sqrtF0 = sqrt(fresnel0);
return Sq(1.0 - 5.0 * sqrtF0) / Sq(5.0 - sqrtF0);
}
// same as regular refract except there is not the test for total internal reflection + the vector is flipped for processing
real3 CoatRefract(real3 X, real3 N, real ieta)
{
real XdotN = saturate(dot(N, X));
return ieta * X + (sqrt(1 + ieta * ieta * (XdotN * XdotN - 1)) - ieta * XdotN) * N;
}
// ----------------------------------------------------------------------------

24
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Lit/Lit.hlsl


{
// General
float clampNdotV; // clamped NdotV
float3 baseFresnel0; // Fresnel0 use with schlick Fresnel (can be affected by clear coat)
// GGX
float partLambdaV;

// Note: coatMask should be just a scale of the IOR to 1. However this only work correctly with true Fresnel equation,
// so in the code we also multiply F_Schlick by bsdfData.coatMask as an approximation
preLightData.coatIEta = lerp(1.0, CLEAR_COAT_IETA, bsdfData.coatMask);
preLightData.coatRefractV = RefractNoTIR(V, N, preLightData.coatIEta);
preLightData.coatRefractV = CoatRefract(V, N, preLightData.coatIEta);
preLightData.coatRoughness = CLEAR_COAT_ROUGHNESS; // This can be modify in punctual light evaluation in case of minRoughness usage
preLightData.coatPartLambdaV = GetSmithJointGGXPartLambdaV(NdotV, CLEAR_COAT_ROUGHNESS); // This will not take into account the modification by minRoughness but we are ok with this

V = preLightData.coatRefractV;
NdotV = saturate(dot(N, V));
// fresnel0 is deduced from interface between air and material (assume to be 1.5 in Unity, or a metal).
// but here we go from clear coat (1.5) to material, we need to update fresnel0
preLightData.baseFresnel0.x = Fresnel0ReajustFor15(bsdfData.fresnel0.x);
preLightData.baseFresnel0.y = Fresnel0ReajustFor15(bsdfData.fresnel0.y);
preLightData.baseFresnel0.z = Fresnel0ReajustFor15(bsdfData.fresnel0.z);
}
else
{

preLightData.baseFresnel0 = bsdfData.fresnel0;
}
// For clear coat and area light we reuse the same 'IBL' algorithm

// Handle IBL + multiscattering
float reflectivity;
GetPreIntegratedFGD(NdotV, preLightData.iblPerceptualRoughness, bsdfData.fresnel0, preLightData.specularFGD, preLightData.diffuseFGD, reflectivity);
GetPreIntegratedFGD(NdotV, preLightData.iblPerceptualRoughness, preLightData.baseFresnel0, preLightData.specularFGD, preLightData.diffuseFGD, reflectivity);
#ifdef LIT_USE_GGX_ENERGY_COMPENSATION
// Ref: Practical multiple scattering compensation for microfacet models.

// TODO: the fit seems rather poor. The scaling factor of 0.5 allows us
// to match the reference for rough metals, but further darkens dielectrics.
preLightData.ltcMagnitudeFresnel = bsdfData.fresnel0 * ltcGGXFresnelMagnitudeDiff + (float3)ltcGGXFresnelMagnitude;
preLightData.ltcMagnitudeFresnel = preLightData.baseFresnel0 * ltcGGXFresnelMagnitudeDiff + (float3)ltcGGXFresnelMagnitude;
// refraction (forward only)
#ifdef REFRACTION_MODEL

// Change the Light and View direction to account for IOR change
// Update the half vector accordingly
V = preLightData.coatRefractV;
L = RefractNoTIR(L, N, preLightData.coatIEta);
L = CoatRefract(L, N, preLightData.coatIEta);
NdotV = saturate(dot(N, V));
}

float DV;
F *= F_Schlick(bsdfData.fresnel0, LdotH);
F *= F_Schlick(preLightData.baseFresnel0, LdotH);
// We avoid divergent evaluation of the GGX, as that nearly doubles the cost.
// If the tile has anisotropy, all the pixels within the tile are evaluated as anisotropic.

// Try to mimic multibounce with specular color. Not the point of the original formula but ok result.
// Take the min of screenspace specular occlusion and visibility cone specular occlusion
#if GTAO_MULTIBOUNCE_APPROX
lighting.indirect.specularReflected *= GTAOMultiBounce(min(bsdfData.specularOcclusion, specularOcclusion), bsdfData.fresnel0);
lighting.indirect.specularReflected *= GTAOMultiBounce(min(bsdfData.specularOcclusion, specularOcclusion), preLightData.baseFresnel0);
#else
lighting.indirect.specularReflected *= lerp(_AmbientOcclusionParam.rgb, float3(1.0, 1.0, 1.0), min(bsdfData.specularOcclusion, specularOcclusion));
#endif

specularLighting = lighting.direct.specular + lighting.indirect.specularReflected;
// Rescale the GGX to account for the multiple scattering.
specularLighting *= 1.0 + bsdfData.fresnel0 * preLightData.energyCompensation;
specularLighting *= 1.0 + preLightData.baseFresnel0 * preLightData.energyCompensation;
#ifdef DEBUG_DISPLAY
if (_DebugLightingMode == DEBUGLIGHTINGMODE_INDIRECT_DIFFUSE_OCCLUSION_FROM_SSAO)

}
else if (_DebugLightingMode == DEBUGLIGHTINGMODE_INDIRECT_SPECULAR_GTAO_FROM_SSAO)
{
diffuseLighting = GTAOMultiBounce(specularOcclusion, bsdfData.fresnel0);
diffuseLighting = GTAOMultiBounce(specularOcclusion, preLightData.baseFresnel0);
specularLighting = float3(0.0, 0.0, 0.0); // Disable specular lighting
}
#endif

正在加载...
取消
保存