浏览代码

Merge pull request #1339 from Unity-Technologies/stacklit

Stacklit
/main
GitHub 7 年前
当前提交
c91916ff
共有 7 个文件被更改,包括 543 次插入121 次删除
  1. 37
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Material/StackLit/StackLitUI.cs
  2. 14
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/StackLit/StackLit.cs
  3. 109
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/StackLit/StackLit.cs.hlsl
  4. 451
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/StackLit/StackLit.hlsl
  5. 20
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/StackLit/StackLit.shader
  6. 13
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/StackLit/StackLitData.hlsl
  7. 20
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/StackLit/StackLitProperties.hlsl

37
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Material/StackLit/StackLitUI.cs


protected const string k_CoatIor = "_CoatIor";
protected const string k_CoatThickness = "_CoatThickness";
protected const string k_CoatExtinction = "_CoatExtinction";
protected const string k_EnableCoatNormalMap = "_EnableCoatNormalMap";
protected const string k_CoatNormalMap = "_CoatNormalMap";
protected const string k_CoatNormalMapUV = "_CoatNormalMapUV";
protected const string k_CoatNormalScale = "_CoatNormalScale";
// SSS
protected const string k_EnableSubsurfaceScattering = "_EnableSubsurfaceScattering";

protected const string kStencilRefMV = "_StencilRefMV";
protected const string kStencilWriteMaskMV = "_StencilWriteMaskMV";
protected const string k_SpecularAntiAliasingEnabled = "_SpecularAntiAliasingEnabled";
protected const string k_NormalCurvatureToRoughnessEnabled = "_NormalCurvatureToRoughnessEnabled";
#endregion
// Add the properties into an array.

private Property EnableSSS;
private Property EnableTransmission;
private Property EnableCoat;
private Property EnableCoatNormalMap;
private Property EnableSpecularAA;
private Property EnableNormalCurvatureToRoughness;
public StackLitGUI()
{
_baseMaterialProperties = new GroupProperty(this, "_BaseMaterial", new BaseProperty[]

EnableSSS = new Property(this, k_EnableSubsurfaceScattering, "Enable Subsurface Scattering", "Enable Subsurface Scattering", true);
EnableTransmission = new Property(this, k_EnableTransmission, "Enable Transmission", "Enable Transmission", true);
EnableCoat = new Property(this, k_EnableCoat, "Enable Coat", "Enable coat layer with true vertical physically based BSDF mixing", true);
EnableCoatNormalMap = new Property(this, k_EnableCoatNormalMap, "Enable Coat Normal Map", "Enable separate top coat normal map", true);
EnableSpecularAA = new Property(this, k_SpecularAntiAliasingEnabled, k_SpecularAntiAliasingEnabled, k_SpecularAntiAliasingEnabled, true);
EnableNormalCurvatureToRoughness = new Property(this, k_NormalCurvatureToRoughnessEnabled, k_NormalCurvatureToRoughnessEnabled, k_NormalCurvatureToRoughnessEnabled, true);
// All material properties
_materialProperties = new GroupProperty(this, "_Material", new BaseProperty[]

EnableDualSpecularLobe,
EnableAnisotropy,
EnableCoat,
EnableCoatNormalMap,
EnableIridescence,
EnableSSS,
EnableTransmission

new TextureProperty(this, k_MetallicMap, k_Metallic, "Metallic", "Metallic", false, false),
new Property(this, k_DielectricIor, "DieletricIor", "IOR use for dielectric material (i.e non metallic material)", false),
new TextureProperty(this, k_SmoothnessAMap, k_SmoothnessA, "Smoothness", "Smoothness", false, false),
new TextureProperty(this, k_NormalMap, k_NormalScale, "Normal", "Normal Map", false, false, true),
new TextureProperty(this, k_NormalMap, k_NormalScale, "Normal", "Normal Map", true, false, true),
new TextureProperty(this, k_AmbientOcclusionMap, k_AmbientOcclusion, "AmbientOcclusion", "AmbientOcclusion Map", false, false),
}),

new GroupProperty(this, "_Coat", "Coat", new BaseProperty[]
{
new TextureProperty(this, k_CoatSmoothnessMap, k_CoatSmoothness, "Coat smoothness", "Coat smoothness", false),
new TextureProperty(this, k_CoatNormalMap, k_CoatNormalScale, "Coat Normal Map", "Coat Normal Map", true, false, true, _ => EnableCoatNormalMap.BoolValue == true),
new Property(this, "_CoatIor", "Coat IOR", "Index of refraction", false),
new Property(this, "_CoatThickness", "Coat Thickness", "Coat thickness", false),
new Property(this, "_CoatExtinction", "Coat Absorption", "Coat absorption tint (the thicker the coat, the more that color is removed)", false),

new GroupProperty(this, "_Debug", "Debug", new BaseProperty[]
{
new Property(this, "_VlayerRecomputePerLight", "Vlayer Recompute Per Light", "", false),
EnableSpecularAA,
new Property(this, "_SpecularAntiAliasingScreenSpaceVariance", "Specular Aliasing Enable", "Specular Aliasing Enable", false, _ => EnableSpecularAA.BoolValue == true),
new Property(this, "_SpecularAntiAliasingThreshold", "Specular Aliasing Enable", "Specular Aliasing Enable", false, _ => EnableSpecularAA.BoolValue == true),
EnableNormalCurvatureToRoughness,
new Property(this, "_NormalCurvatureToRoughnessScale", "Normal Curvature To Roughness Scale", "Normal Curvature To Roughness Scale", false, _ => EnableNormalCurvatureToRoughness.BoolValue == true),
new Property(this, "_NormalCurvatureToRoughnessBias", "Normal Curvature To Roughness Bias", "Normal Curvature To Roughness Bias", false, _ => EnableNormalCurvatureToRoughness.BoolValue == true),
new Property(this, "_NormalCurvatureToRoughnessExponent", "Normal Curvature To Roughness Exponent", "Normal Curvature To Roughness Exponent", false, _ => EnableNormalCurvatureToRoughness.BoolValue == true),
}),
});
}

(TextureProperty.UVMapping) material.GetFloat(k_AnisotropyMapUV),
(TextureProperty.UVMapping) material.GetFloat(k_IridescenceThicknessMapUV),
(TextureProperty.UVMapping) material.GetFloat(k_CoatSmoothnessMapUV),
(TextureProperty.UVMapping) material.GetFloat(k_CoatNormalMapUV),
};
// Set keyword for mapping

bool coatEnabled = material.HasProperty(k_EnableCoat) && material.GetFloat(k_EnableCoat) > 0.0f;
CoreUtils.SetKeyword(material, "_MATERIAL_FEATURE_COAT", coatEnabled);
bool coatNormalMapEnabled = material.HasProperty(k_EnableCoatNormalMap) && material.GetFloat(k_EnableCoatNormalMap) > 0.0f;
CoreUtils.SetKeyword(material, "_MATERIAL_FEATURE_COAT_NORMALMAP", coatNormalMapEnabled);
bool vlayerRecomputePerLight = material.HasProperty("_VlayerRecomputePerLight") && material.GetFloat("_VlayerRecomputePerLight") > 0.0f;
CoreUtils.SetKeyword(material, "_VLAYERED_RECOMPUTE_PERLIGHT", vlayerRecomputePerLight);
// Set the reference value for the stencil test - required for SSS

14
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/StackLit/StackLit.cs


StackLitIridescence = 1 << 4,
StackLitSubsurfaceScattering = 1 << 5,
StackLitTransmission = 1 << 6,
StackLitCoatNormalMap = 1 << 7,
};
//-----------------------------------------------------------------------------

[SurfaceDataAttributes(new string[]{"Normal", "Normal View Space"}, true)]
public Vector3 normalWS;
[SurfaceDataAttributes(new string[]{"Geometric Normal", "Geometric Normal View Space"}, true)]
public Vector3 geomNormalWS;
[SurfaceDataAttributes(new string[]{"Coat Normal", "Coat Normal View Space"}, true)]
public Vector3 coatNormalWS;
[SurfaceDataAttributes("Smoothness A")]
public float perceptualSmoothnessA;

[SurfaceDataAttributes(new string[] { "Normal WS", "Normal View Space" }, true)]
public Vector3 normalWS;
[SurfaceDataAttributes(new string[]{"Geometric Normal", "Geometric Normal View Space"}, true)]
public Vector3 geomNormalWS;
[SurfaceDataAttributes(new string[]{"Coat Normal", "Coat Normal View Space"}, true)]
public Vector3 coatNormalWS;
public float perceptualRoughnessA;
// Dual specular lobe

109
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/StackLit/StackLit.cs.hlsl


#define MATERIALFEATUREFLAGS_STACK_LIT_IRIDESCENCE (16)
#define MATERIALFEATUREFLAGS_STACK_LIT_SUBSURFACE_SCATTERING (32)
#define MATERIALFEATUREFLAGS_STACK_LIT_TRANSMISSION (64)
#define MATERIALFEATUREFLAGS_STACK_LIT_COAT_NORMAL_MAP (128)
//
// UnityEngine.Experimental.Rendering.HDPipeline.StackLit+SurfaceData: static fields

