浏览代码

Add clear coat material in Lit + few cleanup

/main
sebastienlagarde 7 年前
当前提交
e2c021c4
共有 13 个文件被更改,包括 484 次插入222 次删除
  1. 2
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/LightDefinition.cs
  2. 6
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/LightDefinition.cs.hlsl
  3. 1
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/TilePass.cs
  4. 23
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Editor/LitUI.cs
  5. 53
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Lit.cs
  6. 62
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Lit.cs.hlsl
  7. 506
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Lit.hlsl
  8. 7
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Lit.shader
  9. 1
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/LitData.hlsl
  10. 22
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/LitDataInternal.hlsl
  11. 3
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/LitProperties.hlsl
  12. 7
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/LitTessellation.shader
  13. 13
      Assets/ScriptableRenderPipeline/ShaderLibrary/Common.hlsl

2
Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/LightDefinition.cs


public float angleScale; // Spot light
public float angleOffset; // Spot light
public float shadowDimmer;
public int IESIndex; // -1 if unused
public int unused0;
public Vector2 size; // Used by area, frustum projector and spot lights (x = cot(outerHalfAngle))
public GPULightType lightType;

6
Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/LightDefinition.cs.hlsl


float angleScale;
float angleOffset;
float shadowDimmer;
int IESIndex;
int unused0;
float2 size;
int lightType;
float unused;

{
return value.shadowDimmer;
}
int GetIESIndex(LightData value)
int GetUnused0(LightData value)
return value.IESIndex;
return value.unused0;
}
float2 GetSize(LightData value)
{

1
Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/TilePass.cs


if (lightData.diffuseScale <= 0.0f && lightData.specularScale <= 0.0f)
return false;
lightData.IESIndex = -1;
lightData.cookieIndex = -1;
lightData.shadowIndex = -1;

23
Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Editor/LitUI.cs


public static GUIContent thicknessText = new GUIContent("Thickness", "If subsurface scattering is enabled, low values allow some light to be transmitted through the object.");
public static GUIContent thicknessMapText = new GUIContent("Thickness map (R)", "If subsurface scattering is enabled, low values allow some light to be transmitted through the object.");
// Clear Coat
public static GUIContent coatCoverageText = new GUIContent("Coat Coverage", "Percentage of clear coat coverage");
public static GUIContent coatIORText = new GUIContent("Coat IOR", "IOR of clear coat, value is [0..1] + 1.0. i.e 0.5 is IOR 1.5");
// Specular color
public static GUIContent specularColorText = new GUIContent("Specular Color", "Specular color (RGB)");

protected MaterialProperty thicknessMap = null;
protected const string kThicknessMap = "_ThicknessMap";
protected MaterialProperty coatCoverage = null;
protected const string kCoatCoverage = "_CoatCoverage";
protected MaterialProperty coatIOR = null;
protected const string kCoatIOR = "_CoatIOR";
protected MaterialProperty emissiveColorMode = null;
protected const string kEmissiveColorMode = "_EmissiveColorMode";
protected MaterialProperty emissiveColor = null;

thickness = FindProperty(kThickness, props);
thicknessMap = FindProperty(kThicknessMap, props);
// clear coat
coatCoverage = FindProperty(kCoatCoverage, props);
coatIOR = FindProperty(kCoatIOR, props);
// Emissive
emissiveColorMode = FindProperty(kEmissiveColorMode, props);
emissiveColor = FindProperty(kEmissiveColor, props);

m_MaterialEditor.TexturePropertySingleLine(Styles.thicknessMapText, thicknessMap);
}
protected void ShaderClearCoatInputGUI()
{
m_MaterialEditor.ShaderProperty(coatCoverage, Styles.coatCoverageText);
m_MaterialEditor.ShaderProperty(coatIOR, Styles.coatIORText);
}
protected void ShaderAnisoInputGUI()
{
if ((NormalMapSpace)normalMapSpace.floatValue == NormalMapSpace.TangentSpace)

break;
case Lit.MaterialId.LitSpecular:
m_MaterialEditor.TexturePropertySingleLine(Styles.specularColorText, specularColorMap, specularColor);
break;
case Lit.MaterialId.LitClearCoat:
ShaderClearCoatInputGUI();
break;
default:
Debug.Assert(false, "Encountered an unsupported MaterialID.");

//SetKeyword(material, "_MATID_STANDARD", materialId == Lit.MaterialId.LitStandard); // See comment in Lit.shader, it is the default, we don't define it
SetKeyword(material, "_MATID_ANISO", materialId == Lit.MaterialId.LitAniso);
SetKeyword(material, "_MATID_SPECULAR", materialId == Lit.MaterialId.LitSpecular);
SetKeyword(material, "_MATID_CLEARCOAT", materialId == Lit.MaterialId.LitClearCoat);
}
}
} // namespace UnityEditor

53
Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Lit.cs


[GenerateHLSL(PackingRules.Exact)]
public enum MaterialId
{
LitSSS = 0,
LitStandard = 1,
LitUnused0 = 2,
LitUnused1 = 3,
LitSSS = 0,
LitStandard = 1,
LitClearCoat = 2,
LitUnused = 3,
LitAniso = 4,
LitAniso = 4,
LitSpecular = 5,
// For material classification we will use LitStandard too
LitSpecular = 5,
};
// If change, be sure it match what is done in Lit.hlsl: MaterialFeatureFlagsFromGBuffer

{
LitSSS = 1 << MaterialId.LitSSS,
LitStandard = 1 << MaterialId.LitStandard,
LitUnused0 = 1 << MaterialId.LitUnused0,
LitUnused1 = 1 << MaterialId.LitUnused1,
LitAniso = 1 << MaterialId.LitAniso,
LitSSS = 1 << MaterialId.LitSSS,
LitStandard = 1 << MaterialId.LitStandard,
LitClearCoat = 1 << MaterialId.LitClearCoat,
LitUnused = 1 << MaterialId.LitUnused,
LitAniso = 1 << MaterialId.LitAniso,
public enum SpecularValue
public class StandardDefinitions
// Value are defined in the tab name convertSpecularToValue in lit.hlsl
Water = 0, // 0.02 Water or ice
Regular = 1, // 0.04 regular dieletric
Gemstone = 2, // 0.20
SpecularColor = 3 // Special case: use specular color
public static int s_GBufferLitStandardRegularId = 0;
public static int s_GBufferLitStandardSpecularColorId = 1;
public static int s_GBufferLitStandardAnisotropicId = 2;
public static float s_DefaultSpecularValue = 0.04f;
public static float s_SkinSpecularValue = 0.028f;
}
//-----------------------------------------------------------------------------

[SurfaceDataAttributes("Smoothness")]
public float perceptualSmoothness;
[SurfaceDataAttributes("Material ID")]
public MaterialId materialId;
public MaterialId materialId; // matId above 3 are store in standard material gbuffer (2bit reserved)
[SurfaceDataAttributes("Ambient Occlusion")]
public float ambientOcclusion;

public float anisotropy; // anisotropic ratio(0->no isotropic; 1->full anisotropy in tangent direction)
[SurfaceDataAttributes("Metallic")]
public float metallic;
[SurfaceDataAttributes("Specular")]
public SpecularValue specular;
// SSS
[SurfaceDataAttributes("Subsurface Radius")]

// SpecColor
[SurfaceDataAttributes("Specular Color", false, true)]
public Vector3 specularColor;
// ClearCoat
[SurfaceDataAttributes("Coat Normal", true)]
public Vector3 coatNormalWS;
[SurfaceDataAttributes("Coat coverage")]
public float coatCoverage;
[SurfaceDataAttributes("Coat IOR")]
public float coatIOR; // Value is [0..1] for artists but the UI will display the value between [1..2]
};
//-----------------------------------------------------------------------------

