浏览代码

Merge pull request #1476 from Unity-Technologies/StackLit2

Stack lit2
/main
GitHub 6 年前
当前提交
144723e3
共有 13 个文件被更改,包括 562 次插入2096 次删除
  1. 22
      com.unity.render-pipelines.core/CoreRP/ShaderLibrary/BSDF.hlsl
  2. 12
      com.unity.render-pipelines.high-definition/HDRP/Editor/Material/StackLit/StackLitUI.cs
  3. 22
      com.unity.render-pipelines.high-definition/HDRP/Material/LTCAreaLight/LTCAreaLight.cs
  4. 1
      com.unity.render-pipelines.high-definition/HDRP/Material/LTCAreaLight/LTCAreaLight.hlsl
  5. 998
      com.unity.render-pipelines.high-definition/HDRP/Material/LTCAreaLight/LtcData.DisneyDiffuse.cs
  6. 992
      com.unity.render-pipelines.high-definition/HDRP/Material/LTCAreaLight/LtcData.GGX.cs
  7. 69
      com.unity.render-pipelines.high-definition/HDRP/Material/Lit/Lit.hlsl
  8. 3
      com.unity.render-pipelines.high-definition/HDRP/Material/StackLit/StackLit.cs
  9. 34
      com.unity.render-pipelines.high-definition/HDRP/Material/StackLit/StackLit.cs.hlsl
  10. 452
      com.unity.render-pipelines.high-definition/HDRP/Material/StackLit/StackLit.hlsl
  11. 33
      com.unity.render-pipelines.high-definition/HDRP/Material/StackLit/StackLit.shader
  12. 7
      com.unity.render-pipelines.high-definition/HDRP/Material/StackLit/StackLitData.hlsl
  13. 13
      com.unity.render-pipelines.high-definition/HDRP/Material/StackLit/StackLitProperties.hlsl

22
com.unity.render-pipelines.core/CoreRP/ShaderLibrary/BSDF.hlsl


}
// Evaluate the reflectance for a thin-film layer on top of a dielectric medum.
real3 EvalIridescence(real eta_1, real cosTheta1, real iridescenceThickness, real3 baseLayerFresnel0)
real3 EvalIridescence(real eta_1, real cosTheta1, real iridescenceThickness, real3 baseLayerFresnel0, real iorOverBaseLayer = 0.0)
{
// iridescenceThickness unit is micrometer for this equation here. Mean 0.5 is 500nm.
real Dinc = 3.0 * iridescenceThickness;

// Force eta_2 -> eta_1 when Dinc -> 0.0
// real eta_2 = lerp(eta_1, eta_2, smoothstep(0.0, 0.03, Dinc));
// Evaluate the cosTheta on the base layer (Snell law)
real cosTheta2 = sqrt(1.0 - Sq(eta_1 / eta_2) * (1.0 - Sq(cosTheta1)));
real sinTheta2 = Sq(eta_1 / eta_2) * (1.0 - Sq(cosTheta1));
// Handle TIR
if (sinTheta2 > 1.0)
return real3(1.0, 1.0, 1.0);
//Or use this "artistic hack" to get more continuity even though wrong (test with dual normal maps to understand the difference)
//if( sinTheta2 > 1.0 ) { sinTheta2 = 2 - sinTheta2; }
real cosTheta2 = sqrt(1.0 - sinTheta2);
// First interface
real R0 = IorToFresnel0(eta_2, eta_1);

real phi21 = PI - phi12;
// Second interface
// The f0 or the base should account for the new computed eta_2 on top.
// This is optionally done if we are given the needed current ior over the base layer that is accounted for
// in the baseLayerFresnel0 parameter:
if (iorOverBaseLayer > 0.0)
{
// Fresnel0ToIor will give us a ratio of baseIor/topIor, hence we * iorOverBaseLayer to get the baseIor
real3 baseIor = iorOverBaseLayer * Fresnel0ToIor(baseLayerFresnel0 + 0.0001); // guard against 1.0
baseLayerFresnel0 = IorToFresnel0(baseIor, eta_2);
}
real3 R23 = F_Schlick(baseLayerFresnel0, cosTheta2);
real phi23 = 0.0;

12
com.unity.render-pipelines.high-definition/HDRP/Editor/Material/StackLit/StackLitUI.cs


protected const string k_IridescenceThickness = "_IridescenceThickness";
protected const string k_IridescenceThicknessMap = "_IridescenceThicknessMap";
protected const string k_IridescenceThicknessMapUV = "_IridescenceThicknessMapUV";
protected const string k_IridescenceMask = "_IridescenceMask";
protected const string k_IridescenceMaskMap = "_IridescenceMaskMap";
protected const string k_IridescenceMaskMapUV = "_IridescenceMaskMapUV";
// Stencil is use to control lighting mode (regular, split lighting)
protected const string kStencilRef = "_StencilRef";

new GroupProperty(this, "_Iridescence", "Iridescence", new BaseProperty[]
{
new Property(this, "_IridescenceIor", "IOR", "Index of refraction of iridescence layer", false),
new Property(this, "_IridescenceThickness", "Thickness", "Iridescence thickness (Remap to 0..3000nm)", false),
//just to test: to use the same EvalIridescence as lit, find a good mapping for the top IOR (over the iridescence dielectric film)
//when having iridescence:
//new Property(this, "_IridescenceIor", "TopIOR", "Index of refraction on top of iridescence layer", false),
new TextureProperty(this, k_IridescenceMaskMap, k_IridescenceMask, "Iridescence Mask", "Iridescence Mask", false),
new TextureProperty(this, k_IridescenceThicknessMap, k_IridescenceThickness, "Iridescence thickness (Remap to 0..3000nm)", "Iridescence thickness (Remap to 0..3000nm)", false),
}, _ => EnableIridescence.BoolValue == true),
new GroupProperty(this, "_SSS", "Sub-Surface Scattering", new BaseProperty[]

SetupTextureMaterialProperty(material, k_Thickness);
SetupTextureMaterialProperty(material, k_Anisotropy);
SetupTextureMaterialProperty(material, k_IridescenceThickness);
SetupTextureMaterialProperty(material, k_IridescenceMask);
SetupTextureMaterialProperty(material, k_CoatSmoothness);
// Check if we are using specific UVs.

(TextureProperty.UVMapping)material.GetFloat(k_ThicknessMapUV),
(TextureProperty.UVMapping)material.GetFloat(k_AnisotropyMapUV),
(TextureProperty.UVMapping)material.GetFloat(k_IridescenceThicknessMapUV),
(TextureProperty.UVMapping)material.GetFloat(k_IridescenceMaskMapUV),
(TextureProperty.UVMapping)material.GetFloat(k_CoatSmoothnessMapUV),
(TextureProperty.UVMapping)material.GetFloat(k_CoatNormalMapUV),
};

22
com.unity.render-pipelines.high-definition/HDRP/Material/LTCAreaLight/LTCAreaLight.cs


int m_refCounting;
// For area lighting - We pack all texture inside a texture array to reduce the number of resource required
Texture2DArray m_LtcData; // 0: m_LtcGGXMatrix - RGBA, 2: m_LtcDisneyDiffuseMatrix - RGBA, 3: m_LtcMultiGGXFresnelDisneyDiffuse - RGB, A unused
Texture2DArray m_LtcData; // 0: m_LtcGGXMatrix - RGBA, 1: m_LtcDisneyDiffuseMatrix - RGBA
const int k_LtcLUTMatrixDim = 3; // size of the matrix (3x3)
const int k_LtcLUTResolution = 64;

tex.SetPixels(pixels, arrayElement);
}
// Special-case function for 'm_LtcMultiGGXFresnelDisneyDiffuse'.
void LoadLUT(Texture2DArray tex, int arrayElement, TextureFormat format, float[] LtcGGXMagnitudeData, float[] LtcGGXFresnelData, float[] LtcDisneyDiffuseMagnitudeData)
{
const int count = k_LtcLUTResolution * k_LtcLUTResolution;
Color[] pixels = new Color[count];
for (int i = 0; i < count; i++)
{
// We store the result of the subtraction as a run-time optimization.
// See the footnote 2 of "LTC Fresnel Approximation" by Stephen Hill.
pixels[i] = new Color(LtcGGXMagnitudeData[i] - LtcGGXFresnelData[i], LtcGGXFresnelData[i], LtcDisneyDiffuseMagnitudeData[i], 1);
}
tex.SetPixels(pixels, arrayElement);
}
public void Build()
{
Debug.Assert(m_refCounting >= 0);

hideFlags = HideFlags.HideAndDontSave,
wrapMode = TextureWrapMode.Clamp,
filterMode = FilterMode.Bilinear,
name = CoreUtils.GetTextureAutoName(k_LtcLUTResolution, k_LtcLUTResolution, TextureFormat.RGBAHalf, depth: 3, dim: TextureDimension.Tex2DArray, name: "LTC_LUT")
name = CoreUtils.GetTextureAutoName(k_LtcLUTResolution, k_LtcLUTResolution, TextureFormat.RGBAHalf, depth: 2, dim: TextureDimension.Tex2DArray, name: "LTC_LUT")
// TODO: switch to RGBA64 when it becomes available.
LoadLUT(m_LtcData, 2, TextureFormat.RGBAHalf, s_LtcGGXMagnitudeData, s_LtcGGXFresnelData, s_LtcDisneyDiffuseMagnitudeData);
m_LtcData.Apply();
}

