Files
UnrealEngine/Engine/Shaders/Private/ShadingFurnaceTest.usf
2025-05-18 13:04:45 +08:00

265 lines
8.7 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
#include "/Engine/Private/Common.ush"
#include "LargeWorldCoordinates.ush"
#define SUPPORT_CONTACT_SHADOWS 0
#define SHADING_PATH_DEFERRED 1
#define USE_SOURCE_TEXTURE 0
#define DEBUG_ENABLE 0
#define SUBSTRATE_SSS_TRANSMISSION USE_TRANSMISSION
#include "Substrate/Substrate.ush"
#include "DeferredShadingCommon.ush"
#include "DeferredLightingCommon.ush"
#include "MonteCarlo.ush"
#if DEBUG_ENABLE
#include "ShaderPrint.ush"
#include "ColorMap.ush"
#endif
#include "Substrate/SubstrateEvaluation.ush"
#include "Substrate/SubstrateDeferredLighting.ush"
#if SHADER_FURNACE_ANALYTIC
uint IntegratorType;
uint NumSamplesPerSet;
void MainPS(
float4 SVPos : SV_POSITION,
out float4 OutColor : SV_Target0)
{
// Non Substrate path (todo: add Substrate path)
const float2 ScreenUV = SvPositionToBufferUV(SVPos);
const float2 ScreenPosition = SvPositionToScreenPosition(SVPos).xy;
const float2 PixelPos = SVPos.xy;
const FRectTexture RectTexture = InitRectTexture();
const float Dither = InterleavedGradientNoise(PixelPos, View.StateFrameIndexMod8);
bool bIsValid = false;
float Roughness = 0.5f;
float ClearCoatRoughness = 0.5f;
float3 N = float3(0, 0, 1);
float SceneDepth = 0;
#if SUBSTRATE_ENABLED && SUBTRATE_GBUFFER_FORMAT==1
{
// Fetch the first layer of roughness & normal only. This fine for simple material but will not work for clear coat.
FSubstrateAddressing SubstrateAddressing = GetSubstratePixelDataByteOffset(PixelPos, uint2(View.BufferSizeAndInvSize.xy), Substrate.MaxBytesPerPixel);
FSubstratePixelHeader SubstratePixelHeader = UnpackSubstrateHeaderIn(Substrate.MaterialTextureArray, SubstrateAddressing, Substrate.TopLayerTexture);
bIsValid = SubstratePixelHeader.ClosureCount > 0;
if (bIsValid)
{
const float3 DummyV = float3(0, 0, 1);
const float3 DummyL = float3(0, 0, 1);
FSubstrateBSDF BSDF = UnpackSubstrateBSDFIn(Substrate.MaterialTextureArray, SubstrateAddressing, SubstratePixelHeader);
FSubstrateBSDFContext BSDFContext = SubstrateCreateBSDFContext(SubstratePixelHeader, BSDF, SubstrateAddressing, DummyV, DummyL);
SceneDepth = CalcSceneDepth(ScreenUV);
N = BSDFContext.N;
Roughness = SubstrateGetBSDFRoughness(BSDFContext.BSDF);
ClearCoatRoughness = Roughness;
}
}
#else
FScreenSpaceData ScreenSpaceData;
{
ScreenSpaceData = GetScreenSpaceData(ScreenUV);
ScreenSpaceData.AmbientOcclusion = 1.0f;
ScreenSpaceData.GBuffer.Roughness = max(ScreenSpaceData.GBuffer.Roughness, View.MinRoughness* 2.f);
N = ScreenSpaceData.GBuffer.WorldNormal;
SceneDepth = ScreenSpaceData.GBuffer.Depth;
bIsValid = SceneDepth > 0 && ScreenSpaceData.GBuffer.ShadingModelID != SHADINGMODELID_UNLIT;
Roughness = ScreenSpaceData.GBuffer.Roughness;
const bool bIsClearCoat = ScreenSpaceData.GBuffer.ShadingModelID == SHADINGMODELID_CLEAR_COAT;
ClearCoatRoughness = bIsClearCoat ? max(ScreenSpaceData.GBuffer.CustomData.y, 0.02f) : ScreenSpaceData.GBuffer.Roughness;
}
#endif
const float4 PixelLightAttenuation = 1.0f;
const float3 InRadiance = 0.5f;
const float3 WorldPosition = mul(float4(GetScreenPositionForProjectionType(ScreenPosition, SceneDepth), SceneDepth, 1), PrimaryView.ScreenToTranslatedWorld).xyz;
const float3 CameraVector = normalize(WorldPosition - PrimaryView.TranslatedWorldCameraOrigin);
const float3 TranslatedWorldPosition = WorldPosition;
const float3 V = -CameraVector;
#if DEBUG_ENABLE
const float3x3 TangentBasis = GetTangentBasis(N);
const uint2 CursorCoord = GetCursorPos();
const bool bDebugEnabled = all(CursorCoord == uint2(PixelPos));
if (bDebugEnabled)
{
AddReferentialTWS(WorldPosition, TangentBasis[0], TangentBasis[1], TangentBasis[2], 3.f);
AddLineTWS(WorldPosition, WorldPosition + V * 3.0f, ColorPurple);
}
#endif
if (bIsValid)
{
const uint NumSets = 3;
const uint AllocNumSets = 3;
const uint NumSamples[AllocNumSets] =
{
NumSamplesPerSet, // GGX
NumSamplesPerSet, // Cosine hemisphere
NumSamplesPerSet, // GGX coat
};
float3 Acc = 0.f;
float3 FinalRadiance = 0.f;
// Set loop (Cosine/GGX/... distribuciton)
LOOP
for (uint Set = 0; Set < NumSets; Set++)
{
// Samples loop
LOOP
for (uint SampleIt = 0; SampleIt < NumSamples[Set]; ++SampleIt)
{
const float2 E = Hammersley(SampleIt, NumSamples[Set], 0);
// Sample generation
float3 L = 0, H = 0;
if (Set == 0)
{
H = TangentToWorld(ImportanceSampleGGX(E, Pow4(Roughness)).xyz, N);
L = 2 * dot(V, H) * H - V;
}
else if (Set == 1)
{
L = TangentToWorld(CosineSampleHemisphere(E).xyz, N);
H = normalize(V + L);
}
else if (Set == 2)
{
H = TangentToWorld(ImportanceSampleGGX(E, Pow4(ClearCoatRoughness)).xyz, N);
L = 2 * dot(V, H) * H - V;
}
const float NoL = saturate(dot(N, L));
const float NoH = saturate(dot(N, H));
const float VoH = saturate(dot(V, H));
// PDFs
float PDFs[] =
{
NoH > 0 && VoH > 0 ? D_GGX(Pow4(Roughness), NoH) * NoH / (4 * VoH) : 0.f,
NoL / PI,
NoH > 0 && VoH > 0 ? D_GGX(Pow4(ClearCoatRoughness), NoH) * NoH / (4 * VoH) : 0.f,
};
// MIS power heuristic
float InvWeight = 0;
UNROLL for (uint j = 0; j < NumSets; j++)
{
InvWeight += Square(PDFs[j] * NumSamples[j]);
}
float Weight = (InvWeight > 0.f ? rcp(InvWeight) : 0.f) * PDFs[Set] * NumSamples[Set];
#if DEBUG_ENABLE
if (bDebugEnabled)
{
const float Scale = Set == 0 ? 1.f : 2.0f;
const float4 DebugColor = Set == 0 ? ColorOrange : ColorEmerald;
AddLineTWS(WorldPosition, WorldPosition + L * Scale, DebugColor);
}
#endif
FDeferredLightData LightData;
{
LightData.TranslatedWorldPosition = float3(0,0,0); // Directional light
LightData.InvRadius = 0.f; // Directional light
LightData.Color = InRadiance;
LightData.FalloffExponent = 0.f; // Directional light
LightData.Direction = L;
LightData.Tangent = float3(1,0,0);
LightData.SpotAngles = 0.f;
LightData.SourceRadius = 0.f;
LightData.SourceLength = 0.f;
LightData.SoftSourceRadius = 0.f;
LightData.SpecularScale = 1.0f;
LightData.DiffuseScale = 1.0f;
LightData.ContactShadowLength = 0.f;
LightData.ContactShadowLengthInWS = 0.f;
LightData.ContactShadowCastingIntensity = 1.f;
LightData.ContactShadowNonCastingIntensity = 0.f;
LightData.DistanceFadeMAD = 0.f;
LightData.ShadowMapChannelMask = 0;
LightData.ShadowedBits = 0;
LightData.bInverseSquared = false; // Directional light
LightData.bRadialLight = false;
LightData.bSpotLight = false;
LightData.bRectLight = false;
LightData.RectLightData.BarnCosAngle= 0.f;
LightData.RectLightData.BarnLength = 0.f;
LightData.RectLightData.AtlasData.AtlasUVOffset = 0.f;
LightData.RectLightData.AtlasData.AtlasUVScale = 0.f;
LightData.RectLightData.AtlasData.AtlasMaxLevel = 0.f;
LightData.HairTransmittance = InitHairTransmittanceData();
LightData.ShadowedBits = 0;
}
float3 SampleRadiance = 0;
#if !SUBSTRATE_ENABLED
{
float SurfaceShadow = 1.0f;
SampleRadiance = GetDynamicLighting(
TranslatedWorldPosition,
CameraVector,
ScreenSpaceData.GBuffer,
ScreenSpaceData.AmbientOcclusion,
LightData,
PixelLightAttenuation,
Dither,
uint2(PixelPos),
SurfaceShadow).xyz;
}
#elif 0
{
FSubstrateAddressing SubstrateAddressing = GetSubstratePixelDataByteOffset(PixelPos, uint2(View.BufferSizeAndInvSize.xy), Substrate.MaxBytesPerPixel);
FSubstratePixelHeader SubstratePixelHeader = UnpackSubstrateHeaderIn(Substrate.MaterialTextureArray, SubstrateAddressing, Substrate.TopLayerTexture);
const float LightMask = 1;
BRANCH
if (SubstratePixelHeader.BSDFCount > 0)
{
HEADER_SETIRRADIANCE_AO(SubstratePixelHeader.State, SubstratePackIrradianceAndOcclusion(1.0, 1.0));
FSubstrateShadowTermInputParameters SubstrateShadowTermInputParameters = GetInitialisedSubstrateShadowTermInputParameters();
SubstrateShadowTermInputParameters.bEvaluateShadowTerm = false;
SampleRadiance = SubstrateDeferredLighting(
LightData,
V,
L,
L,
LightMask,
SubstrateShadowTermInputParameters,
RectTexture,
Substrate.MaterialTextureArray,
SubstrateAddressing,
SubstratePixelHeader).xyz;
}
}
#endif
FinalRadiance += Weight * SampleRadiance;
}
OutColor = float4(FinalRadiance, 1.f);
}
}
else
{
OutColor = float4(InRadiance, 1.f);
}
}
#endif // SHADER_FURNACE_ANALYTIC
////////////////////////////////////////////////////////////////////////////////////////////////////////////