浏览代码

Merge pull request #1293 from Unity-Technologies/stacklit

Stacklit
/main
GitHub 7 年前
当前提交
41b2865b
共有 8 个文件被更改,包括 749 次插入216 次删除
  1. 48
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Material/StackLit/BaseMaterialUI.cs
  2. 92
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Material/StackLit/StackLitUI.cs
  3. 24
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/StackLit/StackLit.cs
  4. 58
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/StackLit/StackLit.cs.hlsl
  5. 681
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/StackLit/StackLit.hlsl
  6. 33
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/StackLit/StackLit.shader
  7. 20
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/StackLit/StackLitData.hlsl
  8. 9
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/StackLit/StackLitProperties.hlsl

48
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Material/StackLit/BaseMaterialUI.cs


set { m_MaterialProperty.vectorValue = value; }
}
public Property(BaseMaterialGUI parent, string propertyName, string guiText, bool isMandatory = true)
: this(parent, propertyName, guiText, string.Empty, isMandatory)
public Property(BaseMaterialGUI parent, string propertyName, string guiText, bool isMandatory = true, Func<object, bool> isVisible = null)
: this(parent, propertyName, guiText, string.Empty, isMandatory, isVisible)
public Property(BaseMaterialGUI parent, string propertyName, string guiText, string toolTip, bool isMandatory = true)
: base(parent)
public Property(BaseMaterialGUI parent, string propertyName, string guiText, string toolTip, bool isMandatory = true, Func<object, bool> isVisible = null)
: base(parent, isVisible)
{
m_GuiContent = new GUIContent(guiText, toolTip);
PropertyName = propertyName;

private readonly string[] m_Options;
private readonly int[] m_Values = null;
public ComboProperty(BaseMaterialGUI parent, string propertyName, string guiText, string[] options, bool isMandatory = true)
: base(parent, propertyName, guiText, isMandatory)
public ComboProperty(BaseMaterialGUI parent, string propertyName, string guiText, string[] options, bool isMandatory = true, Func<object, bool> isVisible = null)
: base(parent, propertyName, guiText, isMandatory, isVisible)
public ComboProperty(BaseMaterialGUI parent, string propertyName, string guiText, string toolTip, string[] options, bool isMandatory = true)
: base(parent, propertyName, guiText, toolTip, isMandatory)
public ComboProperty(BaseMaterialGUI parent, string propertyName, string guiText, string toolTip, string[] options, bool isMandatory = true, Func<object, bool> isVisible = null)
: base(parent, propertyName, guiText, toolTip, isMandatory, isVisible)
public ComboProperty(BaseMaterialGUI parent, string propertyName, string guiText, string[] options, int[] values, bool isMandatory = true)
: base(parent, propertyName, guiText, isMandatory)
public ComboProperty(BaseMaterialGUI parent, string propertyName, string guiText, string[] options, int[] values, bool isMandatory = true, Func<object, bool> isVisible = null)
: base(parent, propertyName, guiText, isMandatory, isVisible)
public ComboProperty(BaseMaterialGUI parent, string propertyName, string guiText, string toolTip, string[] options, int[] values, bool isMandatory = true)
: base(parent, propertyName, guiText, toolTip, isMandatory)
public ComboProperty(BaseMaterialGUI parent, string propertyName, string guiText, string toolTip, string[] options, int[] values, bool isMandatory = true, Func<object, bool> isVisible = null)
: base(parent, propertyName, guiText, toolTip, isMandatory, isVisible)
{
m_Options = options;
m_Values = values;

public class DiffusionProfileProperty : Property
{
public DiffusionProfileProperty(BaseMaterialGUI parent, string propertyName, string guiText, string toolTip, bool isMandatory = true)
: base(parent, propertyName, guiText, toolTip, isMandatory)
public DiffusionProfileProperty(BaseMaterialGUI parent, string propertyName, string guiText, string toolTip, bool isMandatory = true, Func<object, bool> isVisible = null)
: base(parent, propertyName, guiText, toolTip, isMandatory, isVisible)
{
}

private MaterialProperty m_ExtraProperty;
public TextureOneLineProperty(BaseMaterialGUI parent, string propertyName, string guiText, bool isMandatory = true)
: base(parent, propertyName, guiText, isMandatory)
public TextureOneLineProperty(BaseMaterialGUI parent, string propertyName, string guiText, bool isMandatory = true, Func<object, bool> isVisible = null)
: base(parent, propertyName, guiText, isMandatory, isVisible)
public TextureOneLineProperty(BaseMaterialGUI parent, string propertyName, string guiText, string toolTip, bool isMandatory = true)
: base(parent, propertyName, guiText, toolTip, isMandatory)
public TextureOneLineProperty(BaseMaterialGUI parent, string propertyName, string guiText, string toolTip, bool isMandatory = true, Func<object, bool> isVisible = null)
: base(parent, propertyName, guiText, toolTip, isMandatory, isVisible)
public TextureOneLineProperty(BaseMaterialGUI parent, string propertyName, string extraPropertyName, string guiText, string toolTip, bool isMandatory = true)
: base(parent, propertyName, guiText, toolTip, isMandatory)
public TextureOneLineProperty(BaseMaterialGUI parent, string propertyName, string extraPropertyName, string guiText, string toolTip, bool isMandatory = true, Func<object, bool> isVisible = null)
: base(parent, propertyName, guiText, toolTip, isMandatory, isVisible)
{
ExtraPropertyName = extraPropertyName;
}

public bool m_IsNormalMap;
public TextureProperty(BaseMaterialGUI parent, string propertyName, string constantPropertyName, string guiText, bool useConstantAsTint, bool isMandatory = true, bool isNormalMap = false)
: this(parent, propertyName, constantPropertyName, guiText, string.Empty, useConstantAsTint, isMandatory, isNormalMap)
public TextureProperty(BaseMaterialGUI parent, string propertyName, string constantPropertyName, string guiText, bool useConstantAsTint, bool isMandatory = true, bool isNormalMap = false, Func<object, bool> isVisible = null)
: this(parent, propertyName, constantPropertyName, guiText, string.Empty, useConstantAsTint, isMandatory, isNormalMap, isVisible)
public TextureProperty(BaseMaterialGUI parent, string propertyName, string constantPropertyName, string guiText, string toolTip, bool useConstantAsTint, bool isMandatory = true, bool isNormalMap = false)
: base(parent, propertyName, guiText, toolTip, isMandatory)
public TextureProperty(BaseMaterialGUI parent, string propertyName, string constantPropertyName, string guiText, string toolTip, bool useConstantAsTint, bool isMandatory = true, bool isNormalMap = false, Func<object, bool> isVisible = null)
: base(parent, propertyName, guiText, toolTip, isMandatory, isVisible)
{
m_IsNormalMap = isNormalMap;

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


using UnityEngine;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Experimental.Rendering.HDPipeline;
namespace UnityEditor.Experimental.Rendering.HDPipeline
{

protected const string k_CoatExtinction = "_CoatExtinction";
// SSS
protected const string k_EnableSubsurfaceScattering = "_EnableSubsurfaceScattering";
protected const string k_DiffusionProfile = "_DiffusionProfile";
protected const string k_SubsurfaceMask = "_SubsurfaceMask";
protected const string k_SubsurfaceMaskMap = "_SubsurfaceMaskMap";

protected const string k_EnableTransmission = "_EnableTransmission";
protected const string k_Thickness = "_Thickness";
protected const string k_ThicknessMap = "_ThicknessMap";
protected const string k_ThicknessMapUV = "_ThicknessMapUV";

// Anisotropy
protected const string k_Anisotropy = "_Anisotropy";
protected const string kStencilRef = "_StencilRef";
protected const string kStencilWriteMask = "_StencilWriteMask";
protected const string kStencilRefMV = "_StencilRefMV";
protected const string kStencilWriteMaskMV = "_StencilWriteMaskMV";
//// transparency params
//protected MaterialProperty transmissionEnable = null;
//protected const string kTransmissionEnable = "_TransmissionEnable";

private readonly GroupProperty _baseMaterialProperties = null;
private readonly GroupProperty _materialProperties = null;
private Property EnableSSS;
private Property EnableTransmission;
private Property EnableCoat;
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_CoatEnable, "Coat Enable", "Enable coat layer with true vertical physically based BSDF mixing", true);
// All material properties
new GroupProperty(this, "_MaterialFeatures", "Material Features", new BaseProperty[]
{
EnableSSS,
EnableTransmission,
EnableCoat,
}),
new GroupProperty(this, "_Standard", "Standard", new BaseProperty[]
{
new TextureProperty(this, k_BaseColorMap, k_BaseColor, "Base Color + Opacity", "Albedo (RGB) and Opacity (A)", true, false),

new GroupProperty(this, "_Coat", "Coat", new BaseProperty[]
{
new Property(this, "_CoatEnable", "Coat Enable", "Enable coat layer with true vertical physically based BSDF mixing", false),
}, _ =>EnableCoat.BoolValue == true),
new GroupProperty(this, "_Debug", "Debug", new BaseProperty[]
{
new Property(this, "_DebugEnable", "Debug Enable", "Switch to a debug version of the shader", false),
new Property(this, "_DebugLobeMask", "DebugLobeMask", "xyz is Lobe 0 1 2 Enable, w is Enable VLayering", false),
new Property(this, "_DebugAniso", "DebugAniso", "x is Hack Enable, y is factor", false),
}),
new GroupProperty(this, "_SSS", "Sub-Surface Scattering", new BaseProperty[]

}/*, _ => _materialId == MaterialId.SubSurfaceScattering*/),
}, _ => EnableSSS.BoolValue == true ),
new GroupProperty(this, "_Lobe2", "Second Specular Lobe", new BaseProperty[]
{

new GroupProperty(this, "_Transmission", "Transmission", new BaseProperty[]
{
new DiffusionProfileProperty(this, k_DiffusionProfile, "Diffusion Profile", "A profile determines the shape of the SSS/transmission filter.", false),
new DiffusionProfileProperty(this, k_DiffusionProfile, "Diffusion Profile", "A profile determines the shape of the SSS/transmission filter.", false, _ => EnableSSS.BoolValue == false),
}),
}, _ => EnableTransmission.BoolValue == true),
//new GroupProperty(this, "_Iridescence", "Iridescence", new BaseProperty[]
//{

if (doubleSidedEnable)
{
BaseLitGUI.DoubleSidedNormalMode doubleSidedNormalMode = (BaseLitGUI.DoubleSidedNormalMode)material.GetFloat(k_DoubleSidedNormalMode);
BaseLitGUI.DoubleSidedNormalMode doubleSidedNormalMode =
(BaseLitGUI.DoubleSidedNormalMode) material.GetFloat(k_DoubleSidedNormalMode);
switch (doubleSidedNormalMode)
{
case BaseLitGUI.DoubleSidedNormalMode.Mirror: // Mirror mode (in tangent space)

// Check if we are using specific UVs.
TextureProperty.UVMapping[] uvIndices = new[]
{
(TextureProperty.UVMapping)material.GetFloat(k_BaseColorMapUV),
(TextureProperty.UVMapping)material.GetFloat(k_MetallicMapUV),
(TextureProperty.UVMapping)material.GetFloat(k_NormalMapUV),
(TextureProperty.UVMapping)material.GetFloat(k_Smoothness1MapUV),
(TextureProperty.UVMapping)material.GetFloat(k_Smoothness2MapUV),
(TextureProperty.UVMapping)material.GetFloat(k_AmbientOcclusionMapUV),
(TextureProperty.UVMapping)material.GetFloat(k_EmissiveColorMapUV),
(TextureProperty.UVMapping)material.GetFloat(k_SubsurfaceMaskMapUV),
(TextureProperty.UVMapping)material.GetFloat(k_ThicknessMapUV),
(TextureProperty.UVMapping) material.GetFloat(k_BaseColorMapUV),
(TextureProperty.UVMapping) material.GetFloat(k_MetallicMapUV),
(TextureProperty.UVMapping) material.GetFloat(k_NormalMapUV),
(TextureProperty.UVMapping) material.GetFloat(k_Smoothness1MapUV),
(TextureProperty.UVMapping) material.GetFloat(k_Smoothness2MapUV),
(TextureProperty.UVMapping) material.GetFloat(k_AmbientOcclusionMapUV),
(TextureProperty.UVMapping) material.GetFloat(k_EmissiveColorMapUV),
(TextureProperty.UVMapping) material.GetFloat(k_SubsurfaceMaskMapUV),
(TextureProperty.UVMapping) material.GetFloat(k_ThicknessMapUV),
bool requireUv2 = false;
bool requireUv3 = false;
//bool requireUv2 = false;
//bool requireUv3 = false;
requireUv2 = requireUv2 || uvIndices[i] == TextureProperty.UVMapping.UV2;
requireUv3 = requireUv3 || uvIndices[i] == TextureProperty.UVMapping.UV3;
//requireUv2 = requireUv2 || uvIndices[i] == TextureProperty.UVMapping.UV2;
//requireUv3 = requireUv3 || uvIndices[i] == TextureProperty.UVMapping.UV3;
//CoreUtils.SetKeyword(material, "_USE_UV2", requireUv2);
//CoreUtils.SetKeyword(material, "_USE_UV3", requireUv3);
bool sssEnabled = material.GetFloat(k_EnableSubsurfaceScattering) > 0.0f;
CoreUtils.SetKeyword(material, "_MATERIAL_FEATURE_SUBSURFACE_SCATTERING", sssEnabled);
bool transmissionEnabled = material.GetFloat(k_EnableTransmission) > 0.0f;
CoreUtils.SetKeyword(material, "_MATERIAL_FEATURE_TRANSMISSION", transmissionEnabled);
// Set the reference value for the stencil test.
int stencilRef = (int)StencilLightingUsage.RegularLighting;
if (sssEnabled)
{
stencilRef = (int)StencilLightingUsage.SplitLighting;
}
// As we tag both during velocity pass and Gbuffer pass we need a separate state and we need to use the write mask
material.SetInt(kStencilRef, stencilRef);
material.SetInt(kStencilWriteMask, (int)HDRenderPipeline.StencilBitMask.LightingMask);
material.SetInt(kStencilRefMV, (int)HDRenderPipeline.StencilBitMask.ObjectVelocity);
material.SetInt(kStencilWriteMaskMV, (int)HDRenderPipeline.StencilBitMask.ObjectVelocity);
bool anisotropyEnabled = material.HasProperty(k_Anisotropy) && (material.GetFloat(k_Anisotropy) != 0.0f);
// TODO: When we have a map, also test for map for enable. (This scheme doesn't allow enabling from
// neutral value though, better to still have flag and uncheck it in UI code when reach neutral

bool debugEnabled = material.HasProperty("_DebugEnable") && (material.GetFloat("_DebugEnable") > 0.0f);
CoreUtils.SetKeyword(material, "_STACKLIT_DEBUG", debugEnabled);
}
}

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


public enum MaterialFeatureFlags
{
StackLitStandard = 1 << 0,
StackLitSubsurfaceScattering = 1 << 2,
StackLitTransmission = 1 << 3,
StackLitAnisotropy = 1 << 4,
StackLitCoat = 1 << 6,
};

[SurfaceDataAttributes("Metallic")]
public float metallic;
// SSS
[SurfaceDataAttributes("Diffusion Profile")]
public uint diffusionProfile;
[SurfaceDataAttributes("Subsurface Mask")]
public float subsurfaceMask;
// Transmission
// + Diffusion Profile
[SurfaceDataAttributes("Thickness")]
public float thickness;
// Anisotropic
[SurfaceDataAttributes("Tangent", true)]
public Vector3 tangentWS;

//-----------------------------------------------------------------------------
// BSDFData
//-----------------------------------------------------------------------------
[GenerateHLSL(PackingRules.Exact, false, true, 1400)]
public struct BSDFData
{

public float coatIor;
public float coatThickness;
public Vector3 coatExtinction;
// SSS
public uint diffusionProfile;
public float subsurfaceMask;
// Transmission
// + Diffusion Profile
public float thickness;
public bool useThickObjectMode; // Read from the diffusion profile
public Vector3 transmittance; // Precomputation of transmittance
public float ambientOcclusion;
};

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


// UnityEngine.Experimental.Rendering.HDPipeline.StackLit+MaterialFeatureFlags: static fields
//
#define MATERIALFEATUREFLAGS_STACK_LIT_STANDARD (1)
#define MATERIALFEATUREFLAGS_STACK_LIT_SUBSURFACE_SCATTERING (4)
#define MATERIALFEATUREFLAGS_STACK_LIT_TRANSMISSION (8)
#define MATERIALFEATUREFLAGS_STACK_LIT_ANISOTROPY (16)
#define MATERIALFEATUREFLAGS_STACK_LIT_COAT (64)

#define DEBUGVIEW_STACKLIT_SURFACEDATA_SMOOTHNESS_B (1305)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_LOBE_MIXING (1306)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_METALLIC (1307)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_TANGENT (1308)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_ANISOTROPY (1309)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_COAT_ROUGHNESS (1310)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_COAT_IOR (1311)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_COAT_THICKNESS (1312)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_COAT_EXTINCTION_COEFFICIENT (1313)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_AMBIENT_OCCLUSION (1314)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_DIFFUSION_PROFILE (1308)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_SUBSURFACE_MASK (1309)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_THICKNESS (1310)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_TANGENT (1311)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_ANISOTROPY (1312)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_COAT_ROUGHNESS (1313)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_COAT_IOR (1314)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_COAT_THICKNESS (1315)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_COAT_EXTINCTION_COEFFICIENT (1316)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_AMBIENT_OCCLUSION (1317)
//
// UnityEngine.Experimental.Rendering.HDPipeline.StackLit+BSDFData: static fields

#define DEBUGVIEW_STACKLIT_BSDFDATA_COAT_IOR (1417)
#define DEBUGVIEW_STACKLIT_BSDFDATA_COAT_THICKNESS (1418)
#define DEBUGVIEW_STACKLIT_BSDFDATA_COAT_EXTINCTION (1419)
#define DEBUGVIEW_STACKLIT_BSDFDATA_AMBIENT_OCCLUSION (1420)
#define DEBUGVIEW_STACKLIT_BSDFDATA_DIFFUSION_PROFILE (1420)
#define DEBUGVIEW_STACKLIT_BSDFDATA_SUBSURFACE_MASK (1421)
#define DEBUGVIEW_STACKLIT_BSDFDATA_THICKNESS (1422)
#define DEBUGVIEW_STACKLIT_BSDFDATA_USE_THICK_OBJECT_MODE (1423)
#define DEBUGVIEW_STACKLIT_BSDFDATA_TRANSMITTANCE (1424)
#define DEBUGVIEW_STACKLIT_BSDFDATA_AMBIENT_OCCLUSION (1425)
// Generated from UnityEngine.Experimental.Rendering.HDPipeline.StackLit+SurfaceData
// PackingRules = Exact

float perceptualSmoothnessB;
float lobeMix;
float metallic;
uint diffusionProfile;
float subsurfaceMask;
float thickness;
float3 tangentWS;
float anisotropy;
float coatPerceptualSmoothness;

float coatIor;
float coatThickness;
float3 coatExtinction;
uint diffusionProfile;
float subsurfaceMask;
float thickness;
bool useThickObjectMode;
float3 transmittance;
float ambientOcclusion;
};

break;
case DEBUGVIEW_STACKLIT_SURFACEDATA_METALLIC:
result = surfacedata.metallic.xxx;
break;
case DEBUGVIEW_STACKLIT_SURFACEDATA_DIFFUSION_PROFILE:
result = GetIndexColor(surfacedata.diffusionProfile);
break;
case DEBUGVIEW_STACKLIT_SURFACEDATA_SUBSURFACE_MASK:
result = surfacedata.subsurfaceMask.xxx;
break;
case DEBUGVIEW_STACKLIT_SURFACEDATA_THICKNESS:
result = surfacedata.thickness.xxx;
break;
case DEBUGVIEW_STACKLIT_SURFACEDATA_TANGENT:
result = surfacedata.tangentWS * 0.5 + 0.5;

break;
case DEBUGVIEW_STACKLIT_BSDFDATA_COAT_EXTINCTION:
result = bsdfdata.coatExtinction;
break;
case DEBUGVIEW_STACKLIT_BSDFDATA_DIFFUSION_PROFILE:
result = GetIndexColor(bsdfdata.diffusionProfile);
break;
case DEBUGVIEW_STACKLIT_BSDFDATA_SUBSURFACE_MASK:
result = bsdfdata.subsurfaceMask.xxx;
break;
case DEBUGVIEW_STACKLIT_BSDFDATA_THICKNESS:
result = bsdfdata.thickness.xxx;
break;
case DEBUGVIEW_STACKLIT_BSDFDATA_USE_THICK_OBJECT_MODE:
result = (bsdfdata.useThickObjectMode) ? float3(1.0, 1.0, 1.0) : float3(0.0, 0.0, 0.0);
break;
case DEBUGVIEW_STACKLIT_BSDFDATA_TRANSMITTANCE:
result = bsdfdata.transmittance;
break;
case DEBUGVIEW_STACKLIT_BSDFDATA_AMBIENT_OCCLUSION:
result = bsdfdata.ambientOcclusion.xxx;

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


//-----------------------------------------------------------------------------
// SurfaceData is defined in StackLit.cs which generates StackLit.cs.hlsl
#include "StackLit.cs.hlsl"
//#include "../SubsurfaceScattering/SubsurfaceScattering.hlsl"
#include "../SubsurfaceScattering/SubsurfaceScattering.hlsl"
//#include "CoreRP/ShaderLibrary/VolumeRendering.hlsl"
//NEWLITTODO : wireup CBUFFERs for ambientocclusion, and other uniforms and samplers used:

// Texture and constant buffer declaration
//-----------------------------------------------------------------------------
// Required for SSS, GBuffer texture declaration
TEXTURE2D(_GBufferTexture0);
// Declare the BSDF specific FGD property and its fetching function
#include "../PreIntegratedFGD/PreIntegratedFGD.hlsl"

// Required for SSS
#define GBufferType0 float4
// Needed for MATERIAL_FEATURE_MASK_FLAGS.
#include "../../Lighting/LightLoop/LightLoop.cs.hlsl"
// Additional bits set in 'bsdfData.materialFeatures' to save registers and simplify feature tracking.
#define MATERIAL_FEATURE_FLAGS_SSS_OUTPUT_SPLIT_LIGHTING ((MATERIAL_FEATURE_MASK_FLAGS + 1) << 0)
#define MATERIAL_FEATURE_FLAGS_SSS_TEXTURING_MODE_OFFSET FastLog2((MATERIAL_FEATURE_MASK_FLAGS + 1) << 1) // 2 bits
#define MATERIAL_FEATURE_FLAGS_TRANSMISSION_MODE_MIXED_THICKNESS ((MATERIAL_FEATURE_MASK_FLAGS + 1) << 3)
//#define VLAYERED_RECOMPUTE_PERLIGHT // TODOTODO, and to test, make it a shader_features
// probably too slow but just to check also the difference it makes
//#define _STACKLIT_DEBUG
#ifdef _STACKLIT_DEBUG
# define IF_DEBUG(a) a
# define VLAYERED_DEBUG
#else
# define IF_DEBUG(a)
#endif
// Vlayer config options:
//#define VLAYERED_RECOMPUTE_PERLIGHT // TODO test more, make it a shader_features
// probably too slow but just to check the difference it makes
//#define VLAYERED_USE_REFRACTED_ANGLES_FOR_BASE
//#define VLAYERED_DIFFUSE_ENERGY_HACKED_TERM
//#define VLAYERED_ANISOTROPY_IBL_DESTRETCH
#define VLAYERED_ANISOTROPY_SCALAR_ROUGHNESS
#define VLAYERED_ANISOTROPY_SCALAR_ROUGHNESS_CORRECTANISO
// Automatic:

# define COAT_LOBE_IDX 0
# define BASE_LOBEA_IDX (COAT_LOBE_IDX+1)
# define BASE_LOBEB_IDX (BASE_LOBEA_IDX+1)
# define IF_FEATURE_COAT(a) a
# define COAT_LOBE_IDX (-1)
# define COAT_LOBE_IDX 0
# define BASE_LOBEA_IDX 0
# define BASE_LOBEB_IDX (BASE_LOBEA_IDX+1)
# define IF_FEATURE_COAT(a)
#define BASE_LOBEA_IDX (COAT_LOBE_IDX+1)
#define BASE_LOBEB_IDX (BASE_LOBEA_IDX+1)
#define TOTAL_NB_LOBES (BASE_NB_LOBES+COAT_NB_LOBES)

// ComputeAdding loop
#define NB_VLAYERS 3
//#define NB_TRUE_INTERFACES 2
//#define INTERFACE_TOP_IDX 0
//#define INTERFACE_BASE_IDX 1
// TODOTODO
#define VLAYERED_DIFFUSE_ENERGY_HACKED_TERM
//-----------------------------------------------------------------------------
// Configuration

return (HasFeatureFlag(bsdfData.materialFeatures, MATERIALFEATUREFLAGS_STACK_LIT_COAT));
}
// Assume that bsdfData.diffusionProfile is init
void FillMaterialSSS(uint diffusionProfile, float subsurfaceMask, inout BSDFData bsdfData)
{
bsdfData.diffusionProfile = diffusionProfile;
bsdfData.fresnel0 = _TransmissionTintsAndFresnel0[diffusionProfile].a;
bsdfData.subsurfaceMask = subsurfaceMask;
bsdfData.materialFeatures |= MATERIAL_FEATURE_FLAGS_SSS_OUTPUT_SPLIT_LIGHTING;
bsdfData.materialFeatures |= GetSubsurfaceScatteringTexturingMode(bsdfData.diffusionProfile) << MATERIAL_FEATURE_FLAGS_SSS_TEXTURING_MODE_OFFSET;
}
// Assume that bsdfData.diffusionProfile is init
void FillMaterialTransmission(uint diffusionProfile, float thickness, inout BSDFData bsdfData)
{
bsdfData.diffusionProfile = diffusionProfile;
bsdfData.fresnel0 = _TransmissionTintsAndFresnel0[diffusionProfile].a;
bsdfData.thickness = _ThicknessRemaps[diffusionProfile].x + _ThicknessRemaps[diffusionProfile].y * thickness;
// The difference between the thin and the regular (a.k.a. auto-thickness) modes is the following:
// * in the thin object mode, we assume that the geometry is thin enough for us to safely share
// the shadowing information between the front and the back faces;
// * the thin mode uses baked (textured) thickness for all transmission calculations;
// * the thin mode uses wrapped diffuse lighting for the NdotL;
// * the auto-thickness mode uses the baked (textured) thickness to compute transmission from
// indirect lighting and non-shadow-casting lights; for shadowed lights, it calculates
// the thickness using the distance to the closest occluder sampled from the shadow map.
// If the distance is large, it may indicate that the closest occluder is not the back face of
// the current object. That's not a problem, since large thickness will result in low intensity.
bool useThinObjectMode = IsBitSet(asuint(_TransmissionFlags), diffusionProfile);
bsdfData.materialFeatures |= useThinObjectMode ? 0 : MATERIAL_FEATURE_FLAGS_TRANSMISSION_MODE_MIXED_THICKNESS;
// Compute transmittance using baked thickness here. It may be overridden for direct lighting
// in the auto-thickness mode (but is always be used for indirect lighting).
#if SHADEROPTIONS_USE_DISNEY_SSS
bsdfData.transmittance = ComputeTransmittanceDisney(_ShapeParams[diffusionProfile].rgb,
_TransmissionTintsAndFresnel0[diffusionProfile].rgb,
bsdfData.thickness);
#else
bsdfData.transmittance = ComputeTransmittanceJimenez(_HalfRcpVariancesAndWeights[diffusionProfile][0].rgb,
_HalfRcpVariancesAndWeights[diffusionProfile][0].a,
_HalfRcpVariancesAndWeights[diffusionProfile][1].rgb,
_HalfRcpVariancesAndWeights[diffusionProfile][1].a,
_TransmissionTintsAndFresnel0[diffusionProfile].rgb,
bsdfData.thickness);
#endif
}
// Assume bsdfData.normalWS is init
void FillMaterialAnisotropy(float anisotropy, float3 tangentWS, float3 bitangentWS, inout BSDFData bsdfData)
{

float GetCoatEta(in BSDFData bsdfData)
{
float eta = bsdfData.coatIor / 1.0;
//float eta = 1.5 / 1.0;
//ieta = 1.0 / eta;
return eta;
}

#endif
}
SSSData ConvertSurfaceDataToSSSData(SurfaceData surfaceData)
{
SSSData sssData;
sssData.diffuseColor = surfaceData.baseColor;
sssData.subsurfaceMask = surfaceData.subsurfaceMask;
sssData.diffusionProfile = surfaceData.diffusionProfile;
return sssData;
}
//-----------------------------------------------------------------------------
// conversion function for forward
//-----------------------------------------------------------------------------

bsdfData.lobeMix = surfaceData.lobeMix;
// There is no metallic with SSS and specular color mode
//todo: float metallic = HasFeatureFlag(surfaceData.materialFeatures, MATERIALFEATUREFLAGS_LIT_SPECULAR_COLOR | MATERIALFEATUREFLAGS_LIT_SUBSURFACE_SCATTERING | MATERIALFEATUREFLAGS_LIT_TRANSMISSION) ? 0.0 : surfaceData.metallic;
float metallic = surfaceData.metallic;
float metallic = HasFeatureFlag(surfaceData.materialFeatures, /*MATERIALFEATUREFLAGS_LIT_SPECULAR_COLOR |*/ MATERIALFEATUREFLAGS_STACK_LIT_SUBSURFACE_SCATTERING | MATERIALFEATUREFLAGS_STACK_LIT_TRANSMISSION) ? 0.0 : surfaceData.metallic;
bsdfData.diffuseColor = ComputeDiffuseColor(surfaceData.baseColor, metallic);
bsdfData.fresnel0 = ComputeFresnel0(surfaceData.baseColor, surfaceData.metallic, DEFAULT_SPECULAR_VALUE);

if (HasFeatureFlag(surfaceData.materialFeatures, MATERIALFEATUREFLAGS_STACK_LIT_SUBSURFACE_SCATTERING))
{
// Assign profile id and overwrite fresnel0
FillMaterialSSS(surfaceData.diffusionProfile, surfaceData.subsurfaceMask, bsdfData);
}
if (HasFeatureFlag(surfaceData.materialFeatures, MATERIALFEATUREFLAGS_STACK_LIT_TRANSMISSION))
{
// Assign profile id and overwrite fresnel0
FillMaterialTransmission(surfaceData.diffusionProfile, surfaceData.thickness, bsdfData);
}
if (HasFeatureFlag(surfaceData.materialFeatures, MATERIALFEATUREFLAGS_STACK_LIT_ANISOTROPY))
{
FillMaterialAnisotropy(surfaceData.anisotropy, surfaceData.tangentWS, cross(surfaceData.normalWS, surfaceData.tangentWS), bsdfData);

// We have a coat top layer: change the base fresnel0 accordingdly:
bsdfData.fresnel0 = ConvertF0ForAirInterfaceToF0ForNewTopIor(bsdfData.fresnel0, bsdfData.coatIor);
// We just dont clamp the roughnesses for now, but after the ComputeAdding() which will use those:
// Dont clamp the roughnesses for now, ComputeAdding() will use those directly:
// TODO: add ui inputs, +tangent map for anisotropy;
// TODO: add tangent map for anisotropy;
ConvertAnisotropyToClampRoughness(bsdfData.perceptualRoughnessA, bsdfData.anisotropy, bsdfData.roughnessAT, bsdfData.roughnessAB);
ConvertAnisotropyToClampRoughness(bsdfData.perceptualRoughnessB, bsdfData.anisotropy, bsdfData.roughnessBT, bsdfData.roughnessBB);
}

struct PreLightData
{
float NdotV; // Could be negative due to normal mapping, use ClampNdotV()
float TdotV; // Stored only when VLAYERED_RECOMPUTE_PERLIGHT
float BdotV;
// IBL: we calculate and prefetch the pre-integrated split sum data for
// all needed lobes

// For IBLs (and analytical lights if approximation is used)
float3 vLayerEnergyCoeff[NB_VLAYERS];
float vLayerPerceptualRoughness[NB_VLAYERS];
// We will duplicate one entry to simplify the IBL loop
// (In general it's either that or we add branches (if lobe from bottom interface or
// top inteface) in the loop and make sure the compiler [unroll] - should be automatic
// on a static loop - as then the compiler will remove these known branches as it unrolls.
// All our loops for lobes are static so either way it should unroll and remove either
// duplicated storage or the branch.)
//float energyCompensation[TOTAL_NB_LOBES];
float energyCompensation;
//float vLayerPerceptualRoughness[NB_VLAYERS];
// TODOENERGY: we actually can use a scalar for the non vlayered case to apply at
// PostEvaluateBSDF time, and for the vlayered case, fold compensation into FGD
// terms during ComputeAdding (ie FGD becomes FGDinf) (but the approximation depends on f0,
// our FGD is scalar, not rgb, see GetEnergyCompensationFactor.)
// TODOENERGY:
// For the vlayered case, fold compensation into FGD terms during ComputeAdding
// (ie FGD becomes FGDinf) (but the approximation depends on f0, our FGD is scalar,
// not rgb, see GetEnergyCompensationFactor.)
// Same thing for the F0:
// So we will compute float3 energy factors per lobe:
float3 energyFactor[TOTAL_NB_LOBES];
// We will compute float3 energy factors per lobe.
// We will duplicate one entry to simplify the IBL loop (In general it's either that or
// we add branches (if lobe from bottom interface or top inteface)
// (All our loops for lobes are static so either way the compiler should unroll and remove
// either duplicated storage or the branch.)
float3 energyCompensationFactor[TOTAL_NB_LOBES];
//See VLAYERED_DIFFUSE_ENERGY_HACKED_TERM
float3 diffuseEnergy;

}
}
float GetModifiedAnisotropy0(float anisotropy, float roughness, float newRoughness)
{
float r = (roughness)/(newRoughness+FLT_EPS);
r = sqrt(r);
float newAniso = anisotropy * (r + (1-r) * clamp(5*roughness*roughness,0,1));
return newAniso;
}
float GetModifiedAnisotropy(float anisotropy, float perceptualRoughness, float roughness, float newPerceptualRoughness)
{
float r = (perceptualRoughness)/(newPerceptualRoughness+FLT_MIN*2);
//r = sqrt(r);
float factor = 1000.0;
#ifdef VLAYERED_DEBUG
factor = _DebugAniso.y;
#endif
float newAniso = anisotropy * (r + (1-r) * clamp(factor*roughness*roughness,0,1));
return newAniso;
}
//-----------------------------------------------------------------------------
// About layered BSDF statistical lobe data calculations:
//

// TODOENERGY:
// EnergyCompensation: This term can no longer be used alone in our vlayered BSDF framework as it
// was applied only one time indiscriminately at PostEvaluateBSDF( ) on the specular lighting which
// would be wrong in our case, since the correction terms depend on the interface the lobe
// corresponds to and compensation must happen at each FGD use in ComputeAdding. However, our
// framework is exactly designed to handle that problem, in that if we calculate and apply proper
// energy coefficient terms (should be calculated from FGDinf) and modulate each specular calculations
// with them, this will actually do compensation.
// would be wrong in our case, since the correction terms depend on the FGD of the lobe
// compensation must happen at each FGD use in ComputeAdding. However, our framework is exactly
// designed to handle that problem, in that if we calculate and apply proper energy coefficient
// terms (should be calculated from FGDinf) and modulate each specular calculations with them,
// this will actually do compensation. For now, since FGD fetches are done after ComputeAdding,
// we apply the factors on light samples, less correct, must be moved inside ComputeAdding.
// TODO:
// This creates another performance option: when in VLAYERED_RECOMPUTE_PERLIGHT mode, we

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,
//
//out float s_r12_lobeB,
//
if(i==0) {
if( i == 0 )
{
// Update energy
float R0, n12;

// Update mean
float sti = sqrt(1.0 - Sq(cti));
float stt = sti / n12;
if(stt <= 1.0f) {
if( stt <= 1.0f )
{
// Hack: as roughness -> 1, remove the effect of changing angle also note: we never track means per se
// because of symmetry, we have no azimuth, and don't consider offspecular effect as well as never
// outputting final downward lobes anyway.

//http://www.wolframalpha.com/input/?i=f(alpha)+%3D+(1.0-alpha)*(sqrt(1.0-alpha)+%2B+alpha)+alpha+%3D+0+to+1
stt = scale*stt + (1.0-scale)*sti;
ctt = sqrt(1.0 - stt*stt);
} else {
// TER, flip sign: directions either reflected or transmitted always leave
}
else
{
// TIR, flip sign: directions either reflected or transmitted always leave
// the surface. So here we have ctt instead of cti, we reverse dir by flipping sign.
// Not accounted for though check implications of ctt = -1.0
// TODO

j21 = 1.0/j12;
// Case of the media layer
} else if(i ==1) {
}
else if(i == 1)
{
// Update energy
R12 = float3(0.0, 0.0, 0.0);
T12 = exp(- bsdfData.coatThickness * bsdfData.coatExtinction / cti);

j21 = 1.0;
// Case of the dielectric / conductor base
} else {
}
else
{
// Update energy
R12 = F_Schlick(bsdfData.fresnel0, cti);
T12 = 0.0;

void ComputeAdding(float _cti, in BSDFData bsdfData, inout PreLightData preLightData, bool calledPerLight = false)
{
#ifdef VLAYERED_DEBUG
if( _DebugLobeMask.w == 0.0)
{
preLightData.vLayerEnergyCoeff[COAT_LOBE_IDX] = 0.0 * F_Schlick(IorToFresnel0(bsdfData.coatIor), _cti);
preLightData.iblPerceptualRoughness[COAT_LOBE_IDX] = bsdfData.coatPerceptualRoughness;
preLightData.layeredCoatRoughness = ClampRoughnessForAnalyticalLights(bsdfData.coatRoughness);
preLightData.vLayerEnergyCoeff[BASE_LOBEA_IDX] = 1.0 * F_Schlick(bsdfData.fresnel0, _cti);
preLightData.vLayerEnergyCoeff[BASE_LOBEB_IDX] = 1.0 * F_Schlick(bsdfData.fresnel0, _cti);
preLightData.layeredRoughnessT[0] = ClampRoughnessForAnalyticalLights(bsdfData.roughnessAT);
preLightData.layeredRoughnessB[0] = ClampRoughnessForAnalyticalLights(bsdfData.roughnessAB);
preLightData.layeredRoughnessT[1] = ClampRoughnessForAnalyticalLights(bsdfData.roughnessBT);
preLightData.layeredRoughnessB[1] = ClampRoughnessForAnalyticalLights(bsdfData.roughnessBB);
preLightData.iblPerceptualRoughness[BASE_LOBEA_IDX] = bsdfData.perceptualRoughnessA;
preLightData.iblPerceptualRoughness[BASE_LOBEB_IDX] = bsdfData.perceptualRoughnessB;
return;
}
#endif
// Global Variables
float cti = _cti;
float3 R0i = float3(0.0, 0.0, 0.0), Ri0 = float3(0.0, 0.0, 0.0),

// Iterate over the layers
for(int i = 0; i < NB_VLAYERS; ++i)
{
// Variables for the adding step
float3 R12, T12, R21, T21;
s_r12=0.0;

_s_ri0 = (e_ri0 > 0.0) ? _s_ri0/e_ri0 : 0.0;
// Store the coefficient and variance
if(m_r0i > 0.0) {
// TODO: cleanup and check if unroll works, then need only top layer, can use an if
// and the rest of the array is not needed
preLightData.vLayerEnergyCoeff[i] = m_R0i; // TODO: don't forget to lerp with lobeMix for bottom coefficient
preLightData.vLayerPerceptualRoughness[i] = LinearVarianceToPerceptualRoughness(_s_r0m);
} else {
if(m_r0i > 0.0)
{
preLightData.vLayerEnergyCoeff[i] = m_R0i;
//preLightData.vLayerPerceptualRoughness[i] = LinearVarianceToPerceptualRoughness(_s_r0m);
}
else
{
preLightData.vLayerPerceptualRoughness[i] = 0.0;
//preLightData.vLayerPerceptualRoughness[i] = 0.0;
}
// Update energy

}
//-------------------------------------------------------------
// Post compute: TODO also VLAYERED_RECOMPUTE_PERLIGHT
// Post compute:
//-------------------------------------------------------------
// TODO: dual lobe feature option
//

// We have 6 roughnesses to process;
// TODO: We could probably optimize this a bit.
//
// We need both bottom lobes
// perceptualRoughnessA and perceptualRoughnessB
// for IBLs (because anisotropy will use a hack)
// We need both bottom lobes perceptualRoughnessA and
// perceptualRoughnessB for IBLs (because anisotropy will use a hack)
//
// Then we need anisotropic roughness updates again for the 2
// bottom lobes, for analytical lights.

// but not vLayer*[1] - this is the media "layer")
// Obviously coat roughness is given without ComputeAdding calculations (nothing on top)
//
//preLightData.iblPerceptualRoughness[COAT_LOBE_IDX] = preLightData.vLayerPerceptualRoughness[TOP_VLAYER_IDX];
// ( preLightData.iblPerceptualRoughness[COAT_LOBE_IDX] = preLightData.vLayerPerceptualRoughness[TOP_VLAYER_IDX]; )
#ifdef VLAYERED_RECOMPUTE_PERLIGHT
bool perLightOption = true;

bool haveAnisotropy = HasFeatureFlag(bsdfData.materialFeatures, MATERIALFEATUREFLAGS_STACK_LIT_ANISOTROPY);
if( !calledPerLight )
{
// First, if we're not called per light, always (regardless of perLightOption) calculate
// roughness for top lobe: no adding( ) modifications, just conversion + clamping for
// analytical lights. For these we also don't need to recompute these, but only the Fresnel
// or FGD term are necessary in ComputeAdding, see BSDF().
preLightData.iblPerceptualRoughness[COAT_LOBE_IDX] = bsdfData.coatPerceptualRoughness;
preLightData.layeredCoatRoughness = ClampRoughnessForAnalyticalLights(bsdfData.coatRoughness);
}
// 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,

// 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
// That hack adds complexity because IBLs can't use the T and B roughnesses but at the
// roughness in the anisotropic direction.
// roughness in the anisotropic direction, which is incorrect and with the hack, will appear
// even more so.
#ifdef VLAYERED_ANISOTROPY_SCALAR_ROUGHNESS
// --------------------------------------------------------------------------------
// Scalar treatment of anisotropy: Simple in this case, just modify the scalar
// roughnesses, keep anisotropy the same. Whether we're being called per light or
// not makes little difference on calculations so everything is made generic,
// but if we have the perLightOption enabled, we don't finalize calculations for
// analytical lights.
// --------------------------------------------------------------------------------
preLightData.iblAnisotropy[0] = bsdfData.anisotropy;
preLightData.iblAnisotropy[1] = bsdfData.anisotropy;
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);
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);
#ifdef VLAYERED_ANISOTROPY_SCALAR_ROUGHNESS_CORRECTANISO
// Try to correct stretching that happens when original roughness was low, but not too much
// that destretching happens.
IF_DEBUG( if( _DebugAniso.x == 1) )
{
preLightData.iblAnisotropy[0] = GetModifiedAnisotropy(bsdfData.anisotropy, bsdfData.perceptualRoughnessA,
PerceptualRoughnessToRoughness(bsdfData.perceptualRoughnessA),
preLightData.iblPerceptualRoughness[BASE_LOBEA_IDX]);
preLightData.iblAnisotropy[1] = GetModifiedAnisotropy(bsdfData.anisotropy, bsdfData.perceptualRoughnessB,
PerceptualRoughnessToRoughness(bsdfData.perceptualRoughnessB),
preLightData.iblPerceptualRoughness[BASE_LOBEB_IDX]);
}
#endif
if( !perLightOption )
{
ConvertAnisotropyToClampRoughness(preLightData.iblPerceptualRoughness[BASE_LOBEA_IDX], preLightData.iblAnisotropy[0],
preLightData.layeredRoughnessT[0], preLightData.layeredRoughnessB[0]);
ConvertAnisotropyToClampRoughness(preLightData.iblPerceptualRoughness[BASE_LOBEB_IDX], preLightData.iblAnisotropy[1],
preLightData.layeredRoughnessT[1], preLightData.layeredRoughnessB[1]);
}
#else
// --------------------------------------------------------------------------------
// Non scalar treatment of anisotropy to have the option to remove some anisotropy
// --------------------------------------------------------------------------------
if( !calledPerLight && !haveAnisotropy)
{
// Calculate modified base lobe roughnesses T (no anisotropy)

//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;
float varianceLobeA = _s_r0m;
float tmpB = _s_r0m;
float varianceLobeB = _s_r0m;
preLightData.iblPerceptualRoughness[BASE_LOBEB_IDX] = LinearVarianceToPerceptualRoughness(_s_r0m);
if( !perLightOption )

preLightData.layeredRoughnessT[0] = ClampRoughnessForAnalyticalLights(LinearVarianceToRoughness(tmpA));
preLightData.layeredRoughnessT[1] = ClampRoughnessForAnalyticalLights(LinearVarianceToRoughness(tmpB));
preLightData.layeredRoughnessT[0] = ClampRoughnessForAnalyticalLights(LinearVarianceToRoughness(varianceLobeA));
preLightData.layeredRoughnessT[1] = ClampRoughnessForAnalyticalLights(LinearVarianceToRoughness(varianceLobeB));
}
}

_s_r0m = s_ti0 + j0i*(s_t0i + s_r12 + m_rr*(s_r12+s_ri0));
float roughnessB = LinearVarianceToRoughness(_s_r0m);
//ConvertRoughnessToAnisotropy(roughnessT, roughnessB, preLightData.iblAnisotropy[0]);
#ifdef VLAYERED_ANISOTROPY_IBL_DESTRETCH
ConvertRoughnessToAnisotropy(roughnessT, roughnessB, preLightData.iblAnisotropy[0]);
#else
#endif
// 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);

// 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));
roughnessB = LinearVarianceToRoughness(_s_r0m);
// ConvertRoughnessToAnisotropy(roughnessT, roughnessB, preLightData.iblAnisotropy[1]);
#ifdef VLAYERED_ANISOTROPY_IBL_DESTRETCH
ConvertRoughnessToAnisotropy(roughnessT, roughnessB, preLightData.iblAnisotropy[1]);
#else
#endif
preLightData.iblPerceptualRoughness[BASE_LOBEB_IDX] = RoughnessToPerceptualRoughness((roughnessT + roughnessB)/2.0);
if( !perLightOption )

preLightData.layeredRoughnessB[1] = ClampRoughnessForAnalyticalLights(roughnessB);
}
}
} // if( !calledPerLight && haveAnisotropy)
if( calledPerLight )
{

_s_r0m = s_ti0 + j0i*(s_t0i + s_r12 + m_rr*(s_r12+s_ri0));
preLightData.layeredRoughnessT[0] = ClampRoughnessForAnalyticalLights(LinearVarianceToRoughness(_s_r0m));
// LOBEB roughness for analytical (T part)
// 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));
preLightData.layeredRoughnessT[1] = ClampRoughnessForAnalyticalLights(LinearVarianceToRoughness(_s_r0m));

// LOBEA roughness for analytical (B part)
// LOBEA roughness for analytical lights (B part)
// LOBEB roughness for analytical (B part)
// LOBEB roughness for analytical lights (B part)
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));