// SpecColor
// fold into fresnel0
// ClearCoat
public Vector3 coatNormalWS;
public float coatCoverage;
public float coatIOR; // CoatIOR is in range[1..2] it is surfaceData + 1
};
//-----------------------------------------------------------------------------

62
Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Lit.cs.hlsl


//
#define MATERIALID_LIT_SSS (0)
#define MATERIALID_LIT_STANDARD (1)
#define MATERIALID_LIT_UNUSED0 (2)
#define MATERIALID_LIT_UNUSED1 (3)
#define MATERIALID_LIT_CLEAR_COAT (2)
#define MATERIALID_LIT_UNUSED (3)
#define MATERIALID_LIT_ANISO (4)
#define MATERIALID_LIT_SPECULAR (5)

#define MATERIALFEATUREFLAGS_LIT_SSS (1)
#define MATERIALFEATUREFLAGS_LIT_STANDARD (2)
#define MATERIALFEATUREFLAGS_LIT_UNUSED0 (4)
#define MATERIALFEATUREFLAGS_LIT_UNUSED1 (8)
#define MATERIALFEATUREFLAGS_LIT_CLEAR_COAT (4)
#define MATERIALFEATUREFLAGS_LIT_UNUSED (8)
// UnityEngine.Experimental.Rendering.HDPipeline.Lit+SpecularValue: static fields
// UnityEngine.Experimental.Rendering.HDPipeline.Lit+StandardDefinitions: static fields
#define SPECULARVALUE_WATER (0)
#define SPECULARVALUE_REGULAR (1)
#define SPECULARVALUE_GEMSTONE (2)
#define SPECULARVALUE_SPECULAR_COLOR (3)
#define GBUFFER_LIT_STANDARD_REGULAR_ID (0)
#define GBUFFER_LIT_STANDARD_SPECULAR_COLOR_ID (1)
#define GBUFFER_LIT_STANDARD_ANISOTROPIC_ID (2)
#define DEFAULT_SPECULAR_VALUE (0.04)
#define SKIN_SPECULAR_VALUE (0.028)
//
// UnityEngine.Experimental.Rendering.HDPipeline.Lit+SurfaceData: static fields

#define DEBUGVIEW_LIT_SURFACEDATA_TANGENT_WS (1006)
#define DEBUGVIEW_LIT_SURFACEDATA_ANISOTROPY (1007)
#define DEBUGVIEW_LIT_SURFACEDATA_METALLIC (1008)
#define DEBUGVIEW_LIT_SURFACEDATA_SPECULAR (1009)
#define DEBUGVIEW_LIT_SURFACEDATA_SUBSURFACE_RADIUS (1010)
#define DEBUGVIEW_LIT_SURFACEDATA_THICKNESS (1011)
#define DEBUGVIEW_LIT_SURFACEDATA_SUBSURFACE_PROFILE (1012)
#define DEBUGVIEW_LIT_SURFACEDATA_SPECULAR_COLOR (1013)
#define DEBUGVIEW_LIT_SURFACEDATA_SUBSURFACE_RADIUS (1009)
#define DEBUGVIEW_LIT_SURFACEDATA_THICKNESS (1010)
#define DEBUGVIEW_LIT_SURFACEDATA_SUBSURFACE_PROFILE (1011)
#define DEBUGVIEW_LIT_SURFACEDATA_SPECULAR_COLOR (1012)
#define DEBUGVIEW_LIT_SURFACEDATA_COAT_NORMAL_WS (1013)
#define DEBUGVIEW_LIT_SURFACEDATA_COAT_COVERAGE (1014)
#define DEBUGVIEW_LIT_SURFACEDATA_COAT_IOR (1015)
//
// UnityEngine.Experimental.Rendering.HDPipeline.Lit+TransmissionType: static fields

#define DEBUGVIEW_LIT_BSDFDATA_ENABLE_TRANSMISSION (1045)
#define DEBUGVIEW_LIT_BSDFDATA_USE_THIN_OBJECT_MODE (1046)
#define DEBUGVIEW_LIT_BSDFDATA_TRANSMITTANCE (1047)
#define DEBUGVIEW_LIT_BSDFDATA_COAT_NORMAL_WS (1048)
#define DEBUGVIEW_LIT_BSDFDATA_COAT_COVERAGE (1049)
#define DEBUGVIEW_LIT_BSDFDATA_COAT_IOR (1050)
//
// UnityEngine.Experimental.Rendering.HDPipeline.Lit+GBufferMaterial: static fields

float3 tangentWS;
float anisotropy;
float metallic;
int specular;
float3 coatNormalWS;
float coatCoverage;
float coatIOR;
};
// Generated from UnityEngine.Experimental.Rendering.HDPipeline.Lit+BSDFData

bool enableTransmission;
bool useThinObjectMode;
float3 transmittance;
float3 coatNormalWS;
float coatCoverage;
float coatIOR;
};
//

case DEBUGVIEW_LIT_SURFACEDATA_METALLIC:
result = surfacedata.metallic.xxx;
break;
case DEBUGVIEW_LIT_SURFACEDATA_SPECULAR:
result = GetIndexColor(surfacedata.specular);
break;
case DEBUGVIEW_LIT_SURFACEDATA_SUBSURFACE_RADIUS:
result = surfacedata.subsurfaceRadius.xxx;
break;

result = surfacedata.specularColor;
needLinearToSRGB = true;
break;
case DEBUGVIEW_LIT_SURFACEDATA_COAT_NORMAL_WS:
result = surfacedata.coatNormalWS * 0.5 + 0.5;
break;
case DEBUGVIEW_LIT_SURFACEDATA_COAT_COVERAGE:
result = surfacedata.coatCoverage.xxx;
break;
case DEBUGVIEW_LIT_SURFACEDATA_COAT_IOR:
result = surfacedata.coatIOR.xxx;
break;
}
}

break;
case DEBUGVIEW_LIT_BSDFDATA_TRANSMITTANCE:
result = bsdfdata.transmittance;
break;
case DEBUGVIEW_LIT_BSDFDATA_COAT_NORMAL_WS:
result = bsdfdata.coatNormalWS;
break;
case DEBUGVIEW_LIT_BSDFDATA_COAT_COVERAGE:
result = bsdfdata.coatCoverage.xxx;
break;
case DEBUGVIEW_LIT_BSDFDATA_COAT_IOR:
result = bsdfdata.coatIOR.xxx;
break;
}
}

506
Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Lit.hlsl


// Use optimization of Precomputing LambdaV
// TODO: Test if this is a win
// #define LIT_USE_BSDF_PRE_LAMBDAV
// TODO: Check if anisotropy with a dynamic if on anisotropy > 0 is performant. Because it may mean we always calculate both isotropy and anisotropy case.
// Maybe we should always calculate anisotropy in case of standard ? Don't think the compile can optimize correctly.
// Area light textures specific constant
SamplerState ltc_linear_clamp_sampler;
// TODO: This one should be set into a constant Buffer at pass frequency (with _Screensize)
TEXTURE2D(_PreIntegratedFGD);

#define LTC_LUT_OFFSET (0.5 * rcp(LTC_LUT_SIZE))
#define MIN_N_DOT_V 0.0001 // The minimum value of 'NdotV'
// Subsurface scattering specific constant
#define SSS_WRAP_ANGLE (PI/12) // Used for wrap lighting
#define SSS_WRAP_LIGHT cos(PI/2 - SSS_WRAP_ANGLE)

