193 lines
7.2 KiB
HLSL
193 lines
7.2 KiB
HLSL
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#pragma once
|
|
|
|
#include "../AreaLightCommon.ush"
|
|
|
|
#if USE_LIGHT_FUNCTION_ATLAS
|
|
#include "../LightFunctionAtlas/LightFunctionAtlasCommon.usf"
|
|
#endif
|
|
|
|
// Sanity guard.
|
|
#ifndef SUBSTRATE_ENABLED
|
|
#define SUBSTRATE_ENABLED 1
|
|
#error SUBSTRATE_ENABLED needs to be defined
|
|
#endif
|
|
|
|
// * If enabled, all material data will be loaded from the material buffer
|
|
// * If disabled, material data will be passed to SubstrateDeferredLighting as args. This is only support for single slab material
|
|
#ifndef SUBSTRATE_LOAD_FROM_MATERIALCONTAINER
|
|
#define SUBSTRATE_LOAD_FROM_MATERIALCONTAINER 1
|
|
#endif
|
|
|
|
#if SUBSTRATE_ENABLED
|
|
|
|
float4 SubstrateReadPrecomputedShadowFactors(FSubstratePixelHeader SubstratePixelHeader, int2 PixelPos, Texture2D PrecomputedShadowTexture)
|
|
{
|
|
if (SubstratePixelHeader.HasPrecShadowMask())
|
|
{
|
|
#if ALLOW_STATIC_LIGHTING
|
|
float4 GBufferE = PrecomputedShadowTexture.Load(int3(PixelPos, 0));
|
|
#else
|
|
float4 GBufferE = 1;
|
|
#endif
|
|
return GBufferE;
|
|
}
|
|
return SubstratePixelHeader.HasZeroPrecShadowMask() ? 0.0f : 1.0f;
|
|
}
|
|
|
|
struct FSubstrateShadowTermInputParameters
|
|
{
|
|
bool bEvaluateShadowTerm;
|
|
float SceneDepth;
|
|
float4 PrecomputedShadowFactors;
|
|
float3 TranslatedWorldPosition;
|
|
float4 LightAttenuation;
|
|
float Dither;
|
|
};
|
|
|
|
FSubstrateShadowTermInputParameters GetInitialisedSubstrateShadowTermInputParameters()
|
|
{
|
|
FSubstrateShadowTermInputParameters Params = (FSubstrateShadowTermInputParameters)0;
|
|
return Params;
|
|
}
|
|
|
|
// Analytical lighting evaluation for Substrate material.
|
|
// * SUBSTRATE_LOAD_FROM_MATERIALCONTAINER == 1 : Unpack BSDF on-the-fly
|
|
// * SUBSTRATE_LOAD_FROM_MATERIALCONTAINER == 0 : BSDF passed as argument
|
|
FSubstrateDeferredLighting SubstrateDeferredLighting(
|
|
FDeferredLightData LightData,
|
|
float3 V,
|
|
float3 L,
|
|
float3 ToLight,
|
|
float LightMask,
|
|
FSubstrateShadowTermInputParameters SubstrateShadowTermInputParameters,
|
|
#if SUBSTRATE_LOAD_FROM_MATERIALCONTAINER
|
|
FSubstrateMaterialContainer MaterialBuffer,
|
|
FSubstrateAddressing SubstrateAddressing,
|
|
FSubstratePixelHeader SubstratePixelHeader
|
|
#else
|
|
FSubstrateBSDF BSDF,
|
|
float3x3 BSDFTangentBasis,
|
|
float MaterialAO
|
|
#endif
|
|
)
|
|
{
|
|
FSubstrateDeferredLighting SubstrateLighting = GetInitialisedSubstrateDeferredLighting();
|
|
#if SUBSTRATE_MATERIALCONTAINER_IS_VIEWRESOURCE
|
|
const FSubstrateIntegrationSettings Settings = InitSubstrateIntegrationSettings(false /*bForceFullyRough*/, Substrate.bRoughDiffuse, Substrate.PeelLayersAboveDepth, Substrate.bRoughnessTracking);
|
|
#else
|
|
const FSubstrateIntegrationSettings Settings = InitSubstrateIntegrationSettings();
|
|
#endif
|
|
|
|
FRectTexture RectTexture = ConvertToRectTexture(LightData);
|
|
|
|
// Get the basic shadow terms
|
|
#if SUBSTRATE_LOAD_FROM_MATERIALCONTAINER
|
|
const float MaterialAO = SubstrateGetAO(SubstratePixelHeader);
|
|
#endif
|
|
FShadowTerms ShadowTerms = { MaterialAO, 1.0, 1.0, InitHairTransmittanceData() };
|
|
if (SubstrateShadowTermInputParameters.bEvaluateShadowTerm)
|
|
{
|
|
// Get the shadow term that is independent from Substrate closures.
|
|
GetShadowTermsBase(
|
|
SubstrateShadowTermInputParameters.SceneDepth,
|
|
SubstrateShadowTermInputParameters.PrecomputedShadowFactors,
|
|
LightData,
|
|
SubstrateShadowTermInputParameters.LightAttenuation,
|
|
ShadowTerms);
|
|
|
|
SubstrateLighting.EstimatedCost += 0.3; // add the cost of getting the shadow terms
|
|
}
|
|
|
|
#if USE_LIGHT_FUNCTION_ATLAS
|
|
const FLightFunctionColor LightFunctionColor = GetLocalLightFunctionCommon(SubstrateShadowTermInputParameters.TranslatedWorldPosition, LightData.LightFunctionAtlasLightIndex);
|
|
#endif
|
|
|
|
#if SUBSTRATE_LOAD_FROM_MATERIALCONTAINER
|
|
Substrate_for (uint ClosureIndex = 0, ClosureIndex < SubstratePixelHeader.ClosureCount, ++ClosureIndex)
|
|
#endif
|
|
{
|
|
// Unpack BSDF data
|
|
#if SUBSTRATE_LOAD_FROM_MATERIALCONTAINER
|
|
FSubstrateBSDF BSDF = UnpackSubstrateBSDF(MaterialBuffer, SubstrateAddressing, SubstratePixelHeader);
|
|
FSubstrateBSDFContext BSDFContext = SubstrateCreateBSDFContext(SubstratePixelHeader, BSDF, SubstrateAddressing, V, L);
|
|
#else
|
|
FSubstrateBSDFContext BSDFContext = SubstrateCreateBSDFContext(BSDF, BSDFTangentBasis, V, L);
|
|
#endif
|
|
|
|
FShadowTerms BSDFShadowTerms = ShadowTerms;
|
|
if (SubstrateShadowTermInputParameters.bEvaluateShadowTerm) // This is going to be a evaluation done at compile time
|
|
{
|
|
const float BSDFContactShadowOpacity= 1.f - abs(SLAB_SSSPHASEANISOTROPY(BSDF));
|
|
const uint BSDFShadingModelID = SubstrateGetLegacyShadingModels(BSDF);
|
|
|
|
// Now combine with shadow term that are dependent on the Substrate closures (screens space contact shadow) if necessary.
|
|
ApplyContactShadowWithShadowTerms(
|
|
SubstrateShadowTermInputParameters.SceneDepth,
|
|
BSDFShadingModelID,
|
|
BSDFContactShadowOpacity,
|
|
LightData,
|
|
SubstrateShadowTermInputParameters.TranslatedWorldPosition,
|
|
L,
|
|
SubstrateShadowTermInputParameters.Dither,
|
|
BSDFShadowTerms);
|
|
}
|
|
|
|
|
|
float Roughness = SubstrateGetBSDFRoughness(BSDFContext.BSDF);
|
|
|
|
FAreaLightIntegrateContext AreaLightContext = InitAreaLightIntegrateContext();
|
|
FSubstrateEvaluateResult BSDFEvaluate = (FSubstrateEvaluateResult)0;
|
|
if (LightData.bRectLight)
|
|
{
|
|
FRect Rect = GetRect(ToLight, LightData);
|
|
if (!IsRectVisible(Rect))
|
|
{
|
|
return GetInitialisedSubstrateDeferredLighting(); // Rect light can be non visible due to barn door occlusion
|
|
}
|
|
AreaLightContext = CreateRectIntegrateContext(Roughness, BSDFContext.N, BSDFContext.V, Rect, RectTexture);
|
|
|
|
// We must have the SubstrateIntegrateBSDF inside the if due to the rectlight texture: it must be non ambiguous which texture is going to be used.
|
|
// After the compilation, a local resource must map to a unique global resource (the default or the actual rect light texture).
|
|
BSDFEvaluate = SubstrateEvaluateBSDFCommon(BSDFContext, BSDFShadowTerms, AreaLightContext, Settings, INTEGRATION_AREA_LIGHT_RECT);
|
|
}
|
|
else
|
|
{
|
|
FCapsuleLight Capsule = GetCapsule(ToLight, LightData);
|
|
AreaLightContext = CreateCapsuleIntegrateContext(Roughness, BSDFContext.N, BSDFContext.V, Capsule, LightData.bInverseSquared);
|
|
|
|
BRANCH
|
|
if(IsAreaLight(AreaLightContext.AreaLight))
|
|
{
|
|
BSDFEvaluate = SubstrateEvaluateBSDFCommon(BSDFContext, BSDFShadowTerms, AreaLightContext, Settings, INTEGRATION_AREA_LIGHT_CAPSULE);
|
|
}
|
|
else
|
|
{
|
|
BSDFEvaluate = SubstrateEvaluateBSDFCommon(BSDFContext, BSDFShadowTerms, AreaLightContext, Settings, INTEGRATION_PUNCTUAL_LIGHT);
|
|
}
|
|
}
|
|
|
|
SubstrateLighting.EstimatedCost += 0.4; // add the cost of the lighting computations (should sum up to 1 form one light)
|
|
|
|
float3 DiffuseLuminance = BSDFEvaluate.IntegratedDiffuseValue * LightData.DiffuseScale;
|
|
float3 SpecularLuminance = BSDFEvaluate.IntegratedSpecularValue * LightData.SpecularScale;
|
|
|
|
const float3 CommonMultiplier = LightData.Color * LightMask * LuminanceWeight(BSDFContext, BSDF)
|
|
#if USE_LIGHT_FUNCTION_ATLAS
|
|
* LightFunctionColor
|
|
#endif
|
|
;
|
|
|
|
FLightAccumulator Out = (FLightAccumulator)0;
|
|
LightAccumulator_AddSplit(Out, DiffuseLuminance, SpecularLuminance, DiffuseLuminance, CommonMultiplier, BSDFEvaluate.bPostProcessSubsurface);
|
|
AccumulateSubstrateDeferredLighting(SubstrateLighting, Out, BSDFEvaluate.bPostProcessSubsurface, BSDF_GETISTOPLAYER(BSDF));
|
|
|
|
SubstrateLighting.TotalDiffuseLighting += Out.TotalLightDiffuse;
|
|
SubstrateLighting.TotalSpecularLighting += Out.TotalLightSpecular;
|
|
}
|
|
|
|
return SubstrateLighting;
|
|
}
|
|
|
|
#endif // SUBSTRATE_ENABLED |