// 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 ////////////////////////////////////////////////////////////////////////////////////////////////////////////