1
com.unity.render-pipelines.high-definition/HDRP/Material/LTCAreaLight/LTCAreaLight.hlsl


#define LTC_GGX_MATRIX_INDEX 0 // RGBA
#define LTC_DISNEY_DIFFUSE_MATRIX_INDEX 1 // RGBA
#define LTC_MULTI_GGX_FRESNEL_DISNEY_DIFFUSE_INDEX 2 // RGB, A unused
#define LTC_LUT_SIZE 64
#define LTC_LUT_SCALE ((LTC_LUT_SIZE - 1) * rcp(LTC_LUT_SIZE))

998
com.unity.render-pipelines.high-definition/HDRP/Material/LTCAreaLight/LtcData.DisneyDiffuse.cs
文件差异内容过多而无法显示
查看文件

992
com.unity.render-pipelines.high-definition/HDRP/Material/LTCAreaLight/LtcData.GGX.cs
文件差异内容过多而无法显示
查看文件

69
com.unity.render-pipelines.high-definition/HDRP/Material/Lit/Lit.hlsl


#define CLEAR_COAT_PERCEPTUAL_ROUGHNESS RoughnessToPerceptualRoughness(CLEAR_COAT_ROUGHNESS)
//-----------------------------------------------------------------------------
// Ligth and material classification for the deferred rendering path
// Light and material classification for the deferred rendering path
// Configure what kind of combination is supported
//-----------------------------------------------------------------------------

float3 iblR; // Dominant specular direction, used for IBL in EvaluateBSDF_Env()
float iblPerceptualRoughness;
float3 specularFGD; // Store preconvoled BRDF for both specular and diffuse
float3 specularFGD; // Store preintegrated BSDF for both specular and diffuse
float diffuseFGD;
// Area lights (17 VGPRs)

float3x3 ltcTransformSpecular; // Inverse transformation for GGX (4x VGPRs)
float ltcMagnitudeDiffuse;
float3 ltcMagnitudeFresnel;
// Clear coat
float coatPartLambdaV;

float ltcMagnitudeCoatFresnel;
#if HAS_REFRACTION
// Refraction

// IBL
// Handle IBL + multiscattering
// Handle IBL + multiscattering. Note FGD texture is also use for area light
float specularReflectivity;
GetPreIntegratedFGDGGXAndDisneyDiffuse(NdotV, preLightData.iblPerceptualRoughness, bsdfData.fresnel0, preLightData.specularFGD, preLightData.diffuseFGD, specularReflectivity);
#ifdef USE_DIFFUSE_LAMBERT_BRDF

preLightData.orthoBasisViewNormal[2] = N;
preLightData.orthoBasisViewNormal[1] = cross(preLightData.orthoBasisViewNormal[2], preLightData.orthoBasisViewNormal[0]);
float3 ltcMagnitude = SAMPLE_TEXTURE2D_ARRAY_LOD(_LtcData, s_linear_clamp_sampler, uv, LTC_MULTI_GGX_FRESNEL_DISNEY_DIFFUSE_INDEX, 0).rgb;
float ltcGGXFresnelMagnitudeDiff = ltcMagnitude.r; // The difference of magnitudes of GGX and Fresnel
float ltcGGXFresnelMagnitude = ltcMagnitude.g;
float ltcDisneyDiffuseMagnitude = ltcMagnitude.b;
#ifdef USE_DIFFUSE_LAMBERT_BRDF
preLightData.ltcMagnitudeDiffuse = 1;
#else
preLightData.ltcMagnitudeDiffuse = ltcDisneyDiffuseMagnitude;
#endif
// TODO: the fit seems rather poor. The scaling factor of 0.5 allows us
// to match the reference for rough metals, but further darkens dielectrics.
preLightData.ltcMagnitudeFresnel = bsdfData.fresnel0 * ltcGGXFresnelMagnitudeDiff + (float3)ltcGGXFresnelMagnitude;
preLightData.ltcTransformCoat = 0.0;
if (HasFlag(bsdfData.materialFeatures, MATERIALFEATUREFLAGS_LIT_CLEAR_COAT))
{
float2 uv = LTC_LUT_OFFSET + LTC_LUT_SCALE * float2(CLEAR_COAT_PERCEPTUAL_ROUGHNESS, theta * INV_HALF_PI);

preLightData.ltcTransformCoat = 0.0;
ltcMagnitude = SAMPLE_TEXTURE2D_ARRAY_LOD(_LtcData, s_linear_clamp_sampler, uv, LTC_MULTI_GGX_FRESNEL_DISNEY_DIFFUSE_INDEX, 0).rgb;
ltcGGXFresnelMagnitudeDiff = ltcMagnitude.r; // The difference of magnitudes of GGX and Fresnel
ltcGGXFresnelMagnitude = ltcMagnitude.g;
preLightData.ltcMagnitudeCoatFresnel = (CLEAR_COAT_F0 * ltcGGXFresnelMagnitudeDiff + ltcGGXFresnelMagnitude) * bsdfData.coatMask;
}
else
{
preLightData.ltcTransformCoat = 0.0;
preLightData.ltcMagnitudeCoatFresnel = 0.0;
}
// refraction (forward only)