#endif // #ifdef VLAYERED_ANISOTROPY_SCALAR_ROUGHNESS
// Obviously not correct since this is directional
// probably too much removed, but with a non FGD term, could
// actually balance out (as using FGD would lower this)
// diffuseEnergy = Max3( Ti0.r, Ti0.g, Ti0.b);
// Not correct since these stats are still directional probably too much
// removed, but with a non FGD term, could actually balance out (as using
// FGD would lower this)
#else
preLightData.diffuseEnergy = float3(1.0, 1.0, 1.0);
#endif

preLightData.NdotV = dot(N, V);
float NdotV = ClampNdotV(preLightData.NdotV);
preLightData.diffuseEnergy = float3(1.0, 1.0, 1.0);
// iblPerceptualRoughness for FGD, mip, etc
// iblR (fetch direction compensated dominant spec)
// specularFGD (coatIblF is now in there too)
// energyCompensation (for all light, apply everytime since with layering it becomes
// lobe specific)
// iblPerceptualRoughness (for FGD, mip, etc)
// iblR (fetch direction compensated dominant spec)
// specularFGD (coatIblF is now in there too)
// energyCompensation (to a apply for each light sample since with multiple roughnesses, it becomes lobe specific)
//
// We also need for analytical lights:
//

// The later are done here only if we're not using VLAYERED_RECOMPUTE_PERLIGHT.
//
// The later are done in ComputeAdding at GetPreLightData time only if we're not using
// VLAYERED_RECOMPUTE_PERLIGHT.
//
float3 iblN[TOTAL_NB_LOBES], iblR[TOTAL_NB_LOBES];
float3 iblN[TOTAL_NB_LOBES]; //ZERO_INITIALIZE(float3[TOTAL_NB_LOBES], iblN);
float3 iblR[TOTAL_NB_LOBES];
// See the struct PreLightData, to simplify the IBL loop, we will recopy these
//preLightData.fresnel0[BASE_LOBEA_IDX] = bsdfData.fresnel0;
//preLightData.fresnel0[BASE_LOBEB_IDX] = bsdfData.fresnel0;
//preLightData.fresnel0[COAT_LOBE_IDX] = IorToFresnel0(bsdfData.coatIor);
preLightData.coatIeta = 1.0 / GetCoatEta(bsdfData);
#ifdef _MATERIAL_FEATURE_COAT
// --------------------------------------------------------------------
// VLAYERING:
// --------------------------------------------------------------------
// Obviously coat roughness is given without ComputeAdding calculations (nothing on top)
preLightData.iblPerceptualRoughness[COAT_LOBE_IDX] = bsdfData.coatPerceptualRoughness;
preLightData.layeredCoatRoughness = ClampRoughnessForAnalyticalLights(bsdfData.coatRoughness);
preLightData.coatIeta = 1.0 / GetCoatEta(bsdfData);
// 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.