/* 18 */ LIGHTFEATUREFLAGS_SKY | LIGHTFEATUREFLAGS_DIRECTIONAL | LIGHTFEATUREFLAGS_PUNCTUAL | LIGHTFEATUREFLAGS_ENV | MATERIALFEATUREFLAGS_LIT_SSS | MATERIALFEATUREFLAGS_LIT_STANDARD,
/* 19 */ LIGHT_FEATURE_MASK_FLAGS | MATERIALFEATUREFLAGS_LIT_SSS,
// Future usage
/* 20 */ LIGHTFEATUREFLAGS_SKY | LIGHTFEATUREFLAGS_DIRECTIONAL | LIGHTFEATUREFLAGS_PUNCTUAL | MATERIALFEATUREFLAGS_LIT_UNUSED0,
/* 21 */ LIGHTFEATUREFLAGS_SKY | LIGHTFEATUREFLAGS_DIRECTIONAL | LIGHTFEATUREFLAGS_AREA | MATERIALFEATUREFLAGS_LIT_UNUSED0,
/* 22 */ LIGHTFEATUREFLAGS_SKY | LIGHTFEATUREFLAGS_DIRECTIONAL | LIGHTFEATUREFLAGS_ENV | MATERIALFEATUREFLAGS_LIT_UNUSED0,
/* 23 */ LIGHTFEATUREFLAGS_SKY | LIGHTFEATUREFLAGS_DIRECTIONAL | LIGHTFEATUREFLAGS_PUNCTUAL | LIGHTFEATUREFLAGS_ENV | MATERIALFEATUREFLAGS_LIT_UNUSED0,
/* 24 */ LIGHT_FEATURE_MASK_FLAGS | MATERIALFEATUREFLAGS_LIT_UNUSED0,
// ClearCoat
/* 20 */ LIGHTFEATUREFLAGS_SKY | LIGHTFEATUREFLAGS_DIRECTIONAL | LIGHTFEATUREFLAGS_PUNCTUAL | MATERIALFEATUREFLAGS_LIT_CLEAR_COAT,
/* 21 */ LIGHTFEATUREFLAGS_SKY | LIGHTFEATUREFLAGS_DIRECTIONAL | LIGHTFEATUREFLAGS_AREA | MATERIALFEATUREFLAGS_LIT_CLEAR_COAT,
/* 22 */ LIGHTFEATUREFLAGS_SKY | LIGHTFEATUREFLAGS_DIRECTIONAL | LIGHTFEATUREFLAGS_ENV | MATERIALFEATUREFLAGS_LIT_CLEAR_COAT,
/* 23 */ LIGHTFEATUREFLAGS_SKY | LIGHTFEATUREFLAGS_DIRECTIONAL | LIGHTFEATUREFLAGS_PUNCTUAL | LIGHTFEATUREFLAGS_ENV | MATERIALFEATUREFLAGS_LIT_CLEAR_COAT,
/* 24 */ LIGHT_FEATURE_MASK_FLAGS | MATERIALFEATUREFLAGS_LIT_CLEAR_COAT,
/* 25 */ LIGHTFEATUREFLAGS_SKY | LIGHTFEATUREFLAGS_DIRECTIONAL | LIGHTFEATUREFLAGS_PUNCTUAL | MATERIALFEATUREFLAGS_LIT_UNUSED1,
/* 26 */ LIGHTFEATUREFLAGS_SKY | LIGHTFEATUREFLAGS_DIRECTIONAL | LIGHTFEATUREFLAGS_AREA | MATERIALFEATUREFLAGS_LIT_UNUSED1,
/* 27 */ LIGHTFEATUREFLAGS_SKY | LIGHTFEATUREFLAGS_DIRECTIONAL | LIGHTFEATUREFLAGS_ENV | MATERIALFEATUREFLAGS_LIT_UNUSED1,
/* 28 */ LIGHTFEATUREFLAGS_SKY | LIGHTFEATUREFLAGS_DIRECTIONAL | LIGHTFEATUREFLAGS_PUNCTUAL | LIGHTFEATUREFLAGS_ENV | MATERIALFEATUREFLAGS_LIT_UNUSED1,
/* 29 */ LIGHT_FEATURE_MASK_FLAGS | MATERIALFEATUREFLAGS_LIT_UNUSED1,
/* 25 */ LIGHTFEATUREFLAGS_SKY | LIGHTFEATUREFLAGS_DIRECTIONAL | LIGHTFEATUREFLAGS_PUNCTUAL | MATERIALFEATUREFLAGS_LIT_UNUSED,
/* 26 */ LIGHTFEATUREFLAGS_SKY | LIGHTFEATUREFLAGS_DIRECTIONAL | LIGHTFEATUREFLAGS_AREA | MATERIALFEATUREFLAGS_LIT_UNUSED,
/* 27 */ LIGHTFEATUREFLAGS_SKY | LIGHTFEATUREFLAGS_DIRECTIONAL | LIGHTFEATUREFLAGS_ENV | MATERIALFEATUREFLAGS_LIT_UNUSED,
/* 28 */ LIGHTFEATUREFLAGS_SKY | LIGHTFEATUREFLAGS_DIRECTIONAL | LIGHTFEATUREFLAGS_PUNCTUAL | LIGHTFEATUREFLAGS_ENV | MATERIALFEATUREFLAGS_LIT_UNUSED,
/* 29 */ LIGHT_FEATURE_MASK_FLAGS | MATERIALFEATUREFLAGS_LIT_UNUSED,
/* 30 */ LIGHT_FEATURE_MASK_FLAGS | MATERIAL_FEATURE_MASK_FLAGS, // Catch all case with MATERIAL_FEATURE_MASK_FLAGS is needed in case we disable material classification
};

return int(round(f * 3.0));
}
// For image based lighting, a part of the BSDF is pre-integrated.
// This is done both for specular and diffuse (in case of DisneyDiffuse)
void GetPreIntegratedFGD(float NdotV, float perceptualRoughness, float3 fresnel0, out float3 specularFGD, out float diffuseFGD)
{
// Pre-integrate GGX FGD
// _PreIntegratedFGD.x = Gv * (1 - Fc) with Fc = (1 - H.L)^5
// _PreIntegratedFGD.y = Gv * Fc
// Pre integrate DisneyDiffuse FGD:
// _PreIntegratedFGD.z = DisneyDiffuse
float3 preFGD = SAMPLE_TEXTURE2D_LOD(_PreIntegratedFGD, ltc_linear_clamp_sampler, float2(NdotV, perceptualRoughness), 0).xyz;
// f0 * Gv * (1 - Fc) + Gv * Fc
specularFGD = fresnel0 * preFGD.x + preFGD.y;
#ifdef LIT_DIFFUSE_LAMBERT_BRDF
diffuseFGD = 1.0;
#else
diffuseFGD = preFGD.z;
#endif
}
void ApplyDebugToSurfaceData(inout SurfaceData surfaceData)
{
#ifdef DEBUG_DISPLAY
if (_DebugLightingMode == DEBUGLIGHTINGMODE_SPECULAR_LIGHTING)
{
bool overrideSmoothness = _DebugLightingSmoothness.x != 0.0;
float overrideSmoothnessValue = _DebugLightingSmoothness.y;
if (overrideSmoothness)
{
surfaceData.perceptualSmoothness = overrideSmoothnessValue;
}
}
if (_DebugLightingMode == DEBUGLIGHTINGMODE_DIFFUSE_LIGHTING)
{
surfaceData.baseColor = _DebugLightingAlbedo.xyz;
}
#endif
}
static const float3 convertSpecularToValue = float3(0.02, 0.04, 0.20);
void FillMaterialIdStandardData(float3 baseColor, int specular, float metallic, inout BSDFData bsdfData)
void FillMaterialIdStandardData(float3 baseColor, float metallic, inout BSDFData bsdfData)
float val = convertSpecularToValue[specular];
float val = DEFAULT_SPECULAR_VALUE;
bsdfData.fresnel0 = lerp(val.xxx, baseColor, metallic);
}