#define DEBUGVIEW_STACKLIT_SURFACEDATA_IOR (1304)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_NORMAL (1305)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_NORMAL_VIEW_SPACE (1306)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_SMOOTHNESS_A (1307)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_SMOOTHNESS_B (1308)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_LOBE_MIXING (1309)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_TANGENT (1310)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_ANISOTROPY (1311)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_IRIDESCENCE_IOR (1312)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_IRIDESCENCE_THICKNESS (1313)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_COAT_SMOOTHNESS (1314)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_COAT_IOR (1315)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_COAT_THICKNESS (1316)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_COAT_EXTINCTION_COEFFICIENT (1317)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_DIFFUSION_PROFILE (1318)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_SUBSURFACE_MASK (1319)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_THICKNESS (1320)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_GEOMETRIC_NORMAL (1307)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_GEOMETRIC_NORMAL_VIEW_SPACE (1308)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_COAT_NORMAL (1309)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_COAT_NORMAL_VIEW_SPACE (1310)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_SMOOTHNESS_A (1311)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_SMOOTHNESS_B (1312)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_LOBE_MIXING (1313)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_TANGENT (1314)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_ANISOTROPY (1315)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_IRIDESCENCE_IOR (1316)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_IRIDESCENCE_THICKNESS (1317)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_COAT_SMOOTHNESS (1318)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_COAT_IOR (1319)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_COAT_THICKNESS (1320)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_COAT_EXTINCTION_COEFFICIENT (1321)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_DIFFUSION_PROFILE (1322)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_SUBSURFACE_MASK (1323)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_THICKNESS (1324)
//
// UnityEngine.Experimental.Rendering.HDPipeline.StackLit+BSDFData: static fields

#define DEBUGVIEW_STACKLIT_BSDFDATA_AMBIENT_OCCLUSION (1403)
#define DEBUGVIEW_STACKLIT_BSDFDATA_NORMAL_WS (1404)
#define DEBUGVIEW_STACKLIT_BSDFDATA_NORMAL_VIEW_SPACE (1405)
#define DEBUGVIEW_STACKLIT_BSDFDATA_PERCEPTUAL_ROUGHNESS_A (1406)
#define DEBUGVIEW_STACKLIT_BSDFDATA_PERCEPTUAL_ROUGHNESS_B (1407)
#define DEBUGVIEW_STACKLIT_BSDFDATA_LOBE_MIX (1408)
#define DEBUGVIEW_STACKLIT_BSDFDATA_TANGENT_WS (1409)
#define DEBUGVIEW_STACKLIT_BSDFDATA_BITANGENT_WS (1410)
#define DEBUGVIEW_STACKLIT_BSDFDATA_ROUGHNESS_AT (1411)
#define DEBUGVIEW_STACKLIT_BSDFDATA_ROUGHNESS_AB (1412)
#define DEBUGVIEW_STACKLIT_BSDFDATA_ROUGHNESS_BT (1413)
#define DEBUGVIEW_STACKLIT_BSDFDATA_ROUGHNESS_BB (1414)
#define DEBUGVIEW_STACKLIT_BSDFDATA_ANISOTROPY (1415)
#define DEBUGVIEW_STACKLIT_BSDFDATA_COAT_ROUGHNESS (1416)
#define DEBUGVIEW_STACKLIT_BSDFDATA_COAT_PERCEPTUAL_ROUGHNESS (1417)
#define DEBUGVIEW_STACKLIT_BSDFDATA_COAT_IOR (1418)
#define DEBUGVIEW_STACKLIT_BSDFDATA_COAT_THICKNESS (1419)
#define DEBUGVIEW_STACKLIT_BSDFDATA_COAT_EXTINCTION (1420)
#define DEBUGVIEW_STACKLIT_BSDFDATA_IRIDESCENCE_IOR (1421)
#define DEBUGVIEW_STACKLIT_BSDFDATA_IRIDESCENCE_THICKNESS (1422)
#define DEBUGVIEW_STACKLIT_BSDFDATA_DIFFUSION_PROFILE (1423)
#define DEBUGVIEW_STACKLIT_BSDFDATA_SUBSURFACE_MASK (1424)
#define DEBUGVIEW_STACKLIT_BSDFDATA_THICKNESS (1425)
#define DEBUGVIEW_STACKLIT_BSDFDATA_USE_THICK_OBJECT_MODE (1426)
#define DEBUGVIEW_STACKLIT_BSDFDATA_TRANSMITTANCE (1427)
#define DEBUGVIEW_STACKLIT_BSDFDATA_GEOMETRIC_NORMAL (1406)
#define DEBUGVIEW_STACKLIT_BSDFDATA_GEOMETRIC_NORMAL_VIEW_SPACE (1407)
#define DEBUGVIEW_STACKLIT_BSDFDATA_COAT_NORMAL (1408)
#define DEBUGVIEW_STACKLIT_BSDFDATA_COAT_NORMAL_VIEW_SPACE (1409)
#define DEBUGVIEW_STACKLIT_BSDFDATA_PERCEPTUAL_ROUGHNESS_A (1410)
#define DEBUGVIEW_STACKLIT_BSDFDATA_PERCEPTUAL_ROUGHNESS_B (1411)
#define DEBUGVIEW_STACKLIT_BSDFDATA_LOBE_MIX (1412)
#define DEBUGVIEW_STACKLIT_BSDFDATA_TANGENT_WS (1413)
#define DEBUGVIEW_STACKLIT_BSDFDATA_BITANGENT_WS (1414)
#define DEBUGVIEW_STACKLIT_BSDFDATA_ROUGHNESS_AT (1415)
#define DEBUGVIEW_STACKLIT_BSDFDATA_ROUGHNESS_AB (1416)
#define DEBUGVIEW_STACKLIT_BSDFDATA_ROUGHNESS_BT (1417)
#define DEBUGVIEW_STACKLIT_BSDFDATA_ROUGHNESS_BB (1418)
#define DEBUGVIEW_STACKLIT_BSDFDATA_ANISOTROPY (1419)
#define DEBUGVIEW_STACKLIT_BSDFDATA_COAT_ROUGHNESS (1420)
#define DEBUGVIEW_STACKLIT_BSDFDATA_COAT_PERCEPTUAL_ROUGHNESS (1421)
#define DEBUGVIEW_STACKLIT_BSDFDATA_COAT_IOR (1422)
#define DEBUGVIEW_STACKLIT_BSDFDATA_COAT_THICKNESS (1423)
#define DEBUGVIEW_STACKLIT_BSDFDATA_COAT_EXTINCTION (1424)
#define DEBUGVIEW_STACKLIT_BSDFDATA_IRIDESCENCE_IOR (1425)
#define DEBUGVIEW_STACKLIT_BSDFDATA_IRIDESCENCE_THICKNESS (1426)
#define DEBUGVIEW_STACKLIT_BSDFDATA_DIFFUSION_PROFILE (1427)
#define DEBUGVIEW_STACKLIT_BSDFDATA_SUBSURFACE_MASK (1428)
#define DEBUGVIEW_STACKLIT_BSDFDATA_THICKNESS (1429)
#define DEBUGVIEW_STACKLIT_BSDFDATA_USE_THICK_OBJECT_MODE (1430)
#define DEBUGVIEW_STACKLIT_BSDFDATA_TRANSMITTANCE (1431)
// Generated from UnityEngine.Experimental.Rendering.HDPipeline.StackLit+SurfaceData
// PackingRules = Exact

float metallic;
float dielectricIor;
float3 normalWS;
float3 geomNormalWS;
float3 coatNormalWS;
float perceptualSmoothnessA;
float perceptualSmoothnessB;
float lobeMix;

float3 fresnel0;
float ambientOcclusion;
float3 normalWS;
float3 geomNormalWS;
float3 coatNormalWS;
float perceptualRoughnessA;
float perceptualRoughnessB;
float lobeMix;

case DEBUGVIEW_STACKLIT_SURFACEDATA_NORMAL_VIEW_SPACE:
result = surfacedata.normalWS * 0.5 + 0.5;
break;
case DEBUGVIEW_STACKLIT_SURFACEDATA_GEOMETRIC_NORMAL:
result = surfacedata.geomNormalWS * 0.5 + 0.5;
break;
case DEBUGVIEW_STACKLIT_SURFACEDATA_GEOMETRIC_NORMAL_VIEW_SPACE:
result = surfacedata.geomNormalWS * 0.5 + 0.5;
break;
case DEBUGVIEW_STACKLIT_SURFACEDATA_COAT_NORMAL:
result = surfacedata.coatNormalWS * 0.5 + 0.5;
break;
case DEBUGVIEW_STACKLIT_SURFACEDATA_COAT_NORMAL_VIEW_SPACE:
result = surfacedata.coatNormalWS * 0.5 + 0.5;
break;
case DEBUGVIEW_STACKLIT_SURFACEDATA_SMOOTHNESS_A:
result = surfacedata.perceptualSmoothnessA.xxx;
break;