float BdotV = dot(bsdfData.bitangentWS, V);
#ifndef VLAYERED_RECOMPUTE_PERLIGHT
// We can precalculate lambdaVs for all lights here since we're not doing ComputeAdding per light
#else
// Store those for eval analytical lights since we're going to
// recalculate lambdaV after each ComputeAdding for each light
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.

{
#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] = GetSmithJointGGXPartLambdaV(NdotV, preLightData.layeredRoughnessT[0]);
preLightData.partLambdaV[BASE_LOBEB_IDX] = GetSmithJointGGXPartLambdaV(NdotV, preLightData.layeredRoughnessT[1]);

// them built by ComputeAdding with terms like (FGDinf), (1-FGDinf). Also, the compensation approximation depends on f0.
// See TODOENERGY [eg: (a1*ef)(1-(a2*ef)) != ef (a1)(1-a2) ]
float specularReflectivityBase = lerp(specularReflectivity[BASE_LOBEA_IDX], specularReflectivity[BASE_LOBEB_IDX], bsdfData.lobeMix);
//preLightData.energyCompensation[BASE_LOBEA_IDX] = CalculateEnergyCompensationFromSpecularReflectivity(specularReflectivityBase);
//preLightData.energyCompensation[BASE_LOBEB_IDX] = preLightData.energyCompensation[BASE_LOBEA_IDX];
//preLightData.energyCompensation[COAT_LOBE_IDX] = CalculateEnergyCompensationFromSpecularReflectivity(specularReflectivity[COAT_LOBE_IDX]);
preLightData.energyFactor[BASE_LOBEA_IDX] = GetEnergyCompensationFactor(specularReflectivityBase, bsdfData.fresnel0);
preLightData.energyFactor[BASE_LOBEB_IDX] = GetEnergyCompensationFactor(specularReflectivityBase, bsdfData.fresnel0);
preLightData.energyFactor[COAT_LOBE_IDX] = GetEnergyCompensationFactor(specularReflectivity[COAT_LOBE_IDX], IorToFresnel0(bsdfData.coatIor));
preLightData.energyCompensationFactor[BASE_LOBEA_IDX] = GetEnergyCompensationFactor(specularReflectivity[BASE_LOBEA_IDX], bsdfData.fresnel0);
preLightData.energyCompensationFactor[BASE_LOBEB_IDX] = GetEnergyCompensationFactor(specularReflectivity[BASE_LOBEB_IDX], bsdfData.fresnel0);
preLightData.energyCompensationFactor[COAT_LOBE_IDX] = GetEnergyCompensationFactor(specularReflectivity[COAT_LOBE_IDX], IorToFresnel0(bsdfData.coatIor));
//preLightData.energyCompensation[COAT_LOBE_IDX] =
//preLightData.energyCompensation[BASE_LOBEA_IDX] =
//preLightData.energyCompensation[BASE_LOBEB_IDX] = 0.0;
preLightData.energyFactor[BASE_LOBEA_IDX] =
preLightData.energyFactor[BASE_LOBEB_IDX] =
preLightData.energyFactor[COAT_LOBE_IDX] = 1.0;
preLightData.energyCompensationFactor[BASE_LOBEA_IDX] =
preLightData.energyCompensationFactor[BASE_LOBEB_IDX] =
preLightData.energyCompensationFactor[COAT_LOBE_IDX] = 1.0;
#endif //ifdef _MATERIAL_FEATURE_COAT
// --------------------------------------------------------------------
// --------------------------------------------------------------------
// To make BSDF( ) evaluation more generic, even if we're not vlayered,
// we will use these:
// 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
// permit array definitions in the shader include attributes TODOTODO)
// no coat here: preLightData.layeredCoatRoughness = bsdfData.coatRoughness;
preLightData.layeredRoughnessT[0] = bsdfData.roughnessAT;
preLightData.layeredRoughnessB[0] = bsdfData.roughnessAB;

}
else
{
preLightData.partLambdaV[0] = GetSmithJointGGXPartLambdaV(NdotV, bsdfData.roughnessAT);
preLightData.partLambdaV[1] = GetSmithJointGGXPartLambdaV(NdotV, bsdfData.roughnessBT);
preLightData.partLambdaV[0] = GetSmithJointGGXPartLambdaV(NdotV, preLightData.layeredRoughnessT[0]);
preLightData.partLambdaV[1] = GetSmithJointGGXPartLambdaV(NdotV, preLightData.layeredRoughnessT[1]);
iblN[0] = iblN[1] = N;
} // ...no anisotropy