ltcValue = LTCEvaluate(P1, P2, B, preLightData.ltcTransformDiffuse);
ltcValue *= lightData.diffuseScale;
// We don't multiply by 'bsdfData.diffuseColor' here. It's done only once in PostEvaluateBSDF().
lighting.diffuse = preLightData.ltcMagnitudeDiffuse * ltcValue;
// See comment for specular magnitude, it apply to diffuse as well
lighting.diffuse = preLightData.diffuseFGD * ltcValue;
UNITY_BRANCH if (HasFlag(bsdfData.materialFeatures, MATERIALFEATUREFLAGS_LIT_TRANSMISSION))
{

// Evaluate the specular part
ltcValue = LTCEvaluate(P1, P2, B, preLightData.ltcTransformSpecular);
ltcValue *= lightData.specularScale;
lighting.specular = preLightData.ltcMagnitudeFresnel * ltcValue;
// We need to multiply by the magnitude of the integral of the BRDF
// ref: http://advances.realtimerendering.com/s2016/s2016_ltc_fresnel.pdf
// This value is what we store in specularFGD, so reuse it
lighting.specular = preLightData.specularFGD * ltcValue;
lighting.diffuse *= (1.0 - preLightData.ltcMagnitudeCoatFresnel);
lighting.specular *= (1.0 - preLightData.ltcMagnitudeCoatFresnel);
lighting.specular += preLightData.ltcMagnitudeCoatFresnel * ltcValue;
// For clear coat we don't fetch specularFGD we can use directly the perfect fresnel coatIblF
lighting.diffuse *= (1.0 - preLightData.coatIblF);
lighting.specular *= (1.0 - preLightData.coatIblF);
lighting.specular += preLightData.coatIblF * ltcValue;
}
// Save ALU by applying 'lightData.color' only once.

}
//-----------------------------------------------------------------------------
// EvaluateBSDF_Area - Approximation with Linearly Transformed Cosines
// EvaluateBSDF_Rect - Approximation with Linearly Transformed Cosines
//-----------------------------------------------------------------------------
// #define ELLIPSOIDAL_ATTENUATION

ltcValue = PolygonIrradiance(mul(lightVerts, preLightData.ltcTransformDiffuse));
ltcValue *= lightData.diffuseScale;
// We don't multiply by 'bsdfData.diffuseColor' here. It's done only once in PostEvaluateBSDF().
lighting.diffuse = preLightData.ltcMagnitudeDiffuse * ltcValue;
// See comment for specular magnitude, it apply to diffuse as well
lighting.diffuse = preLightData.diffuseFGD * ltcValue;
UNITY_BRANCH if (HasFlag(bsdfData.materialFeatures, MATERIALFEATUREFLAGS_LIT_TRANSMISSION))
{

// Polygon irradiance in the transformed configuration.
ltcValue = PolygonIrradiance(mul(lightVerts, preLightData.ltcTransformSpecular));
ltcValue *= lightData.specularScale;
lighting.specular += preLightData.ltcMagnitudeFresnel * ltcValue;
// We need to multiply by the magnitude of the integral of the BRDF
// ref: http://advances.realtimerendering.com/s2016/s2016_ltc_fresnel.pdf
// This value is what we store in specularFGD, so reuse it
lighting.specular += preLightData.specularFGD * ltcValue;
lighting.diffuse *= (1.0 - preLightData.ltcMagnitudeCoatFresnel);
lighting.specular *= (1.0 - preLightData.ltcMagnitudeCoatFresnel);
lighting.specular += preLightData.ltcMagnitudeCoatFresnel * ltcValue;
// For clear coat we don't fetch specularFGD we can use directly the perfect fresnel coatIblF
lighting.diffuse *= (1.0 - preLightData.coatIblF);
lighting.specular *= (1.0 - preLightData.coatIblF);
lighting.specular += preLightData.coatIblF * ltcValue;
}
// Save ALU by applying 'lightData.color' only once.

3
com.unity.render-pipelines.high-definition/HDRP/Material/StackLit/StackLit.cs


public float iridescenceIor;
[SurfaceDataAttributes("IridescenceThickness")]
public float iridescenceThickness;
[SurfaceDataAttributes("Iridescence Mask")]
public float iridescenceMask;
// Top interface and media (clearcoat)
[SurfaceDataAttributes("Coat Smoothness")]

// iridescence
public float iridescenceIor;
public float iridescenceThickness;
public float iridescenceMask;
// SSS
public uint diffusionProfile;

34
com.unity.render-pipelines.high-definition/HDRP/Material/StackLit/StackLit.cs.hlsl


#define DEBUGVIEW_STACKLIT_SURFACEDATA_ANISOTROPY (1115)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_IRIDESCENCE_IOR (1116)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_IRIDESCENCE_THICKNESS (1117)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_COAT_SMOOTHNESS (1118)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_COAT_IOR (1119)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_COAT_THICKNESS (1120)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_COAT_EXTINCTION_COEFFICIENT (1121)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_DIFFUSION_PROFILE (1122)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_SUBSURFACE_MASK (1123)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_THICKNESS (1124)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_IRIDESCENCE_MASK (1118)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_COAT_SMOOTHNESS (1119)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_COAT_IOR (1120)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_COAT_THICKNESS (1121)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_COAT_EXTINCTION_COEFFICIENT (1122)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_DIFFUSION_PROFILE (1123)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_SUBSURFACE_MASK (1124)
#define DEBUGVIEW_STACKLIT_SURFACEDATA_THICKNESS (1125)
//
// UnityEngine.Experimental.Rendering.HDPipeline.StackLit+BSDFData: static fields

#define DEBUGVIEW_STACKLIT_BSDFDATA_COAT_EXTINCTION (1174)
#define DEBUGVIEW_STACKLIT_BSDFDATA_IRIDESCENCE_IOR (1175)
#define DEBUGVIEW_STACKLIT_BSDFDATA_IRIDESCENCE_THICKNESS (1176)
#define DEBUGVIEW_STACKLIT_BSDFDATA_DIFFUSION_PROFILE (1177)
#define DEBUGVIEW_STACKLIT_BSDFDATA_SUBSURFACE_MASK (1178)
#define DEBUGVIEW_STACKLIT_BSDFDATA_THICKNESS (1179)
#define DEBUGVIEW_STACKLIT_BSDFDATA_USE_THICK_OBJECT_MODE (1180)
#define DEBUGVIEW_STACKLIT_BSDFDATA_TRANSMITTANCE (1181)
#define DEBUGVIEW_STACKLIT_BSDFDATA_IRIDESCENCE_MASK (1177)
#define DEBUGVIEW_STACKLIT_BSDFDATA_DIFFUSION_PROFILE (1178)
#define DEBUGVIEW_STACKLIT_BSDFDATA_SUBSURFACE_MASK (1179)
#define DEBUGVIEW_STACKLIT_BSDFDATA_THICKNESS (1180)
#define DEBUGVIEW_STACKLIT_BSDFDATA_USE_THICK_OBJECT_MODE (1181)
#define DEBUGVIEW_STACKLIT_BSDFDATA_TRANSMITTANCE (1182)
// Generated from UnityEngine.Experimental.Rendering.HDPipeline.StackLit+SurfaceData
// PackingRules = Exact

float anisotropy;
float iridescenceIor;
float iridescenceThickness;
float iridescenceMask;
float coatPerceptualSmoothness;
float coatIor;
float coatThickness;

float3 coatExtinction;
float iridescenceIor;
float iridescenceThickness;
float iridescenceMask;
uint diffusionProfile;
float subsurfaceMask;
float thickness;

break;
case DEBUGVIEW_STACKLIT_SURFACEDATA_IRIDESCENCE_THICKNESS:
result = surfacedata.iridescenceThickness.xxx;
break;
case DEBUGVIEW_STACKLIT_SURFACEDATA_IRIDESCENCE_MASK:
result = surfacedata.iridescenceMask.xxx;
break;
case DEBUGVIEW_STACKLIT_SURFACEDATA_COAT_SMOOTHNESS:
result = surfacedata.coatPerceptualSmoothness.xxx;

break;
case DEBUGVIEW_STACKLIT_BSDFDATA_IRIDESCENCE_THICKNESS:
result = bsdfdata.iridescenceThickness.xxx;
break;
case DEBUGVIEW_STACKLIT_BSDFDATA_IRIDESCENCE_MASK:
result = bsdfdata.iridescenceMask.xxx;
break;
case DEBUGVIEW_STACKLIT_BSDFDATA_DIFFUSION_PROFILE:
result = GetIndexColor(bsdfdata.diffusionProfile);

452
com.unity.render-pipelines.high-definition/HDRP/Material/StackLit/StackLit.hlsl