{
bsdfData.diffuseColor = baseColor;
// TODO take from subsurfaceProfile
bsdfData.fresnel0 = 0.04; // Should be 0.028 for the skin
bsdfData.fresnel0 = SKIN_SPECULAR_VALUE; // TODO take from subsurfaceProfile instead
bsdfData.thickness = _ThicknessRemaps[subsurfaceProfile].x +
_ThicknessRemaps[subsurfaceProfile].y * thickness;
bsdfData.thickness = _ThicknessRemaps[subsurfaceProfile].x + _ThicknessRemaps[subsurfaceProfile].y * thickness;
uint transmissionMode = BitFieldExtract(_TransmissionFlags, 2u, 2u * subsurfaceProfile);

}
}
void FillMaterialIdClearCoatData(float3 coatNormalWS, float coatCoverage, float coatIOR, inout BSDFData bsdfData)
{
bsdfData.coatNormalWS = lerp(bsdfData.normalWS, coatNormalWS, coatCoverage);
bsdfData.coatIOR = lerp(1.0, 1.0 + coatIOR, coatCoverage);
bsdfData.coatCoverage = coatCoverage;
}
// For image based lighting, a part of the BSDF is pre-integrated.
// This is done both for specular and diffuse (in case of DisneyDiffuse)
void GetPreIntegratedFGD(float NdotV, float perceptualRoughness, float3 fresnel0, out float3 specularFGD, out float diffuseFGD)
{
// Pre-integrate GGX FGD
// _PreIntegratedFGD.x = Gv * (1 - Fc) with Fc = (1 - H.L)^5
// _PreIntegratedFGD.y = Gv * Fc
// Pre integrate DisneyDiffuse FGD:
// _PreIntegratedFGD.z = DisneyDiffuse
float3 preFGD = SAMPLE_TEXTURE2D_LOD(_PreIntegratedFGD, ltc_linear_clamp_sampler, float2(NdotV, perceptualRoughness), 0).xyz;
// f0 * Gv * (1 - Fc) + Gv * Fc
specularFGD = fresnel0 * preFGD.x + preFGD.y;
#ifdef LIT_DIFFUSE_LAMBERT_BRDF
diffuseFGD = 1.0;
#else
diffuseFGD = preFGD.z;
#endif
}
void ApplyDebugToSurfaceData(inout SurfaceData surfaceData)
{
#ifdef DEBUG_DISPLAY
if (_DebugLightingMode == DEBUGLIGHTINGMODE_SPECULAR_LIGHTING)
{
bool overrideSmoothness = _DebugLightingSmoothness.x != 0.0;
float overrideSmoothnessValue = _DebugLightingSmoothness.y;
if (overrideSmoothness)
{
surfaceData.perceptualSmoothness = overrideSmoothnessValue;
}
}
if (_DebugLightingMode == DEBUGLIGHTINGMODE_DIFFUSE_LIGHTING)
{
surfaceData.baseColor = _DebugLightingAlbedo.xyz;
}
#endif
}
//-----------------------------------------------------------------------------
// conversion function for forward
//-----------------------------------------------------------------------------

// IMPORTANT: In case of foward or gbuffer pass we must know what we are statically, so compiler can do compile time optimization
if (bsdfData.materialId == MATERIALID_LIT_STANDARD)
{
if (surfaceData.specular == SPECULARVALUE_SPECULAR_COLOR)
{
bsdfData.diffuseColor = surfaceData.baseColor;
bsdfData.fresnel0 = surfaceData.specularColor;
}
else
{
FillMaterialIdStandardData(surfaceData.baseColor, surfaceData.specular, surfaceData.metallic, bsdfData);
}
FillMaterialIdStandardData(surfaceData.baseColor, surfaceData.metallic, bsdfData);
}
else if (bsdfData.materialId == MATERIALID_LIT_SPECULAR)
{
// Note: Specular is not a material id but just a way to parameterize the standard materialid, thus we reset materialId to MATERIALID_LIT_STANDARD
bsdfData.materialId = MATERIALID_LIT_STANDARD;
bsdfData.diffuseColor = surfaceData.baseColor;
bsdfData.fresnel0 = surfaceData.specularColor;
FillMaterialIdStandardData(surfaceData.baseColor, surfaceData.specular, surfaceData.metallic, bsdfData);
FillMaterialIdStandardData(surfaceData.baseColor, surfaceData.metallic, bsdfData);
}
else if (bsdfData.materialId == MATERIALID_LIT_CLEAR_COAT)
{
// When using clear coat we assume that bottom layer is regular
FillMaterialIdStandardData(surfaceData.baseColor, surfaceData.metallic, bsdfData);
FillMaterialIdClearCoatData(surfaceData.coatNormalWS, surfaceData.coatCoverage, surfaceData.coatIOR, bsdfData);
}
return bsdfData;

#endif
)
{
#if SHADEROPTIONS_PACK_GBUFFER_IN_U16
#if SHADEROPTIONS_PACK_GBUFFER_IN_U16
#endif
#endif
ApplyDebugToSurfaceData(surfaceData);

// RT2 - 8:8:8:8
if (surfaceData.materialId == MATERIALID_LIT_STANDARD)
{
// Encode specular on two bit for the enum
// Note: we encode two parametrization at the same time, specularColor and metal/specular
if (surfaceData.specular == SPECULARVALUE_SPECULAR_COLOR)
{
outGBuffer2 = float4(surfaceData.specularColor, PackFloatInt8bit(0.0, surfaceData.specular, 4.0)); // As all is static, Pack function should produce the result compile time
}
else
{
// Note: it is important to setup anisotropy field to 0 else materialId will be anisotropic
outGBuffer2 = float4(float3(0.0, 0.0, 0.0), PackFloatInt8bit(surfaceData.metallic, surfaceData.specular, 4.0));
}
outGBuffer2 = float4(float3(0.0, 0.0, 0.0), PackFloatInt8bit(surfaceData.metallic, GBUFFER_LIT_STANDARD_REGULAR_ID, 4.0));
}
else if (surfaceData.materialId == MATERIALID_LIT_SPECULAR)
{
outGBuffer1.a = PackMaterialId(MATERIALID_LIT_STANDARD); // Encode MATERIALID_LIT_SPECULAR as MATERIALID_LIT_STANDARD + GBUFFER_LIT_STANDARD_SPECULAR_COLOR_ID value in GBuffer2
outGBuffer2 = float4(surfaceData.specularColor, PackFloatInt8bit(0.0, GBUFFER_LIT_STANDARD_SPECULAR_COLOR_ID, 4.0));
outGBuffer1.a = PackMaterialId(MATERIALID_LIT_STANDARD); // We save 1bit in gbuffer1 and use aniso value instead to detect we are aniso
outGBuffer1.a = PackMaterialId(MATERIALID_LIT_STANDARD); // Encode MATERIALID_LIT_SPECULAR as MATERIALID_LIT_STANDARD + GBUFFER_LIT_STANDARD_ANISOTROPIC_ID value in GBuffer2
// To be recognize as anisotropic material, we need to have anisotropy > 0 (Else artits can be confuse to not have anisotropic material in material classification), thus the max
outGBuffer2 = float4(octTangentWS * 0.5 + 0.5, max(surfaceData.anisotropy, 1.5 / 255.0), PackFloatInt8bit(surfaceData.metallic, surfaceData.specular, 4.0));
outGBuffer2 = float4(octTangentWS * 0.5 + 0.5, surfaceData.anisotropy, PackFloatInt8bit(surfaceData.metallic, GBUFFER_LIT_STANDARD_ANISOTROPIC_ID, 4.0));
outGBuffer2 = float4(surfaceData.subsurfaceRadius, surfaceData.thickness, 0, PackByte(surfaceData.subsurfaceProfile));
outGBuffer2 = float4(surfaceData.subsurfaceRadius, surfaceData.thickness, 0.0, PackByte(surfaceData.subsurfaceProfile));
}
else if (surfaceData.materialId == MATERIALID_LIT_CLEAR_COAT)
{
float2 octCoatNormalWS = PackNormalOctEncode(surfaceData.coatNormalWS);
outGBuffer2 = float4(octCoatNormalWS * 0.5 + 0.5, surfaceData.coatCoverage, PackFloatInt8bit(surfaceData.coatIOR, (int)(surfaceData.metallic * 15.5f), 16.0) );
#if SHADEROPTIONS_PACK_GBUFFER_IN_U16
#if SHADEROPTIONS_PACK_GBUFFER_IN_U16
// Now pack all buffer into 2 uint buffer
// We don't have hardware sRGB to store base color in case we pack int u16, so rather than perform full sRGB encoding just use cheap gamma20

PackFloatToUInt(outGBuffer2.z, 8, 0) | PackFloatToUInt(outGBuffer2.w, 8, 8),
(packedGBuffer3 & 0x0000FFFF),
(packedGBuffer3 & 0xFFFF0000) >> 16);
#endif
#endif
}
float4 DecodeGBuffer0(GBufferType0 encodedGBuffer0)