// (akin to a "split sum" approximation) we will just lerp our two "specularReflectivities".
// When in vlayering, the same split approximation idea is embedded in the whole aggregate statistical
// formulation. ie Compensation corresponds to using FGDinf instead of FGD.
float specR = lerp(specularReflectivity[0], specularReflectivity[1], bsdfData.lobeMix);
//preLightData.energyCompensation[0] = CalculateEnergyCompensationFromSpecularReflectivity(specR);
preLightData.energyCompensation = CalculateEnergyCompensationFromSpecularReflectivity(specR);
preLightData.energyCompensationFactor[BASE_LOBEA_IDX] = GetEnergyCompensationFactor(specularReflectivity[BASE_LOBEA_IDX], bsdfData.fresnel0);
preLightData.energyCompensationFactor[BASE_LOBEB_IDX] = GetEnergyCompensationFactor(specularReflectivity[BASE_LOBEB_IDX], bsdfData.fresnel0);
preLightData.energyCompensation = 0.0;
preLightData.energyCompensationFactor[BASE_LOBEA_IDX] =
preLightData.energyCompensationFactor[BASE_LOBEB_IDX] = 1.0;
#endif
} //...else !IsVLayeredEnabled

}
//-----------------------------------------------------------------------------
// Subsurface Scattering functions
//-----------------------------------------------------------------------------
bool ShouldOutputSplitLighting(BSDFData bsdfData)
{
return HasFeatureFlag(bsdfData.materialFeatures, MATERIAL_FEATURE_FLAGS_SSS_OUTPUT_SPLIT_LIGHTING);
}
//-----------------------------------------------------------------------------
// LightLoop related function (Only include if required)
// HAS_LIGHTLOOP is define in Lighting.hlsl
//-----------------------------------------------------------------------------