//-----------------------------------------------------------------------------
// Choose between Lambert diffuse and Disney diffuse (enable only one of them)
// TODO Disney Diffuse
// Enable reference mode for IBL and area lights
// Both reference defined below can be defined only if LightLoop is present, else we get a compile error
#ifdef HAS_LIGHTLOOP
// TODO for stacklit
// #define STACK_LIT_DISPLAY_REFERENCE_AREA
// #define STACK_LIT_DISPLAY_REFERENCE_IBL
#endif
//-----------------------------------------------------------------------------
// Texture and constant buffer declaration
//-----------------------------------------------------------------------------

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

#ifdef _MATERIAL_FEATURE_COAT
# define COAT_NB_LOBES 1
# define COAT_LOBE_IDX 0
# define COAT_LOBE_IDX 0 // Leave coat index == 0, otherwise change IF_FEATURE_COAT etc
# define BASE_LOBEA_IDX (COAT_LOBE_IDX+1)
# define BASE_LOBEB_IDX (BASE_LOBEA_IDX+1)

#else // ! _MATERIAL_FEATURE_COAT
// For iridescence, we will reuse the recompute per light keyword even when not vlayered.
// When vlayered and iridescence is on, iridescence is also automatically recomputed per light too,
// so the following gives the recompute option for iridescence when NOT vlayered:
#ifdef VLAYERED_RECOMPUTE_PERLIGHT
# if _MATERIAL_FEATURE_IRIDESCENCE
# define IRIDESCENCE_RECOMPUTE_PERLIGHT
# endif
#endif
# undef VLAYERED_RECOMPUTE_PERLIGHT
# undef VLAYERED_USE_REFRACTED_ANGLES_FOR_BASE
# undef _MATERIAL_FEATURE_COAT_NORMALMAP // enforce a "coat enabled subfeature" condition on this shader_feature

bsdfData.anisotropy = anisotropy;
bsdfData.tangentWS = tangentWS;
bsdfData.bitangentWS = bitangentWS;
}
void FillMaterialIridescence(float mask, float thickness, float ior, inout BSDFData bsdfData)
{
bsdfData.iridescenceMask = mask;
bsdfData.iridescenceThickness = thickness;
bsdfData.iridescenceIor = ior;
}
void FillMaterialCoatData(float coatPerceptualRoughness, float coatIor, float coatThickness, float3 coatExtinction, inout BSDFData bsdfData)

bsdfData.lobeMix = surfaceData.lobeMix;
// There is no metallic with SSS and specular color mode
float metallic = HasFlag(surfaceData.materialFeatures, /*MATERIALFEATUREFLAGS_LIT_SPECULAR_COLOR |*/ MATERIALFEATUREFLAGS_STACK_LIT_SUBSURFACE_SCATTERING | MATERIALFEATUREFLAGS_STACK_LIT_TRANSMISSION) ? 0.0 : surfaceData.metallic;
float metallic = HasFlag(surfaceData.materialFeatures, 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, IorToFresnel0(surfaceData.dielectricIor));