// The code is also call from MaterialFeatureFlagsFromGBuffer, so must work fully dynamic if featureFlags is 0xFFFFFFFF
int supportsStandard = (featureFlags & (MATERIALFEATUREFLAGS_LIT_STANDARD | MATERIALFEATUREFLAGS_LIT_ANISO)) != 0;
int supportsSSS = (featureFlags & (MATERIALFEATUREFLAGS_LIT_SSS)) != 0;
int supportClearCoat = (featureFlags & (MATERIALFEATUREFLAGS_LIT_CLEAR_COAT)) != 0;
if (supportsStandard + supportsSSS > 1)
if (supportsStandard + supportsSSS + supportClearCoat > 1)
{
// only fetch materialid if it is not statically known from feature flags
bsdfData.materialId = UnpackMaterialId(inGBuffer1.a);

// materialid is statically known. this allows the compiler to eliminate a lot of code.
if (supportsStandard)
bsdfData.materialId = MATERIALID_LIT_STANDARD;
else // if (supportsSSS)
else if (supportsSSS)
else
bsdfData.materialId = MATERIALID_LIT_CLEAR_COAT;
int specular;
UnpackFloatInt8bit(inGBuffer2.a, 4.0, metallic, specular);
int materialIdExtent;
UnpackFloatInt8bit(inGBuffer2.a, 4.0, metallic, materialIdExtent);
if (specular == SPECULARVALUE_SPECULAR_COLOR)
if (materialIdExtent == GBUFFER_LIT_STANDARD_SPECULAR_COLOR_ID)
// Note: Specular is not a material id but just a way to parameterize the standard materialid, thus we reset materialId to MATERIALID_LIT_STANDARD
// For material classification it will be consider as Standard as well, thus no need to create special case
FillMaterialIdStandardData(baseColor, specular, metallic, bsdfData);
FillMaterialIdStandardData(baseColor, metallic, bsdfData);
FillMaterialIdStandardData(baseColor, specular, metallic, bsdfData);
FillMaterialIdStandardData(baseColor, metallic, bsdfData);
if (specular == SPECULARVALUE_SPECULAR_COLOR)
if (materialIdExtent == GBUFFER_LIT_STANDARD_SPECULAR_COLOR_ID)
// Note: Specular is not a material id but just a way to parameterize the standard materialid, thus we reset materialId to MATERIALID_LIT_STANDARD
// For material classification it will be consider as Standard as well, thus no need to create special case
else if (anisotropy > 0.0)
else if (materialIdExtent == GBUFFER_LIT_STANDARD_ANISOTROPIC_ID)
FillMaterialIdStandardData(baseColor, specular, metallic, bsdfData);
FillMaterialIdStandardData(baseColor, metallic, bsdfData);
else
else // GBUFFER_LIT_STANDARD_REGULAR_ID
FillMaterialIdStandardData(baseColor, specular, metallic, bsdfData);
FillMaterialIdStandardData(baseColor, metallic, bsdfData);
else // bsdfData.materialId == MATERIALID_LIT_SSS
else if (bsdfData.materialId == MATERIALID_LIT_SSS)
{
float subsurfaceRadius = inGBuffer2.x;
float thickness = inGBuffer2.y;

}
else //if (bsdfData.materialId == MATERIALID_LIT_CLEAR_COAT)
{
float3 coatNormalWS = UnpackNormalOctEncode(float2(inGBuffer2.rg * 2.0 - 1.0));
float coatCoverage = inGBuffer2.b;
float coatIOR;
int metallic;
UnpackFloatInt8bit(inGBuffer2.a, 16.0, coatIOR, metallic);
// When using clear coat we assume that bottom layer is regular
FillMaterialIdStandardData(baseColor, metallic / 15.0f, bsdfData);
FillMaterialIdClearCoatData(coatNormalWS, coatCoverage, coatIOR, bsdfData);
// Function call from the material classification compute shader
// Note that as we store materialId on two buffer (for anisotropy case), the code need to load 2 RGBA8 buffer
uint MaterialFeatureFlagsFromGBuffer(
#if SHADEROPTIONS_PACK_GBUFFER_IN_U16
GBufferType0 inGBufferU0,

void GetSurfaceDataDebug(uint paramId, SurfaceData surfaceData, inout float3 result, inout bool needLinearToSRGB)
{
GetGeneratedSurfaceDataDebug(paramId, surfaceData, result, needLinearToSRGB);
switch (paramId)
{
// TODO: Remap here!
case DEBUGVIEW_LIT_SURFACEDATA_SPECULAR:
result = surfaceData.specular.xxx;
break;
}
}
void GetBSDFDataDebug(uint paramId, BSDFData bsdfData, inout float3 result, inout bool needLinearToSRGB)

float BdotV;
float anisoGGXLambdaV;
// Clear coat
float coatNdotV;
float ieta;
float coatFresnel0;
float3 coatV;
float3 refractV; // The view vector refracted through clear coat interface
// IBL clear coat
float3 coatIblDirWS;
float3 specularFGD; // Store preconvoled BRDF for both specular and diffuse
float diffuseFGD;

float ltcGGXFresnelMagnitudeDiff; // The difference of magnitudes of GGX and Fresnel
float ltcGGXFresnelMagnitude;
float3 ltcGGXFresnelTerm;
// area light clear coat
float3x3 ltcXformClearCoat; // TODO: make sure the compiler not wasting VGPRs on constants
float ltcClearCoatFresnelTerm;
float3x3 ltcCoatT;
// This is a refract - TODO: do we call original refract or this one, original maybe slightly emore expensive, to check
float3 ClearCoatTransform(float3 X, float3 N, float ieta)
{
float XdotN = saturate(dot(N, X));
return ieta * X + (sqrt(1 + ieta * ieta * (XdotN * XdotN - 1)) - ieta * XdotN) * N;
}
float NdotV = dot(bsdfData.normalWS, V);
if (bsdfData.materialId == MATERIALID_LIT_CLEAR_COAT)
{
float ieta = 1.0 / bsdfData.coatIOR; // inverse eta
preLightData.ieta = ieta;
preLightData.coatFresnel0 = Sqr(bsdfData.coatIOR - 1.0) / Sqr(bsdfData.coatIOR + 1.0);
float3 iblNormalWS = GetViewShiftedNormal(bsdfData.normalWS, V, NdotV, MIN_N_DOT_V);
preLightData.coatNdotV = dot(bsdfData.coatNormalWS, V);
preLightData.NdotV = NdotV; // Store the unaltered (geometric) version
NdotV = max(NdotV, MIN_N_DOT_V); // Use the modified (clamped) version
// Clear coat IBL
// In the case of IBL we want shift a bit the normal that are not toward the viewver to reduce artifact
float3 coatIblNormalWS = GetViewShiftedNormal(bsdfData.coatNormalWS, V, preLightData.coatNdotV, MIN_N_DOT_V);
preLightData.coatIblDirWS = reflect(-V, coatIblNormalWS);
// Clear coat area light
float theta = FastACos(preLightData.coatNdotV);
float2 uv = LTC_LUT_OFFSET + LTC_LUT_SCALE * float2(0.0, theta * INV_HALF_PI); // Use Roughness of 0.0 for clearCoat roughness
// Get the inverse LTC matrix for GGX
// Note we load the matrix transpose (avoid to have to transpose it in shader)
preLightData.ltcXformClearCoat = 0.0;
preLightData.ltcXformClearCoat._m22 = 1.0;
preLightData.ltcXformClearCoat._m00_m02_m11_m20 = SAMPLE_TEXTURE2D_ARRAY_LOD(_LtcData, ltc_linear_clamp_sampler, uv, LTC_GGX_MATRIX_INDEX, 0);
float3 ltcMagnitude = SAMPLE_TEXTURE2D_ARRAY_LOD(_LtcData, ltc_linear_clamp_sampler, uv, LTC_MULTI_GGX_FRESNEL_DISNEY_DIFFUSE_INDEX, 0).rgb;
float ltcClearCoatFresnelMagnitudeDiff = ltcMagnitude.r; // The difference of magnitudes of GGX and Fresnel
float ltcClearCoatFresnelMagnitude = ltcMagnitude.g;
preLightData.ltcClearCoatFresnelTerm = preLightData.coatFresnel0 * ltcClearCoatFresnelMagnitudeDiff + ltcClearCoatFresnelMagnitude;
// TODO: Convert the area light with respect to Fresnel transmission
float3 N = bsdfData.coatNormalWS; // TODO : check with Laurentb
preLightData.ltcCoatT = float3x3( ieta + (1.0 - ieta) * N.x * N.x, 0.0 + (1.0 - ieta) * N.y * N.x, 0.0 + (1.0 - ieta) * N.z * N.x,
0.0 + (1.0 - ieta) * N.x * N.y, ieta + (1.0 - ieta) * N.y * N.y, 0.0 + (1.0 - ieta) * N.z * N.y,
0.0 + (1.0 - ieta) * N.x * N.z, 0.0 + (1.0 - ieta) * N.y * N.z, ieta + (1.0 - ieta) * N.z * N.z );
// Modify V for following calculation
preLightData.refractV = ClearCoatTransform(V, bsdfData.coatNormalWS, ieta);
V = preLightData.refractV;
}
preLightData.NdotV = dot(bsdfData.normalWS, V); // Store the unaltered (geometric) version
float NdotV = preLightData.NdotV;
// In the case of IBL we want shift a bit the normal that are not toward the viewver to reduce artifact
float3 iblNormalWS = GetViewShiftedNormal(bsdfData.normalWS, V, NdotV, MIN_N_DOT_V); // Use non clamped NdotV
NdotV = max(NdotV, MIN_N_DOT_V); // Use the modified (clamped) version
preLightData.TdotV = 0;
preLightData.BdotV = 0;
preLightData.TdotV = 0.0;
preLightData.BdotV = 0.0;
if (bsdfData.materialId == MATERIALID_LIT_ANISO)
{
preLightData.TdotV = dot(bsdfData.tangentWS, V);

// IBL
GetPreIntegratedFGD(NdotV, bsdfData.perceptualRoughness, bsdfData.fresnel0, preLightData.specularFGD, preLightData.diffuseFGD);
preLightData.iblDirWS = GetSpecularDominantDir(iblNormalWS, iblR, bsdfData.roughness, NdotV);
preLightData.iblMipLevel = PerceptualRoughnessToMipmapLevel(bsdfData.perceptualRoughness);
if (bsdfData.materialId == MATERIALID_LIT_CLEAR_COAT)
{
// Update the roughness and the IBL miplevel
// Bottom layer is affected by upper layer BRDF, result can't be more sharp than input (it is to mimic what a path tracer will do)
float roughness = PerceptualRoughnessToRoughness(bsdfData.perceptualRoughness);
float shininess = Sqr(preLightData.ieta) * (2.0 / Sqr(roughness) - 2.0);
roughness = sqrt(2.0 / (shininess + 2.0));
preLightData.iblDirWS = GetSpecularDominantDir(iblNormalWS, iblR, roughness, NdotV);
preLightData.iblMipLevel = PerceptualRoughnessToMipmapLevel(RoughnessToPerceptualRoughness(roughness));
}
else
{
preLightData.iblDirWS = GetSpecularDominantDir(iblNormalWS, iblR, bsdfData.roughness, NdotV);
preLightData.iblMipLevel = PerceptualRoughnessToMipmapLevel(bsdfData.perceptualRoughness);
}
float theta = FastACos(NdotV);
float theta = FastACos(NdotV); // For Area light - UVs for sampling the LUTs
float2 uv = LTC_LUT_OFFSET + LTC_LUT_SCALE * float2(bsdfData.perceptualRoughness, theta * INV_HALF_PI);
// Get the inverse LTC matrix for GGX

preLightData.ltcXformDisneyDiffuse._m00_m02_m11_m20 = SAMPLE_TEXTURE2D_ARRAY_LOD(_LtcData, ltc_linear_clamp_sampler, uv, LTC_DISNEY_DIFFUSE_MATRIX_INDEX, 0);
float3 ltcMagnitude = SAMPLE_TEXTURE2D_ARRAY_LOD(_LtcData, ltc_linear_clamp_sampler, uv, LTC_MULTI_GGX_FRESNEL_DISNEY_DIFFUSE_INDEX, 0).rgb;
preLightData.ltcGGXFresnelMagnitudeDiff = ltcMagnitude.r;
preLightData.ltcGGXFresnelMagnitude = ltcMagnitude.g;
float ltcGGXFresnelMagnitudeDiff = ltcMagnitude.r; // The difference of magnitudes of GGX and Fresnel
float ltcGGXFresnelMagnitude = ltcMagnitude.g;
// 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.
if (bsdfData.materialId == MATERIALID_LIT_CLEAR_COAT)
{
// Change the Fresnel term to account for transmission through Clear Coat and reflection on the base layer
float F = F_Schlick(preLightData.coatFresnel0, preLightData.coatNdotV);
F = Sqr(-F * bsdfData.coatCoverage + 1.0);
F /= preLightData.ieta; //TODO: LaurentB why / ieta here and not for other lights ?
preLightData.ltcGGXFresnelTerm = F * bsdfData.fresnel0 * ltcGGXFresnelMagnitudeDiff + (float3)ltcGGXFresnelMagnitude;
}
else
{
preLightData.ltcGGXFresnelTerm = bsdfData.fresnel0 * ltcGGXFresnelMagnitudeDiff + (float3)ltcGGXFresnelMagnitude;
}
return preLightData;
}

out float3 diffuseLighting,
out float3 specularLighting)
{
float3 F = 1.0;
specularLighting = float3(0.0, 0.0, 0.0);
if (bsdfData.materialId == MATERIALID_LIT_CLEAR_COAT)
{
// Optimized math. Ref: PBR Diffuse Lighting for GGX + Smith Microsurfaces (slide 114).
float NdotL = saturate(dot(bsdfData.coatNormalWS, L));
float NdotV = preLightData.coatNdotV;
float LdotV = dot(L, V);
float invLenLV = rsqrt(abs(2 * LdotV + 2));
float NdotH = saturate((NdotL + NdotV) * invLenLV);
float LdotH = saturate(invLenLV * LdotV + invLenLV);
// Evaluate Fresnel on the Clear Coat
F = F_Schlick(preLightData.coatFresnel0, LdotH);
// TODO: No need to call D (to see with LaurentB) + question on * NdotL
//specularLighting += F * D_GGX(NdotH, max(bsdfdata.MinRoughness, 0.01)) * NdotL;
specularLighting += F * D_GGX(NdotH, 0.01) * NdotL * bsdfData.coatCoverage;
// Change the Fresnel term to account for transmission through Clear Coat and reflection on the base layer
F = Sqr(-F * bsdfData.coatCoverage + 1.0);
// Change the Light and View direction to account for IOR change.
// Update the half vector accordingly
V = preLightData.refractV;
L = ClearCoatTransform(L, bsdfData.coatNormalWS, preLightData.ieta);
}
// Optimized math. Ref: PBR Diffuse Lighting for GGX + Smith Microsurfaces (slide 114).
float NdotL = saturate(dot(bsdfData.normalWS, L)); // Must have the same value without the clamp
float NdotV = preLightData.NdotV; // Get the unaltered (geometric) version

NdotV = max(NdotV, MIN_N_DOT_V); // Use the modified (clamped) version
float3 F = F_Schlick(bsdfData.fresnel0, LdotH);
F *= F_Schlick(bsdfData.fresnel0, LdotH);
// TODO: this way of handling aniso may not be efficient, or maybe with material classification, need to check perf here
// Maybe always using aniso maybe a win ?
if (bsdfData.materialId == MATERIALID_LIT_ANISO)
{
float3 H = (L + V) * invLenLV;

#endif
D = D_GGX(NdotH, bsdfData.roughness);
}
specularLighting = F * (Vis * D);
specularLighting += F * (Vis * D);
#ifdef LIT_DIFFUSE_LAMBERT_BRDF
float diffuseTerm = Lambert();

float ltcValue;
// Evaluate the diffuse part.
// Evaluate the diffuse part
#endif
#ifndef LIT_DIFFUSE_LAMBERT_BRDF
ltcValue *= preLightData.ltcDisneyDiffuseMagnitude;
#endif

// Evaluate the specular part.
// Evaluate the coat part
if (bsdfData.materialId == MATERIALID_LIT_CLEAR_COAT)
// 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.
float3 fresnelTerm = bsdfData.fresnel0 * preLightData.ltcGGXFresnelMagnitudeDiff
+ (float3)preLightData.ltcGGXFresnelMagnitude;
ltcValue = LTCEvaluate(P1, P2, B, preLightData.ltcXformClearCoat);
specularLighting += ltcValue * bsdfData.coatCoverage;
// TODO: no fresnel ?
}
ltcValue = LTCEvaluate(P1, P2, B, preLightData.ltcXformGGX);
ltcValue *= lightData.specularScale;
specularLighting = fresnelTerm * lightData.color * ltcValue;
// Evaluate the specular part
{
ltcValue = LTCEvaluate(P1, P2, B, preLightData.ltcXformGGX);
specularLighting += ltcValue;
// TODO: no fresnel ?
specularLighting *= lightData.color * lightData.specularScale;
}
#endif // LIT_DISPLAY_REFERENCE_AREA
}

float ltcValue;
// Evaluate the diffuse part.
// Evaluate the diffuse part
#endif
#ifndef LIT_DIFFUSE_LAMBERT_BRDF
ltcValue *= preLightData.ltcDisneyDiffuseMagnitude;
#endif

// Evaluate the specular part.
// Evaluate the coat part
if (bsdfData.materialId == MATERIALID_LIT_CLEAR_COAT)
// 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.
float3 fresnelTerm = bsdfData.fresnel0 * preLightData.ltcGGXFresnelMagnitudeDiff
+ (float3)preLightData.ltcGGXFresnelMagnitude;
ltcValue = LTCEvaluate(matL, V, bsdfData.coatNormalWS, preLightData.coatNdotV, preLightData.ltcXformClearCoat);
specularLighting += preLightData.ltcClearCoatFresnelTerm * ltcValue * bsdfData.coatCoverage;
// modify matL value based on Fresnel transmission
matL = mul(matL, preLightData.ltcCoatT);
V = preLightData.refractV;
}
// Evaluate the specular part
{
ltcValue *= lightData.specularScale;
specularLighting = fresnelTerm * lightData.color * ltcValue;
specularLighting += preLightData.ltcGGXFresnelTerm * ltcValue;
specularLighting *= lightData.color * lightData.specularScale;
}
#endif // LIT_DISPLAY_REFERENCE_AREA
}