// BSDF share between directional light, punctual light and area light (reference)
//-----------------------------------------------------------------------------
// helpers
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;
// For anisotropy we must not saturate these values
TdotH = dot(bsdfData.tangentWS, H);
TdotL = dot(bsdfData.tangentWS, L);
BdotH = dot(bsdfData.bitangentWS, H);
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)
{
// Optimized math. Ref: PBR Diffuse Lighting for GGX + Smith Microsurfaces (slide 114).
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
NdotH = saturate((NdotL + unclampedNdotV) * invLenLV); // Do not clamp NdotV here
LdotH = saturate(invLenLV * LdotV + invLenLV);
NdotV = ClampNdotV(unclampedNdotV);
}
// This function apply BSDF. Assumes that NdotL is positive.
void BSDF( float3 V, float3 L, float NdotL, float3 positionWS, PreLightData preLightData, BSDFData bsdfData,

float3 N = bsdfData.normalWS;
float LdotV, invLenLV, NdotH, LdotH, NdotV;
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);
//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);
CalculateAngles(L, V, NdotL, preLightData.NdotV, LdotV, invLenLV, NdotH, LdotH, NdotV);
float3 DV[TOTAL_NB_LOBES];
// TODO: with iridescence, will be per light sample.
// TODO: with iridescence, will be optionally per light sample
float DV[2];
if( IsVLayeredEnabled(bsdfData) )
{
#ifdef _MATERIAL_FEATURE_COAT
// --------------------------------------------------------------------
// VLAYERING:
// --------------------------------------------------------------------
DV[0] = DV_SmithJointGGX(NdotH, NdotL, NdotV, bsdfData.roughnessAT, preLightData.partLambdaV[0]);
DV[1] = DV_SmithJointGGX(NdotH, NdotL, NdotV, bsdfData.roughnessBT, preLightData.partLambdaV[1]);
// 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
// TODOWIP
// 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
// coefficients already (vLayerEnergyCoeff), which are like FGD (but no deferred
// FGD fetch to do here for analytical lights), so normally, we should use
// an output lobe parametrization, but multiple-scattering is not accounted fully
// byt ComputeAdding (by deriving azimuth dependent covariance operators).
// In the IBL case, we don't have a specific incoming light direction so the light
// representation matches more the correct context of a split sum approximation,
// though we don't handle anisotropy correctly either anyway.
// In both cases we need to work around it, so just to test:
float3 H = (L + V) * invLenLV;
// H stays the same so calculate it one time
V = CoatRefract(V, H, preLightData.coatIeta);
L = reflect(-V, H);
NdotL = dot(N,L);
//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
//NdotH = saturate((NdotL + dot(N, V)) * invLenLV); // Do not clamp NdotV here
//LdotH = saturate(invLenLV * LdotV + invLenLV);
//NdotV = ClampNdotV(dot(N, V));
CalculateAngles(L, V, NdotL, dot(N, V), LdotV, invLenLV, NdotH, LdotH, NdotV);
#endif // #if VLAYERED_USE_REFRACTED_ANGLES_FOR_BASE
#ifdef VLAYERED_RECOMPUTE_PERLIGHT
// TODOWIP
// Must call ComputeAdding and update partLambdaV
ComputeAdding(topLdotH, bsdfData, preLightData, true);
// Notice topLdotH as interface angle, symmetric model parametrization (see 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);
#endif
// p9 eq(39): if we don't recompute per light, we just reuse the IBL energy terms as the fresnel terms
// for our LdotH, too bad (similar to what we do with iridescence), along with the "wrongly" calculated energy.
// Note that in any case, we should have used FGD terms (except for R12 at the start of the process)
// for the analytical light case, see comments at the top of ComputeAdding
specularLighting = F * lerp(DV[0], DV[1], bsdfData.lobeMix);
if (HasFeatureFlag(bsdfData.materialFeatures, MATERIALFEATUREFLAGS_STACK_LIT_ANISOTROPY))
{
#ifdef VLAYERED_RECOMPUTE_PERLIGHT
#ifdef VLAYERED_USE_REFRACTED_ANGLES_FOR_BASE
// we just changed V, update those:
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.layeredRoughnessT[0], preLightData.layeredRoughnessB[0]);
preLightData.partLambdaV[BASE_LOBEB_IDX] = GetSmithJointGGXAnisoPartLambdaV(preLightData.TdotV, preLightData.BdotV, NdotV,
preLightData.layeredRoughnessT[1], preLightData.layeredRoughnessB[1]);
#endif
//float3 H = (L + V) * invLenLV;
float TdotH, TdotL, BdotH, BdotL;
CalculateAnisoAngles(bsdfData, L, V, invLenLV, TdotH, TdotL, BdotH, BdotL);
DV[BASE_LOBEA_IDX] = DV_SmithJointGGXAniso(TdotH, BdotH, NdotH, NdotV, TdotL, BdotL, NdotL,
preLightData.layeredRoughnessT[0], preLightData.layeredRoughnessB[0],
preLightData.partLambdaV[BASE_LOBEA_IDX]);
DV[BASE_LOBEB_IDX] = DV_SmithJointGGXAniso(TdotH, BdotH, NdotH, NdotV, TdotL, BdotL, NdotL,
preLightData.layeredRoughnessT[1], preLightData.layeredRoughnessB[1],
preLightData.partLambdaV[BASE_LOBEB_IDX]);
DV[COAT_LOBE_IDX] = DV_SmithJointGGX(topNdotH, topNdotL, topNdotV, preLightData.layeredCoatRoughness, preLightData.partLambdaV[COAT_LOBE_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]);
#endif
DV[COAT_LOBE_IDX] = DV_SmithJointGGX(topNdotH, topNdotL, topNdotV, preLightData.layeredCoatRoughness, preLightData.partLambdaV[COAT_LOBE_IDX]);
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]);
}
specularLighting = preLightData.vLayerEnergyCoeff[BOTTOM_VLAYER_IDX]
* lerp(DV[BASE_LOBEA_IDX] * preLightData.energyCompensationFactor[BASE_LOBEA_IDX],
DV[BASE_LOBEB_IDX] * preLightData.energyCompensationFactor[BASE_LOBEB_IDX],
bsdfData.lobeMix);
specularLighting += preLightData.vLayerEnergyCoeff[TOP_VLAYER_IDX]
* preLightData.energyCompensationFactor[COAT_LOBE_IDX]
* DV[COAT_LOBE_IDX];
#endif // ..._MATERIAL_FEATURE_COAT
} // if( IsVLayeredEnabled(bsdfData) )
else
{
// --------------------------------------------------------------------
// NO VLAYERING:
// --------------------------------------------------------------------
if (HasFeatureFlag(bsdfData.materialFeatures, MATERIALFEATUREFLAGS_STACK_LIT_ANISOTROPY))
{
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,
bsdfData.roughnessAT, bsdfData.roughnessAB,
preLightData.partLambdaV[0]);
DV[1] = DV_SmithJointGGXAniso(TdotH, BdotH, NdotH, NdotV, TdotL, BdotL, NdotL,
bsdfData.roughnessBT, bsdfData.roughnessBB,
preLightData.partLambdaV[1]);
}
else
{
DV[0] = DV_SmithJointGGX(NdotH, NdotL, NdotV, bsdfData.roughnessAT, preLightData.partLambdaV[0]);
DV[1] = DV_SmithJointGGX(NdotH, NdotL, NdotV, bsdfData.roughnessBT, preLightData.partLambdaV[1]);
}
specularLighting = F * lerp(DV[0]*preLightData.energyCompensationFactor[BASE_LOBEA_IDX],
DV[1]*preLightData.energyCompensationFactor[BASE_LOBEB_IDX],
bsdfData.lobeMix);
//...and energy compensation is applied at PostEvaluateBSDF when no vlayering.
}
float diffuseTerm = Lambert();
float3 diffuseTerm = Lambert();
#ifdef VLAYERED_DIFFUSE_ENERGY_HACKED_TERM
// TODOTODO: Energy when vlayered.
if( IsVLayeredEnabled(bsdfData) )
{
diffuseTerm *= preLightData.diffuseEnergy;
}
#endif
// TODO: coat
}
}//...BSDF
//-----------------------------------------------------------------------------
// EvaluateBSDF_Directional

