#define LTC_LUT_OFFSET (0.5 * rcp(LTC_LUT_SIZE))
// SSS parameters
#define SSS_N_PROFILES 8
#define SSS_UNIT_CONVERSION (1.0 / 300.0) // From 1/3 centimeters to meters
#define SSS_LOW_THICKNESS 0.005 // 5 mm
#define SSS_N_PROFILES 8
#define SSS_UNIT_CONVERSION (1.0 / 300.0) // From 1/3 centimeters to meters
#define SSS_LOW_THICKNESS 0.005 // 0.5 cm
#define CENTIMETERS_TO_METERS (1.0 / 100.0)
uint _EnableSSS; // Globally toggles subsurface scattering on/off
uint _TransmissionFlags; // 1 bit/profile; 0 = inf. thick, 1 = supports transmission
void ApplyDebugToBSDFData(inout BSDFData bsdfData)
{
#ifdef DEBUG_DISPLAY
if (_DebugDisplayMode == DEBUGDISPLAY MODE_SPECULAR_LIGHTING)
if (_DebugLightingMode == DEBUGLIGHTING MODE_SPECULAR_LIGHTING)
{
bool overrideSmoothness = _DebugLightingSmoothness.x != 0.0;
float overrideSmoothnessValue = _DebugLightingSmoothness.y;
}
}
if (_DebugDisplayMode == DEBUGDISPLAYMODE_DIFFUSE_LIGHTING)
if (_DebugLightingMode == DEBUGLIGHTINGMODE_DIFFUSE_LIGHTING)
}
void ConfigureTexturingForSSS(inout BSDFData bsdfData)
{
bool performPostScatterTexturing = IsBitSet(_TexturingModeFlags, bsdfData.subsurfaceProfile);
// It's either post-scatter, or pre- and post-scatter texturing.
bsdfData.diffuseColor = performPostScatterTexturing ? float3(1, 1, 1)
: sqrt(bsdfData.diffuseColor);
}
// Evaluates transmittance for a linear combination of two normalized 2D Gaussians.
// Thickness and SSS radius are decoupled for artists.
// In theory, we should modify the thickness by the inverse of the radius scale of the profile.
// thickness /= radiusScale;
thickness /= SSS_UNIT_CONVERSION ;
thickness /= CENTIMETERS_TO_METERS ;
float t2 = thickness * thickness;
return transmittance * tintColor;
}
void FillMaterialIdStandardData(float3 baseColor, float specular, float metallic, float roughness, float3 normalWS, float3 tangentWS, float anisotropy, inout BSDFData bsdfData)
{
bsdfData.diffuseColor = baseColor * (1.0 - metallic);
bsdfData.fresnel0 = lerp(float3(specular.xxx), baseColor, metallic);
// TODO: encode specular
bsdfData.tangentWS = tangentWS;
bsdfData.bitangentWS = cross(normalWS, tangentWS);
ConvertAnisotropyToRoughness(roughness, anisotropy, bsdfData.roughnessT, bsdfData.roughnessB);
bsdfData.anisotropy = anisotropy;
}
void FillMaterialIdSSSData(float3 baseColor, int subsurfaceProfile, float subsurfaceRadius, float thickness, inout BSDFData bsdfData)
{
bsdfData.diffuseColor = baseColor;
// TODO take from subsurfaceProfile
bsdfData.fresnel0 = 0.04; // Should be 0.028 for the skin
bsdfData.subsurfaceProfile = subsurfaceProfile;
// Make the Std. Dev. of 1 correspond to the effective radius of 1 cm (three-sigma rule).
bsdfData.subsurfaceRadius = SSS_UNIT_CONVERSION * subsurfaceRadius + 0.0001;
bsdfData.thickness = CENTIMETERS_TO_METERS * (_ThicknessRemaps[subsurfaceProfile][0] +
_ThicknessRemaps[subsurfaceProfile][1] * thickness);
bsdfData.enableTransmission = IsBitSet(_TransmissionFlags, subsurfaceProfile);
if (bsdfData.enableTransmission)
{
bsdfData.transmittance = ComputeTransmittance( _HalfRcpVariancesAndLerpWeights[subsurfaceProfile][0].xyz,
_HalfRcpVariancesAndLerpWeights[subsurfaceProfile][0].w,
_HalfRcpVariancesAndLerpWeights[subsurfaceProfile][1].xyz,
_HalfRcpVariancesAndLerpWeights[subsurfaceProfile][1].w,
_TintColors[subsurfaceProfile].rgb, bsdfData.thickness, bsdfData.subsurfaceRadius);
}
#ifndef SSS_FILTER_HORIZONTAL_AND_COMBINE // When doing the SSS comine pass, we must not apply the modification of diffuse color
// Handle post-scatter, or pre- and post-scatter texturing.
// We modify diffuseColor here so it affect all the lighting + GI (lightprobe / lightmap) (Need to be done also in GBuffer pass) + transmittance
// diffuseColor will be solely use during lighting pass. The other contribution will be apply in subsurfacescattering convolution.
bool performPostScatterTexturing = IsBitSet(_TexturingModeFlags, subsurfaceProfile);
bsdfData.diffuseColor = performPostScatterTexturing ? float3(1.0, 1.0, 1.0) : sqrt(bsdfData.diffuseColor);
#endif
}
//-----------------------------------------------------------------------------
// conversion function for forward
//-----------------------------------------------------------------------------
if (bsdfData.materialId == MATERIALID_LIT_STANDARD)
{
bsdfData.diffuseColor = surfaceData.baseColor * (1.0 - surfaceData.metallic);
bsdfData.fresnel0 = lerp(float3(surfaceData.specular, surfaceData.specular, surfaceData.specular), surfaceData.baseColor, surfaceData.metallic);
bsdfData.tangentWS = surfaceData.tangentWS;
bsdfData.bitangentWS = cross(surfaceData.normalWS, surfaceData.tangentWS);
ConvertAnisotropyToRoughness(bsdfData.roughness, surfaceData.anisotropy, bsdfData.roughnessT, bsdfData.roughnessB);
bsdfData.anisotropy = surfaceData.anisotropy;
bsdfData.materialId = surfaceData.anisotropy > 0 ? MATERIALID_LIT_ANISO : bsdfData.materialId;
FillMaterialIdStandardData(surfaceData.baseColor, surfaceData.specular, surfaceData.metallic, bsdfData.roughness, surfaceData.normalWS, surfaceData.tangentWS, surfaceData.anisotropy, bsdfData);
bsdfData.materialId = surfaceData.anisotropy > 0.0 ? MATERIALID_LIT_ANISO : bsdfData.materialId;
bsdfData.diffuseColor = surfaceData.baseColor;
// TODO take from subsurfaceProfile
bsdfData.fresnel0 = 0.04; /* 0.028 ? */
bsdfData.subsurfaceProfile = surfaceData.subsurfaceProfile;
// Make the Std. Dev. of 1 correspond to the effective radius of 1 cm (three-sigma rule).
bsdfData.subsurfaceRadius = SSS_UNIT_CONVERSION * surfaceData.subsurfaceRadius + 0.0001;
bsdfData.thickness = SSS_UNIT_CONVERSION * (_ThicknessRemaps[bsdfData.subsurfaceProfile][0] +
_ThicknessRemaps[bsdfData.subsurfaceProfile][1] * surfaceData.thickness);
bsdfData.enableTransmission = IsBitSet(_TransmissionFlags, bsdfData.subsurfaceProfile);
if (bsdfData.enableTransmission)
{
bsdfData.transmittance = ComputeTransmittance(_HalfRcpVariancesAndLerpWeights[bsdfData.subsurfaceProfile][0].xyz,
_HalfRcpVariancesAndLerpWeights[bsdfData.subsurfaceProfile][0].w,
_HalfRcpVariancesAndLerpWeights[bsdfData.subsurfaceProfile][1].xyz,
_HalfRcpVariancesAndLerpWeights[bsdfData.subsurfaceProfile][1].w,
_TintColors[bsdfData.subsurfaceProfile].rgb, bsdfData.thickness, bsdfData.subsurfaceRadius);
}
}
else if (bsdfData.materialId == MATERIALID_LIT_CLEAR_COAT)
{
bsdfData.diffuseColor = surfaceData.baseColor * (1.0 - surfaceData.metallic);
bsdfData.fresnel0 = lerp(float3(surfaceData.specular, surfaceData.specular, surfaceData.specular), surfaceData.baseColor, surfaceData.metallic);
bsdfData.coatNormalWS = surfaceData.coatNormalWS;
bsdfData.coatRoughness = PerceptualSmoothnessToRoughness(surfaceData.coatPerceptualSmoothness);
FillMaterialIdSSSData(surfaceData.baseColor, surfaceData.subsurfaceProfile, surfaceData.subsurfaceRadius, surfaceData.thickness, bsdfData);
}
else if (bsdfData.materialId == MATERIALID_LIT_SPECULAR)
{
#ifdef OUTPUT_SPLIT_LIGHTING
ConfigureTexturingForSSS(bsdfData);
#endif
ApplyDebugToBSDFData(bsdfData);
return bsdfData;
// conversion function for deferred
//-----------------------------------------------------------------------------
// Tetra encoding 10:10 + 2 seems equivalent to oct 11:11, as oct is cheaper use that. Let here for future testing in reflective scene for comparison
//#define USE_NORMAL_TETRAHEDRON_ENCODING
// Encode SurfaceData (BSDF parameters) into GBuffer
// Must be in sync with RT declared in HDRenderPipeline.cs ::Rebuild
outGBuffer0 = float4(surfaceData.baseColor, surfaceData.specularOcclusion);
// RT1 - 10:10:10:2
// Encode normal on 20bit with oct compression
float2 octNormalWS = PackNormalOctEncode(surfaceData.normalWS);
// TODO: Store 2 bit of flag into perceptualSmoothness (one for SSR, other is free (deferred planar reflection ID ? / MatID extension ?)
outGBuffer1 = float4(octNormalWS * 0.5 + 0.5, PerceptualSmoothnessToPerceptualRoughness(surfaceData.perceptualSmoothness), PackMaterialId(surfaceData.materialId));
#ifdef USE_NORMAL_TETRAHEDRON_ENCODING
// Encode normal on 20bit + 2bit (faceIndex) with tetrahedal compression
uint faceIndex;
float2 tetraNormalWS = PackNormalTetraEncode(surfaceData.normalWS, faceIndex);
// Store faceIndex on two bits with perceptualRoughness
outGBuffer1 = float4(tetraNormalWS * 0.5 + 0.5, PackFloatInt10bit(PerceptualSmoothnessToPerceptualRoughness(surfaceData.perceptualSmoothness), faceIndex, 4.0), PackMaterialId(surfaceData.materialId));
#else
// Encode normal on 20bit with oct compression + 2bit of sign
float2 octNormalWS = PackNormalOctEncode(surfaceData.normalWS);
// To have more precision encode the sign of xy in a separate uint
uint octNormalSign = (octNormalWS.x > 0.0 ? 1 : 0) + (octNormalWS.y > 0.0 ? 2 : 0);
// Store octNormalSign on two bits with perceptualRoughness
outGBuffer1 = float4(abs(octNormalWS), PackFloatInt10bit(PerceptualSmoothnessToPerceptualRoughness(surfaceData.perceptualSmoothness), octNormalSign, 4.0), PackMaterialId(surfaceData.materialId));
#endif
// RT2 - 8:8:8:8
if (surfaceData.materialId == MATERIALID_LIT_STANDARD)
else if (surfaceData.materialId == MATERIALID_LIT_SSS)
{
outGBuffer2 = float4(surfaceData.subsurfaceRadius, surfaceData.thickness, 0.0, surfaceData.subsurfaceProfile * rcp(SSS_N_PROFILES - 1));
}
else if (surfaceData.materialId == MATERIALID_LIT_CLEAR_COAT)
{
// Encode coat normal on 16bit with oct compression
float2 octCoatNormalWS = PackNormalOctEncode(surfaceData.coatNormalWS);
// TODO: store metal and specular together, specular should be an enum (fixed value)
outGBuffer2 = float4(octCoatNormalWS * 0.5 + 0.5, PerceptualSmoothnessToRoughness(surfaceData.coatPerceptualSmoothness), surfaceData.metallic);
}
else if (surfaceData.materialId == MATERIALID_LIT_SPECULAR)
{
float3 baseColor = inGBuffer0.rgb;
bsdfData.specularOcclusion = inGBuffer0.a;
bsdfData.normalWS = UnpackNormalOctEncode(float2(inGBuffer1.r * 2.0 - 1.0, inGBuffer1.g * 2.0 - 1.0));
bsdfData.perceptualRoughness = inGBuffer1.b;
#ifdef USE_NORMAL_TETRAHEDRON_ENCODING
uint faceIndex;
UnpackFloatInt10bit(inGBuffer1.b, 4.0, bsdfData.perceptualRoughness, faceIndex);
bsdfData.normalWS = UnpackNormalTetraEncode(inGBuffer1.xy * 2.0 - 1.0, faceIndex);
#else
uint octNormalSign;
UnpackFloatInt10bit(inGBuffer1.b, 4.0, bsdfData.perceptualRoughness, octNormalSign);
inGBuffer1.r *= (octNormalSign & 1) ? 1.0 : -1.0;
inGBuffer1.g *= (octNormalSign & 2) ? 1.0 : -1.0;
bsdfData.normalWS = UnpackNormalOctEncode(float2(inGBuffer1.r, inGBuffer1.g));
#endif
int supportsClearCoat = (featureFlags & (MATERIALID_LIT_CLEAR_COAT)) != 0;
if(supportsStandard + supportsSSS + supportsClearCoat + supportsSpecular > 1)
if(supportsStandard + supportsSSS + supportsSpecular > 1)
{
bsdfData.materialId = UnpackMaterialId(inGBuffer1.a); // only fetch materialid if it is not statically known from feature flags
}
if(supportsStandard) bsdfData.materialId = MATERIALID_LIT_STANDARD;
else if(supportsSSS) bsdfData.materialId = MATERIALID_LIT_SSS;
else if(supportsClearCoat) bsdfData.materialId = MATERIALID_LIT_CLEAR_COAT;
else bsdfData.materialId = MATERIALID_LIT_SPECULAR;
}
// TODO extract spec
float specular = 0.04;
float specular = 0.04; // TODO extract spec
bsdfData.diffuseColor = baseColor * (1.0 - metallic);
bsdfData.fresnel0 = lerp(float3(specular, specular, specular), baseColor, metallic);
bsdfData.tangentWS = UnpackNormalOctEncode(float2(inGBuffer2.rg * 2.0 - 1.0));
bsdfData.bitangentWS = cross(bsdfData.normalWS, bsdfData.tangentWS);
ConvertAnisotropyToRoughness(bsdfData.roughness, anisotropy, bsdfData.roughnessT, bsdfData.roughnessB);
bsdfData.anisotropy = anisotropy;
float3 tangentWS = UnpackNormalOctEncode(float2(inGBuffer2.rg * 2.0 - 1.0));
FillMaterialIdStandardData(baseColor, specular, metallic, bsdfData.roughness, bsdfData.normalWS, tangentWS, anisotropy, bsdfData);
if ((featureFlags & FEATURE_FLAG_MATERIAL_LIT_ANISO) && (featureFlags & FEATURE_FLAG_MATERIAL_LIT_STANDARD) == 0 || anisotropy > 0)
{
else if (supportsSSS && bsdfData.materialId == MATERIALID_LIT_SSS)
{
bsdfData.diffuseColor = baseColor;
// TODO take from subsurfaceProfile
bsdfData.fresnel0 = 0.04; /* 0.028 ? */
bsdfData.subsurfaceProfile = (SSS_N_PROFILES - 1) * inGBuffer2.a + 0.1; // Need to bias for integers to round trip through the G-buffer
// Make the Std. Dev. of 1 correspond to the effective radius of 1 cm (three-sigma rule).
bsdfData.subsurfaceRadius = SSS_UNIT_CONVERSION * inGBuffer2.r + 0.0001;
bsdfData.thickness = SSS_UNIT_CONVERSION * (_ThicknessRemaps[bsdfData.subsurfaceProfile][0] +
_ThicknessRemaps[bsdfData.subsurfaceProfile][1] * inGBuffer2.g);
bsdfData.enableTransmission = IsBitSet(_TransmissionFlags, bsdfData.subsurfaceProfile);
if (bsdfData.enableTransmission)
{
bsdfData.transmittance = ComputeTransmittance(_HalfRcpVariancesAndLerpWeights[bsdfData.subsurfaceProfile][0].xyz,
_HalfRcpVariancesAndLerpWeights[bsdfData.subsurfaceProfile][0].w,
_HalfRcpVariancesAndLerpWeights[bsdfData.subsurfaceProfile][1].xyz,
_HalfRcpVariancesAndLerpWeights[bsdfData.subsurfaceProfile][1].w,
_TintColors[bsdfData.subsurfaceProfile].rgb, bsdfData.thickness, bsdfData.subsurfaceRadius);
}
}
else if (supportsClearCoat && bsdfData.materialId == MATERIALID_LIT_CLEAR_COAT)
{
float metallic = inGBuffer2.a;
// TODO extract spec
float specular = 0.04;
bsdfData.diffuseColor = baseColor * (1.0 - metallic);
bsdfData.fresnel0 = lerp(float3(specular, specular, specular), baseColor, metallic);
bsdfData.coatNormalWS = UnpackNormalOctEncode(float2(inGBuffer2.rg * 2.0 - 1.0));
bsdfData.coatRoughness = inGBuffer2.b;
int subsurfaceProfile = (SSS_N_PROFILES - 0.9) * inGBuffer2.a;
float subsurfaceRadius = inGBuffer2.r;
float thickness = inGBuffer2.g;
FillMaterialIdSSSData(baseColor, subsurfaceProfile, subsurfaceRadius, thickness, bsdfData);
}
else if (supportsSpecular && bsdfData.materialId == MATERIALID_LIT_SPECULAR)
{
bakeDiffuseLighting = inGBuffer3.rgb;
#ifdef OUTPUT_SPLIT_LIGHTING
ConfigureTexturingForSSS(bsdfData);
#endif
ApplyDebugToBSDFData(bsdfData);
}
{
featureFlags |= FEATURE_FLAG_MATERIAL_LIT_SSS;
}
else if (materialId == MATERIALID_LIT_CLEAR_COAT)
{
featureFlags |= FEATURE_FLAG_MATERIAL_LIT_CLEAR_COAT;
}
else if (materialId == MATERIALID_LIT_SPECULAR)
{
featureFlags |= FEATURE_FLAG_MATERIAL_LIT_SPECULAR;
// Precomputed lighting data to send to the various lighting functions
struct PreLightData
{
float NdotV;
// General
float NdotV; // Between 0.0001 and 1
float unNdotV; // Between -1 and 1
// GGX iso
// Aniso
// GGX Aniso
// IBL
float3 iblDirWS; // Dominant specular direction, used for IBL in EvaluateBSDF_Env()
float iblMipLevel;
{
PreLightData preLightData;
// We have handle the case of NdotV being negative in GetData() function with GetShiftedNdotV.
// So we don't need to saturate or take the abs here.
// In case a material use negative normal for double sided lighting like speedtree this will be handle in the GetData() code too.
preLightData.NdotV = dot(bsdfData.normalWS, V);
// General
float3 iblNormalWS = bsdfData.normalWS;
preLightData.unNdotV = dot(bsdfData.normalWS, V);
// GetShiftedNdotV return a positive NdotV
// In case a material use negative normal for double sided lighting like Speedtree they need to do a new calculation
preLightData.NdotV = GetShiftedNdotV(iblNormalWS, V, preLightData.unNdotV);
// GGX iso
float iblNdotV = preLightData.NdotV;
float3 iblNormalWS = bsdfData.normalWS;
// Check if we precompute anisotropy too
// GGX aniso
if (bsdfData.materialId == MATERIALID_LIT_ANISO)
{
preLightData.TdotV = dot(bsdfData.tangentWS, V);
iblNormalWS = GetAnisotropicModifiedNormal(bsdfData.bitangentWS, bsdfData.normalWS, V, bsdfData.anisotropy);
iblNormalWS = GetAnisotropicModifiedNormal(bsdfData.bitangentWS, iblNormalWS, V, bsdfData.anisotropy);
// NOTE: If we follow the theory we should use the modified normal for the different calculation implying a normal (like NDotV) and use iblNormalWS
// NOTE: If we follow the theory we should use the modified normal for the different calculation implying a normal (like NdotV) and use iblNormalWS
GetPreIntegratedFGD(iblNdotV, bsdfData.perceptualRoughness, bsdfData.fresnel0, preLightData.specularFGD, preLightData.diffuseFGD);
// IBL
GetPreIntegratedFGD(preLightData.NdotV, bsdfData.perceptualRoughness, bsdfData.fresnel0, preLightData.specularFGD, preLightData.diffuseFGD);
// Area light specific
// Area light
// UVs for sampling the LUTs
float theta = FastACos(preLightData.NdotV);
float2 uv = LTC_LUT_OFFSET + LTC_LUT_SCALE * float2(bsdfData.perceptualRoughness, theta * INV_HALF_PI);
out float3 specularLighting)
{
float NdotL = saturate(dot(bsdfData.normalWS, L));
float NdotV = preLightData.NdotV;
float NdotV = preLightData.unNdotV; // This value must not be clamped
float invLenLV = rsqrt(abs(2 + 2 * LdotV)); // invLenLV = rcp(length(L + V))
// GCN Optimization: reference PBR Diffuse Lighting for GGX + Smith Microsurfaces
float invLenLV = rsqrt(abs(2.0 * LdotV + 2.0)); // invLenLV = rcp(length(L + V))
float LdotH = saturate(invLenLV + invLenLV * LdotV);
float LdotH = saturate(invLenLV * LdotV + invLenLV);
float3 F = F_Schlick(bsdfData.fresnel0, LdotH);
bsdfData.roughnessB = ClampRoughnessForAnalyticalLights(bsdfData.roughnessB);
#ifdef LIT_USE_BSDF_PRE_LAMBDAV
Vis = V_SmithJointGGXAnisoLambdaV( preLightData.TdotV, preLightData.BdotV, NdotV, TdotL, BdotL, NdotL,
bsdfData.roughnessT, bsdfData.roughnessB, preLightData.anisoGGXLambdaV);
Vis = V_SmithJointGGXAnisoLambdaV(preLightData.TdotV, preLightData.BdotV, preLightData. NdotV, TdotL, BdotL, NdotL,
bsdfData.roughnessT, bsdfData.roughnessB, preLightData.anisoGGXLambdaV);
Vis = V_SmithJointGGXAniso( preLightData.TdotV, preLightData.BdotV, NdotV, TdotL, BdotL, NdotL,
bsdfData.roughnessT, bsdfData.roughnessB);
Vis = V_SmithJointGGXAniso(preLightData.TdotV, preLightData.BdotV, preLightData. NdotV, TdotL, BdotL, NdotL,
bsdfData.roughnessT, bsdfData.roughnessB);
#endif
D = D_GGXAniso(TdotH, BdotH, NdotH, bsdfData.roughnessT, bsdfData.roughnessB);
bsdfData.roughness = ClampRoughnessForAnalyticalLights(bsdfData.roughness);
#ifdef LIT_USE_BSDF_PRE_LAMBDAV
Vis = V_SmithJointGGX(NdotL, NdotV, bsdfData.roughness, preLightData.ggxLambdaV);
Vis = V_SmithJointGGX(NdotL, preLightData. NdotV, bsdfData.roughness, preLightData.ggxLambdaV);
Vis = V_SmithJointGGX(NdotL, NdotV, bsdfData.roughness);
Vis = V_SmithJointGGX(NdotL, preLightData. NdotV, bsdfData.roughness);
#endif
D = D_GGX(NdotH, bsdfData.roughness);
}
float diffuseTerm = Lambert();
#elif LIT_DIFFUSE_GGX_BRDF
float3 diffuseTerm = DiffuseGGX(bsdfData.diffuseColor, NdotV, NdotL, NdotH, LdotV, bsdfData.perceptualRoughness);
float3 diffuseTerm = DiffuseGGX(bsdfData.diffuseColor, preLightData. NdotV, NdotL, NdotH, LdotV, bsdfData.perceptualRoughness);
float diffuseTerm = DisneyDiffuse(NdotV, NdotL, LdotH, bsdfData.perceptualRoughness);
float diffuseTerm = DisneyDiffuse(preLightData. NdotV, NdotL, LdotH, bsdfData.perceptualRoughness);
#endif
diffuseLighting = bsdfData.diffuseColor * diffuseTerm;
float4 cookie = float4(1.0, 1.0, 1.0, 1.0);
float shadow = 1;
[branch] if (lightData.shadowIndex >= 0 && illuminance > 0.0 )
[branch] if (lightData.shadowIndex >= 0)
{
#ifdef SHADOWS_USE_SHADOWCTXT
shadow = GetDirectionalShadowAttenuation(lightLoopContext.shadowContext, positionWS, lightData.shadowIndex, L, posInput.unPositionSS);
illuminance *= shadow;
}
[branch] if (lightData.cookieIndex >= 0 && illuminance > 0.0 )
[branch] if (lightData.cookieIndex >= 0)
{
float3 lightToSurface = positionWS - lightData.positionWS;
[branch] if (bsdfData.enableTransmission)
{
// Reverse the normal.
illuminance = saturate(dot(-bsdfData.normalWS, L));
// Reverse the normal + do some wrap lighting to have a nicer transition between regular lighting and transmittance
// Ref: Steve McAuley - Energy-Conserving Wrapped Diffuse
const float w = 0.15;
float illuminance = saturate((dot(-bsdfData.normalWS, L) + w) / ((1.0 + w) * (1.0 + w)));
// For low thickness, we can reuse the shadowing status for the back of the object.
shadow = (bsdfData.thickness <= SSS_LOW_THICKNESS) ? shadow : 1;
illuminance *= shadow * cookie.a;
// illuminance *= SampleIES(lightLoopContext, lightData.IESIndex, sphericalCoord, 0).r;
//}
[branch] if (lightData.shadowIndex >= 0 && illuminance > 0.0 )
[branch] if (lightData.shadowIndex >= 0)
{
float3 offset = float3(0.0, 0.0, 0.0); // GetShadowPosOffset(nDotL, normal);
#ifdef SHADOWS_USE_SHADOWCTXT
illuminance *= shadow;
}
[branch] if (lightData.cookieIndex >= 0 && illuminance > 0.0 )
[branch] if (lightData.cookieIndex >= 0)
{
float3x3 lightToWorld = float3x3(lightData.right, lightData.up, lightData.forward);
[branch] if (bsdfData.enableTransmission)
{
// Reverse the normal.
illuminance = saturate(dot(-bsdfData.normalWS, L)) * attenuation;
// Reverse the normal + do some wrap lighting to have a nicer transition between regular lighting and transmittance
// Ref: Steve McAuley - Energy-Conserving Wrapped Diffuse
const float w = 0.15;
float illuminance = saturate((dot(-bsdfData.normalWS, L) + w) / ((1.0 + w) * (1.0 + w)));
illuminance *= attenuation;
// For low thickness, we can reuse the shadowing status for the back of the object.
shadow = (bsdfData.thickness <= SSS_LOW_THICKNESS) ? shadow : 1;
illuminance *= shadow * cookie.a;
float4 cookie = float4(1.0, 1.0, 1.0, 1.0);
float shadow = 1;
[branch] if (lightData.shadowIndex >= 0 && illuminance > 0.0 )
[branch] if (lightData.shadowIndex >= 0)
{
#ifdef SHADOWS_USE_SHADOWCTXT
shadow = GetDirectionalShadowAttenuation(lightLoopContext.shadowContext, positionWS, lightData.shadowIndex, L, posInput.unPositionSS);
illuminance *= shadow;
}
[branch] if (lightData.cookieIndex >= 0 && illuminance > 0.0 )
[branch] if (lightData.cookieIndex >= 0)
{
// Compute the texture coordinates in [0, 1]^2.
float2 coord = positionNDC * 0.5 + 0.5;
[branch] if (bsdfData.enableTransmission)
{
// Reverse the normal.
illuminance = saturate(dot(-bsdfData.normalWS, L) * clipFactor);
// Reverse the normal + do some wrap lighting to have a nicer transition between regular lighting and transmittance
// Ref: Steve McAuley - Energy-Conserving Wrapped Diffuse
const float w = 0.15;
float illuminance = saturate((dot(-bsdfData.normalWS, L) + w) / ((1.0 + w) * (1.0 + w)));
illuminance *= clipFactor;
// For low thickness, we can reuse the shadowing status for the back of the object.
shadow = (bsdfData.thickness <= SSS_LOW_THICKNESS) ? shadow : 1;
illuminance *= shadow * cookie.a;
ltcValue = LTCEvaluate(P1, P2, B, preLightData.ltcXformDisneyDiffuse);
#endif
if (ltcValue == 0.0)
{
// The light is below the horizon.
return;
}
#ifndef LIT_DIFFUSE_LAMBERT_BRDF
ltcValue *= preLightData.ltcDisneyDiffuseMagnitude;
#endif
float3 unL = lightData.positionWS - positionWS;
[branch]
if (dot(lightData.forward, unL) >= 0)
if (dot(lightData.forward, unL) >= 0.0001 )
{
// The light is back-facing.
return;
#else
ltcValue = LTCEvaluate(matL, V, bsdfData.normalWS, preLightData.NdotV, preLightData.ltcXformDisneyDiffuse);
#endif
if (ltcValue == 0.0)
{
// The polygon is either back-facing, or has been completely clipped.
return;
}
#ifndef LIT_DIFFUSE_LAMBERT_BRDF
ltcValue *= preLightData.ltcDisneyDiffuseMagnitude;