// We use this formulation as it is the one of legacy unity that was using only AABB box.
float3 R = preLightData.iblDirWS;
float3 coatR = preLightData.coatIblDirWS;
if (lightData.envShapeType == ENVSHAPETYPE_BOX)
if (lightData.envShapeType == ENVSHAPETYPE_SPHERE)
{
float3 dirLS = mul(R, worldToLocal);
float sphereOuterDistance = lightData.innerDistance.x + lightData.blendDistance;
float dist = SphereRayIntersectSimple(positionLS, dirLS, sphereOuterDistance);
R = (positionWS + dist * R) - lightData.positionWS;
// Test again for clear code
if (bsdfData.materialId == MATERIALID_LIT_CLEAR_COAT)
{
dirLS = mul(coatR, worldToLocal);
dist = SphereRayIntersectSimple(positionLS, dirLS, sphereOuterDistance);
coatR = (positionWS + dist * coatR) - lightData.positionWS;
}
}
else if (lightData.envShapeType == ENVSHAPETYPE_BOX)
{
float3 dirLS = mul(R, worldToLocal);
float3 boxOuterDistance = lightData.innerDistance + float3(lightData.blendDistance, lightData.blendDistance, lightData.blendDistance);

R = (positionWS + dist * R) - lightData.positionWS;
// TODO: add distance based roughness
}
else if (lightData.envShapeType == ENVSHAPETYPE_SPHERE)
{
float3 dirLS = mul(R, worldToLocal);
float sphereOuterDistance = lightData.innerDistance.x + lightData.blendDistance;
float dist = SphereRayIntersectSimple(positionLS, dirLS, sphereOuterDistance);
R = (positionWS + dist * R) - lightData.positionWS;
// Test again for clear code
if (bsdfData.materialId == MATERIALID_LIT_CLEAR_COAT)
{
dirLS = mul(coatR, worldToLocal);
dist = BoxRayIntersectSimple(positionLS, dirLS, -boxOuterDistance, boxOuterDistance);
coatR = (positionWS + dist * coatR) - lightData.positionWS;
}
}
// 2. Apply the influence volume (Box volume is used for culling whatever the influence shape)