{
IndirectLighting lighting;
ZERO_INITIALIZE(IndirectLighting, lighting);
//return lighting;
// TODO: Refraction
// There is no coat handling in Lit for refractions.
// Here handle one lobe instead of all the others basically, or we could want it all.

{
float3 L;
#ifdef VLAYERED_DEBUG
IF_FEATURE_COAT( if( (i == 0) && _DebugLobeMask.x == 0.0) continue; )
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]);
// When we are rough, we tend to see outward shifting of the reflection when at the boundary of the projection volume

// Note that when we're not vlayered, we apply it not at each light sample but at the end,
// at PostEvaluateBSDF.
// Incorrect, but just for now:
//L = ApplyEnergyCompensationToSpecularLighting(L, preLightData.fresnel0[i], preLightData.energyCompensation[i]);
L *= preLightData.energyFactor[i];
L *= preLightData.energyCompensationFactor[i];
}
envLighting += L;
}

weight += tempWeight[i];
}
weight /= TOTAL_NB_LOBES;
weight = tempWeight[1];
#endif // LIT_DISPLAY_REFERENCE_IBL

diffuseLighting = bsdfData.diffuseColor * lighting.direct.diffuse + bakeDiffuseLighting;
specularLighting = lighting.direct.specular + lighting.indirect.specularReflected;
if (!IsVLayeredEnabled(bsdfData))
{
// Note that when we're vlayered, this can be different per lobe depending on
// which interface generates it.
// Apply the fudge factor (boost) to compensate for multiple scattering not accounted for in the BSDF.
// This assumes all spec comes from a GGX BSDF.
specularLighting = ApplyEnergyCompensationToSpecularLighting(specularLighting, bsdfData.fresnel0, preLightData.energyCompensation);
}
#ifdef DEBUG_DISPLAY