FillMaterialAnisotropy(surfaceData.anisotropy, surfaceData.tangentWS, cross(surfaceData.normalWS, surfaceData.tangentWS), bsdfData);
}
if (HasFlag(surfaceData.materialFeatures, MATERIALFEATUREFLAGS_STACK_LIT_IRIDESCENCE))
{
FillMaterialIridescence(surfaceData.iridescenceMask, surfaceData.iridescenceThickness, surfaceData.iridescenceIor, bsdfData);
}
if (HasFlag(surfaceData.materialFeatures, MATERIALFEATUREFLAGS_STACK_LIT_COAT))
{
FillMaterialCoatData(PerceptualSmoothnessToPerceptualRoughness(surfaceData.coatPerceptualSmoothness),

{
float NdotV[NB_NORMALS]; // Could be negative due to normal mapping, use ClampNdotV()
float geomNdotV;
float bottomAngleFGD;
float bottomAngleFGD; // Only used when dual normal maps are enabled
float TdotV; // Stored only when VLAYERED_RECOMPUTE_PERLIGHT
float BdotV;

// is split by anisotropy, while IBL anisotropy is delt with a hack on the used iblR
// vector, with the non-anisotropic roughness).
float3 specularFGD[TOTAL_NB_LOBES]; // Store preconvoled BSDF for both specular and diffuse
float3 specularFGD[TOTAL_NB_LOBES]; // Store preintegrated BSDF for both specular and diffuse
float diffuseFGD;

// for it (hence the name iblF in Lit). Here, we will fold all data into
// lobe-indexed arrays.
// For iridescence, to avoid recalculation per analytical light, we store the calculated
// iridescence reflectance that was used (as an approximation to "iridescent pre-integrated" FGD)
// to calculate FGD with the precalculated table:
float3 fresnelIridforCalculatingFGD;
// For clarity, we will dump the base layer lobes roughnesses used by analytical lights
// here, to avoid confusion with the per-vlayer (vs per lobe) vLayerPerceptualRoughness

// For IBLs (and analytical lights if approximation is used)
float3 vLayerEnergyCoeff[NB_VLAYERS];
//float vLayerPerceptualRoughness[NB_VLAYERS];
// TODOENERGY
// For now since FGD fetches aren't used in compute adding (instead we do non integrated
// Fresnel( ) evaluations and 1 - Fresnel( ) which is wrong, the former only ok for analytical
// lights for the top interface for R12), we will use these for FGD fetches but keep them
// for BSDF( ) eval for analytical lights since the later don't use FGD terms.
// TODOENERGY:
// For the vlayered case, fold compensation into FGD terms during ComputeAdding

//See VLAYERED_DIFFUSE_ENERGY_HACKED_TERM
float3 diffuseEnergy;
float3 diffuseEnergy; // We don't fold into diffuseFGD because of analytical lights that require it separately.
//
// Area lights
// TODO: 'orthoBasisViewNormal' is just a rotation around the normal and should thus be just 1x VGPR.
float3x3 orthoBasisViewNormal[NB_NORMALS]; // Right-handed view-dependent orthogonal basis around the normal
float3x3 ltcTransformDiffuse; // Inverse transformation for Lambertian or Disney Diffuse
float3x3 ltcTransformSpecular[TOTAL_NB_LOBES]; // Inverse transformation for GGX
//-----------------------------------------------------------------------------
//
// PreLightData: Vertically Layered BSDF Computations ("VLayering")

// correct is a (1-FGD) term at the top), ie, for everything below the first interface,
// but use the actual Fresnel term for that light for R12 at the start
// of the algo (top interface) and not FGD.
//
// Interaction and performance considerations with the recompute per light option:
//
// If you recompute everything per light, FGD fetches per light might be expensive,
// so could use the FGD used for IBLs, angle used will be more or less incorrect
// depending on light directions, but probably better than using F0 terms everywhere).

// Update energy
R12 = F_Schlick(bsdfData.fresnel0, ctiForFGD);
if (HasFlag(bsdfData.materialFeatures, MATERIALFEATUREFLAGS_STACK_LIT_IRIDESCENCE))
{
if (bsdfData.iridescenceMask > 0.0)
{
//float topIor = bsdfData.coatIor;
// TODO:
// We will avoid using coatIor directly as with the fake refraction, it can cause TIR
// which even when handled in EvalIridescence (tested), doesn't look pleasing and
// creates a discontinuity.
float scale = clamp((1.0-bsdfData.coatPerceptualRoughness), 0.0, 1.0);
float topIor = lerp(1.0001, bsdfData.coatIor, scale);
R12 = lerp(R12, EvalIridescence(topIor, ctiForFGD, bsdfData.iridescenceThickness, bsdfData.fresnel0), bsdfData.iridescenceMask);
}
}
T12 = 0.0;
#ifdef VLAYERED_DIFFUSE_ENERGY_HACKED_TERM
// Still should use FGD!

#endif
}
void PreLightData_SetupAreaLightBasis(float3 V, float3 N, int normalIdx, inout PreLightData preLightData)
{
// Construct a right-handed view-dependent orthogonal basis around the normal
preLightData.orthoBasisViewNormal[normalIdx][0] = normalize(V - N * preLightData.NdotV[normalIdx]); // Do not clamp NdotV here
preLightData.orthoBasisViewNormal[normalIdx][2] = N;
preLightData.orthoBasisViewNormal[normalIdx][1] = cross(preLightData.orthoBasisViewNormal[normalIdx][2], preLightData.orthoBasisViewNormal[normalIdx][0]);
}
void PreLightData_LoadLtcTransformSpecular(float2 uv, int lobeIdx, inout PreLightData preLightData)
{
// Get the inverse LTC matrix for GGX
// Note we load the matrix transpose (avoid to have to transpose it in shader)
preLightData.ltcTransformSpecular[lobeIdx] = 0.0;
preLightData.ltcTransformSpecular[lobeIdx]._m22 = 1.0;
preLightData.ltcTransformSpecular[lobeIdx]._m00_m02_m11_m20 = SAMPLE_TEXTURE2D_ARRAY_LOD(_LtcData, s_linear_clamp_sampler, uv, LTC_GGX_MATRIX_INDEX, 0);
}
void PreLightData_SetupAreaLights(BSDFData bsdfData, float3 V, float3 N[NB_NORMALS], float NdotV[NB_NORMALS], inout PreLightData preLightData)
{
// For sampling the LUTs
float theta[NB_NORMALS];
float2 uv[TOTAL_NB_LOBES];
// These 2 cases will generate the same code when no dual normal maps since COAT_NORMAL_IDX == BASE_NORMAL_IDX == 0,
// and one will be pruned out:
theta[COAT_NORMAL_IDX] = FastACosPos(NdotV[COAT_NORMAL_IDX]);
theta[BASE_NORMAL_IDX] = FastACosPos(NdotV[BASE_NORMAL_IDX]);
PreLightData_SetupAreaLightBasis(V, N[COAT_NORMAL_IDX], COAT_NORMAL_IDX, preLightData);
PreLightData_SetupAreaLightBasis(V, N[BASE_NORMAL_IDX], BASE_NORMAL_IDX, preLightData);
if( IsVLayeredEnabled(bsdfData) )
{
uv[COAT_LOBE_IDX] = LTC_LUT_OFFSET + LTC_LUT_SCALE * float2(bsdfData.coatPerceptualRoughness, theta[COAT_NORMAL_IDX] * INV_HALF_PI);
PreLightData_LoadLtcTransformSpecular(uv[COAT_LOBE_IDX], COAT_LOBE_IDX, preLightData);
}
uv[BASE_LOBEA_IDX] = LTC_LUT_OFFSET + LTC_LUT_SCALE * float2(bsdfData.perceptualRoughnessA, theta[BASE_NORMAL_IDX] * INV_HALF_PI);
uv[BASE_LOBEB_IDX] = LTC_LUT_OFFSET + LTC_LUT_SCALE * float2(bsdfData.perceptualRoughnessB, theta[BASE_NORMAL_IDX] * INV_HALF_PI);
PreLightData_LoadLtcTransformSpecular(uv[BASE_LOBEA_IDX], BASE_LOBEA_IDX, preLightData);
PreLightData_LoadLtcTransformSpecular(uv[BASE_LOBEB_IDX], BASE_LOBEB_IDX, preLightData);
#ifdef USE_DIFFUSE_LAMBERT_BRDF
preLightData.ltcTransformDiffuse = k_identity3x3;
#else
// TODO
// Get the inverse LTC matrix for Disney Diffuse
//preLightData.ltcTransformDiffuse = 0.0;
//preLightData.ltcTransformDiffuse._m22 = 1.0;
//preLightData.ltcTransformDiffuse._m00_m02_m11_m20 = SAMPLE_TEXTURE2D_ARRAY_LOD(_LtcData, s_linear_clamp_sampler, uv, LTC_DISNEY_DIFFUSE_MATRIX_INDEX, 0);
#endif
}
PreLightData GetPreLightData(float3 V, PositionInputs posInput, inout BSDFData bsdfData)
{
PreLightData preLightData;

//
// preLightData.iblPerceptualRoughness[]
// preLightData.vLayerEnergyCoeff[]
// preLightData.diffuseEnergy (just one term, computed ifdef VLAYERED_DIFFUSE_ENERGY_HACKED_TERM)
// preLightData.iblAnisotropy[] (only if anisotropy is enabled)
// If we're not using VLAYERED_RECOMPUTE_PERLIGHT we also have calculated

iblN[0] = iblN[1] = N[0];
} // ...no anisotropy
float3 f0forCalculatingFGD = bsdfData.fresnel0;
if (HasFlag(bsdfData.materialFeatures, MATERIALFEATUREFLAGS_STACK_LIT_IRIDESCENCE))
{
float topIor = 1.0; // Air on top, no coat.
if (bsdfData.iridescenceMask > 0.0)
{
preLightData.fresnelIridforCalculatingFGD = EvalIridescence(topIor, NdotV[0], bsdfData.iridescenceThickness, bsdfData.fresnel0);
f0forCalculatingFGD = lerp(f0forCalculatingFGD, preLightData.fresnelIridforCalculatingFGD, bsdfData.iridescenceMask);
}
}
// IBL
// Handle IBL pre calculated data + GGX multiscattering energy loss compensation term

bsdfData.fresnel0,
f0forCalculatingFGD,
preLightData.specularFGD[BASE_LOBEA_IDX],
diffuseFGD[0],
specularReflectivity[BASE_LOBEA_IDX]);

bsdfData.fresnel0,
f0forCalculatingFGD,
preLightData.specularFGD[BASE_LOBEB_IDX],
diffuseFGD[1],
specularReflectivity[BASE_LOBEB_IDX]);

preLightData.diffuseFGD = lerp(diffuseFGD[0], diffuseFGD[1], bsdfData.lobeMix);
#ifdef USE_DIFFUSE_LAMBERT_BRDF
// TODO: DiffuseFGD not done anyway, applied on bakeddiffuse:
// Area Lights:
PreLightData_SetupAreaLights(bsdfData, V, N, NdotV, preLightData);
return preLightData;
}

// This function require the 3 structure surfaceData, builtinData, bsdfData because it may require both the engine side data, and data that will not be store inside the gbuffer.
float3 GetBakedDiffuseLighting(SurfaceData surfaceData, BuiltinData builtinData, BSDFData bsdfData, PreLightData preLightData)
{
// Note bsdfData isn't modified outside of this function scope.
// SSS Texturing mode can change albedo because diffuse maps can already contain some SSS too
bsdfData.diffuseColor = GetModifiedDiffuseColorForSSS(bsdfData); // local modification of bsdfData
}

#endif
// Premultiply bake diffuse lighting information
return builtinData.bakeDiffuseLighting * surfaceData.ambientOcclusion * bsdfData.diffuseColor + builtinData.emissiveColor;
// preLightData.diffuseEnergy will be 1,1,1 if no vlayering or no VLAYERED_DIFFUSE_ENERGY_HACKED_TERM
return builtinData.bakeDiffuseLighting * preLightData.diffuseFGD * preLightData.diffuseEnergy * surfaceData.ambientOcclusion * bsdfData.diffuseColor + builtinData.emissiveColor;
}

// Note (see 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.
// TODOENERGY:
// 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
#endif //...VLAYERED_RECOMPUTE_PERLIGHT