// Smooth weighting
weight.x = 0.0;
weight.y = smoothstep01(weight.y);
weight.y = Smoothstep01(weight.y);
float3 F = 1.0;
specularLighting = float3(0.0, 0.0, 0.0);
// Evaluate the Clear Coat component if needed and change the BSDF roughness to match Fresnel transmission
if (bsdfData.materialId == MATERIALID_LIT_CLEAR_COAT)
{
F = F_Schlick(preLightData.coatFresnel0, preLightData.coatNdotV);
// Evaluate the Clear Coat color
float4 preLD = SampleEnv(lightLoopContext, lightData.envIndex, coatR, 0.0);
specularLighting += F * preLD.rgb * bsdfData.coatCoverage;
// Change the Fresnel term to account for transmission through Clear Coat and reflection on the base layer.
F = Sqr(-F * bsdfData.coatCoverage + 1.0);
}
specularLighting = preLD.rgb * preLightData.specularFGD;
specularLighting += F * preLD.rgb * preLightData.specularFGD;
// Apply specular occlusion on it
specularLighting *= bsdfData.specularOcclusion * GetSpecularOcclusion(preLightData.NdotV, lightLoopContext.ambientOcclusion, bsdfData.roughness);

7
Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Lit.shader


_Thickness("Thickness", Range(0.0, 1.0)) = 1.0
_ThicknessMap("Thickness Map", 2D) = "white" {}
_CoatCoverage("Coat Coverage", Range(0.0, 1.0)) = 1.0
_CoatIOR("Coat IOR", Range(0.0, 1.0)) = 0.5
_SpecularColor("SpecularColor", Color) = (1, 1, 1, 1)
_SpecularColorMap("SpecularColorMap", 2D) = "white" {}