break;
case DEBUGVIEW_STACKLIT_BSDFDATA_NORMAL_VIEW_SPACE:
result = bsdfdata.normalWS * 0.5 + 0.5;
break;
case DEBUGVIEW_STACKLIT_BSDFDATA_GEOMETRIC_NORMAL:
result = bsdfdata.geomNormalWS * 0.5 + 0.5;
break;
case DEBUGVIEW_STACKLIT_BSDFDATA_GEOMETRIC_NORMAL_VIEW_SPACE:
result = bsdfdata.geomNormalWS * 0.5 + 0.5;
break;
case DEBUGVIEW_STACKLIT_BSDFDATA_COAT_NORMAL:
result = bsdfdata.coatNormalWS * 0.5 + 0.5;
break;
case DEBUGVIEW_STACKLIT_BSDFDATA_COAT_NORMAL_VIEW_SPACE:
result = bsdfdata.coatNormalWS * 0.5 + 0.5;
break;
case DEBUGVIEW_STACKLIT_BSDFDATA_PERCEPTUAL_ROUGHNESS_A:
result = bsdfdata.perceptualRoughnessA.xxx;

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


// Vlayer config options:
//#define VLAYERED_RECOMPUTE_PERLIGHT // TODO test more, make it a shader_features
#ifdef _VLAYERED_RECOMPUTE_PERLIGHT
# define VLAYERED_RECOMPUTE_PERLIGHT
// Now a shader_features
#endif
//#define VLAYERED_USE_REFRACTED_ANGLES_FOR_BASE
#define VLAYERED_DIFFUSE_ENERGY_HACKED_TERM
//#define VLAYERED_ANISOTROPY_IBL_DESTRETCH

// Mostly for struct array declarations, not really loops:
#ifdef _MATERIAL_FEATURE_COAT
#ifdef _MATERIAL_FEATURE_COAT_NORMALMAP
# define NB_NORMALS 2 // NB of interfaces with different normals (for additional clear coat normal map)
#else
# define NB_NORMALS 1
#endif
#else
#else // _MATERIAL_FEATURE_COAT
# undef _MATERIAL_FEATURE_COAT_NORMALMAP // enforce a "coat enabled subfeature" condition on this shader_feature
# define NB_NORMALS 1
#endif
#endif // #ifdef _MATERIAL_FEATURE_COAT
// For NB_NORMALS arrays:
#define COAT_NORMAL_IDX 0
#define BASE_NORMAL_IDX (NB_NORMALS-1)
// TODO: if dual lobe base
//#define BASE_NB_LOBES 1

bool IsVLayeredEnabled(BSDFData bsdfData)
{
return (HasFeatureFlag(bsdfData.materialFeatures, MATERIALFEATUREFLAGS_STACK_LIT_COAT));
}
bool IsCoatNormalMapEnabled(BSDFData bsdfData)
{
return (HasFeatureFlag(bsdfData.materialFeatures, MATERIALFEATUREFLAGS_STACK_LIT_COAT_NORMAL_MAP));
}
// Assume that bsdfData.diffusionProfile is init

return sssData;
}
// Specular antialiasing
float NormalCurvatureToRoughness(float3 n)
{
float3 dNdx = ddx(n);
float3 dNdy = ddy(n);
float curvature = pow(max(dot(dNdx, dNdx), dot(dNdy, dNdy)), _NormalCurvatureToRoughnessExponent);
return saturate(curvature * _NormalCurvatureToRoughnessScale + _NormalCurvatureToRoughnessBias);
}
float FilterRoughness_TOKUYOSHI(float3 n, float r)
{
float3 deltaU = ddx(n);
float3 deltaV = ddy(n);
float variance = _SpecularAntiAliasingScreenSpaceVariance * (dot(deltaU, deltaU) + dot(deltaV, deltaV));
float squaredRoughness = saturate(r * r + min(2.0 * variance, _SpecularAntiAliasingThreshold));
return sqrt(squaredRoughness);
}
//-----------------------------------------------------------------------------
// conversion function for forward
//-----------------------------------------------------------------------------

// IMPORTANT: In our forward only case, all enable flags are statically know at compile time, so the compiler can do compile time optimization
bsdfData.materialFeatures = surfaceData.materialFeatures;
bsdfData.geomNormalWS = surfaceData.geomNormalWS; // We should always have this whether we enable coat normals or not.
// Specular AA: NormalCurvatureToRoughness
float normalCurvatureToRoughnessA = max(NormalCurvatureToRoughness(bsdfData.normalWS), bsdfData.perceptualRoughnessA);
float normalCurvatureToRoughnessB = max(NormalCurvatureToRoughness(bsdfData.normalWS), bsdfData.perceptualRoughnessB);
bsdfData.perceptualRoughnessA = lerp(bsdfData.perceptualRoughnessA, normalCurvatureToRoughnessA, _NormalCurvatureToRoughnessEnabled);
bsdfData.perceptualRoughnessB = lerp(bsdfData.perceptualRoughnessB, normalCurvatureToRoughnessB, _NormalCurvatureToRoughnessEnabled);
// Specular AA: Tokuyoshi Filtering.
float filterRoughnessA = FilterRoughness_TOKUYOSHI(bsdfData.normalWS, bsdfData.perceptualRoughnessA);
float filterRoughnessB = FilterRoughness_TOKUYOSHI(bsdfData.normalWS, bsdfData.perceptualRoughnessB);
bsdfData.perceptualRoughnessA = lerp(bsdfData.perceptualRoughnessA, filterRoughnessA, _SpecularAntiAliasingEnabled);
bsdfData.perceptualRoughnessB = lerp(bsdfData.perceptualRoughnessB, filterRoughnessB, _SpecularAntiAliasingEnabled);
bsdfData.lobeMix = surfaceData.lobeMix;
// There is no metallic with SSS and specular color mode

