// Otherwise, the calculation of these is done for each light
//
// Handle IBL + area light + multiscattering.
// Note: use the not modified by anisotropy iblPerceptualRoughness here.
// Here, we will fetch our actual FGD terms, see ComputeAdding for details: the F0 params
// will be replaced by our energy coefficients. Note that the way to do it depends on the
// formulation of ComputeAdding (with FGD fetches or only Fresnel terms).
// Also note that while the fetch directions for the light samples (IBL) are the ones
// at the top interface, for the FGD terms (in fact, for all angle dependent BSDF
// parametrization data), we need to use the actual interface angle a propagated direction
// would have. So, for the base layer, this is a refracted direction through the coat.
// Same for the top, but this is just NdotV.
// This is because we should really have fetched FGD with the tracked cti (cos theta incoming)
// at the bottom layer or top layer during ComputeAdding itself. We delayed the fetch after,
// because our ComputeAdding formulation is with "energy" coefficients calculated with a
// chain of Fresnel terms instead of a correct chain computed with the true FGD.
float baseLayerNdotV = PreLightData_GetBaseNdotVForFGD(bsdfData, preLightData, NdotV);
float diffuseFGDTmp; // unused, for coat layer FGD fetch
GetPreIntegratedFGDGGXAndDisneyDiffuse(NdotV[COAT_NORMAL_IDX],
preLightData.iblPerceptualRoughness[COAT_LOBE_IDX],
preLightData.vLayerEnergyCoeff[TOP_VLAYER_IDX],
preLightData.specularFGD[COAT_LOBE_IDX],
diffuseFGDTmp,
specularReflectivity[COAT_LOBE_IDX]);
GetPreIntegratedFGDGGXAndDisneyDiffuse(baseLayerNdotV,
preLightData.iblPerceptualRoughness[BASE_LOBEA_IDX],
preLightData.vLayerEnergyCoeff[BOTTOM_VLAYER_IDX],
preLightData.specularFGD[BASE_LOBEA_IDX],
diffuseFGD[0],
specularReflectivity[BASE_LOBEA_IDX]);
GetPreIntegratedFGDGGXAndDisneyDiffuse(baseLayerNdotV,
preLightData.iblPerceptualRoughness[BASE_LOBEB_IDX],
preLightData.vLayerEnergyCoeff[BOTTOM_VLAYER_IDX],
preLightData.specularFGD[BASE_LOBEB_IDX],
diffuseFGD[1],
specularReflectivity[BASE_LOBEB_IDX]);
if (HasFlag(bsdfData.materialFeatures, MATERIALFEATUREFLAGS_STACK_LIT_ANISOTROPY))
{
// Note: there's no anisotropy possible on coat.
preLightData.TdotV = TdotV;
preLightData.BdotV = BdotV;
#endif
// For GGX aniso and IBL we have done an empirical (eye balled) approximation compare to the reference.
// We use a single fetch, and we stretch the normal to use based on various criteria.
// result are far away from the reference but better than nothing
// For positive anisotropy values: tangent = highlight stretch (anisotropy) direction, bitangent = grain (brush) direction.
float3 grainDirWS[2];
//grainDirWS[0] = (bsdfData.anisotropy >= 0.0) ? bsdfData.bitangentWS : bsdfData.tangentWS;
grainDirWS[0] = (preLightData.iblAnisotropy[0] >= 0.0) ? bsdfData.bitangentWS : bsdfData.tangentWS;
grainDirWS[1] = (preLightData.iblAnisotropy[1] >= 0.0) ? bsdfData.bitangentWS : bsdfData.tangentWS;
// Reduce stretching for (perceptualRoughness < 0.2).
float stretch[2];
stretch[0] = abs(preLightData.iblAnisotropy[0]) * saturate(5 * preLightData.iblPerceptualRoughness[BASE_LOBEA_IDX]);
stretch[1] = abs(preLightData.iblAnisotropy[1]) * saturate(5 * preLightData.iblPerceptualRoughness[BASE_LOBEB_IDX]);
// perceptualRoughness is use as input and output here
GetGGXAnisotropicModifiedNormalAndRoughness(bsdfData.bitangentWS, bsdfData.tangentWS, N, V, preLightData.iblAnisotropy[0], preLightData.iblPerceptualRoughness[BASE_LOBEA_IDX], iblN[BASE_LOBEA_IDX], preLightData.iblPerceptualRoughness[BASE_LOBEA_IDX]);
GetGGXAnisotropicModifiedNormalAndRoughness(bsdfData.bitangentWS, bsdfData.tangentWS, N, V, preLightData.iblAnisotropy[1], preLightData.iblPerceptualRoughness[BASE_LOBEB_IDX], iblN[BASE_LOBEB_IDX], preLightData.iblPerceptualRoughness[BASE_LOBEB_IDX]);
iblN[BASE_LOBEA_IDX] = GetAnisotropicModifiedNormal(grainDirWS[0], N[BASE_NORMAL_IDX], V, stretch[0]);
iblN[BASE_LOBEB_IDX] = GetAnisotropicModifiedNormal(grainDirWS[1], N[BASE_NORMAL_IDX], V, stretch[1]);
}
else
{
// IBL
// Handle IBL pre calculated data + GGX multiscattering energy loss compensation term
// Here, we will fetch our actual FGD terms, see ComputeAdding for details: the F0 params
// will be replaced by our energy coefficients. Note that the way to do it depends on the
// formulation of ComputeAdding (with FGD fetches or only Fresnel terms).
// Also note that while the fetch directions for the light samples (IBL) are the ones
// at the top interface, for the FGD terms (in fact, for all angle dependent BSDF
// parametrization data), we need to use the actual interface angle a propagated direction
// would have. So, for the base layer, this is a refracted direction through the coat.
// Same for the top, but this is just NdotV.
// This is because we should really have fetched FGD with the tracked cti (cos theta incoming)
// at the bottom layer or top layer during ComputeAdding itself. We delayed the fetch after,
// because our ComputeAdding formulation is with "energy" coefficients calculated with a
// chain of Fresnel terms instead of a correct chain computed with the true FGD.
float baseLayerNdotV = PreLightData_GetBaseNdotVForFGD(bsdfData, preLightData, NdotV);
float diffuseFGDTmp; // unused, for coat layer FGD fetch
GetPreIntegratedFGDGGXAndDisneyDiffuse(NdotV[COAT_NORMAL_IDX],
preLightData.iblPerceptualRoughness[COAT_LOBE_IDX],
preLightData.vLayerEnergyCoeff[TOP_VLAYER_IDX],
preLightData.specularFGD[COAT_LOBE_IDX],
diffuseFGDTmp,
specularReflectivity[COAT_LOBE_IDX]);
GetPreIntegratedFGDGGXAndDisneyDiffuse(baseLayerNdotV,
preLightData.iblPerceptualRoughness[BASE_LOBEA_IDX],
preLightData.vLayerEnergyCoeff[BOTTOM_VLAYER_IDX],
preLightData.specularFGD[BASE_LOBEA_IDX],
diffuseFGD[0],
specularReflectivity[BASE_LOBEA_IDX]);
GetPreIntegratedFGDGGXAndDisneyDiffuse(baseLayerNdotV,
preLightData.iblPerceptualRoughness[BASE_LOBEB_IDX],
preLightData.vLayerEnergyCoeff[BOTTOM_VLAYER_IDX],
preLightData.specularFGD[BASE_LOBEB_IDX],
diffuseFGD[1],
specularReflectivity[BASE_LOBEB_IDX]);
// This is a ad-hoc tweak to better match reference of anisotropic GGX.
// TODO: We need a better hack.
preLightData.iblPerceptualRoughness[BASE_LOBEA_IDX] *= saturate(1.2 - abs(preLightData.iblAnisotropy[0]));
preLightData.iblPerceptualRoughness[BASE_LOBEB_IDX] *= saturate(1.2 - abs(preLightData.iblAnisotropy[1]));
// Correction of reflected direction for better handling of rough material