[Enum(TangentSpace, 0, ObjectSpace, 1)] _NormalMapSpace("NormalMap space", Float) = 0
// Note: 2 and 3 are currently unused
[Enum(Subsurface Scattering, 0, Standard, 1, Anisotropy, 4, Specular Color, 5)] _MaterialID("MaterialId", Int) = 1 // MaterialId.RegularLighting
[Enum(Subsurface Scattering, 0, Standard, 1, ClearCoat, 2, Anisotropy, 4, Specular Color, 5)] _MaterialID("MaterialId", Int) = 1 // MaterialId.RegularLighting
[ToggleOff] _EnablePerPixelDisplacement("Enable per pixel displacement", Float) = 0.0
_PPDMinSamples("Min sample for POM", Range(1.0, 64.0)) = 5

// MaterialId are used as shader feature to allow compiler to optimize properly
// Note _MATID_STANDARD is not define as there is always the default case "_". We assign default as _MATID_STANDARD, so we never test _MATID_STANDARD
#pragma shader_feature _ _MATID_SSS _MATID_ANISO _MATID_SPECULAR
#pragma shader_feature _ _MATID_SSS _MATID_ANISO _MATID_SPECULAR _MATID_CLEARCOAT
#pragma multi_compile LIGHTMAP_OFF LIGHTMAP_ON
#pragma multi_compile DIRLIGHTMAP_OFF DIRLIGHTMAP_COMBINED

1
Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/LitData.hlsl


// Init other parameters
surfaceData.materialId = 1; // MaterialId.LitStandard
surfaceData.anisotropy = 0;
surfaceData.specular = 0.04;
surfaceData.subsurfaceRadius = 1.0;
surfaceData.thickness = 0.0;
surfaceData.subsurfaceProfile = 0;

22
Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/LitDataInternal.hlsl


#elif defined(_MATID_ANISO)
surfaceData.materialId = MATERIALID_LIT_ANISO;
#elif defined(_MATID_SPECULAR)
surfaceData.materialId = MATERIALID_LIT_STANDARD; // Specular is not a different BRDF, it is just different parametrization, do'nt do a separate matId for it
surfaceData.materialId = MATERIALID_LIT_SPECULAR;
#elif defined(_MATID_CLEARCOAT)
surfaceData.materialId = MATERIALID_LIT_CLEAR_COAT;
#else // Default
surfaceData.materialId = MATERIALID_LIT_STANDARD;
#endif

surfaceData.anisotropy = 1.0;
#endif
surfaceData.anisotropy *= ADD_IDX(_Anisotropy);
// This surfaceData.specular must be static to allow the compiler to optimize the code when converting / encoding the values
#ifdef _MATID_SPECULAR
surfaceData.specular = SPECULARVALUE_SPECULAR_COLOR;
#else
surfaceData.specular = SPECULARVALUE_REGULAR;
#endif
surfaceData.subsurfaceProfile = _SubsurfaceProfile;
surfaceData.subsurfaceRadius = _SubsurfaceRadius;

surfaceData.specularColor *= SAMPLE_UVMAPPING_TEXTURE2D(_SpecularColorMap, sampler_SpecularColorMap, layerTexCoord.base).rgb;
#endif
surfaceData.coatNormalWS = input.worldToTangent[2].xyz; // Assign vertex normal
surfaceData.coatCoverage = _CoatCoverage;
surfaceData.coatIOR = _CoatIOR;
surfaceData.materialId = 1; // MaterialId.LitStandard
surfaceData.materialId = MATERIALID_LIT_STANDARD;
surfaceData.specular = 0.0;
surfaceData.subsurfaceRadius = 0.0;
surfaceData.thickness = 0.0;

surfaceData.coatNormalWS = float3(0.0, 0.0, 0.0);
surfaceData.coatCoverage = 0.0f;
surfaceData.coatIOR = 0.5;
#endif // #if !defined(LAYERED_LIT_SHADER)

3
Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/LitProperties.hlsl


float _SubsurfaceRadius;
float _Thickness;
float _CoatCoverage;
float _CoatIOR;
float4 _SpecularColor;
float _TexWorldScale;

7
Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/LitTessellation.shader


_Thickness("Thickness", Range(0.0, 1.0)) = 1.0
_ThicknessMap("Thickness Map", 2D) = "white" {}
_CoatCoverage("Coat Coverage", Range(0.0, 1.0)) = 1.0
_CoatIOR("Coat IOR", Range(0.0, 1.0)) = 0.5
_SpecularColor("SpecularColor", Color) = (1, 1, 1, 1)
_SpecularColorMap("SpecularColorMap", 2D) = "white" {}

[Enum(TangentSpace, 0, ObjectSpace, 1)] _NormalMapSpace("NormalMap space", Float) = 0
// Note: 2 and 3 are currently unused
[Enum(Subsurface Scattering, 0, Standard, 1, Anisotropy, 4, Specular Color, 5)] _MaterialID("MaterialId", Int) = 1 // MaterialId.RegularLighting
[Enum(Subsurface Scattering, 0, Standard, 1, ClearCoat, 2, Anisotropy, 4, Specular Color, 5)] _MaterialID("MaterialId", Int) = 1 // MaterialId.RegularLighting
[ToggleOff] _EnablePerPixelDisplacement("Enable per pixel displacement", Float) = 0.0
_PPDMinSamples("Min sample for POM", Range(1.0, 64.0)) = 5

// MaterialId are used as shader feature to allow compiler to optimize properly
// Note _MATID_STANDARD is not define as there is always the default case "_". We assign default as _MATID_STANDARD, so we never test _MATID_STANDARD
#pragma shader_feature _ _MATID_SSS _MATID_ANISO _MATID_SPECULAR
#pragma shader_feature _ _MATID_SSS _MATID_ANISO _MATID_SPECULAR _MATID_CLEARCOAT
#pragma multi_compile LIGHTMAP_OFF LIGHTMAP_ON
#pragma multi_compile DIRLIGHTMAP_OFF DIRLIGHTMAP_COMBINED

13
Assets/ScriptableRenderPipeline/ShaderLibrary/Common.hlsl


return rad * 180.0 / PI;
}
// Square functions for cleaner code
float Sqr(float x)
{
return x * x;
}
float3 Sqr(float3 x)
{
return x * x;
}
// Acos in 14 cycles.
// Ref: https://seblagarde.wordpress.com/2014/12/01/inverse-trigonometric-functions-gpu-optimization-for-amd-gcn-architecture/
float FastACos(float inX)

}
// Same as smoothstep except it assume 0, 1 interval for x
float smoothstep01(float x)
float Smoothstep01(float x)
{
return x * x * (3.0 - (2.0 * x));
}

正在加载...
取消
保存