if (HasFeatureFlag(surfaceData.materialFeatures, MATERIALFEATUREFLAGS_STACK_LIT_COAT))
{
if (HasFeatureFlag(surfaceData.materialFeatures, MATERIALFEATUREFLAGS_STACK_LIT_COAT_NORMAL_MAP))
{
bsdfData.coatNormalWS = surfaceData.coatNormalWS;
}
FillMaterialCoatData(PerceptualSmoothnessToPerceptualRoughness(surfaceData.coatPerceptualSmoothness),
surfaceData.coatIor, surfaceData.coatThickness, surfaceData.coatExtinction, bsdfData);

// Precomputed lighting data to send to the various lighting functions
struct PreLightData
{
float NdotV; // Could be negative due to normal mapping, use ClampNdotV()
float NdotV[NB_NORMALS]; // Could be negative due to normal mapping, use ClampNdotV()
//float NdotV;
float bottomAngleFGD;
float TdotV; // Stored only when VLAYERED_RECOMPUTE_PERLIGHT
float BdotV;

return newAniso;
}
// Get the orthogonal component (or complement) of a vector V with regard to the vector N.
float3 GetOrthogonalComponent(float3 V, float3 N)
{
// V and N are supposed to be unit vectors
float VdotN = dot(V, N);
float3 VOrtho = V - VdotN * N;
float3 unitVOrtho = VOrtho * rsqrt(1.0 - Sq(VdotN));
return unitVOrtho;
}
float3 GetDirFromAngleAndOrthoFrame(float3 V, float3 N, float newVdotN)
{
float sintheta = sqrt(1.0 - Sq(newVdotN));
float3 newV = newVdotN * N + sintheta * V;
return newV;
}
void ComputeAdding_GetVOrthoGeomN(BSDFData bsdfData, float3 V, bool calledPerLight, out float3 vOrthoGeomN, out bool useGeomN)
{
vOrthoGeomN = (float3)0;
useGeomN = false;
if( !calledPerLight && IsCoatNormalMapEnabled(bsdfData) )
{
// In that case, since we have 2 normal maps we need to decide on a common orientation
// for our parallel interface model, otherwise the series expression doesn't make any
// sense. We will settle on using the geometric normal. It will be used for
// average mean propagation but all FGD or Fresnel terms will use the corresponding
// interface's normal map's normal for calculation. IBL fetches and lighting
// calculations (shading) for analytical lights should also use these.
// The rational for the later is that the resulting stats are still a local model, so
// all scattered rays should exit back up with the same normal as the ray that spawned
// them had on entry on top. So we assume bending is cancelled out.
//
// Also, since we are using a fake (and adjusted / lerped depending on roughness)
// refraction for the top (coat) interface, and this will be done, like stated,
// using the geometric normal, we will reconstruct a direction for the bottom
// interface using the "V and geomNormalWS" plane as a plane of incidence. So we
// calculate a pseudo-refracted angle in this plane, and with an orthogonal basis
// of it (using the orthogonal complement of V vs geomNormalWS), we will reconstruct
// the "V at the bottom interface". This V will then in turn be usable for further
// FGD / Fresnel calculations with the bottom interface normal (from the bottom
// normal map), which is not necessarily coplanar with V and geomNormalWS, hence
// this method.
//
// In all other cases: we either don't have a dual normal map, or we recompute the
// stats per light and in that case, the H vector serves as a common orientation
// and we calculate everything with it anyway (symmetric parametrization), so no
// normal map is involved.
vOrthoGeomN = GetOrthogonalComponent(V, bsdfData.geomNormalWS);
useGeomN = true;
}
}
//-----------------------------------------------------------------------------
// About layered BSDF statistical lobe data calculations:

// T12 should be multiplied by TIR.
// (more like p8, T21 <- T21*TIR, R21 <- R21 + (1-TIR)*T21 )
//
void ComputeStatistics(in float cti, in int i, in BSDFData bsdfData,
//ComputeStatistics(cti, V, vOrthoGeomN, useGeomN, i, bsdfData, preLightData, ctt, R12, T12, R21, T21, s_r12, s_t12, j12, s_r21, s_t21, j21);
void ComputeStatistics(in float cti, in float3 V, in float3 vOrthoGeomN, in bool useGeomN, in int i, in BSDFData bsdfData,
inout PreLightData preLightData,
out float ctt,
out float3 R12, out float3 T12, out float3 R21, out float3 T21,
out float s_r12, out float s_t12, out float j12,

n12 = GetCoatEta(bsdfData); //n2/n1;
R0 = FresnelUnpolarized(cti, n12, 1.0);
// At this point cti should be properly (coatNormalWS dot V) or NdotV or VdotH, see ComputeAdding.
// In the special case where we do have a coat normal, we will propagate a different angle than
// (coatNormalWS dot V) and vOrthoGeomN will be used.
if (useGeomN)
{
cti = ClampNdotV(dot(bsdfData.geomNormalWS, V));
}
R12 = R0; // TODO: FGD
T12 = 1.0 - R12;
R21 = R12;

}
else
{
float ctiForFGD = cti;
// If we use the geometric normal propagation hack, we want to calculate FGD / Fresnel with
// an angle at the bottom interface between the average propagated direction and the normal from
// the bottom normal map. For that, we will recover a direction from the angle we propagated in
// the "V and geomNormalWS" plane of incidence. That direction will then serve to calculate an
// angle with the non-coplanar bottom normal from the normal map.
if (useGeomN)
{
float3 bottomDir = GetDirFromAngleAndOrthoFrame(vOrthoGeomN, bsdfData.geomNormalWS, cti);
ctiForFGD = ClampNdotV(dot(bsdfData.normalWS, bottomDir));
}
// We will also save this average bottom angle:
preLightData.bottomAngleFGD = ctiForFGD;
R12 = F_Schlick(bsdfData.fresnel0, cti);
R12 = F_Schlick(bsdfData.fresnel0, ctiForFGD);
T12 = 0.0;
#ifdef VLAYERED_DIFFUSE_ENERGY_HACKED_TERM
// Still should use FGD!

} //...ComputeStatistics()
void ComputeAdding(float _cti, in BSDFData bsdfData, inout PreLightData preLightData, bool calledPerLight = false)
void ComputeAdding(float _cti, float3 V, in BSDFData bsdfData, inout PreLightData preLightData, bool calledPerLight = false)
// _cti should be LdotH or VdotH if calledPerLight == true (symmetric parametrization), V is unused in this case.
// _cti should be NdotV if calledPerLight == false and no independent coat normal map is used (ie single normal map), V is unused in this case.
// _cti should be (coatNormalWS dot V) if calledPerLight == false and we have a coat normal map. V is used in this case
#ifdef VLAYERED_DEBUG
if( _DebugLobeMask.w == 0.0)

#endif
// Global Variables
// Decide if we need the special path/hack for the coat normal map mode:
bool useGeomN;
float3 vOrthoGeomN; // only valid if useGeomN == true
ComputeAdding_GetVOrthoGeomN(bsdfData, V, calledPerLight, vOrthoGeomN, useGeomN);
float cti = _cti;
float3 R0i = float3(0.0, 0.0, 0.0), Ri0 = float3(0.0, 0.0, 0.0),
T0i = float3(1.0, 1.0, 1.0), Ti0 = float3(1.0, 1.0, 1.0);

float s_r21=0.0, s_t12=0.0, s_t21=0.0, j12=1.0, j21=1.0, ctt;
// Layer specific evaluation of the transmittance, reflectance, variance
ComputeStatistics(cti, i, bsdfData, ctt, R12, T12, R21, T21, s_r12, s_t12, j12, s_r21, s_t21, j21);
ComputeStatistics(cti, V, vOrthoGeomN, useGeomN, i, bsdfData, preLightData, ctt, R12, T12, R21, T21, s_r12, s_t12, j12, s_r21, s_t21, j21);
// Multiple scattering forms
float3 denom = (float3(1.0, 1.0, 1.0) - Ri0*R12); //i = new layer, 0 = cumulative top (llab3.1 to 3.4)

}
#endif
if( !perLightOption )
if( !perLightOption || calledPerLight)
{
ConvertAnisotropyToClampRoughness(preLightData.iblPerceptualRoughness[BASE_LOBEA_IDX], preLightData.iblAnisotropy[0],
preLightData.layeredRoughnessT[0], preLightData.layeredRoughnessB[0]);

// slnote dual map
float PreLightData_GetBaseNdotVForFGD(BSDFData bsdfData, PreLightData preLightData, float NdotV[NB_NORMALS])
{
float baseLayerNdotV;
if ( IsCoatNormalMapEnabled(bsdfData) )
{
//slnote
baseLayerNdotV = preLightData.bottomAngleFGD;
}
else
{
//slnote: TODO TOTEST
//baseLayerNdotV = preLightData.bottomAngleFGD;
baseLayerNdotV = sqrt(1 + Sq(preLightData.coatIeta)*(Sq(NdotV[0]) - 1));
//TODO refactor with EvalIridescence, Lit::GetPreLightData
}
return baseLayerNdotV;
}
// slnote dual map
void PreLightData_SetupNormals(BSDFData bsdfData, inout PreLightData preLightData, float3 V, out float3 N[NB_NORMALS], out float NdotV[NB_NORMALS])
{
N[BASE_NORMAL_IDX] = bsdfData.normalWS;
preLightData.NdotV[BASE_NORMAL_IDX] = dot(N[BASE_NORMAL_IDX], V);
NdotV[BASE_NORMAL_IDX] = ClampNdotV(preLightData.NdotV[BASE_NORMAL_IDX]);
#ifdef _MATERIAL_FEATURE_COAT_NORMALMAP
if ( IsCoatNormalMapEnabled(bsdfData) )
{
N[COAT_NORMAL_IDX] = bsdfData.coatNormalWS;
preLightData.NdotV[COAT_NORMAL_IDX] = dot(N[COAT_NORMAL_IDX], V);
NdotV[COAT_NORMAL_IDX] = ClampNdotV(preLightData.NdotV[COAT_NORMAL_IDX]);
}
#endif
}
PreLightData GetPreLightData(float3 V, PositionInputs posInput, inout BSDFData bsdfData)
{

float3 N = bsdfData.normalWS;
preLightData.NdotV = dot(N, V);
float NdotV = ClampNdotV(preLightData.NdotV);
float3 N[NB_NORMALS];
float NdotV[NB_NORMALS];
// slnote dual map
PreLightData_SetupNormals(bsdfData, preLightData, V, N, NdotV);
preLightData.diffuseEnergy = float3(1.0, 1.0, 1.0);

// iblR (fetch direction compensated dominant spec)
// iblR (fetch direction in dominant spec direction / compensated for offspecular effect)
// energyCompensation (to a apply for each light sample since with multiple roughnesses, it becomes lobe specific)
// energyCompensation (to apply for each light sample since with multiple roughnesses, it becomes lobe specific)
//
// We also need for analytical lights:
//

float3 iblR[TOTAL_NB_LOBES];
float specularReflectivity[TOTAL_NB_LOBES];
float diffuseFGD[BASE_NB_LOBES];
float baseLayerNdotV = NdotV;
//float baseLayerNdotV = NdotV; slnote
if( IsVLayeredEnabled(bsdfData) )
{

// --------------------------------------------------------------------
// A secondary coat normal map is possible here, NdotV[] and N[] are sized
// accordingly and are accessed by COAT|BASE_NORMAL_IDX
ComputeAdding(NdotV, bsdfData, preLightData, false);
ComputeAdding(NdotV[COAT_NORMAL_IDX], V, bsdfData, preLightData, false);
// After ComputeAdding, these are done for all lobes:
//

#ifndef VLAYERED_RECOMPUTE_PERLIGHT
// We can precalculate lambdaVs for all lights here since we're not doing ComputeAdding per light
preLightData.partLambdaV[COAT_LOBE_IDX] = GetSmithJointGGXPartLambdaV(NdotV, preLightData.layeredCoatRoughness);
preLightData.partLambdaV[BASE_LOBEA_IDX] = GetSmithJointGGXAnisoPartLambdaV(TdotV, BdotV, NdotV, preLightData.layeredRoughnessT[0], preLightData.layeredRoughnessB[0]);
preLightData.partLambdaV[BASE_LOBEB_IDX] = GetSmithJointGGXAnisoPartLambdaV(TdotV, BdotV, NdotV, preLightData.layeredRoughnessT[1], preLightData.layeredRoughnessB[1]);
preLightData.partLambdaV[COAT_LOBE_IDX] = GetSmithJointGGXPartLambdaV(NdotV[COAT_NORMAL_IDX], preLightData.layeredCoatRoughness);
preLightData.partLambdaV[BASE_LOBEA_IDX] = GetSmithJointGGXAnisoPartLambdaV(TdotV, BdotV, NdotV[BASE_NORMAL_IDX],
preLightData.layeredRoughnessT[0], preLightData.layeredRoughnessB[0]);
preLightData.partLambdaV[BASE_LOBEB_IDX] = GetSmithJointGGXAnisoPartLambdaV(TdotV, BdotV, NdotV[BASE_NORMAL_IDX],
preLightData.layeredRoughnessT[1], preLightData.layeredRoughnessB[1]);
#else
// Store those for eval analytical lights since we're going to
// recalculate lambdaV after each ComputeAdding for each light

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[COAT_LOBE_IDX] = N; // no anisotropy for coat.
iblN[BASE_LOBEA_IDX] = GetAnisotropicModifiedNormal(grainDirWS[0], N, V, stretch[0]);
iblN[BASE_LOBEB_IDX] = GetAnisotropicModifiedNormal(grainDirWS[1], N, V, stretch[1]);
iblN[COAT_LOBE_IDX] = N[COAT_NORMAL_IDX]; // no anisotropy for coat.
iblN[BASE_LOBEA_IDX] = GetAnisotropicModifiedNormal(grainDirWS[0], N[BASE_NORMAL_IDX], V, stretch[0]); // slnote dual map
iblN[BASE_LOBEB_IDX] = GetAnisotropicModifiedNormal(grainDirWS[1], N[BASE_NORMAL_IDX], V, stretch[1]);
}
else

// We can precalculate lambdaVs for all lights here since we're not doing ComputeAdding per light
preLightData.partLambdaV[COAT_LOBE_IDX] = GetSmithJointGGXPartLambdaV(NdotV, preLightData.layeredCoatRoughness);
preLightData.partLambdaV[BASE_LOBEA_IDX] = GetSmithJointGGXPartLambdaV(NdotV, preLightData.layeredRoughnessT[0]);
preLightData.partLambdaV[BASE_LOBEB_IDX] = GetSmithJointGGXPartLambdaV(NdotV, preLightData.layeredRoughnessT[1]);
preLightData.partLambdaV[COAT_LOBE_IDX] = GetSmithJointGGXPartLambdaV(NdotV[COAT_NORMAL_IDX], preLightData.layeredCoatRoughness);
preLightData.partLambdaV[BASE_LOBEA_IDX] = GetSmithJointGGXPartLambdaV(NdotV[BASE_NORMAL_IDX], preLightData.layeredRoughnessT[0]);
preLightData.partLambdaV[BASE_LOBEB_IDX] = GetSmithJointGGXPartLambdaV(NdotV[BASE_NORMAL_IDX], preLightData.layeredRoughnessT[1]);
iblN[0] = iblN[1] = iblN[2] = N;
iblN[COAT_LOBE_IDX] = N[COAT_NORMAL_IDX];
iblN[BASE_LOBEA_IDX] = iblN[BASE_LOBEB_IDX] = N[BASE_NORMAL_IDX]; // slnote dual map
} // anisotropy
// IBL

// 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.
baseLayerNdotV = sqrt(1 + Sq(preLightData.coatIeta)*(Sq(NdotV) - 1));
// slnote dual map: get base layer angle: could store it always from computeadding
//float baseLayerNdotV = sqrt(1 + Sq(preLightData.coatIeta)*(Sq(NdotV) - 1));
float baseLayerNdotV = PreLightData_GetBaseNdotVForFGD(bsdfData, preLightData, NdotV);
GetPreIntegratedFGDGGXAndDisneyDiffuse(NdotV,
GetPreIntegratedFGDGGXAndDisneyDiffuse(NdotV[COAT_NORMAL_IDX],
preLightData.iblPerceptualRoughness[COAT_LOBE_IDX],
preLightData.vLayerEnergyCoeff[TOP_VLAYER_IDX],
preLightData.specularFGD[COAT_LOBE_IDX],

// Notice again that the roughness and iblR properly use the output lobe statistics, but baseLayerNdotV
// is used for the offspecular correction because the true original offspecular tilt is parametrized by
// the angle at the base layer and the correction itself is influenced by that. See comments above.
preLightData.iblR[COAT_LOBE_IDX] = GetSpecularDominantDir(N, iblR[COAT_LOBE_IDX], preLightData.iblPerceptualRoughness[COAT_LOBE_IDX], NdotV);
preLightData.iblR[BASE_LOBEA_IDX] = GetSpecularDominantDir(N, iblR[BASE_LOBEA_IDX], preLightData.iblPerceptualRoughness[BASE_LOBEA_IDX], baseLayerNdotV);
preLightData.iblR[BASE_LOBEB_IDX] = GetSpecularDominantDir(N, iblR[BASE_LOBEB_IDX], preLightData.iblPerceptualRoughness[BASE_LOBEB_IDX], baseLayerNdotV);
preLightData.iblR[COAT_LOBE_IDX] = GetSpecularDominantDir(N[COAT_NORMAL_IDX], iblR[COAT_LOBE_IDX], preLightData.iblPerceptualRoughness[COAT_LOBE_IDX], NdotV[COAT_NORMAL_IDX]);
preLightData.iblR[BASE_LOBEA_IDX] = GetSpecularDominantDir(N[BASE_NORMAL_IDX], iblR[BASE_LOBEA_IDX], preLightData.iblPerceptualRoughness[BASE_LOBEA_IDX], baseLayerNdotV);
preLightData.iblR[BASE_LOBEB_IDX] = GetSpecularDominantDir(N[BASE_NORMAL_IDX], iblR[BASE_LOBEB_IDX], preLightData.iblPerceptualRoughness[BASE_LOBEB_IDX], baseLayerNdotV);
#ifdef LIT_USE_GGX_ENERGY_COMPENSATION
// TODOENERGY:

// NO VLAYERING:
// --------------------------------------------------------------------
// Only a single normal map possible here, NdotV[] and N[] are sized to 1
// See ConvertSurfaceDataToBSDFData : The later are already clamped if
// vlayering is disabled, so could be used directly, but for later
// refactoring (instead of BSDFdata A and B values, we should really

float TdotV = dot(bsdfData.tangentWS, V);
float BdotV = dot(bsdfData.bitangentWS, V);
preLightData.partLambdaV[0] = GetSmithJointGGXAnisoPartLambdaV(TdotV, BdotV, NdotV, preLightData.layeredRoughnessT[0], preLightData.layeredRoughnessB[0]);
preLightData.partLambdaV[1] = GetSmithJointGGXAnisoPartLambdaV(TdotV, BdotV, NdotV, preLightData.layeredRoughnessT[1], preLightData.layeredRoughnessB[1]);
preLightData.partLambdaV[0] = GetSmithJointGGXAnisoPartLambdaV(TdotV, BdotV, NdotV[0], preLightData.layeredRoughnessT[0], preLightData.layeredRoughnessB[0]);
preLightData.partLambdaV[1] = GetSmithJointGGXAnisoPartLambdaV(TdotV, BdotV, NdotV[0], preLightData.layeredRoughnessT[1], preLightData.layeredRoughnessB[1]);
// 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.

float stretch[2];
stretch[0] = abs(bsdfData.anisotropy) * saturate(5 * preLightData.iblPerceptualRoughness[0]);
stretch[1] = abs(bsdfData.anisotropy) * saturate(5 * preLightData.iblPerceptualRoughness[1]);
iblN[0] = GetAnisotropicModifiedNormal(grainDirWS, N, V, stretch[0]);
iblN[1] = GetAnisotropicModifiedNormal(grainDirWS, N, V, stretch[1]);
iblN[0] = GetAnisotropicModifiedNormal(grainDirWS, N[0], V, stretch[0]);
iblN[1] = GetAnisotropicModifiedNormal(grainDirWS, N[0], V, stretch[1]);
preLightData.partLambdaV[0] = GetSmithJointGGXPartLambdaV(NdotV, preLightData.layeredRoughnessT[0]);
preLightData.partLambdaV[1] = GetSmithJointGGXPartLambdaV(NdotV, preLightData.layeredRoughnessT[1]);
iblN[0] = iblN[1] = N;
preLightData.partLambdaV[0] = GetSmithJointGGXPartLambdaV(NdotV[0], preLightData.layeredRoughnessT[0]);
preLightData.partLambdaV[1] = GetSmithJointGGXPartLambdaV(NdotV[0], preLightData.layeredRoughnessT[1]);
iblN[0] = iblN[1] = N[0];
} // ...no anisotropy

GetPreIntegratedFGDGGXAndDisneyDiffuse(baseLayerNdotV, // just NdotV here...
GetPreIntegratedFGDGGXAndDisneyDiffuse(NdotV[0],
preLightData.iblPerceptualRoughness[BASE_LOBEA_IDX],
bsdfData.fresnel0,
preLightData.specularFGD[BASE_LOBEA_IDX],

GetPreIntegratedFGDGGXAndDisneyDiffuse(baseLayerNdotV,
GetPreIntegratedFGDGGXAndDisneyDiffuse(NdotV[0],
preLightData.iblPerceptualRoughness[BASE_LOBEB_IDX],
bsdfData.fresnel0,
preLightData.specularFGD[BASE_LOBEB_IDX],

preLightData.iblPerceptualRoughness[0] *= fact;
preLightData.iblPerceptualRoughness[1] *= fact;
// Correction of reflected direction for better handling of rough material
preLightData.iblR[0] = GetSpecularDominantDir(N, iblR[0], preLightData.iblPerceptualRoughness[0], NdotV);
preLightData.iblR[1] = GetSpecularDominantDir(N, iblR[1], preLightData.iblPerceptualRoughness[1], NdotV);
preLightData.iblR[0] = GetSpecularDominantDir(N[0], iblR[0], preLightData.iblPerceptualRoughness[0], NdotV[0]);
preLightData.iblR[1] = GetSpecularDominantDir(N[0], iblR[1], preLightData.iblPerceptualRoughness[1], NdotV[0]);
#ifdef LIT_USE_GGX_ENERGY_COMPENSATION
// Here, since this compensation term is already an average applied to a sum

//-----------------------------------------------------------------------------
// helpers
void BSDF_SetupNormals(BSDFData bsdfData, float3 L, out float3 N[NB_NORMALS], out float NdotL[NB_NORMALS])
{
N[BASE_NORMAL_IDX] = bsdfData.normalWS;
NdotL[BASE_NORMAL_IDX] = dot(N[BASE_NORMAL_IDX], L);
#ifdef _MATERIAL_FEATURE_COAT_NORMALMAP
if ( IsCoatNormalMapEnabled(bsdfData) )
{
N[COAT_NORMAL_IDX] = bsdfData.coatNormalWS;
NdotL[COAT_NORMAL_IDX] = dot(N[COAT_NORMAL_IDX], L);
}
#endif
}
void CalculateAnisoAngles(BSDFData bsdfData, float3 L, float3 V, float invLenLV, out float TdotH, out float TdotL, out float BdotH, out float BdotL)
{
float3 H = (L + V) * invLenLV;

BdotL = dot(bsdfData.bitangentWS, L);
}
void CalculateAngles(float3 L, float3 V, float NdotL, float unclampedNdotV,
out float LdotV, out float invLenLV, out float NdotH, out float LdotH, out float NdotV)
void CalculateAngles(BSDFData bsdfData, float3 L, float3 V, float NdotL[NB_NORMALS], float unclampedNdotV[NB_NORMALS],
out float LdotV, out float invLenLV, out float NdotH[NB_NORMALS], out float LdotH, out float NdotV[NB_NORMALS])
NdotH = saturate((NdotL + unclampedNdotV) * invLenLV); // Do not clamp NdotV here
NdotV = ClampNdotV(unclampedNdotV);
NdotH[BASE_NORMAL_IDX] = saturate((NdotL[BASE_NORMAL_IDX] + unclampedNdotV[BASE_NORMAL_IDX]) * invLenLV); // Do not clamp NdotV here
NdotV[BASE_NORMAL_IDX] = ClampNdotV(unclampedNdotV[BASE_NORMAL_IDX]);
#ifdef _MATERIAL_FEATURE_COAT_NORMALMAP
if ( IsCoatNormalMapEnabled(bsdfData) )
{
NdotH[COAT_NORMAL_IDX] = saturate((NdotL[COAT_NORMAL_IDX] + unclampedNdotV[COAT_NORMAL_IDX]) * invLenLV); // Do not clamp NdotV here
NdotV[COAT_NORMAL_IDX] = ClampNdotV(unclampedNdotV[COAT_NORMAL_IDX]);
}
#endif
void BSDF( float3 V, float3 L, float NdotL, float3 positionWS, PreLightData preLightData, BSDFData bsdfData,
void BSDF( float3 V, float3 L, float inNdotL, float3 positionWS, PreLightData preLightData, BSDFData bsdfData,
float3 N = bsdfData.normalWS;
//float3 N = bsdfData.normalWS; // slnote : dual normal maps
float3 N[NB_NORMALS];
float NdotL[NB_NORMALS];
BSDF_SetupNormals(bsdfData, L, N, NdotL);
float LdotV, invLenLV, NdotH, LdotH, NdotV;
float LdotV, invLenLV, NdotH[NB_NORMALS], LdotH, NdotV[NB_NORMALS];
// Optimized math. Ref: PBR Diffuse Lighting for GGX + Smith Microsurfaces (slide 114).
//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

CalculateAngles(L, V, NdotL, preLightData.NdotV, LdotV, invLenLV, NdotH, LdotH, NdotV);
CalculateAngles(bsdfData, L, V, NdotL, preLightData.NdotV, LdotV, invLenLV, NdotH, LdotH, NdotV);
float3 DV[TOTAL_NB_LOBES];

// Save top angles in case VLAYERED_USE_REFRACTED_ANGLES_FOR_BASE option is used
float topLdotH = LdotH; // == VdotH)
float topNdotH = NdotH;
float topNdotL = NdotL;
float topNdotV = NdotV;
#if VLAYERED_USE_REFRACTED_ANGLES_FOR_BASE
float topNdotH = NdotH[COAT_NORMAL_IDX];
float topNdotL = NdotL[COAT_NORMAL_IDX];
float topNdotV = NdotV[COAT_NORMAL_IDX];
#ifdef VLAYERED_USE_REFRACTED_ANGLES_FOR_BASE
// TODO: not done with dual normal maps
// Use the refracted angle at the bottom interface for BSDF calculations:
// Seems like the more correct ones to use, but not obvious as we have the energy

// byt ComputeAdding (by deriving azimuth dependent covariance operators).
// by ComputeAdding (for anisotropy by deriving azimuth dependent covariance operators).
// In both cases we need to work around it, so just to test:
// In both cases we need to work around it.
//
// Using refracted angles for BSDF eval for the base in the case of analytical lights
// must be seen as a hack on top of the ComputeAdding method in which we consider that
// even though the output (energy coefficients) of the method are statistical averages
// over all incoming light directions and so to be used in the context of a split sum
// approximation, the analytical lights have all their energy in a specific ray direction
// and moreover, currently, the output coefficients of the method are formed from straight
// Fresnel terms, and not FGD terms.
//
NdotL = dot(N,L);
NdotL = dot(N,L); // slnote : dual normal maps
//LdotV = dot(L, V);
//invLenLV = rsqrt(max(2.0 * LdotV + 2.0, FLT_EPS)); // invLenLV = rcp(length(L + V)), clamp to avoid rsqrt(0) = NaN

CalculateAngles(L, V, NdotL, dot(N, V), LdotV, invLenLV, NdotH, LdotH, NdotV);
CalculateAngles(L, V, NdotL, dot(N, V), LdotV, invLenLV, NdotH, LdotH, NdotV); // slnote : dual normal maps
#endif // #if VLAYERED_USE_REFRACTED_ANGLES_FOR_BASE
#endif // #ifdef VLAYERED_USE_REFRACTED_ANGLES_FOR_BASE
ComputeAdding(topLdotH, bsdfData, preLightData, true);
// Notice topLdotH as interface angle, symmetric model parametrization (see sec. 6 and comments
ComputeAdding(topLdotH, V, bsdfData, preLightData, true);
//slnote dual maps
//ComputeAdding(NdotV[COAT_NORMAL_IDX], V, bsdfData, preLightData, false);
// Notice topLdotH as interface angle, symmetric model parametrization (see paper sec. 6 and comments
// on ComputeAdding)
// layered*Roughness* and vLayerEnergyCoeff are now updated for the proper light direction.
preLightData.partLambdaV[COAT_LOBE_IDX] = GetSmithJointGGXPartLambdaV(topNdotV, preLightData.layeredCoatRoughness);

preLightData.TdotV = dot(bsdfData.tangentWS, V);
preLightData.BdotV = dot(bsdfData.bitangentWS, V);
#endif
preLightData.partLambdaV[BASE_LOBEA_IDX] = GetSmithJointGGXAnisoPartLambdaV(preLightData.TdotV, preLightData.BdotV, NdotV,
preLightData.partLambdaV[BASE_LOBEA_IDX] = GetSmithJointGGXAnisoPartLambdaV(preLightData.TdotV, preLightData.BdotV, NdotV[BASE_NORMAL_IDX],
preLightData.partLambdaV[BASE_LOBEB_IDX] = GetSmithJointGGXAnisoPartLambdaV(preLightData.TdotV, preLightData.BdotV, NdotV,
preLightData.partLambdaV[BASE_LOBEB_IDX] = GetSmithJointGGXAnisoPartLambdaV(preLightData.TdotV, preLightData.BdotV, NdotV[BASE_NORMAL_IDX],
preLightData.layeredRoughnessT[1], preLightData.layeredRoughnessB[1]);
#endif

DV[BASE_LOBEA_IDX] = DV_SmithJointGGXAniso(TdotH, BdotH, NdotH, NdotV, TdotL, BdotL, NdotL,
DV[BASE_LOBEA_IDX] = DV_SmithJointGGXAniso(TdotH, BdotH, NdotH[BASE_NORMAL_IDX], NdotV[BASE_NORMAL_IDX], TdotL, BdotL, NdotL[BASE_NORMAL_IDX],
DV[BASE_LOBEB_IDX] = DV_SmithJointGGXAniso(TdotH, BdotH, NdotH, NdotV, TdotL, BdotL, NdotL,
DV[BASE_LOBEB_IDX] = DV_SmithJointGGXAniso(TdotH, BdotH, NdotH[BASE_NORMAL_IDX], NdotV[BASE_NORMAL_IDX], TdotL, BdotL, NdotL[BASE_NORMAL_IDX],
preLightData.layeredRoughnessT[1], preLightData.layeredRoughnessB[1],
preLightData.partLambdaV[BASE_LOBEB_IDX]);

else
{
#ifdef VLAYERED_RECOMPUTE_PERLIGHT
preLightData.partLambdaV[BASE_LOBEA_IDX] = GetSmithJointGGXPartLambdaV(NdotV, preLightData.layeredRoughnessT[0]);
preLightData.partLambdaV[BASE_LOBEB_IDX] = GetSmithJointGGXPartLambdaV(NdotV, preLightData.layeredRoughnessT[1]);
preLightData.partLambdaV[BASE_LOBEA_IDX] = GetSmithJointGGXPartLambdaV(NdotV[BASE_NORMAL_IDX], preLightData.layeredRoughnessT[0]);
preLightData.partLambdaV[BASE_LOBEB_IDX] = GetSmithJointGGXPartLambdaV(NdotV[BASE_NORMAL_IDX], preLightData.layeredRoughnessT[1]);
DV[BASE_LOBEA_IDX] = DV_SmithJointGGX(NdotH, NdotL, NdotV, preLightData.layeredRoughnessT[0], preLightData.partLambdaV[BASE_LOBEA_IDX]);
DV[BASE_LOBEB_IDX] = DV_SmithJointGGX(NdotH, NdotL, NdotV, preLightData.layeredRoughnessT[1], preLightData.partLambdaV[BASE_LOBEB_IDX]);
DV[BASE_LOBEA_IDX] = DV_SmithJointGGX(NdotH[BASE_NORMAL_IDX], NdotL[BASE_NORMAL_IDX], NdotV[BASE_NORMAL_IDX],
preLightData.layeredRoughnessT[0], preLightData.partLambdaV[BASE_LOBEA_IDX]);
DV[BASE_LOBEB_IDX] = DV_SmithJointGGX(NdotH[BASE_NORMAL_IDX], NdotL[BASE_NORMAL_IDX], NdotV[BASE_NORMAL_IDX],
preLightData.layeredRoughnessT[1], preLightData.partLambdaV[BASE_LOBEB_IDX]);
}

float3 H = (L + V) * invLenLV;
float TdotH, TdotL, BdotH, BdotL;
CalculateAnisoAngles(bsdfData, L, V, invLenLV, TdotH, TdotL, BdotH, BdotL);
DV[0] = DV_SmithJointGGXAniso(TdotH, BdotH, NdotH, NdotV, TdotL, BdotL, NdotL,
DV[0] = DV_SmithJointGGXAniso(TdotH, BdotH, NdotH[0], NdotV[0], TdotL, BdotL, NdotL[0],
DV[1] = DV_SmithJointGGXAniso(TdotH, BdotH, NdotH, NdotV, TdotL, BdotL, NdotL,
DV[1] = DV_SmithJointGGXAniso(TdotH, BdotH, NdotH[0], NdotV[0], TdotL, BdotL, NdotL[0],
DV[0] = DV_SmithJointGGX(NdotH, NdotL, NdotV, bsdfData.roughnessAT, preLightData.partLambdaV[0]);
DV[1] = DV_SmithJointGGX(NdotH, NdotL, NdotV, bsdfData.roughnessBT, preLightData.partLambdaV[1]);
DV[0] = DV_SmithJointGGX(NdotH[0], NdotL[0], NdotV[0], bsdfData.roughnessAT, preLightData.partLambdaV[0]);
DV[1] = DV_SmithJointGGX(NdotH[0], NdotL[0], NdotV[0], bsdfData.roughnessBT, preLightData.partLambdaV[1]);
}
specularLighting = F * lerp(DV[0]*preLightData.energyCompensationFactor[BASE_LOBEA_IDX],
DV[1]*preLightData.energyCompensationFactor[BASE_LOBEB_IDX],

return intensity * transmittance;
}
void EvaluateBSDF_GetNormalUnclampedNdotV(BSDFData bsdfData, PreLightData preLightData, float3 V, out float3 N, out float unclampedNdotV)
{
#ifdef _MATERIAL_FEATURE_COAT_NORMALMAP
//TODOWIP for now just return geometric normal:
if ( IsCoatNormalMapEnabled(bsdfData) )
{
N = bsdfData.geomNormalWS;
unclampedNdotV = dot(N, V);
}
else
#endif
{
// TODOWIP, for now, preserve previous behavior
N = bsdfData.normalWS;
unclampedNdotV = preLightData.NdotV[BASE_NORMAL_IDX];
}
}
//-----------------------------------------------------------------------------
// EvaluateBSDF_Directional
//-----------------------------------------------------------------------------

DirectLighting lighting;
ZERO_INITIALIZE(DirectLighting, lighting);
float3 N = bsdfData.normalWS;
// slnote : dual normal maps
float3 N; float unclampedNdotV;
EvaluateBSDF_GetNormalUnclampedNdotV(bsdfData, preLightData, V, N, unclampedNdotV);
//float3 N = bsdfData.normalWS;
float NdotV = ClampNdotV(preLightData.NdotV);
//float NdotV = ClampNdotV(preLightData.NdotV);
float NdotV = ClampNdotV(unclampedNdotV);
float NdotL = dot(N, L);
float LdotV = dot(L, V);

distances.xyz = float3(dist, distSq, distRcp);
}
float3 N = bsdfData.normalWS;
float NdotV = ClampNdotV(preLightData.NdotV);
// slnote : dual normal maps
float3 N; float unclampedNdotV;
EvaluateBSDF_GetNormalUnclampedNdotV(bsdfData, preLightData, V, N, unclampedNdotV);
//float3 N = bsdfData.normalWS;
//float NdotV = ClampNdotV(preLightData.NdotV);
float NdotV = ClampNdotV(unclampedNdotV);
float NdotL = dot(N, L);
float LdotV = dot(L, V);

// Since the weights are influence blending weights, we can correctly
// use our lobe weight and mix them.
// -Fudge the sampling direction to dampen boundary artefacts.
// -Do early discard for planar reflections.
// -Fetch samples of preintegrated environment lighting
// (see preLD, first part of the split-sum approx.)
// -Use the BSDF preintegration terms we pre-fetched in preLightData

// and lerp them and/or add them.
// Note: using influenceShapeType and projectionShapeType instead of (lightData|proxyData).shapeType allow to make compiler optimization in case the type is know (like for sky)
// slnote : dual normal maps
float3 influenceNormal; float unclampedNdotV;
EvaluateBSDF_GetNormalUnclampedNdotV(bsdfData, preLightData, V, influenceNormal, unclampedNdotV);
for ( i = 0; i < TOTAL_NB_LOBES; ++i)
{

if( (i == (0 IF_FEATURE_COAT(+1))) && _DebugLobeMask.y == 0.0) continue;
if( (i == (1 IF_FEATURE_COAT(+1))) && _DebugLobeMask.z == 0.0) continue;
#endif
EvaluateLight_EnvIntersection(positionWS, bsdfData.normalWS, lightData, influenceShapeType, R[i], tempWeight[i]);
// slnote : dual normal maps
//EvaluateLight_EnvIntersection(positionWS, bsdfData.normalWS, lightData, influenceShapeType, R[i], tempWeight[i]);
EvaluateLight_EnvIntersection(positionWS, influenceNormal, lightData, influenceShapeType, R[i], tempWeight[i]);
// When we are rough, we tend to see outward shifting of the reflection when at the boundary of the projection volume
// Also it appear like more sharp. To avoid these artifact and at the same time get better match to reference we lerp to original unmodified reflection.

{
float3 bakeDiffuseLighting = bakeLightingData.bakeDiffuseLighting;
float3 N; float unclampedNdotV;
EvaluateBSDF_GetNormalUnclampedNdotV(bsdfData, preLightData, V, N, unclampedNdotV);
GetScreenSpaceAmbientOcclusionMultibounce(posInput.positionSS, preLightData.NdotV, lerp(bsdfData.perceptualRoughnessA, bsdfData.perceptualRoughnessB, bsdfData.lobeMix), bsdfData.ambientOcclusion, 1.0, bsdfData.diffuseColor, bsdfData.fresnel0, aoFactor);
//GetScreenSpaceAmbientOcclusionMultibounce(posInput.positionSS, preLightData.NdotV, lerp(bsdfData.perceptualRoughnessA, bsdfData.perceptualRoughnessB, bsdfData.lobeMix), bsdfData.ambientOcclusion, 1.0, bsdfData.diffuseColor, bsdfData.fresnel0, aoFactor);
GetScreenSpaceAmbientOcclusionMultibounce(posInput.positionSS, unclampedNdotV, lerp(bsdfData.perceptualRoughnessA, bsdfData.perceptualRoughnessB, bsdfData.lobeMix), bsdfData.ambientOcclusion, 1.0, bsdfData.diffuseColor, bsdfData.fresnel0, aoFactor);
// Add indirect diffuse + emissive (if any) - Ambient occlusion is multiply by emissive which is wrong but not a big deal
bakeDiffuseLighting *= aoFactor.indirectAmbientOcclusion;

20
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/StackLit/StackLit.shader


[HideInInspector] _SmoothnessBRange("SmoothnessB Range", Vector) = (0, 1, 0, 0)
_LobeMix("Lobe Mix", Range(0.0, 1.0)) = 0
[ToggleUI] _VlayerRecomputePerLight("Vlayer Recompute Per Light", Float) = 0.0 // UI only
[ToggleUI] _DebugEnable("Debug Enable", Float) = 0.0 // UI only
_DebugLobeMask("DebugLobeMask", Vector) = (1, 1, 1, 1)
_DebugAniso("DebugAniso", Vector) = (1, 0, 0, 1000.0)

_CoatIor("Coat IOR", Range(1.0001, 2.0)) = 1.5
_CoatThickness("Coat Thickness", Range(0.0, 0.99)) = 0.0
_CoatExtinction("Coat Extinction Coefficient", Color) = (1,1,1) // in thickness^-1 units
[ToggleUI] _EnableCoatNormalMap("Enable Coat Normal Map", Float) = 0.0 // UI only
[HideInInspector] _CoatNormalMapShow("Coat NormalMap Show", Float) = 0.0
_CoatNormalMap("Coat NormalMap", 2D) = "bump" {} // Tangent space normal map
_CoatNormalMapUV("Coat NormalMapUV", Float) = 0.0
_CoatNormalMapUVLocal("Coat NormalMapUV Local", Float) = 0.0
_CoatNormalMapObjSpace("Coat NormalMap ObjSpace", Float) = 0.0
_CoatNormalScale("Coat NormalMap Scale", Range(0.0, 2.0)) = 1
[HideInInspector] _NormalMapShow("NormalMap Show", Float) = 0.0
_NormalMap("NormalMap", 2D) = "bump" {} // Tangent space normal map

[HideInInspector] _ZTestDepthEqualForOpaque("_ZTestDepthEqualForOpaque", Int) = 4 // Less equal
[HideInInspector] _ZTestModeDistortion("_ZTestModeDistortion", Int) = 8
[ToggleUI] _SpecularAntiAliasingEnabled("Specular Anti Aliasing Enabled", Float) = 0.0
_SpecularAntiAliasingScreenSpaceVariance("SpecularAntiAliasingScreenSpaceVariance", Range(0.0, 1.0)) = 1.0
_SpecularAntiAliasingThreshold("SpecularAntiAliasingThreshold", Range(0.0, 1.0)) = 0.18
[ToggleUI] _NormalCurvatureToRoughnessEnabled("_NormalCurvatureToRoughnessEnabled", Float) = 0.0
_NormalCurvatureToRoughnessScale("_NormalCurvatureToRoughnessScale", Range(0.0, 2.0)) = 1.0
_NormalCurvatureToRoughnessBias("_NormalCurvatureToRoughnessBias", Range(-1.0, 1.0)) = 0.0
_NormalCurvatureToRoughnessExponent("_NormalCurvatureToRoughnessExponent", Range(0.05, 20.0)) = 0.333
[ToggleUI] _EnableFogOnTransparent("Enable Fog", Float) = 1.0
[ToggleUI] _EnableBlendModePreserveSpecularLighting("Enable Blend Mode Preserve Specular Lighting", Float) = 1.0

#pragma shader_feature _MATERIAL_FEATURE_DUAL_SPECULAR_LOBE
#pragma shader_feature _MATERIAL_FEATURE_ANISOTROPY
#pragma shader_feature _MATERIAL_FEATURE_COAT
#pragma shader_feature _MATERIAL_FEATURE_COAT_NORMALMAP
#pragma shader_feature _VLAYERED_RECOMPUTE_PERLIGHT
#pragma shader_feature _STACKLIT_DEBUG

13
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/StackLit/StackLitData.hlsl


}
#endif
float2 deriv = UnpackDerivativeNormalRGorAG(SampleTexture2DScaleBias(TEXTURE2D_PARAM(textureName, samplerName), textureNameUV, textureNameUVLocal, textureNameST, uvMapping));
float2 deriv = UnpackDerivativeNormalRGorAG(SampleTexture2DScaleBias(TEXTURE2D_PARAM(textureName, samplerName), textureNameUV, textureNameUVLocal, textureNameST, uvMapping), scale);
if (textureNameUV <= TEXCOORD_INDEX_UV3)
{

#endif
surfaceData.tangentWS = normalize(input.worldToTangent[0].xyz); // The tangent is not normalize in worldToTangent for mikkt. TODO: Check if it expected that we normalize with Morten. Tag: SURFACE_GRADIENT
float3 coatGradient = float3(0.0, 0.0, 0.0);
#ifdef _MATERIAL_FEATURE_COAT
surfaceData.materialFeatures |= MATERIALFEATUREFLAGS_STACK_LIT_COAT;
surfaceData.coatPerceptualSmoothness = dot(SAMPLE_TEXTURE2D_SCALE_BIAS(_CoatSmoothnessMap), _CoatSmoothnessMapChannelMask);

surfaceData.coatThickness = _CoatThickness;
surfaceData.coatExtinction = _CoatExtinction; // in thickness^-1 units
#ifdef _MATERIAL_FEATURE_COAT_NORMALMAP
surfaceData.materialFeatures |= MATERIALFEATUREFLAGS_STACK_LIT_COAT_NORMAL_MAP;
coatGradient = SAMPLE_TEXTURE2D_NORMAL_SCALE_BIAS(_CoatNormalMap, _CoatNormalScale);
#endif
#endif
#endif // _MATERIAL_FEATURE_COAT
#ifdef _MATERIAL_FEATURE_IRIDESCENCE
surfaceData.materialFeatures |= MATERIALFEATUREFLAGS_STACK_LIT_IRIDESCENCE;

// Surface Data Part 2 (outsite GetSurfaceData( ) in Lit shader):
// -------------------------------------------------------------
surfaceData.geomNormalWS = input.worldToTangent[2];
surfaceData.coatNormalWS = SurfaceGradientResolveNormal(input.worldToTangent[2], coatGradient);
// TODO: decal etc.

20
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/StackLit/StackLitProperties.hlsl


TEXTURE2D(_NormalMap);
SAMPLER(sampler_NormalMap);
TEXTURE2D(_CoatNormalMap);
SAMPLER(sampler_CoatNormalMap);
TEXTURE2D(_SmoothnessBMap);
SAMPLER(sampler_SmoothnessBMap);

float _CoatThickness;
float3 _CoatExtinction;
float _CoatNormalScale;
float _CoatNormalMapUV;
float _CoatNormalMapUVLocal;
float _CoatNormalMapObjSpace;
float4 _CoatNormalMap_ST;
float4 _CoatNormalMap_TexelSize;
float4 _CoatNormalMap_MipInfo;
float _IridescenceThickness;
float _IridescenceThicknessUseMap;
float _IridescenceThicknessMapUV;

float _EmissiveColorMapUVLocal;
float _EmissiveIntensity;
float _AlbedoAffectEmissive;
float _SpecularAntiAliasingEnabled;
float _SpecularAntiAliasingScreenSpaceVariance;
float _SpecularAntiAliasingThreshold;
float _NormalCurvatureToRoughnessEnabled;
float _NormalCurvatureToRoughnessScale;
float _NormalCurvatureToRoughnessBias;
float _NormalCurvatureToRoughnessExponent;
float _AlphaCutoff;
float4 _DoubleSidedConstants;

正在加载...
取消
保存