// TODO: Proper Fresnel
float3 F = F_Schlick(bsdfData.fresnel0, savedLdotH);
if (HasFlag(bsdfData.materialFeatures, MATERIALFEATUREFLAGS_STACK_LIT_IRIDESCENCE))
{
float3 fresnelIridescent = preLightData.fresnelIridforCalculatingFGD;
#ifdef IRIDESCENCE_RECOMPUTE_PERLIGHT
float topIor = 1.0; // default air on top.
fresnelIridescent = EvalIridescence(topIor, savedLdotH, bsdfData.iridescenceThickness, bsdfData.fresnel0);
#endif
F = lerp(F, fresnelIridescent, bsdfData.iridescenceMask);
}
if (HasFlag(bsdfData.materialFeatures, MATERIALFEATUREFLAGS_STACK_LIT_ANISOTROPY))
{
float TdotH, TdotL, BdotH, BdotL;

float3 diffuseTerm = Lambert() * max(0, NdotL[DNLV_BASE_IDX]);
#ifdef VLAYERED_DIFFUSE_ENERGY_HACKED_TERM
// TODOTODO: Energy when vlayered.
// TODOENERGYDIFFUSE: Energy when vlayered.
// Controlled by ifdef VLAYERED_DIFFUSE_ENERGY_HACKED_TERM
// since preLightData.diffuseEnergy == float3(1,1,1) when not defined
diffuseTerm *= preLightData.diffuseEnergy;
}
#endif

float NdotV = ClampNdotV(unclampedNdotV);
float LdotV = dot(L, V);
// We use diffuse lighting for accumulation since it is going to be blurred during the SSS pass.
// TODOENERGYDIFFUSE:
//
// With coat, will need a diffuse energy term here. eg preLightData.diffuseEnergyTransmitted, from something like e_T0i,
// but we would need to balance it with the term used from e_Ti0 == preLightData.diffuseEnergy, as
// the term as computed with VLAYERED_DIFFUSE_ENERGY_HACKED_TERM, assumes that all light that is not (Fresnel) reflected
// at the bottom interface thus corresponds to diffuse light.
// If we use the same term, we could just apply it in the end to diffuse light since coat can't produce diffuse lighting,
// so diffuse lighting from the base interface should all have the term applied. (Then, we would need to make sure the
// energy term is separate from diffuseFGD.) But the terms are not the same:
//
// Even without energy conservation, preLightData.diffuseEnergyTransmitted should still != preLightData.diffuseEnergy
// as although statistics T12 == T21 for the interface, the stack has terms e_T0i != e_Ti0
lighting.diffuse += EvaluateTransmission(bsdfData, transmittance, NdotL, NdotV, LdotV, attenuation * lightData.diffuseScale);
}

float3 color;
float attenuation;
// For shadow attenuation (ie receiver bias), always use the geometric normal:
EvaluateLight_Punctual(lightLoopContext, posInput, lightData, bakeLightingData, shadowBiasNormal, L,
lightToSample, distances, color, attenuation);

float NdotV = ClampNdotV(unclampedNdotV);
float LdotV = dot(L, V);
// We use diffuse lighting for accumulation since it is going to be blurred during the SSS pass.
// TODOENERGYDIFFUSE
lighting.diffuse += EvaluateTransmission(bsdfData, transmittance, NdotL, NdotV, LdotV, attenuation * lightData.diffuseScale);
}

return lighting;
}
// NEWLITTODO: For a refence rendering option for area light, like LIT_DISPLAY_REFERENCE_AREA option in eg EvaluateBSDF_<area light type> :
// NEWLITTODO: For a refence rendering option for area light, like STACK_LIT_DISPLAY_REFERENCE_AREA option in eg EvaluateBSDF_<area light type> :
//#include "LitReference.hlsl"
//-----------------------------------------------------------------------------

DirectLighting lighting;
ZERO_INITIALIZE(DirectLighting, lighting);
//NEWLITTODO
float3 positionWS = posInput.positionWS;
#ifdef STACK_LIT_DISPLAY_REFERENCE_AREA
// TODO This ref doesn't handle the StackLit model
IntegrateBSDF_LineRef(V, positionWS, preLightData, lightData, bsdfData,
lighting.diffuse, lighting.specular);
#else
float len = lightData.size.x;
float3 T = lightData.right;
float3 unL = lightData.positionWS - positionWS;
// Pick the major axis of the ellipsoid.
float3 axis = lightData.right;
// We define the ellipsoid s.t. r1 = (r + len / 2), r2 = r3 = r.
// TODO: This could be precomputed.
float radius = rsqrt(lightData.rangeAttenuationScale); // // rangeAttenuationScale is inverse Square Radius
float invAspectRatio = saturate(radius / (radius + (0.5 * len)));
// Compute the light attenuation.
float intensity = EllipsoidalDistanceAttenuation(unL, lightData.rangeAttenuationScale, lightData.rangeAttenuationBias,
axis, invAspectRatio);
// Terminate if the shaded point is too far away.
if (intensity == 0.0)
return lighting;
lightData.diffuseScale *= intensity;
lightData.specularScale *= intensity;
// Translate the light s.t. the shaded point is at the origin of the coordinate system.
lightData.positionWS -= positionWS;
// TODO: some of this could be precomputed.
float3 P1 = lightData.positionWS - T * (0.5 * len);
float3 P2 = lightData.positionWS + T * (0.5 * len);
// Rotate the endpoints into the local coordinate system.
float3 localP1 = mul(P1, transpose(preLightData.orthoBasisViewNormal[BASE_NORMAL_IDX]));
float3 localP2 = mul(P2, transpose(preLightData.orthoBasisViewNormal[BASE_NORMAL_IDX]));
// Compute the binormal in the local coordinate system.
float3 B = normalize(cross(localP1, localP2));
float ltcValue;
// Evaluate the diffuse part
ltcValue = LTCEvaluate(localP1, localP2, B, preLightData.ltcTransformDiffuse);
ltcValue *= lightData.diffuseScale;
// We don't multiply by 'bsdfData.diffuseColor' here. It's done only once in PostEvaluateBSDF().
lighting.diffuse = preLightData.diffuseFGD * preLightData.diffuseEnergy * ltcValue;
UNITY_BRANCH if (HasFlag(bsdfData.materialFeatures, MATERIALFEATUREFLAGS_STACK_LIT_TRANSMISSION))
{
// Flip the view vector and the normal. The bitangent stays the same.
float3x3 flipMatrix = float3x3(-1, 0, 0,
0, 1, 0,
0, 0, -1);
// Use the Lambertian approximation for performance reasons.
// The matrix multiplication should not generate any extra ALU on GCN.
// TODO: double evaluation is very inefficient! This is a temporary solution.
ltcValue = LTCEvaluate(localP1, localP2, B, mul(flipMatrix, k_identity3x3));
ltcValue *= lightData.diffuseScale;
// TODOENERGYDIFFUSE: In Lit with Lambert, there's no diffuseFGD, it is one. In our case, we also
// need a diffuse energy term when vlayered. See preLightData.diffuseEnergyTransmitted
// We use diffuse lighting for accumulation since it is going to be blurred during the SSS pass.
// We don't multiply by 'bsdfData.diffuseColor' here. It's done only once in PostEvaluateBSDF().
lighting.diffuse += bsdfData.transmittance * ltcValue;
}
// Evaluate the specular lobes for the stack
IF_DEBUG( if ( _DebugLobeMask.y != 0.0) )
{
ltcValue = LTCEvaluate(localP1, localP2, B, preLightData.ltcTransformSpecular[BASE_LOBEA_IDX]);
lighting.specular += preLightData.specularFGD[BASE_LOBEA_IDX] * ltcValue;
}
IF_DEBUG( if ( _DebugLobeMask.z != 0.0) )
{
ltcValue = LTCEvaluate(localP1, localP2, B, preLightData.ltcTransformSpecular[BASE_LOBEB_IDX]);
lighting.specular += preLightData.specularFGD[BASE_LOBEB_IDX] * ltcValue;
}
if (IsVLayeredEnabled(bsdfData))
{
if (IsCoatNormalMapEnabled(bsdfData))
{
// Rotate the endpoints into the local coordinate system using the coat normal.
localP1 = mul(P1, transpose(preLightData.orthoBasisViewNormal[COAT_NORMAL_IDX]));
localP2 = mul(P2, transpose(preLightData.orthoBasisViewNormal[COAT_NORMAL_IDX]));
// Reompute the binormal in the local coordinate system.
B = normalize(cross(localP1, localP2));
}
IF_DEBUG( if ( _DebugLobeMask.x != 0.0) )
{
ltcValue = LTCEvaluate(localP1, localP2, B, preLightData.ltcTransformSpecular[COAT_LOBE_IDX]);
lighting.specular += preLightData.specularFGD[COAT_LOBE_IDX] * ltcValue;
}
}
lighting.specular *= lightData.specularScale;
// Save ALU by applying 'lightData.color' only once.
lighting.diffuse *= lightData.color;
lighting.specular *= lightData.color;
#ifdef DEBUG_DISPLAY
if (_DebugLightingMode == DEBUGLIGHTINGMODE_LUX_METER)
{
// Only lighting, not BSDF
// Apply area light on lambert then multiply by PI to cancel Lambert
lighting.diffuse = LTCEvaluate(localP1, localP2, B, k_identity3x3);
lighting.diffuse *= PI * lightData.diffuseScale;
}
#endif
#endif // STACK_LIT_DISPLAY_REFERENCE_AREA
// EvaluateBSDF_Area - Approximation with Linearly Transformed Cosines
// EvaluateBSDF_Rect - Approximation with Linearly Transformed Cosines
//-----------------------------------------------------------------------------
// #define ELLIPSOIDAL_ATTENUATION

