浏览代码

Some modifications (not enabled for now) to try to handle anisotropy better.

/main
Stephane Laroche 7 年前
当前提交
e982f099
共有 2 个文件被更改,包括 146 次插入62 次删除
  1. 5
      ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/CommonMaterial.hlsl
  2. 203
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/StackLit/StackLit.hlsl

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


roughnessB = roughness * (1 - anisotropy);
}
real RoughnessToAnisotropy(real roughnessT, real roughnessB)
{
return ((roughnessT - roughnessB) / (roughnessT + roughnessB + 0.0001));
}
// Same as ConvertAnisotropyToRoughness but
// roughnessT and roughnessB are clamped, and are meant to be used with punctual and directional lights.
void ConvertAnisotropyToClampRoughness(real perceptualRoughness, real anisotropy, out real roughnessT, out real roughnessB)

203
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/StackLit/StackLit.hlsl


// We have a coat top layer: change the base fresnel0 accordingdly:
bsdfData.fresnel0 = ConvertF0ForAirInterfaceToF0ForNewTopIor(bsdfData.fresnel0, bsdfData.coatIor);
// We just dont clamp the roughnesses now, but after the ComputeAdding() which will use those:
// We just dont clamp the roughnesses for now, but after the ComputeAdding() which will use those:
//
//bsdfData.roughnessAT = PerceptualRoughnessToRoughness(bsdfData.perceptualRoughnessA);
//bsdfData.roughnessBT = PerceptualRoughnessToRoughness(bsdfData.perceptualRoughnessB);
ConvertAnisotropyToRoughness(bsdfData.perceptualRoughnessA, bsdfData.anisotropy, bsdfData.roughnessAT, bsdfData.roughnessAB);
ConvertAnisotropyToRoughness(bsdfData.perceptualRoughnessB, bsdfData.anisotropy, bsdfData.roughnessBT, bsdfData.roughnessBB);
bsdfData.coatRoughness = PerceptualRoughnessToRoughness(bsdfData.coatPerceptualRoughness);

// For consistency with nonperceptual anisotropic and clamped roughnessAT/AB/BT/BB
// which are stored in BSDFData, coatRoughness (for analytical lights) will
// also be stored in BSDFData.
float iblAnisotropy[BASE_NB_LOBES];
// GGX

