// Precomputed lighting data to send to the various lighting functions
struct PreLightData
{
float NdotV; // Could be negative due to normal mapping, use ClampNdotV()
// GGX
float partLambdaV;
float energyCompensation;
float iblPerceptualRoughness;
float3 specularFGD; // Store preconvoled BRDF for both specular and diffuse
float diffuseFGD;
float3 specularFGD; // Store preconvoled BRDF for both specular and diffuse
float diffuseFGD;
float3x3 orthoBasisViewNormal; // Right-handed view-dependent orthogonal basis around the normal (6x VGPRs)
float3x3 ltcTransformDiffuse; // Inverse transformation for Lambertian or Disney Diffuse (4x VGPRs)
float3x3 ltcTransformSpecular; // Inverse transformation for GGX (4x VGPRs)
float3x3 orthoBasisViewNormal; // Right-handed view-dependent orthogonal basis around the normal (6x VGPRs)
float3x3 ltcTransformDiffuse; // Inverse transformation for Lambertian or Disney Diffuse (4x VGPRs)
float3x3 ltcTransformSpecular; // Inverse transformation for GGX (4x VGPRs)
float ltcMagnitudeDiffuse;
float3 ltcMagnitudeFresnel;
float coatIblF; // Fresnel term for view vector
float3x3 ltcTransformCoat; // Inverse transformation for GGX (4x VGPRs)
float coatIblF; // Fresnel term for view vector
float3x3 ltcTransformCoat; // Inverse transformation for GGX (4x VGPRs)
float3 transparentRefractV; // refracted view vector after exiting the shape
float3 transparentPositionWS; // start of the refracted ray after exiting the shape
float3 transparentTransmittance; // transmittance due to absorption
float transparentSSMipLevel; // mip level of the screen space gaussian pyramid for rough refraction
float3 transparentRefractV; // refracted view vector after exiting the shape
float3 transparentPositionWS; // start of the refracted ray after exiting the shape
float3 transparentTransmittance; // transmittance due to absorption
float transparentSSMipLevel; // mip level of the screen space gaussian pyramid for rough refraction
};
PreLightData GetPreLightData(float3 V, PositionInputs posInput, BSDFData bsdfData)
float3 N = bsdfData.normalWS;
float NdotV = saturate(dot(N, V));
preLightData.NdotV = dot(N, V);
float NdotV = ClampNdotV(preLightData.NdotV);
if (HasFeatureFlag(bsdfData.materialFeatures, MATERIALFEATUREFLAGS_LIT_CLEAR_COAT))
{
preLightData.ltcTransformSpecular._m00_m02_m11_m20 = SAMPLE_TEXTURE2D_ARRAY_LOD(_LtcData, s_linear_clamp_sampler, uv, LTC_GGX_MATRIX_INDEX, 0);
// Construct a right-handed view-dependent orthogonal basis around the normal
preLightData.orthoBasisViewNormal[0] = normalize(V - N * NdotV);
preLightData.orthoBasisViewNormal[0] = normalize(V - N * preLightData. NdotV); // Do not clamp NdotV here
preLightData.orthoBasisViewNormal[2] = N;
preLightData.orthoBasisViewNormal[1] = cross(preLightData.orthoBasisViewNormal[2], preLightData.orthoBasisViewNormal[0]);
{
float3 N = bsdfData.normalWS;
float NdotV = dot(N, V);
/*
float3 H = normalize(V + L);
float NdotH = saturate(dot(N, H));
float LdotH = saturate(dot(L, H));
float LdotV = dot(L, V);
*/
float LdotV = dot(L, V);
float invLenLV = rsqrt(2.0 * LdotV + 2.0); // invLenLV = rcp(length(L + V)) - caution about the case where V and L are opposite, it can happen, use max to avoid this
float NdotH = saturate((NdotL + NdotV) * invLenLV);
float LdotH = saturate(invLenLV * LdotV + invLenLV);
// The abs need to happen AFTER the processing above, else value above are incorrect...
N += (2.0 * saturate(-NdotV)) * V;
NdotV = abs(dot(N, V));
float LdotV = dot(L, V);
float invLenLV = rsqrt(max(2.0 * LdotV + 2.0, FLT_EPS)); // invLenLV = rcp(length(L + V)), clamp to avoid rsqrt(0) = NaN
float NdotH = saturate((NdotL + preLightData.NdotV) * invLenLV); // Do not clamp NdotV here
float LdotH = saturate(invLenLV * LdotV + invLenLV);
float NdotV = ClampNdotV(preLightData.NdotV);
float3 F = F_Schlick(bsdfData.fresnel0, LdotH);
float DV;
float3 H = (L + V) * invLenLV; // <= this is not correct!
float3 H = (L + V) * invLenLV;
// For anisotropy we must not saturate these values
float TdotH = dot(bsdfData.tangentWS, H);
DV = DV_SmithJointGGX(NdotH, NdotL, NdotV, bsdfData.roughnessT, preLightData.partLambdaV);
}
specularLighting = F * DV;
// Reset everything:
N = bsdfData.normalWS;
NdotV = saturate(dot(N, V));
#ifdef LIT_DIFFUSE_LAMBERT_BRDF
float diffuseTerm = Lambert();