33
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] _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.0, 2.0)) = 1.5
_CoatIor("Coat IOR", Range(1.0001, 2.0)) = 1.5
_CoatExtinction("Coat Extinction Coefficient", Color) = (1,1,1,1) // in thickness^-1 units
_CoatExtinction("Coat Extinction Coefficient", Color) = (1,1,1) // in thickness^-1 units
[HideInInspector] _NormalMapShow("NormalMap Show", Float) = 0.0
_NormalMap("NormalMap", 2D) = "bump" {} // Tangent space normal map

_EmissiveIntensity("Emissive Intensity", Float) = 0
[ToggleUI] _AlbedoAffectEmissive("Albedo Affect Emissive", Float) = 0.0
[ToggleUI] _EnableSubsurfaceScattering("Enable Subsurface Scattering", Float) = 0.0
_DiffusionProfile("Diffusion Profile", Int) = 0
_SubsurfaceMaskUSeMap("Subsurface Mask Use Map", Float) = 0
_SubsurfaceMaskUseMap("Subsurface Mask Use Map", Float) = 0
_SubsurfaceMaskMapUVLocal("Subsurface Mask UV Local", Float) = 0.0
[ToggleUI] _EnableTransmission("Enable Transmission", Float) = 0.0
_ThicknessMapUVLocal("Thickness Map UV Local", Float) = 0.0
_ThicknessMapChannel("Thickness Map Channel", Float) = 0.0
_ThicknessMapChannelMask("Thickness Map Channel Mask", Vector) = (1, 0, 0, 0)
_ThicknessRemap("Thickness Remap", Vector) = (0, 1, 0, 0)

