/* 2 */ LIGHTFEATUREFLAGS_SKY | LIGHTFEATUREFLAGS_DIRECTIONAL | LIGHTFEATUREFLAGS_AREA | MATERIALFEATUREFLAGS_LIT_STANDARD,
/* 3 */ LIGHTFEATUREFLAGS_SKY | LIGHTFEATUREFLAGS_DIRECTIONAL | LIGHTFEATUREFLAGS_ENV | MATERIALFEATUREFLAGS_LIT_STANDARD,
/* 4 */ LIGHTFEATUREFLAGS_SKY | LIGHTFEATUREFLAGS_DIRECTIONAL | LIGHTFEATUREFLAGS_PUNCTUAL | LIGHTFEATUREFLAGS_ENV | MATERIALFEATUREFLAGS_LIT_STANDARD,
/* 5 */ LIGHT_FEATURE_MASK_FLAGS | MATERIALFEATUREFLAGS_LIT_STANDARD,
/* 5 */ LIGHT_FEATURE_MASK_FLAGS_OPAQUE | MATERIALFEATUREFLAGS_LIT_STANDARD,
// SSS
/* 6 */ LIGHTFEATUREFLAGS_SKY | LIGHTFEATUREFLAGS_DIRECTIONAL | LIGHTFEATUREFLAGS_PUNCTUAL | MATERIALFEATUREFLAGS_LIT_SSS,
/* 10 */ LIGHT_FEATURE_MASK_FLAGS | MATERIALFEATUREFLAGS_LIT_SSS,
/* 10 */ LIGHT_FEATURE_MASK_FLAGS_OPAQUE | MATERIALFEATUREFLAGS_LIT_SSS,
// Aniso
/* 11 */ LIGHTFEATUREFLAGS_SKY | LIGHTFEATUREFLAGS_DIRECTIONAL | LIGHTFEATUREFLAGS_PUNCTUAL | MATERIALFEATUREFLAGS_LIT_ANISO,
/* 15 */ LIGHT_FEATURE_MASK_FLAGS | MATERIALFEATUREFLAGS_LIT_ANISO,
/* 15 */ LIGHT_FEATURE_MASK_FLAGS_OPAQUE | MATERIALFEATUREFLAGS_LIT_ANISO,
// With foliage or crowd with SSS and standard can overlap a lot, better to have a dedicated combination
/* 16 */ LIGHTFEATUREFLAGS_SKY | LIGHTFEATUREFLAGS_DIRECTIONAL | LIGHTFEATUREFLAGS_PUNCTUAL | MATERIALFEATUREFLAGS_LIT_SSS | MATERIALFEATUREFLAGS_LIT_STANDARD,
/* 20 */ LIGHT_FEATURE_MASK_FLAGS | MATERIALFEATUREFLAGS_LIT_SSS | MATERIALFEATUREFLAGS_LIT_STANDARD,
/* 20 */ LIGHT_FEATURE_MASK_FLAGS_OPAQUE | MATERIALFEATUREFLAGS_LIT_SSS | MATERIALFEATUREFLAGS_LIT_STANDARD,
// ClearCoat
/* 21 */ LIGHTFEATUREFLAGS_SKY | LIGHTFEATUREFLAGS_DIRECTIONAL | LIGHTFEATUREFLAGS_PUNCTUAL | MATERIALFEATUREFLAGS_LIT_CLEAR_COAT,
/* 25 */ LIGHT_FEATURE_MASK_FLAGS | MATERIALFEATUREFLAGS_LIT_CLEAR_COAT,
/* 25 */ LIGHT_FEATURE_MASK_FLAGS_OPAQUE | MATERIALFEATUREFLAGS_LIT_CLEAR_COAT,
/* 26 */ LIGHT_FEATURE_MASK_FLAGS | MATERIAL_FEATURE_MASK_FLAGS, // Catch all case with MATERIAL_FEATURE_MASK_FLAGS is needed in case we disable material classification
/* 26 */ LIGHT_FEATURE_MASK_FLAGS_OPAQUE | MATERIAL_FEATURE_MASK_FLAGS, // Catch all case with MATERIAL_FEATURE_MASK_FLAGS is needed in case we disable material classification
};
uint FeatureFlagsToTileVariant(uint featureFlags)
// We deem the intensity difference of a couple of percent for high values of roughness
// to not be worth the cost of another precomputed table.
// Note: this formulation bakes the BSDF non-symmetric!
preLightData.energyCompensation = 1 / reflectivity - 1;
preLightData.energyCompensation = 1.0 / reflectivity - 1.0 ;
preLightData.energyCompensation = 0;
preLightData.energyCompensation = 0.0 ;
#endif // LIT_USE_GGX_ENERGY_COMPENSATION
// Area light
#ifdef HAS_LIGHTLOOP
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
// This structure allow to accumulate lighting accross the Lit material
// It is init to zero and transfer by the LightLoop, but the LightLoop can't access its content.
struct Lighting
{
float3 directDiffuse;
float3 directSpecular;
float3 refraction;
float3 envSpecular;
};
//-----------------------------------------------------------------------------
// BSDF share between directional light, punctual light and area light (reference)
//-----------------------------------------------------------------------------
}
else
{
isInBounds = Max3(abs(positionNDC.x), abs(positionNDC.y), 1 - positionLS.z) <= 1;
isInBounds = Max3(abs(positionNDC.x), abs(positionNDC.y), 1.0 - positionLS.z) <= 1.0 ;
}
// We let the sampler handle tiling or clamping to border.
cookie.a = isInBounds ? cookie.a : 0;
cookie.a = isInBounds ? cookie.a : 0.0;
return cookie;
}
DirectionalLightData lightData, BSDFData bsdfData,
out float3 diffuseLighting,
out float3 specularLighting)
inout Lighting lighting)
{
float3 positionWS = posInput.positionWS;
diffuseLighting = float3(0, 0, 0); // TODO: check whether using 'out' instead of 'inout' increases the VGPR pressure
specularLighting = float3(0, 0, 0); // TODO: check whether using 'out' instead of 'inout' increases the VGPR pressure
float3 diffuseLighting = float3(0, 0, 0);
float3 specularLighting = float3(0, 0, 0);
float shadow = 1;
[branch] if (lightData.shadowIndex >= 0)
// Save ALU by applying 'lightData.color' only once.
diffuseLighting *= lightData.color;
specularLighting *= lightData.color;
lighting.directDiffuse += diffuseLighting;
lighting.directSpecular += specularLighting;
}
//-----------------------------------------------------------------------------
void EvaluateBSDF_Punctual( LightLoopContext lightLoopContext,
float3 V, PositionInputs posInput,
PreLightData preLightData, LightData lightData, BSDFData bsdfData, int GPULightType,
out float3 diffuseLighting,
out float3 specularLighting)
inout Lighting lighting)
{
float3 positionWS = posInput.positionWS;
int lightType = GPULightType;
lightData.diffuseScale *= attenuation;
lightData.specularScale *= attenuation;
diffuseLighting = float3(0, 0, 0); // TODO: check whether using 'out' instead of 'inout' increases the VGPR pressure
specularLighting = float3(0, 0, 0); // TODO: check whether using 'out' instead of 'inout' increases the VGPR pressure
float shadow = 1;
float3 diffuseLighting = float3(0.0 , 0.0 , 0. 0);
float3 specularLighting = float3(0.0 , 0.0 , 0. 0);
float shadow = 1.0 ;
[branch] if (lightData.shadowIndex >= 0)
{
// Save ALU by applying 'lightData.color' only once.
diffuseLighting *= lightData.color;
specularLighting *= lightData.color;
lighting.directDiffuse += diffuseLighting;
lighting.directSpecular += specularLighting;
}
#include "LitReference.hlsl"
void EvaluateBSDF_Line(LightLoopContext lightLoopContext,
float3 V, PositionInputs posInput,
PreLightData preLightData, LightData lightData, BSDFData bsdfData,
out float3 diffuseLighting, out float3 specularLighting)
inout Lighting lighting)
float3 diffuseLighting = float3(0.0, 0.0, 0.0);
float3 specularLighting = float3(0.0, 0.0, 0.0);
diffuseLighting = float3(0.0, 0.0, 0.0);
specularLighting = float3(0.0, 0.0, 0.0);
float len = lightData.size.x;
float3 T = lightData.right;
diffuseLighting *= lightData.color;
specularLighting *= lightData.color;
#endif // LIT_DISPLAY_REFERENCE_AREA
lighting.directDiffuse += diffuseLighting;
lighting.directSpecular += specularLighting;
}
//-----------------------------------------------------------------------------
void EvaluateBSDF_Rect( LightLoopContext lightLoopContext,
float3 V, PositionInputs posInput,
PreLightData preLightData, LightData lightData, BSDFData bsdfData,
out float3 diffuseLighting, out float3 specularLighting)
inout Lighting lighting)
float3 diffuseLighting = float3(0.0, 0.0, 0.0);
float3 specularLighting = float3(0.0, 0.0, 0.0);
diffuseLighting = float3(0.0, 0.0, 0.0);
specularLighting = float3(0.0, 0.0, 0.0);
float3 unL = lightData.positionWS - positionWS;
[branch]
diffuseLighting *= lightData.color;
specularLighting *= lightData.color;
#endif // LIT_DISPLAY_REFERENCE_AREA
lighting.directDiffuse += diffuseLighting;
lighting.directSpecular += specularLighting;
out float3 diffuseLighting, out float3 specularLighting)
inout Lighting lighting)
EvaluateBSDF_Line(lightLoopContext, V, posInput, preLightData, lightData, bsdfData, diffuseLighting, specularLighting);
EvaluateBSDF_Line(lightLoopContext, V, posInput, preLightData, lightData, bsdfData, lighting);
EvaluateBSDF_Rect(lightLoopContext, V, posInput, preLightData, lightData, bsdfData, diffuseLighting, specularLighting);
EvaluateBSDF_Rect(lightLoopContext, V, posInput, preLightData, lightData, bsdfData, lighting);
// EvaluateBSDF_SSL
// EvaluateBSDF_SSLighting for screen space lighting
void EvaluateBSDF_SSL(float3 V, PositionInputs posInput, BSDFData bsdfData, out float3 diffuseLighting, out float3 specularLighting, out float2 weight)
void EvaluateBSDF_SSReflection( LightLoopContext lightLoopContext,
float3 V, PositionInputs posInput,
PreLightData preLightData, BSDFData bsdfData,
inout Lighting lighting, inout float hierarchyWeight)
diffuseLighting = float3(0.0, 0.0, 0.0);
specularLighting = float3(0.0, 0.0, 0.0);
weight = float2(0.0, 0.0);
// TODO
}
void EvaluateBSDF_SSRefraction( LightLoopContext lightLoopContext,
float3 V, PositionInputs posInput,
PreLightData preLightData, BSDFData bsdfData,
inout Lighting lighting, inout float hierarchyWeight)
{
// 3. If this point is available (ie: in color GBuffer and point is not in front of the object)
// 3. If this point is available (ie: in color buffer and point is not in front of the object)
weight.x = bsdfData.transmittanceMask;
float3 diffuseLighting = float3(0.0, 0.0, 0.0);
float3 refractedBackPointWS = float3(0.0, 0.0, 0.0);
float opticalDepth = 0.0;
// we approximate the scene as a plane (back plane) with normal -V at the depth hit point.
// (We avoid to raymarch the depth texture to get the refracted point.)
#if defined(_REFRACTION_PLANE)
// Plane shape model:
// We approximate locally the shape of the object as a plane with normal {bsdfData.normalWS} at {bsdfData.positionWS}
// with a thickness {bsdfData.thickness}
// Plane shape model:
// We approximate locally the shape of the object as a plane with normal {bsdfData.normalWS} at {bsdfData.positionWS}
// with a thickness {bsdfData.thickness}
// Refracted ray
// Refracted ray
// Get the depth of the approximated back plane
// Get the depth of the approximated back plane
// Distance from point to the back plane
// Distance from point to the back plane
// Optical depth within the thin plane
// Optical depth within the thin plane
// The refracted ray exiting the thin plane is the same as the incident ray (parallel interfaces and same ior)
// The refracted ray exiting the thin plane is the same as the incident ray (parallel interfaces and same ior)
float VoR = dot(-V, R);
float VoN = dot(V, bsdfData.normalWS);
refractedBackPointWS = posInput.positionWS + R * opticalDepth - V * (distFromP - VoR * opticalDepth);
|| any(refractedBackPointSS > 1.0))
{
diffuseLighting = SAMPLE_TEXTURE2D_LOD(_GaussianPyramidColorTexture, s_trilinear_clamp_sampler, posInput.positionSS, 0.0).rgb;
// TODO: check with fred. If a pixel is in front of the object we should not sample at all and put hierarchyWeight to 1.0 so we discard the effect as it is occlusion
// Otherwise fallback on cubemap
return;
}
// Beer-Lamber law for absorption
float3 transmittance = exp(-bsdfData.absorptionCoefficient * opticalDepth);
diffuseLighting *= transmittance;
#endif // HAS_REFRACTION
float weight = 1.0;
UpdateLightingHierarchyWeights(hierarchyWeight, weight);
lighting.refraction += diffuseLighting * weight;
#else
// No refraction, no need to go further
hierarchyWeight = 1.0;
#endif
}
//-----------------------------------------------------------------------------
void EvaluateBSDF_Env( LightLoopContext lightLoopContext,
float3 V, PositionInputs posInput,
PreLightData preLightData, EnvLightData lightData, BSDFData bsdfData, int envShapeType,
out float3 diffuseLighting, out float3 specularLighting, out float2 weight)
inout Lighting lighting, inout float hierarchyWeight)
weight = float2(0.0, 1.0);
float3 specularLighting = float3(0.0, 0.0, 0.0);
float weight = 1.0;
#ifdef LIT_DISPLAY_REFERENCE_IBL
#ifdef LIT_DIFFUSE_LAMBERT_BRDF
diffuseLighting = IntegrateLambertIBLRef(lightData, V, bsdfData);
lighting.directDiffuse + = IntegrateLambertIBLRef(lightData, V, bsdfData);
diffuseLighting = IntegrateDisneyDiffuseIBLRef(lightLoopContext, V, preLightData, lightData, bsdfData);
lighting.directDiffuse + = IntegrateDisneyDiffuseIBLRef(lightLoopContext, V, preLightData, lightData, bsdfData);
diffuseLighting = float3(0.0, 0.0, 0.0) ;
hierarchyWeight = 0.0 ;
#else
// 2. Process the influence
float distFade = max(length(positionLS) - lightData.innerDistance.x, 0.0);
weight.y = saturate(1.0 - distFade / max(lightData.blendDistance, 0.0001)); // avoid divide by zero
weight = saturate(1.0 - distFade / max(lightData.blendDistance, 0.0001)); // avoid divide by zero
}
else if (envShapeType == ENVSHAPETYPE_BOX)
{
// Influence volume
// Calculate falloff value, so reflections on the edges of the volume would gradually blend to previous reflection.
float distFade = DistancePointBox(positionLS, -lightData.innerDistance, lightData.innerDistance);
weight.y = saturate(1.0 - distFade / max(lightData.blendDistance, 0.0001)); // avoid divide by zero
weight = saturate(1.0 - distFade / max(lightData.blendDistance, 0.0001)); // avoid divide by zero
weight.y = Smoothstep01(weight.y);
weight = Smoothstep01(weight);
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 && HasMaterialFeatureFlag(MATERIALFEATUREFLAGS_LIT_CLEAR_COAT))
float4 preLD = SampleEnv(lightLoopContext, lightData.envIndex, R, preLightData.iblMipLevel);
specularLighting += F * preLD.rgb * preLightData.specularFGD;
diffuseLighting = float3(0.0, 0.0, 0.0);
#endif
#endif
UpdateLightingHierarchyWeights(hierarchyWeight, weight);
lighting.envSpecular += specularLighting * weight;
}
//-----------------------------------------------------------------------------
void PostEvaluateBSDF( LightLoopContext lightLoopContext,
float3 V, PositionInputs posInput,
PreLightData preLightData, LightLoopAccumulatedLighting accLighting, BSDFData bsdfData, float3 bakeDiffuseLighting,
PreLightData preLightData, BSDFData bsdfData, float3 bakeDiffuseLighting, Lighting lighting,
out float3 diffuseLighting, out float3 specularLighting)
{
// Use GTAOMultiBounce approximation for ambient occlusion (allow to get a tint from the baseColor)
// Try to mimic multibounce with specular color. Not the point of the original formula but ok result.
// Take the min of screenspace specular occlusion and visibility cone specular occlusion
#if GTAO_MULTIBOUNCE_APPROX
accLighting.envSpecularLighting *= GTAOMultiBounce(min(bsdfData.specularOcclusion, specularOcclusion), bsdfData.fresnel0);
lighting.envSpecular *= GTAOMultiBounce(min(bsdfData.specularOcclusion, specularOcclusion), bsdfData.fresnel0);
accLighting.envSpecularLighting *= lerp(_AmbientOcclusionParam.rgb, float3(1.0, 1.0, 1.0), min(bsdfData.specularOcclusion, specularOcclusion));
lighting.envSpecular *= lerp(_AmbientOcclusionParam.rgb, float3(1.0, 1.0, 1.0), min(bsdfData.specularOcclusion, specularOcclusion));
float3 directDiffuseLighting = (accLighting.dirDiffuseLighting + accLighting.punctualDiffuseLighting + accLighting.areaDiffuseLighting)
lighting.directDiffuse *=
* GTAOMultiBounce(directAmbientOcclusion, bsdfData.diffuseColor);
GTAOMultiBounce(directAmbientOcclusion, bsdfData.diffuseColor);
* lerp(_AmbientOcclusionParam.rgb, float3(1.0, 1.0, 1.0), directAmbientOcclusion);
lerp(_AmbientOcclusionParam.rgb, float3(1.0, 1.0, 1.0), directAmbientOcclusion);
#endif
diffuseLighting = lighting.directDiffuse + bakeDiffuseLighting;
// If refraction is enable we use the transmittanceMask to lerp between current diffuse lighting and refraction value
// Physically speaking, it should be transmittanceMask should be 1, but for artistic reasons, we let the value varie
#if HAS_REFRACTION
diffuseLighting = lerp(diffuseLighting, lighting.refraction, bsdfData.transmittanceMask);
// envDiffuseLighting is used for refraction in this Lit material. Use the weight to balance between transmission and reflection
diffuseLighting = lerp(directDiffuseLighting + bakeDiffuseLighting, accLighting.envDiffuseLighting, accLighting.envDiffuseLightingWeight);
specularLighting = accLighting.dirSpecularLighting + accLighting.punctualSpecularLighting + accLighting.areaSpecularLighting + accLighting.envSpecularLighting;
specularLighting = lighting.directSpecular + lighting.envSpecular;
specularLighting *= 1 + bsdfData.fresnel0 * preLightData.energyCompensation;
specularLighting *= 1.0 + bsdfData.fresnel0 * preLightData.energyCompensation;
#ifdef DEBUG_DISPLAY
if (_DebugLightingMode == DEBUGLIGHTINGMODE_INDIRECT_DIFFUSE_OCCLUSION_FROM_SSAO)
#endif
#endif
}
#endif // #ifdef HAS_LIGHTLOOP