350 lines
12 KiB
HLSL
350 lines
12 KiB
HLSL
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#pragma once
|
|
|
|
#if SUBSTRATE_ENABLED && SUBSTRATE_GBUFFER_FORMAT==0
|
|
#define SUBSTRATE_LOAD_FROM_MATERIALCONTAINER 0
|
|
#endif
|
|
|
|
#include "../DeferredShadingCommon.ush"
|
|
#include "../Lumen/LumenPosition.ush"
|
|
|
|
#include "../HairStrands/HairStrandsVisibilityCommon.ush"
|
|
#include "../HairStrands/HairStrandsVisibilityUtils.ush"
|
|
#include "../HairStrands/HairStrandsCommon.ush"
|
|
#include "../HairStrands/HairStrandsDeepTransmittanceCommon.ush"
|
|
#include "../HairStrands/HairStrandsDeepTransmittanceDualScattering.ush"
|
|
|
|
#include "../Substrate/Substrate.ush"
|
|
#include "../Substrate/SubstrateEvaluation.ush"
|
|
#include "../Substrate/SubstrateDeferredLighting.ush"
|
|
#include "../Substrate/SubstrateMaterialSampling.ush"
|
|
#include "../Substrate/SubstrateTile.ush"
|
|
#include "../Substrate/SubstrateRead.ush"
|
|
|
|
// Types of FMegaLightsMaterial input
|
|
#define INPUT_TYPE_GBUFFER 0
|
|
#define INPUT_TYPE_HAIRSTRANDS 1
|
|
|
|
#ifndef INPUT_TYPE
|
|
#define INPUT_TYPE INPUT_TYPE_GBUFFER
|
|
#endif
|
|
|
|
struct FMegaLightsMaterial
|
|
{
|
|
float Depth;
|
|
float3 WorldNormal;
|
|
float3 WorldNormalForPositionBias;
|
|
float Roughness;
|
|
bool bIsValid;
|
|
bool bIsSimple;
|
|
bool bIsSingle;
|
|
bool bIsComplexSpecial;
|
|
bool bIsHair;
|
|
bool bHasBackfaceDiffuse;
|
|
bool bNeedsSeparateSubsurfaceLightAccumulation;
|
|
bool bNeedsComplexTransmittance;
|
|
bool bAllowSpatialFilter;
|
|
uint LightingChannelMask; // Not loaded by default
|
|
float Coverage;
|
|
uint GlobalIndex1D;
|
|
uint2 GlobalIndex2D;
|
|
|
|
float3 DiffuseColor;
|
|
float3 SpecularColor;
|
|
|
|
bool IsValid()
|
|
{
|
|
return bIsValid;
|
|
}
|
|
|
|
bool IsSimple()
|
|
{
|
|
return bIsSimple;
|
|
}
|
|
|
|
bool IsSingle()
|
|
{
|
|
return bIsSingle;
|
|
}
|
|
|
|
bool IsComplexSpecial()
|
|
{
|
|
return bIsComplexSpecial;
|
|
}
|
|
|
|
void SetDepth(float In)
|
|
{
|
|
Depth = In;
|
|
#if !SUBSTRATE_ENABLED || SUBSTRATE_GBUFFER_FORMAT==0
|
|
GBuffer.Depth = In;
|
|
#endif
|
|
}
|
|
|
|
#if INPUT_TYPE == INPUT_TYPE_HAIRSTRANDS
|
|
FGBufferData GBuffer;
|
|
uint MacroGroupId;
|
|
#elif SUBSTRATE_ENABLED && SUBSTRATE_GBUFFER_FORMAT==1
|
|
uint ClosureIndex;
|
|
float PDF;
|
|
FSubstrateBSDF BSDF;
|
|
float3x3 BSDFTangentBasis;
|
|
float BSDFAO;
|
|
#elif SUBSTRATE_ENABLED && SUBSTRATE_GBUFFER_FORMAT==0
|
|
FGBufferData GBuffer;
|
|
FSubstrateBSDF BSDF;
|
|
float3x3 BSDFTangentBasis;
|
|
float BSDFAO;
|
|
#else
|
|
FGBufferData GBuffer;
|
|
#endif
|
|
};
|
|
|
|
FMegaLightsMaterial LoadMaterial(float2 ScreenUV, uint2 ScreenCoord, bool bForceSimpleShading = false, uint SampleIt=0)
|
|
#if INPUT_TYPE == INPUT_TYPE_HAIRSTRANDS
|
|
{
|
|
const uint3 PixelCoord = uint3(ScreenCoord, 0);
|
|
const float HairDeviceZ = HairStrands.HairOnlyDepthTexture.Load(PixelCoord).x;
|
|
const FNodeDesc NodeDesc = DecodeNodeDesc(HairStrands.HairSampleOffset.Load(PixelCoord));
|
|
const float PixelCoverage = min(HairStrands.HairCoverageTexture.Load(PixelCoord), 1);
|
|
|
|
FMegaLightsMaterial Out = (FMegaLightsMaterial)0;
|
|
Out.Depth = ConvertFromDeviceZ(HairDeviceZ);
|
|
Out.bIsValid = HairDeviceZ > 0 && NodeDesc.Count > 0 && PixelCoverage > 0 && SampleIt < NodeDesc.Count;
|
|
|
|
const uint TotalNodeCount = HairStrands.HairSampleCount[0];
|
|
const uint2 Resolution = GetHairSampleResolution(TotalNodeCount);
|
|
|
|
if (Out.bIsValid)
|
|
{
|
|
{
|
|
const FHairSample Sample = UnpackHairSample(HairStrands.HairSampleData[NodeDesc.Offset + SampleIt]);
|
|
FGBufferData GBuffer = HairSampleToGBufferData(Sample);
|
|
const bool bIsLit = GBuffer.ShadingModelID != SHADINGMODELID_UNLIT;
|
|
GBuffer.Roughness = max(GBuffer.Roughness, View.MinRoughness);
|
|
|
|
Out.bIsValid = bIsLit;
|
|
Out.bIsSimple = false; //GBuffer.ShadingModelID == SHADINGMODELID_DEFAULT_LIT;
|
|
Out.bIsSingle = false;
|
|
Out.bIsComplexSpecial= false;
|
|
Out.bIsHair = true;
|
|
Out.bHasBackfaceDiffuse = false;
|
|
Out.bNeedsSeparateSubsurfaceLightAccumulation = false;
|
|
Out.bNeedsComplexTransmittance = true;
|
|
Out.WorldNormal = GBuffer.WorldNormal;
|
|
Out.WorldNormalForPositionBias = GBuffer.WorldNormal;
|
|
Out.Depth = GBuffer.Depth;
|
|
Out.Roughness = GBuffer.Roughness;
|
|
Out.DiffuseColor = GBuffer.DiffuseColor;
|
|
Out.SpecularColor = GBuffer.SpecularColor;
|
|
Out.GBuffer = GBuffer;
|
|
Out.bAllowSpatialFilter = true; // false ?
|
|
{
|
|
Out.WorldNormalForPositionBias = ComputeHairNormalForPositionBias(ScreenUV, Out.Depth, Out.WorldNormal);
|
|
}
|
|
|
|
Out.MacroGroupId = Sample.MacroGroupId;
|
|
Out.LightingChannelMask = Sample.LightChannelMask;
|
|
Out.Coverage = saturate(From8bitCoverage(Sample.Coverage8bit));
|
|
Out.GlobalIndex1D = NodeDesc.Offset + SampleIt;
|
|
Out.GlobalIndex2D = GetHairSampleCoord(Out.GlobalIndex1D, Resolution);
|
|
}
|
|
}
|
|
return Out;
|
|
}
|
|
#elif INPUT_TYPE == INPUT_TYPE_GBUFFER && SUBSTRATE_GBUFFER_FORMAT==1
|
|
{
|
|
#if SUBSTRATE_STOCHASTIC_LIGHTING
|
|
if (Substrate.bStochasticLighting)
|
|
{
|
|
const FSubstrateSampledMaterial SampledMaterial = UnpackSampledMaterial(Substrate.SampledMaterialTexture[ScreenCoord]);
|
|
|
|
FMegaLightsMaterial Out = (FMegaLightsMaterial)0;
|
|
Out.WorldNormal = SampledMaterial.WorldNormal;
|
|
Out.WorldNormalForPositionBias = SampledMaterial.WorldNormal;
|
|
Out.Depth = ConvertFromDeviceZ(SceneTexturesStruct.SceneDepthTexture.Load(int3(ScreenCoord, 0)).r);
|
|
Out.Roughness = SampledMaterial.Roughness;
|
|
Out.bAllowSpatialFilter = SampledMaterial.bAllowSpatialFilter;
|
|
|
|
Out.bIsValid = SampledMaterial.bIsValid;
|
|
Out.bIsSimple = SampledMaterial.bIsSimple;
|
|
Out.bIsSingle = SampledMaterial.bIsSingle;
|
|
Out.bIsComplexSpecial = false;
|
|
Out.bIsHair = SampledMaterial.bIsHair;
|
|
|
|
// SUBSTRATE_TODO: implement Out.bHasBackfaceDiffuse
|
|
Out.bHasBackfaceDiffuse = false;
|
|
Out.bNeedsComplexTransmittance = false;
|
|
|
|
Out.bNeedsSeparateSubsurfaceLightAccumulation = SampledMaterial.bNeedsSeparateSubsurfaceLightAccumulation;
|
|
Out.DiffuseColor = SampledMaterial.DiffuseAlbedo;
|
|
Out.SpecularColor = SampledMaterial.SpecularAlbedo;
|
|
Out.ClosureIndex = SampledMaterial.ClosureIndex;
|
|
Out.PDF = SampledMaterial.PDF;
|
|
Out.Coverage = 1;
|
|
return Out;
|
|
}
|
|
else
|
|
#endif // SUBSTRATE_STOCHASTIC_LIGHTING
|
|
{
|
|
const FSubstrateTopLayerData TopLayerData = SubstrateUnpackTopLayerData(Substrate.TopLayerTexture.Load(uint3(ScreenCoord, 0)));
|
|
FMegaLightsMaterial Out = (FMegaLightsMaterial)0;
|
|
Out.WorldNormal = TopLayerData.WorldNormal;
|
|
Out.WorldNormalForPositionBias = TopLayerData.WorldNormal;
|
|
Out.Depth = ConvertFromDeviceZ(SceneTexturesStruct.SceneDepthTexture.Load(int3(ScreenCoord, 0)).r);
|
|
Out.Roughness = TopLayerData.Roughness;
|
|
Out.bAllowSpatialFilter = true;
|
|
Out.ClosureIndex = 0;
|
|
Out.PDF = 1.f;
|
|
Out.Coverage = 1;
|
|
#if SUBSTRATE_MATERIALCONTAINER_IS_VIEWRESOURCE
|
|
|
|
const float3 TranslatedWorldPosition = GetTranslatedWorldPositionFromScreenUV(ScreenUV, Out.Depth);
|
|
const float3 V = -GetCameraVectorFromTranslatedWorldPosition(TranslatedWorldPosition);
|
|
|
|
const FSubstrateIntegrationSettings Settings = InitSubstrateIntegrationSettings(false /*bForceFullyRough*/, Substrate.bRoughDiffuse, Substrate.PeelLayersAboveDepth, Substrate.bRoughnessTracking);
|
|
FSubstrateAddressing SubstrateAddressing = GetSubstratePixelDataByteOffset(ScreenCoord, uint2(View.BufferSizeAndInvSize.xy), Substrate.MaxBytesPerPixel);
|
|
FSubstratePixelHeader SubstratePixelHeader = UnpackSubstrateHeaderIn(Substrate.MaterialTextureArray, SubstrateAddressing, Substrate.TopLayerTexture);
|
|
|
|
Out.bIsValid = SubstratePixelHeader.IsSubstrateMaterial();
|
|
Out.bIsSimple = SubstratePixelHeader.IsSimpleMaterial();
|
|
Out.bIsSingle = SubstratePixelHeader.IsSingleMaterial();
|
|
Out.bIsComplexSpecial = SubstratePixelHeader.IsComplexSpecialMaterial();
|
|
Out.bIsHair = SubstratePixelHeader.IsHair();
|
|
Out.bHasBackfaceDiffuse = SubstratePixelHeader.SubstrateGetBSDFType() == SUBSTRATE_BSDF_TYPE_SLAB && SubstratePixelHeader.HasSubsurface();
|
|
Out.bNeedsComplexTransmittance = false;
|
|
|
|
#if SUBSTRATE_LOAD_FROM_MATERIALCONTAINER
|
|
Substrate_for(uint ClosureIndex = 0, ClosureIndex < SubstratePixelHeader.ClosureCount, ++ClosureIndex)
|
|
#else
|
|
if (SubstratePixelHeader.ClosureCount > 0)
|
|
#endif
|
|
{
|
|
FSubstrateBSDF BSDF = UnpackSubstrateBSDF(Substrate.MaterialTextureArray, SubstrateAddressing, SubstratePixelHeader);
|
|
|
|
// Create the BSDF context
|
|
FSubstrateBSDFContext SubstrateBSDFContext = SubstrateCreateBSDFContext(SubstratePixelHeader, BSDF, SubstrateAddressing, V);
|
|
const float3 BSDFThroughput = LuminanceWeight(SubstrateBSDFContext, BSDF);
|
|
|
|
// Evaluate environment lighting
|
|
FSubstrateEnvLightResult SubstrateEnvLight = SubstrateEvaluateForEnvLight(SubstrateBSDFContext, true /*bEnableSpecular*/, Settings);
|
|
|
|
Out.DiffuseColor += BSDFThroughput * SubstrateEnvLight.DiffuseColor; //SubstrateEnvLight.DiffuseWeight;
|
|
Out.SpecularColor += BSDFThroughput * SubstrateEnvLight.SpecularColor; //SubstrateEnvLight.SpecularWeight;
|
|
|
|
#if SUBSTRATE_FASTPATH==0
|
|
if (any(SubstrateEnvLight.SpecularHazeWeight > 0.0f))
|
|
{
|
|
Out.SpecularColor += BSDFThroughput * SubstrateEnvLight.SpecularHazeWeight;
|
|
}
|
|
#endif
|
|
|
|
if (SubstrateEnvLight.bPostProcessSubsurface)
|
|
{
|
|
Out.bNeedsSeparateSubsurfaceLightAccumulation = true;
|
|
}
|
|
|
|
#if SUBSTRATE_FASTPATH==0
|
|
if (SubstratePixelHeader.IsComplexSpecialMaterial() && BSDF_GETHASGLINT(BSDF))
|
|
{
|
|
Out.bAllowSpatialFilter = false;
|
|
}
|
|
#endif
|
|
|
|
#if SUBSTRATE_LOAD_FROM_MATERIALCONTAINER == 0
|
|
Out.BSDF = BSDF;
|
|
Out.BSDFTangentBasis = SubstrateBSDFContext.TangentBasis;
|
|
Out.BSDFAO = SubstrateGetAO(SubstratePixelHeader);
|
|
#endif
|
|
}
|
|
#endif //SUBSTRATE_MATERIALCONTAINER_IS_VIEWRESOURCE
|
|
|
|
return Out;
|
|
}
|
|
}
|
|
#elif INPUT_TYPE == INPUT_TYPE_GBUFFER
|
|
{
|
|
FGBufferData GBuffer = GetGBufferData(ScreenUV);
|
|
GBuffer.Roughness = max(GBuffer.Roughness, View.MinRoughness);
|
|
const bool bIsLit = GBuffer.ShadingModelID != SHADINGMODELID_UNLIT;
|
|
|
|
if (bForceSimpleShading)
|
|
{
|
|
checkSlow(GBuffer.ShadingModelID == SHADINGMODELID_DEFAULT_LIT || GBuffer.ShadingModelID == SHADINGMODELID_UNLIT);
|
|
GBuffer.ShadingModelID = SHADINGMODELID_DEFAULT_LIT;
|
|
}
|
|
|
|
FMegaLightsMaterial Out = (FMegaLightsMaterial)0;
|
|
Out.bIsValid = bIsLit;
|
|
Out.bIsSimple = GBuffer.ShadingModelID == SHADINGMODELID_DEFAULT_LIT;
|
|
Out.bIsSingle = false;
|
|
Out.bIsComplexSpecial = false;
|
|
Out.bIsHair = GBuffer.ShadingModelID == SHADINGMODELID_HAIR;
|
|
Out.bHasBackfaceDiffuse = GBuffer.ShadingModelID == SHADINGMODELID_TWOSIDED_FOLIAGE || GBuffer.ShadingModelID == SHADINGMODELID_SUBSURFACE;
|
|
Out.bNeedsSeparateSubsurfaceLightAccumulation = UseSubsurfaceProfile(GBuffer.ShadingModelID);
|
|
Out.bNeedsComplexTransmittance = GBuffer.ShadingModelID == SHADINGMODELID_HAIR && ShouldUseHairComplexTransmittance(GBuffer);
|
|
Out.WorldNormal = GBuffer.WorldNormal;
|
|
Out.WorldNormalForPositionBias = GBuffer.WorldNormal;
|
|
Out.Depth = GBuffer.Depth;
|
|
Out.Roughness = GBuffer.Roughness;
|
|
Out.DiffuseColor = GBuffer.DiffuseColor;
|
|
Out.SpecularColor = GBuffer.SpecularColor;
|
|
Out.GBuffer = GBuffer;
|
|
Out.bAllowSpatialFilter = true;
|
|
Out.Coverage = 1;
|
|
|
|
if (GBuffer.ShadingModelID == SHADINGMODELID_HAIR)
|
|
{
|
|
Out.WorldNormalForPositionBias = ComputeHairNormalForPositionBias(ScreenUV, Out.Depth, Out.WorldNormal);
|
|
}
|
|
|
|
#if SUBSTRATE_ENABLED && SUBSTRATE_GBUFFER_FORMAT==0
|
|
|
|
const bool bIsComplex = abs(GBuffer.Anisotropy) > 0 || GBuffer.ShadingModelID == SHADINGMODELID_EYE || GBuffer.ShadingModelID == SHADINGMODELID_HAIR;
|
|
Out.bIsSimple = Out.bIsSimple && abs(GBuffer.Anisotropy) == 0;
|
|
Out.bIsSingle = !Out.bIsSimple && !bIsComplex;
|
|
|
|
FScreenSpaceData ScreenSpaceData;
|
|
ScreenSpaceData.GBuffer = GBuffer;
|
|
ScreenSpaceData.AmbientOcclusion = 1.f;
|
|
FSubstrateGBufferBSDF GBufferBSDF = SubstrateReadGBufferBSDF(ScreenSpaceData);
|
|
Out.BSDF = GBufferBSDF.BSDF;
|
|
Out.BSDFTangentBasis = GBufferBSDF.BSDFTangentBasis;
|
|
Out.BSDFAO = GBufferBSDF.BSDFAO;
|
|
#endif
|
|
|
|
return Out;
|
|
}
|
|
#endif
|
|
|
|
struct FDenoisingModulateFactors
|
|
{
|
|
float3 Diffuse;
|
|
float3 Specular;
|
|
};
|
|
|
|
/**
|
|
* Factors used to remove non-stochastic material detail before denoising in order to preserve texture detail
|
|
* Divide before denoising and multiply after
|
|
*/
|
|
FDenoisingModulateFactors GetDenoisingModulateFactors(FMegaLightsMaterial Material, float3 TranslatedWorldPosition)
|
|
{
|
|
const float3 N = Material.WorldNormal;
|
|
const float3 V = normalize(View.TranslatedWorldCameraOrigin - TranslatedWorldPosition);
|
|
const float NoV = saturate(dot(N, V));
|
|
float3 SpecularEnv = EnvBRDF(Material.SpecularColor, Material.Roughness, NoV);
|
|
|
|
// Hair should technically use the follow function, but it is expansive and does not improve visuals/stability.
|
|
#if 0
|
|
if (Material.bIsHair)
|
|
{
|
|
float3 L = 0;
|
|
SpecularEnv = EvaluateEnvHair(Material.GBuffer, V, N, L /*out*/);
|
|
}
|
|
#endif
|
|
|
|
FDenoisingModulateFactors Factors;
|
|
Factors.Diffuse = clamp(Material.DiffuseColor, 0.04f, 1.0f);
|
|
Factors.Specular = clamp(SpecularEnv, 0.1f, 1.0f);
|
|
return Factors;
|
|
} |