// Sections show values.
[HideInInspector] _MaterialFeaturesShow("_MaterialFeaturesShow", Float) = 1.0
[HideInInspector] _DebugShow("_DebugShow", Float) = 0.0
[HideInInspector] _SSSShow("_SSSShow", Float) = 0.0
[HideInInspector] _Lobe2Show("_Lobe2Show", Float) = 0.0
[HideInInspector] _AnisotropyShow("_AnisotropyShow", Float) = 0.0

// but we need it right away for toggle with LayerTexCoord mapping so we might need them
// from the Frag input right away. See also ShaderPass/StackLitSharePass.hlsl.
#pragma shader_feature _NORMALMAP
#pragma shader_feature _MASKMAPA
#pragma shader_feature _MASKMAPB
#pragma shader_feature _EMISSIVE_COLOR_MAP
#pragma shader_feature _MATERIAL_FEATURE_SUBSURFACE_SCATTERING
#pragma shader_feature _MATERIAL_FEATURE_TRANSMISSION
//#pragma shader_feature _EMISSIVE_COLOR_MAP
// Keyword for transparent
#pragma shader_feature _SURFACE_TYPE_TRANSPARENT

#pragma shader_feature _MATERIAL_FEATURE_COAT
#pragma shader_feature _MATERIAL_FEATURE_DUAL_LOBE
#pragma shader_feature _STACKLIT_DEBUG
//enable GPU instancing support
#pragma multi_compile_instancing

#define UNITY_MATERIAL_STACKLIT // Need to be define before including Material.hlsl
// If we use subsurface scattering, enable output split lighting (for forward pass)
#if defined(_MATERIAL_FEATURE_SUBSURFACE_SCATTERING) && !defined(_SURFACE_TYPE_TRANSPARENT)
#define OUTPUT_SPLIT_LIGHTING
#endif
//-------------------------------------------------------------------------------------
// Include

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


// knows the value of surfaceData.materialFeatures.
surfaceData.materialFeatures = MATERIALFEATUREFLAGS_STACK_LIT_STANDARD;
#ifdef _MATERIAL_FEATURE_SUBSURFACE_SCATTERING
surfaceData.materialFeatures |= MATERIALFEATUREFLAGS_STACK_LIT_SUBSURFACE_SCATTERING;
#endif
#ifdef _MATERIAL_FEATURE_TRANSMISSION
surfaceData.materialFeatures |= MATERIALFEATUREFLAGS_STACK_LIT_TRANSMISSION;
#endif
#ifdef _MATERIAL_FEATURE_ANISOTROPY
surfaceData.materialFeatures |= MATERIALFEATUREFLAGS_STACK_LIT_ANISOTROPY;
#endif

surfaceData.coatExtinction = _CoatExtinction; // in thickness^-1 units
#else
surfaceData.coatPerceptualSmoothness = 0.0;
surfaceData.coatIor = 1.0;
surfaceData.coatIor = 1.0001;
surfaceData.coatThickness = 0.0;
surfaceData.coatExtinction = float3(1.0, 1.0, 1.0);
#endif

surfaceData.metallic = 0.0;
}
#endif
surfaceData.diffusionProfile = _DiffusionProfile;
surfaceData.subsurfaceMask = dot(SAMPLE_TEXTURE2D_SCALE_BIAS(_SubsurfaceMaskMap), _SubsurfaceMaskMapChannelMask);
surfaceData.subsurfaceMask = lerp(_SubsurfaceMaskRange.x, _SubsurfaceMaskRange.y, surfaceData.subsurfaceMask);
surfaceData.subsurfaceMask = lerp(_SubsurfaceMask, surfaceData.subsurfaceMask, _SubsurfaceMaskUseMap);
surfaceData.thickness = dot(SAMPLE_TEXTURE2D_SCALE_BIAS(_ThicknessMap), _ThicknessMapChannelMask);
surfaceData.thickness = lerp(_ThicknessRange.x, _ThicknessRange.y, surfaceData.thickness);
surfaceData.thickness = lerp(_Thickness, surfaceData.thickness, _ThicknessUseMap);
// -------------------------------------------------------------
// Builtin Data:

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


float4 _SmoothnessAMap_MipInfo;
float4 _SmoothnessAMapChannelMask;
float4 _SmoothnessARange;
float _SmoothnessB;
float _SmoothnessBUseMap;
float _SmoothnessBMapUV;

float4 _SmoothnessBRange;
float _LobeMix;
float4 _DebugLobeMask;
float4 _DebugAniso;
float4 _CoatExtinction;
float3 _CoatExtinction;
float _NormalScale;
float _NormalMapUV;

float _EmissiveIntensity;
float _AlbedoAffectEmissive;
int _DiffusionProfile;
float _SubsurfaceMaskMapUVLocal;
float4 _SubsurfaceMaskMap_ST;
float4 _SubsurfaceMaskMap_TexelSize;
float4 _SubsurfaceMaskMap_MipInfo;

float _Thickness;
float _ThicknessUseMap;
float _ThicknessMapUV;
float _ThicknessMapUVLocal;
float4 _ThicknessMap_ST;
float4 _ThicknessMap_TexelSize;
float4 _ThicknessMap_MipInfo;

正在加载...
取消
保存