DirectLighting lighting;
ZERO_INITIALIZE(DirectLighting, lighting);
//NEWLITTODO
float3 positionWS = posInput.positionWS;
#ifdef STACK_LIT_DISPLAY_REFERENCE_AREA
IntegrateBSDF_AreaRef(V, positionWS, preLightData, lightData, bsdfData,
lighting.diffuse, lighting.specular);
#else
float3 unL = lightData.positionWS - positionWS;
if (dot(lightData.forward, unL) >= 0.0001)
{
// The light is back-facing.
return lighting;
}
// Rotate the light direction into the light space.
float3x3 lightToWorld = float3x3(lightData.right, lightData.up, -lightData.forward);
unL = mul(unL, transpose(lightToWorld));
// TODO: This could be precomputed.
float halfWidth = lightData.size.x * 0.5;
float halfHeight = lightData.size.y * 0.5;
// Define the dimensions of the attenuation volume.
// TODO: This could be precomputed.
float radius = rsqrt(lightData.rangeAttenuationScale); // rangeAttenuationScale is inverse Square Radius
float3 invHalfDim = rcp(float3(radius + halfWidth,
radius + halfHeight,
radius));
// Compute the light attenuation.
#ifdef ELLIPSOIDAL_ATTENUATION
// The attenuation volume is an axis-aligned ellipsoid s.t.
// r1 = (r + w / 2), r2 = (r + h / 2), r3 = r.
float intensity = EllipsoidalDistanceAttenuation(unL, invHalfDim);
#else
// The attenuation volume is an axis-aligned box s.t.
// hX = (r + w / 2), hY = (r + h / 2), hZ = r.
float intensity = BoxDistanceAttenuation(unL, invHalfDim);
#endif
// Terminate if the shaded point is too far away.
if (intensity == 0.0)
return lighting;
lightData.diffuseScale *= intensity;
lightData.specularScale *= intensity;
// Translate the light s.t. the shaded point is at the origin of the coordinate system.
lightData.positionWS -= positionWS;
float4x3 lightVerts;
// TODO: some of this could be precomputed.
lightVerts[0] = lightData.positionWS + lightData.right * halfWidth + lightData.up * halfHeight;
lightVerts[1] = lightData.positionWS + lightData.right * halfWidth + lightData.up * -halfHeight;
lightVerts[2] = lightData.positionWS + lightData.right * -halfWidth + lightData.up * -halfHeight;
lightVerts[3] = lightData.positionWS + lightData.right * -halfWidth + lightData.up * halfHeight;
// Rotate the endpoints into the local coordinate system.
float4x3 localLightVerts = mul(lightVerts, transpose(preLightData.orthoBasisViewNormal[BASE_NORMAL_IDX]));
float ltcValue;
// Evaluate the diffuse part
// Polygon irradiance in the transformed configuration.
ltcValue = PolygonIrradiance(mul(localLightVerts, preLightData.ltcTransformDiffuse));
ltcValue *= lightData.diffuseScale;
// We don't multiply by 'bsdfData.diffuseColor' here. It's done only once in PostEvaluateBSDF().
lighting.diffuse = preLightData.diffuseFGD * preLightData.diffuseEnergy * ltcValue;
UNITY_BRANCH if (HasFlag(bsdfData.materialFeatures, MATERIALFEATUREFLAGS_STACK_LIT_TRANSMISSION))
{
// Flip the view vector and the normal. The bitangent stays the same.
float3x3 flipMatrix = float3x3(-1, 0, 0,
0, 1, 0,
0, 0, -1);
// Use the Lambertian approximation for performance reasons.
// The matrix multiplication should not generate any extra ALU on GCN.
float3x3 ltcTransform = mul(flipMatrix, k_identity3x3);
// Polygon irradiance in the transformed configuration.
// TODO: double evaluation is very inefficient! This is a temporary solution.
ltcValue = PolygonIrradiance(mul(localLightVerts, ltcTransform));
ltcValue *= lightData.diffuseScale;
// TODOENERGYDIFFUSE: In Lit with Lambert, there's no diffuseFGD, it is one. In our case, we also
// need a diffuse energy term when vlayered. See preLightData.diffuseEnergyTransmitted
// We use diffuse lighting for accumulation since it is going to be blurred during the SSS pass.
// We don't multiply by 'bsdfData.diffuseColor' here. It's done only once in PostEvaluateBSDF().
lighting.diffuse += bsdfData.transmittance * ltcValue;
}
// Evaluate the specular lobes for the stack
IF_DEBUG( if ( _DebugLobeMask.y != 0.0) )
{
// Polygon irradiance in the transformed configuration.
ltcValue = PolygonIrradiance(mul(localLightVerts, preLightData.ltcTransformSpecular[BASE_LOBEA_IDX]));
lighting.specular += preLightData.specularFGD[BASE_LOBEA_IDX] * ltcValue;
}
IF_DEBUG( if ( _DebugLobeMask.z != 0.0) )
{
ltcValue = PolygonIrradiance(mul(localLightVerts, preLightData.ltcTransformSpecular[BASE_LOBEB_IDX]));
lighting.specular += preLightData.specularFGD[BASE_LOBEB_IDX] * ltcValue;
}
if (IsVLayeredEnabled(bsdfData))
{
if (IsCoatNormalMapEnabled(bsdfData))
{
localLightVerts = mul(lightVerts, transpose(preLightData.orthoBasisViewNormal[COAT_NORMAL_IDX]));
}
IF_DEBUG( if ( _DebugLobeMask.x != 0.0) )
{
ltcValue = PolygonIrradiance(mul(localLightVerts, preLightData.ltcTransformSpecular[COAT_LOBE_IDX]));
lighting.specular += preLightData.specularFGD[COAT_LOBE_IDX] * ltcValue;
}
}
lighting.specular *= lightData.specularScale;
// Save ALU by applying 'lightData.color' only once.
lighting.diffuse *= lightData.color;
lighting.specular *= lightData.color;
#ifdef DEBUG_DISPLAY
if (_DebugLightingMode == DEBUGLIGHTINGMODE_LUX_METER)
{
// Only lighting, not BSDF
// Apply area light on lambert then multiply by PI to cancel Lambert
lighting.diffuse = PolygonIrradiance(mul(localLightVerts, k_identity3x3));
lighting.diffuse *= PI * lightData.diffuseScale;
}
#endif
#endif // STACK_LIT_DISPLAY_REFERENCE_AREA
return lighting;
}