// (so 2 vs the 3 “virtual” layer structure here).
// (FGDinf can be obtained from our FGD)
//
// Anisotropy:
// ------------
// The argument for handling the anisotropy is as follow. (Note a good scalar measure for a
// covariance matrix is Sqrt(|C|)). Normally if all layers were anisotropic, this would mean
// tracking and updating covariance matrices. Here, we already exploit symmetries by having
// a single elevation angle, and doing all operations "as if" we were in the same incident plane.
// Only the bottom interface is anisotropic. Since any reference frame can be used for the T and B
// basis because of that, and all rebounds are wrt to those same T and B, we can align T to
// the incident plane. Isotropic roughness is decomposed on the diagonal of C and anisotropic
// roughness is also diagonal, just different for xx and yy. So we just use the same scalar
// variance updating equations (in a state that account for the whole stack) multiple times
// at the end for the different variances of the bottom layer.
//
// Of course in practice these will only be useful for analytical lights, as IBLs use a hacked
// direction parametrized by the scalar roughness.
//
// Note that anisotropy_decomposition( variance_adding_operator( isotropic_roughness ) )
// is not the same as variance_adding_operator( anisotropy_decomposition(isotropic_roughness ) ),
// the anisotropic decomposition is done on rougness and roughness is transformed in linearized
// variance.

} //...ComputeStatistics()
void ComputeAdding(float _cti, in BSDFData bsdfData, inout PreLightData preLightData, bool perLightCaller = false)
void ComputeAdding(float _cti, in BSDFData bsdfData, inout PreLightData preLightData, bool calledPerLight = false)
{
// Global Variables
float cti = _cti;

// Then we need anisotropic roughness updates again for the 2
// bottom lobes, for analytical lights.
//
// TODO: VLAYERED_RECOMPUTE_PERLIGHT and perLightCaller bool
// TODO: VLAYERED_RECOMPUTE_PERLIGHT and calledPerLight bool
// First, to be less messy, immediately transfer vLayerPerceptualRoughness
// data into the iblPerceptualRoughness[] array

preLightData.iblPerceptualRoughness[COAT_LOBE_IDX] = preLightData.vLayerPerceptualRoughness[TOP_VLAYER_IDX];
// Obviously coat roughness is given without ComputeAdding calculations (nothing on top)
//
//preLightData.iblPerceptualRoughness[COAT_LOBE_IDX] = preLightData.vLayerPerceptualRoughness[TOP_VLAYER_IDX];
#ifdef VLAYERED_RECOMPUTE_PERLIGHT
bool perLightOption = true;
#else
bool perLightOption = false;
#endif
bool haveAnisotropy = HasFeatureFlag(bsdfData.materialFeatures, MATERIALFEATUREFLAGS_STACK_LIT_ANISOTROPY);
// calledPerLight and all of the bools above are static time known.
// What we have to calculate is a bit messy here.
// Basically, If we're in a mode where we will compute the vlayer stats per analytical light,
// and our calling context here is per light, we shouldn't deal with the perceptual roughnesses
// for IBLs, nor with their anisotropy parameter recalculation. So we only deal with the roughness
// used by analytical lights (no iblPerceptualRoughness)
//
// Otherwise, depending on if we have anisotropy or not, we might still have to deal with
// the T and B terms to have isotropic modulation by the above layer and re-infer back a
// a corrected anisotropy and scalar roughness for use with the IBL hack.
// That hack adds complexity because IBLs they can't use the T and B roughnesses but at the
// same time we can't just update their scalar roughness because then it will only give them more
// roughness in the anisotropic direction.
if( !calledPerLight && !haveAnisotropy)
{
// Calculate modified base lobe roughnesses T (no anisotropy)
// There's no anisotropy and we haven't clamped the roughness in the T and B fields, so
// that we can use directly bsdfData.roughness?T == bsdfData.roughness?B
// == PerceptualRoughnessToRoughness(bsdfData.perceptualRoughnessA)) :
//s_r12 = RoughnessToLinearVariance(PerceptualRoughnessToRoughness(bsdfData.perceptualRoughnessA));
s_r12 = RoughnessToLinearVariance(bsdfData.roughnessAT);
_s_r0m = s_ti0 + j0i*(s_t0i + s_r12 + m_rr*(s_r12+s_ri0));
float tmpA = _s_r0m;
preLightData.iblPerceptualRoughness[BASE_LOBEA_IDX] = LinearVarianceToPerceptualRoughness(_s_r0m);
//s_r12 = RoughnessToLinearVariance(PerceptualRoughnessToRoughness(bsdfData.perceptualRoughnessB));
s_r12 = RoughnessToLinearVariance(bsdfData.roughnessBT);
_s_r0m = s_ti0 + j0i*(s_t0i + s_r12 + m_rr*(s_r12+s_ri0));
float tmpB = _s_r0m;
preLightData.iblPerceptualRoughness[BASE_LOBEB_IDX] = LinearVarianceToPerceptualRoughness(_s_r0m);
if( !perLightOption )
{
// We're not going to get called again per analytical light so store the result needed and used by them:
// LOBEA and LOBEB but only the T part...
preLightData.layeredRoughnessT[0] = ClampRoughnessForAnalyticalLights(LinearVarianceToRoughness(tmpA));
preLightData.layeredRoughnessT[1] = ClampRoughnessForAnalyticalLights(LinearVarianceToRoughness(tmpB));
}
}
if( !calledPerLight && haveAnisotropy)
{
// We're in GetPreLightData context so we need to deal with IBL precalc, and
// regardless of if we had the VLAYERED_RECOMPUTE_PERLIGHT option or not, we
// still need to compute the full anistropic modification of variances.
// We proceed as follow: Convert T & B roughnesses to variance, propagate the effect of layers,
// infer back a new anisotropy parameter and roughness from them:
// TODOANISOTROPY
// LOBEA roughness for analytical lights (T part)
s_r12 = RoughnessToLinearVariance(bsdfData.roughnessAT);
_s_r0m = s_ti0 + j0i*(s_t0i + s_r12 + m_rr*(s_r12+s_ri0));
float roughnessT = LinearVarianceToRoughness(_s_r0m);
// LOBEA roughness for analytical (B part)
s_r12 = RoughnessToLinearVariance(bsdfData.roughnessAB);
_s_r0m = s_ti0 + j0i*(s_t0i + s_r12 + m_rr*(s_r12+s_ri0));
float roughnessB = LinearVarianceToRoughness(_s_r0m);
//preLightData.iblAnisotropy[0] = RoughnessToAnisotropy(roughnessT, roughnessB);
// TODOANISOTROPY
preLightData.iblAnisotropy[0] = bsdfData.anisotropy;
preLightData.iblPerceptualRoughness[BASE_LOBEA_IDX] = RoughnessToPerceptualRoughness((roughnessT + roughnessB)/2.0);
if( !perLightOption )
{
// We're not going to get called again per analytical light so store the result needed and used by them:
// LOBEA T and B part:
preLightData.layeredRoughnessT[0] = ClampRoughnessForAnalyticalLights(roughnessT);
preLightData.layeredRoughnessB[0] = ClampRoughnessForAnalyticalLights(roughnessB);
}
// We do the same for LOBEB:
// -------------------------
// LOBEB roughness for analytical lights (T part)
s_r12 = RoughnessToLinearVariance(bsdfData.roughnessBT);
_s_r0m = s_ti0 + j0i*(s_t0i + s_r12 + m_rr*(s_r12+s_ri0));
roughnessT = LinearVarianceToRoughness(_s_r0m);
// LOBEB roughness for analytical (B part)
s_r12 = RoughnessToLinearVariance(bsdfData.roughnessBB);
_s_r0m = s_ti0 + j0i*(s_t0i + s_r12 + m_rr*(s_r12+s_ri0));
roughnessB = LinearVarianceToRoughness(_s_r0m);
//preLightData.iblAnisotropy[1] = RoughnessToAnisotropy(roughnessT, roughnessB);
// TODOANISOTROPY
preLightData.iblAnisotropy[1] = bsdfData.anisotropy;
preLightData.iblPerceptualRoughness[BASE_LOBEB_IDX] = RoughnessToPerceptualRoughness((roughnessT + roughnessB)/2.0);
// We need to compute the rest here:
// LOBEA roughness for IBL
s_r12 = RoughnessToLinearVariance(PerceptualRoughnessToRoughness(bsdfData.perceptualRoughnessA));
_s_r0m = s_ti0 + j0i*(s_t0i + s_r12 + m_rr*(s_r12+s_ri0));
preLightData.iblPerceptualRoughness[BASE_LOBEA_IDX] = LinearVarianceToPerceptualRoughness(_s_r0m);
if( !perLightOption )
{
// We're not going to get called again per analytical light so store the result needed and used by them:
// LOBEB T and B part:
preLightData.layeredRoughnessT[1] = ClampRoughnessForAnalyticalLights(roughnessT);
preLightData.layeredRoughnessB[1] = ClampRoughnessForAnalyticalLights(roughnessB);
}
// LOBEB roughness for IBL
s_r12 = RoughnessToLinearVariance(PerceptualRoughnessToRoughness(bsdfData.perceptualRoughnessB));
_s_r0m = s_ti0 + j0i*(s_t0i + s_r12 + m_rr*(s_r12+s_ri0));
preLightData.iblPerceptualRoughness[BASE_LOBEB_IDX] = LinearVarianceToPerceptualRoughness(_s_r0m);
}
// ANALYTICAL LIGHTS rougness:
//
// If we're in the mode where we will compute the vlayer stats per analytical light,
// and our calling context here is for IBLs, we will not compute the additional
// roughnesses (avoid waste, these wouldn't be used for any light then!):
#ifdef VLAYERED_RECOMPUTE_PERLIGHT
if(perLightCaller)
if( calledPerLight )
{
#ifndef VLAYERED_RECOMPUTE_PERLIGHT
//error
{
// Coat lobe rougness for analytical lights
preLightData.layeredCoatRoughness = PerceptualRoughnessToRoughness(preLightData.vLayerPerceptualRoughness[TOP_VLAYER_IDX]);
preLightData.layeredCoatRoughness = ClampRoughnessForAnalyticalLights(preLightData.layeredCoatRoughness);
// Finally, if we're computing all this for one light, first the option should have been declared,
// and we don't compute anything IBL related, already done in GetPreLightData's context.
// We just need to propagate variance for LOBEA and LOBEB and clamp.
// (for 2 lobe structs, we still use numbers only)
s_r12 = RoughnessToLinearVariance(bsdfData.roughnessAT);
_s_r0m = s_ti0 + j0i*(s_t0i + s_r12 + m_rr*(s_r12+s_ri0));
preLightData.layeredRoughnessT[0] = ClampRoughnessForAnalyticalLights(LinearVarianceToRoughness(_s_r0m));

_s_r0m = s_ti0 + j0i*(s_t0i + s_r12 + m_rr*(s_r12+s_ri0));
preLightData.layeredRoughnessT[1] = ClampRoughnessForAnalyticalLights(LinearVarianceToRoughness(_s_r0m));
if (HasFeatureFlag(bsdfData.materialFeatures, MATERIALFEATUREFLAGS_STACK_LIT_ANISOTROPY))
if ( haveAnisotropy )
// LOBEA roughness for analytical (B part)
s_r12 = RoughnessToLinearVariance(bsdfData.roughnessAB);
_s_r0m = s_ti0 + j0i*(s_t0i + s_r12 + m_rr*(s_r12+s_ri0));

s_r12 = RoughnessToLinearVariance(bsdfData.roughnessBB);
_s_r0m = s_ti0 + j0i*(s_t0i + s_r12 + m_rr*(s_r12+s_ri0));
preLightData.layeredRoughnessB[1] = ClampRoughnessForAnalyticalLights(LinearVarianceToRoughness(_s_r0m));
}
}
#ifdef VLAYERED_DIFFUSE_ENERGY_HACKED_TERM
// TODO

//preLightData.fresnel0[COAT_LOBE_IDX] = IorToFresnel0(bsdfData.coatIor);
preLightData.coatIeta = 1.0 / GetCoatEta(bsdfData);
// Obviously coat roughness is given without ComputeAdding calculations (nothing on top)
preLightData.iblPerceptualRoughness[COAT_LOBE_IDX] = bsdfData.coatPerceptualRoughness;
preLightData.layeredCoatRoughness = ClampRoughnessForAnalyticalLights(bsdfData.coatRoughness);
// First thing we need is compute the energy coefficients and new roughnesses.
// Even if configured to do it also per analytical light, we need it for IBLs too.
ComputeAdding(NdotV, bsdfData, preLightData, false);

// preLightData.iblPerceptualRoughness[]
// preLightData.vLayerEnergyCoeff[]
// preLightData.iblAnisotropy[] (only if anisotropy is enabled)
// If we're not using VLAYERED_RECOMPUTE_PERLIGHT we also have calculated
// preLightData.layeredRoughnessT and B[],

// 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 = (bsdfData.anisotropy >= 0.0) ? bsdfData.bitangentWS : bsdfData.tangentWS;
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;
stretch[0] = abs(bsdfData.anisotropy) * saturate(5 * preLightData.iblPerceptualRoughness[BASE_LOBEA_IDX]);
stretch[1] = abs(bsdfData.anisotropy) * saturate(5 * preLightData.iblPerceptualRoughness[BASE_LOBEB_IDX]);
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]);
iblN[BASE_LOBEA_IDX] = GetAnisotropicModifiedNormal(grainDirWS, N, V, stretch[0]);
iblN[BASE_LOBEB_IDX] = GetAnisotropicModifiedNormal(grainDirWS, N, V, stretch[1]);
iblN[BASE_LOBEA_IDX] = GetAnisotropicModifiedNormal(grainDirWS[0], N, V, stretch[0]);
iblN[BASE_LOBEB_IDX] = GetAnisotropicModifiedNormal(grainDirWS[1], N, V, stretch[1]);
}
else

iblR[2] = reflect(-V, iblN[2]);
// This is a ad-hoc tweak to better match reference of anisotropic GGX.
// TODO: We need a better hack.
float fact = saturate(1.2 - abs(bsdfData.anisotropy));
preLightData.iblPerceptualRoughness[0] *= fact;
preLightData.iblPerceptualRoughness[1] *= fact;
preLightData.iblPerceptualRoughness[2] *= fact;
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

正在加载...
取消
保存