float3 positionWS = posInput.positionWS;
float weight = 0.0;
#ifdef LIT_DISPLAY_REFERENCE_IBL
#ifdef STACK_LIT_DISPLAY_REFERENCE_IBL
envLighting = IntegrateSpecularGGXIBLRef(lightLoopContext, V, preLightData, lightData, bsdfData);

for( i = 0; i < TOTAL_NB_LOBES; ++i)
{
//TOTO not needed anymore, single R
R[i] = preLightData.iblR[i];
tempWeight[i] = 1.0;
}

weight /= TOTAL_NB_LOBES;
weight = tempWeight[1];
#endif // LIT_DISPLAY_REFERENCE_IBL
#endif // STACK_LIT_DISPLAY_REFERENCE_IBL
UpdateLightingHierarchyWeights(hierarchyWeight, weight);
envLighting *= weight * lightData.multiplier;

33
com.unity.render-pipelines.high-definition/HDRP/Material/StackLit/StackLit.shader


[HideInInspector] _ThicknessRange("Thickness Range", Vector) = (0, 1, 0, 0)
[ToggleUI] _EnableIridescence("Enable Iridescence", Float) = 0.0 // UI only
_IridescenceIor("Coat IOR", Range(1.0, 2.0)) = 1.5
_IridescenceThickness("_IridescenceThickness", Range(0.0, 1.0)) = 0.0
_IridescenceThicknessMap("IridescenceThickness Color Map", 2D) = "black" {}
_IridescenceIor("TopIOR over iridescent layer", Range(1.0, 2.0)) = 1.5
[HideInInspector] _IridescenceThicknessMapShow("IridescenceThickness Map Show", Float) = 0
_IridescenceThickness("IridescenceThickness", Range(0.0, 1.0)) = 0.0
_IridescenceThicknessMap("IridescenceThickness Map", 2D) = "black" {}
_IridescenceThicknessMapChannel("IridescenceThickness Mask Map Channel", Float) = 0.0
_IridescenceThicknessMapChannelMask("IridescenceThickness Mask Map Channel Mask", Vector) = (1, 0, 0, 0)
_IridescenceThicknessMapChannel("IridescenceThickness Map Channel", Float) = 0.0
_IridescenceThicknessMapChannelMask("IridescenceThickness Map Channel Mask", Vector) = (1, 0, 0, 0)
_IridescenceThicknessRemap("IridescenceThickness Remap", Vector) = (0, 1, 0, 0)
[ToggleUI] _IridescenceThicknessRemapInverted("Invert IridescenceThickness Remap", Float) = 0.0
[HideInInspector] _IridescenceMaskMapShow("Iridescence Mask Map Show", Float) = 0
_IridescenceMask("Iridescence Mask", Range(0.0, 1.0)) = 1.0
_IridescenceMaskMap("Iridescence Mask Map", 2D) = "black" {}
_IridescenceMaskUseMap("Iridescence Mask Use Map", Float) = 0
_IridescenceMaskMapUV("Iridescence Mask Map UV", Float) = 0.0
_IridescenceMaskMapUVLocal("Iridescence Mask UV Local", Float) = 0.0
_IridescenceMaskMapChannel("Iridescence Mask Map Channel", Float) = 0.0
_IridescenceMaskMapChannelMask("Iridescence Mask Map Channel Mask", Vector) = (1, 0, 0, 0)
_IridescenceMaskRemap("Iridescence Mask Remap", Vector) = (0, 1, 0, 0)
[HideInInspector] _IridescenceMaskRange("Iridescence Mask Range", Vector) = (0, 1, 0, 0)
_DistortionVectorMap("DistortionVectorMap", 2D) = "black" {}
[ToggleUI] _DistortionEnable("Enable Distortion", Float) = 0.0

#pragma multi_compile _ DEBUG_DISPLAY
//NEWLITTODO
//#pragma multi_compile _ LIGHTMAP_ON
//#pragma multi_compile _ DIRLIGHTMAP_COMBINED
//#pragma multi_compile _ DYNAMICLIGHTMAP_ON
//#pragma multi_compile _ SHADOWS_SHADOWMASK
#pragma multi_compile _ LIGHTMAP_ON
#pragma multi_compile _ DIRLIGHTMAP_COMBINED
#pragma multi_compile _ DYNAMICLIGHTMAP_ON
#pragma multi_compile _ SHADOWS_SHADOWMASK
// #include "../../Lighting/Forward.hlsl" : nothing left in there.
//#pragma multi_compile LIGHTLOOP_SINGLE_PASS LIGHTLOOP_TILE_PASS

7
com.unity.render-pipelines.high-definition/HDRP/Material/StackLit/StackLitData.hlsl


surfaceData.iridescenceThickness = dot(SAMPLE_TEXTURE2D_SCALE_BIAS(_IridescenceThicknessMap), _IridescenceThicknessMapChannelMask);
surfaceData.iridescenceThickness = lerp(_IridescenceThicknessRange.x, _IridescenceThicknessRange.y, surfaceData.iridescenceThickness);
surfaceData.iridescenceThickness = lerp(_IridescenceThickness, surfaceData.iridescenceThickness, _IridescenceThicknessUseMap);
surfaceData.iridescenceMask = dot(SAMPLE_TEXTURE2D_SCALE_BIAS(_IridescenceMaskMap), _IridescenceMaskMapChannelMask);
surfaceData.iridescenceMask = lerp(_IridescenceMaskRange.x, _IridescenceMaskRange.y, surfaceData.iridescenceMask);
surfaceData.iridescenceMask = lerp(_IridescenceMask, surfaceData.iridescenceMask, _IridescenceMaskUseMap);
surfaceData.iridescenceMask = 0.0;
#endif
#if defined(_MATERIAL_FEATURE_SUBSURFACE_SCATTERING) || defined(_MATERIAL_FEATURE_TRANSMISSION)

// Convert back to world space normal
surfaceData.normalWS = SurfaceGradientResolveNormal(input.worldToTangent[2], gradient.xyz);
surfaceData.coatNormalWS = SurfaceGradientResolveNormal(input.worldToTangent[2], coatGradient.xyz);
surfaceData.tangentWS = Orthonormalize(surfaceData.tangentWS, surfaceData.normalWS);
if ((_GeometricNormalFilteringEnabled + _TextureNormalFilteringEnabled) > 0.0)
{

13
com.unity.render-pipelines.high-definition/HDRP/Material/StackLit/StackLitProperties.hlsl


TEXTURE2D(_IridescenceThicknessMap);
SAMPLER(sampler_IridescenceThicknessMap);
TEXTURE2D(_IridescenceMaskMap);
SAMPLER(sampler_IridescenceMaskMap);
TEXTURE2D(_SubsurfaceMaskMap);
SAMPLER(sampler_SubsurfaceMaskMap);

float4 _IridescenceThicknessMapChannelMask;
float4 _IridescenceThicknessRange;
float _IridescenceIor;
float _IridescenceMask;
float _IridescenceMaskUseMap;
float _IridescenceMaskMapUV;
float _IridescenceMaskMapUVLocal;
float4 _IridescenceMaskMap_ST;
float4 _IridescenceMaskMap_TexelSize;
float4 _IridescenceMaskMap_MipInfo;
float4 _IridescenceMaskMapChannelMask;
float4 _IridescenceMaskRange;
int _DiffusionProfile;
float _SubsurfaceMask;

正在加载...
取消
保存