Files
UnrealEngine/Engine/Source/Runtime/Renderer/Private/HairStrands/HairStrandsEnvironment.cpp
2025-05-18 13:04:45 +08:00

569 lines
27 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "HairStrandsEnvironment.h"
#include "BasePassRendering.h"
#include "Shader.h"
#include "GlobalShader.h"
#include "ShaderParameters.h"
#include "ShaderParameterStruct.h"
#include "SceneTextureParameters.h"
#include "SceneRenderTargetParameters.h"
#include "RenderGraph.h"
#include "RenderGraphUtils.h"
#include "SceneRendering.h"
#include "PixelShaderUtils.h"
#include "SystemTextures.h"
#include "HairStrandsRendering.h"
#include "ReflectionEnvironment.h"
#include "ScenePrivate.h"
#include "SceneProxies/SkyLightSceneProxy.h"
#include "RenderGraphEvent.h"
#include "PostProcess/PostProcessing.h"
#include "ShaderPrint.h"
#include "Lumen/LumenRadianceCache.h"
#include "Lumen/LumenScreenProbeGather.h"
#include "IndirectLightRendering.h"
#include "DistanceFieldAmbientOcclusion.h"
#include "RenderGraphEvent.h"
///////////////////////////////////////////////////////////////////////////////////////////////////
static int32 GHairScatterSceneLighting = 1;
static FAutoConsoleVariableRef CVarHairScatterSceneLighting(TEXT("r.HairStrands.ScatterSceneLighting"), GHairScatterSceneLighting, TEXT("Enable scene color lighting scattering into hair (valid for short hair only)."));
static int32 GHairSkylightingEnable = 1;
static FAutoConsoleVariableRef CVarHairSkylightingEnable(TEXT("r.HairStrands.SkyLighting"), GHairSkylightingEnable, TEXT("Enable sky lighting on hair."));
static int32 GHairSkyAOEnable = 1;
static FAutoConsoleVariableRef CVarHairSkyAOEnable(TEXT("r.HairStrands.SkyAO"), GHairSkyAOEnable, TEXT("Enable (sky) AO on hair."));
static float GHairSkylightingConeAngle = 3;
static FAutoConsoleVariableRef CVarHairSkylightingConeAngle(TEXT("r.HairStrands.SkyLighting.ConeAngle"), GHairSkylightingConeAngle, TEXT("Cone angle for tracing sky lighting on hair."));
static int32 GHairStrandsSkyLightingSampleCount = 16;
static FAutoConsoleVariableRef CVarHairStrandsSkyLightingSampleCount(TEXT("r.HairStrands.SkyLighting.SampleCount"), GHairStrandsSkyLightingSampleCount, TEXT("Number of samples used for evaluating multiple scattering and visible area (default is set to 16)."), ECVF_Scalability | ECVF_RenderThreadSafe);
static int32 GHairStrandsSkyAOSampleCount = 4;
static FAutoConsoleVariableRef CVarHairStrandsSkyAOSampleCount(TEXT("r.HairStrands.SkyAO.SampleCount"), GHairStrandsSkyAOSampleCount, TEXT("Number of samples used for evaluating hair AO (default is set to 16)."), ECVF_Scalability | ECVF_RenderThreadSafe);
static float GHairStrandsTransmissionDensityScaleFactor = 10;
static FAutoConsoleVariableRef CVarHairStrandsTransmissionDensityScaleFactor(TEXT("r.HairStrands.SkyLighting.TransmissionDensityScale"), GHairStrandsTransmissionDensityScaleFactor, TEXT("Density scale for controlling how much sky lighting is transmitted."), ECVF_Scalability | ECVF_RenderThreadSafe);
static int32 GHairStrandsSkyLightingUseHairCountTexture = 1;
static FAutoConsoleVariableRef CVarHairStrandsSkyLightingUseHairCountTexture(TEXT("r.HairStrands.SkyLighting.UseViewHairCount"), GHairStrandsSkyLightingUseHairCountTexture, TEXT("Use the view hair count texture for estimating background transmitted light (enabled by default)."), ECVF_Scalability | ECVF_RenderThreadSafe);
static float GHairStrandsSkyAODistanceThreshold = 10;
static float GHairStrandsSkyLightingDistanceThreshold = 10;
static FAutoConsoleVariableRef CVarHairStrandsSkyAOThreshold(TEXT("r.HairStrands.SkyAO.DistanceThreshold"), GHairStrandsSkyAODistanceThreshold, TEXT("Max distance for occlusion search."), ECVF_Scalability | ECVF_RenderThreadSafe);
static FAutoConsoleVariableRef CVarHairStrandsSkyLightingDistanceThreshold(TEXT("r.HairStrands.SkyLighting.DistanceThreshold"), GHairStrandsSkyLightingDistanceThreshold, TEXT("Max distance for occlusion search."), ECVF_Scalability | ECVF_RenderThreadSafe);
static int32 GHairStrandsSkyLighting_IntegrationType = 2;
static FAutoConsoleVariableRef CVarHairStrandsSkyLighting_IntegrationType(TEXT("r.HairStrands.SkyLighting.IntegrationType"), GHairStrandsSkyLighting_IntegrationType, TEXT("Hair env. lighting integration type (0:Adhoc, 1:Uniform."), ECVF_Scalability | ECVF_RenderThreadSafe);
static int32 GHairStrandsSkyLighting_DebugSample = 0;
static FAutoConsoleVariableRef CVarHairStrandsSkyLighting_DebugSample(TEXT("r.HairStrands.SkyLighting.DebugSample"), GHairStrandsSkyLighting_DebugSample, TEXT("Enable debug view for visualizing sample used for the sky integration"), ECVF_Scalability | ECVF_RenderThreadSafe);
static int32 GHairStrandsSkyLighting_ScreenTraceOcclusion = 0;
static FAutoConsoleVariableRef CVarHairStrandsSkyLighting_ScreenTraceOcclusion(TEXT("r.HairStrands.SkyLighting.ScreenTraceOcclusion"), GHairStrandsSkyLighting_ScreenTraceOcclusion, TEXT("Enable screen trace occlusion for during hair env. lighting integration"), ECVF_Scalability | ECVF_RenderThreadSafe);
///////////////////////////////////////////////////////////////////////////////////////////////////
DECLARE_GPU_STAT_NAMED(HairSkyLighting, TEXT("Hair Sky lighting"));
///////////////////////////////////////////////////////////////////////////////////////////////////
enum class EHairLightingSourceType : uint8
{
SceneColor = 0,
ReflectionProbe = 1,
Lumen = 2,
Count
};
enum class EHairLightingIntegrationType : uint8
{
SceneColor = 0,
AdHoc = 1,
Uniform = 2,
SH = 3,
Count
};
bool GetHairStrandsSkyLightingEnable() { return GHairSkylightingEnable > 0; }
bool GetHairStrandsSkyLightingDebugEnable() { return GHairSkylightingEnable > 0 && GHairStrandsSkyLighting_DebugSample > 0; }
static bool GetHairStrandsSkyAOEnable() { return GHairSkyAOEnable > 0; }
static float GetHairStrandsSkyLightingConeAngle() { return FMath::Max(0.f, GHairSkylightingConeAngle); }
DECLARE_GPU_STAT_NAMED(HairStrandsReflectionEnvironment, TEXT("Hair Strands Reflection Environment"));
///////////////////////////////////////////////////////////////////////////////////////////////////
// AO
class FHairEnvironmentAO : public FGlobalShader
{
DECLARE_GLOBAL_SHADER(FHairEnvironmentAO);
SHADER_USE_PARAMETER_STRUCT(FHairEnvironmentAO, FGlobalShader)
class FSampleSet : SHADER_PERMUTATION_INT("PERMUTATION_SAMPLESET", 2);
using FPermutationDomain = TShaderPermutationDomain<FSampleSet>;
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
return IsHairStrandsSupported(EHairStrandsShaderType::Strands, Parameters.Platform);
}
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER(uint32, Voxel_MacroGroupId)
SHADER_PARAMETER(float, Voxel_TanConeAngle)
SHADER_PARAMETER(float, AO_Power)
SHADER_PARAMETER(float, AO_Intensity)
SHADER_PARAMETER(uint32, AO_SampleCount)
SHADER_PARAMETER(float, AO_DistanceThreshold)
SHADER_PARAMETER(uint32, Output_bHalfRes)
SHADER_PARAMETER(FVector2f, Output_InvResolution)
SHADER_PARAMETER_STRUCT_INCLUDE(FSceneTextureParameters, SceneTextures)
SHADER_PARAMETER_STRUCT_REF(FViewUniformShaderParameters, ViewUniformBuffer)
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FVirtualVoxelParameters, VirtualVoxel)
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FHairStrandsViewUniformParameters, HairStrands)
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FSubstrateGlobalUniformParameters, Substrate)
SHADER_PARAMETER_STRUCT_INCLUDE(ShaderPrint::FShaderParameters, ShaderPrintParameters)
RENDER_TARGET_BINDING_SLOTS()
END_SHADER_PARAMETER_STRUCT()
};
IMPLEMENT_GLOBAL_SHADER(FHairEnvironmentAO, "/Engine/Private/HairStrands/HairStrandsEnvironmentAO.usf", "MainPS", SF_Pixel);
static void AddHairStrandsEnvironmentAOPass(
FRDGBuilder& GraphBuilder,
const FViewInfo& View,
const FHairStrandsVoxelResources& VoxelResources,
const FHairStrandsMacroGroupData& MacroGroupData,
FRDGTextureRef Output)
{
check(Output);
FSceneTextureParameters SceneTextures = GetSceneTextureParameters(GraphBuilder, View);
const FIntRect Viewport = View.ViewRect;
const FIntRect HalfResViewport = FIntRect::DivideAndRoundUp(Viewport, 2);
const bool bHalfRes = Output->Desc.Extent.X == HalfResViewport.Width();
FHairEnvironmentAO::FParameters* PassParameters = GraphBuilder.AllocParameters<FHairEnvironmentAO::FParameters>();
PassParameters->Voxel_MacroGroupId = MacroGroupData.MacroGroupId;
PassParameters->Voxel_TanConeAngle = View.IsPerspectiveProjection() ? FMath::Tan(FMath::DegreesToRadians(GetHairStrandsSkyLightingConeAngle())) : 1.0f;
PassParameters->SceneTextures = SceneTextures;
PassParameters->VirtualVoxel = VoxelResources.UniformBuffer;
PassParameters->ViewUniformBuffer = View.ViewUniformBuffer;
PassParameters->HairStrands = HairStrands::BindHairStrandsViewUniformParameters(View);
PassParameters->Substrate = Substrate::BindSubstrateGlobalUniformParameters(View);
const FFinalPostProcessSettings& Settings = View.FinalPostProcessSettings;
PassParameters->AO_Power = Settings.AmbientOcclusionPower;
PassParameters->AO_Intensity = Settings.AmbientOcclusionIntensity;
PassParameters->AO_SampleCount = FMath::Max(uint32(GHairStrandsSkyAOSampleCount), 1u);
PassParameters->AO_DistanceThreshold = FMath::Max(GHairStrandsSkyAODistanceThreshold, 1.f);
PassParameters->RenderTargets[0] = FRenderTargetBinding(Output, ERenderTargetLoadAction::ELoad);
PassParameters->Output_bHalfRes = bHalfRes;
PassParameters->Output_InvResolution = FVector2f(1.f/Output->Desc.Extent.X, 1.f/Output->Desc.Extent.Y);
FIntRect ViewRect;
if (bHalfRes)
{
ViewRect.Min.X = 0;
ViewRect.Min.Y = 0;
ViewRect.Max = Output->Desc.Extent;
}
else
{
ViewRect = View.ViewRect;
}
if (ShaderPrint::IsValid(View.ShaderPrintData))
{
ShaderPrint::SetParameters(GraphBuilder, View.ShaderPrintData, PassParameters->ShaderPrintParameters);
}
FHairEnvironmentAO::FPermutationDomain PermutationVector;
PermutationVector.Set<FHairEnvironmentAO::FSampleSet>(PassParameters->AO_SampleCount <= 16 ? 0 : 1);
TShaderMapRef<FHairEnvironmentAO> PixelShader(View.ShaderMap, PermutationVector);
ClearUnusedGraphResources(PixelShader, PassParameters);
GraphBuilder.AddPass(
RDG_EVENT_NAME("HairStrands::AO %dx%d", ViewRect.Width(), ViewRect.Height()),
PassParameters,
ERDGPassFlags::Raster,
[PassParameters, &View, PixelShader, ViewRect](FRDGAsyncTask, FRHICommandList& InRHICmdList)
{
InRHICmdList.SetViewport(ViewRect.Min.X, ViewRect.Min.Y, 0.0f, ViewRect.Max.X, ViewRect.Max.Y, 1.0f);
FGraphicsPipelineStateInitializer GraphicsPSOInit;
FPixelShaderUtils::InitFullscreenPipelineState(InRHICmdList, View.ShaderMap, PixelShader, GraphicsPSOInit);
GraphicsPSOInit.BlendState = TStaticBlendState<CW_RGBA, BO_Min, BF_SourceColor, BF_DestColor, BO_Add, BF_Zero, BF_DestAlpha>::GetRHI();
SetGraphicsPipelineState(InRHICmdList, GraphicsPSOInit, 0);
SetShaderParameters(InRHICmdList, PixelShader, PixelShader.GetPixelShader(), *PassParameters);
FPixelShaderUtils::DrawFullscreenTriangle(InRHICmdList);
});
}
///////////////////////////////////////////////////////////////////////////////////////////////////
class FHairEnvironmentLightingVS : public FGlobalShader
{
DECLARE_GLOBAL_SHADER(FHairEnvironmentLightingVS);
SHADER_USE_PARAMETER_STRUCT(FHairEnvironmentLightingVS, FGlobalShader)
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FHairStrandsViewUniformParameters, HairStrands)
END_SHADER_PARAMETER_STRUCT()
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
{
OutEnvironment.SetDefine(TEXT("LIGHTING_VS"), 1);
}
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
return IsHairStrandsSupported(EHairStrandsShaderType::Strands, Parameters.Platform);
}
};
class FHairEnvironmentLightingPS : public FGlobalShader
{
DECLARE_GLOBAL_SHADER(FHairEnvironmentLightingPS);
SHADER_USE_PARAMETER_STRUCT(FHairEnvironmentLightingPS, FGlobalShader)
class FIntegrationType : SHADER_PERMUTATION_INT("PERMUTATION_INTEGRATION_TYPE", uint32(EHairLightingIntegrationType::Count));
class FDebug : SHADER_PERMUTATION_BOOL("PERMUTATION_DEBUG");
class FLumen : SHADER_PERMUTATION_BOOL("PERMUTATION_LUMEN");
class FStaticLighting : SHADER_PERMUTATION_BOOL("PERMUTATION_STATIC_LIGHTING");
using FPermutationDomain = TShaderPermutationDomain<FIntegrationType, FLumen, FDebug, FStaticLighting>;
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER_STRUCT_INCLUDE(FSkyDiffuseLightingParameters, SkyDiffuseLighting)
SHADER_PARAMETER_STRUCT_INCLUDE(FSceneTextureParameters, SceneTextures)
SHADER_PARAMETER_STRUCT_INCLUDE(LumenRadianceCache::FRadianceCacheInterpolationParameters, RadianceCache)
SHADER_PARAMETER_STRUCT_INCLUDE(ShaderPrint::FShaderParameters, ShaderPrintParameters)
SHADER_PARAMETER_STRUCT_INCLUDE(FHairStrandsDebugData::FWriteParameters, DebugData)
SHADER_PARAMETER_STRUCT_REF(FBlueNoise, BlueNoise)
SHADER_PARAMETER(uint32, bDynamicSkyLight)
SHADER_PARAMETER(uint32, bHasStaticLighting)
SHADER_PARAMETER(uint32, MultipleScatterSampleCount)
SHADER_PARAMETER(float, HairDualScatteringRoughnessOverride)
SHADER_PARAMETER(float, TransmissionDensityScaleFactor)
SHADER_PARAMETER(float, HairDistanceThreshold)
SHADER_PARAMETER(uint32, bHairUseViewHairCount)
SHADER_PARAMETER(uint32, bScreenTrace)
SHADER_PARAMETER(float, SlopeCompareToleranceScale)
SHADER_PARAMETER(float, MaxScreenTraceFraction)
SHADER_PARAMETER(float, ScreenTraceNoFallbackThicknessScale)
SHADER_PARAMETER_STRUCT_INCLUDE(FHZBParameters, HZBParameters)
SHADER_PARAMETER_TEXTURE(Texture2D, PreIntegratedGF)
SHADER_PARAMETER_SAMPLER(SamplerState, PreIntegratedGFSampler)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D, SceneColorTexture)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D, HairEnergyLUTTexture)
SHADER_PARAMETER_STRUCT_REF(FViewUniformShaderParameters, ViewUniformBuffer)
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FReflectionUniformParameters, ReflectionsParameters)
SHADER_PARAMETER_STRUCT_REF(FReflectionCaptureShaderData, ReflectionCaptureData)
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FForwardLightUniformParameters, ForwardLightStruct)
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FHairStrandsViewUniformParameters, HairStrands)
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FVirtualVoxelParameters, VirtualVoxel)
SHADER_PARAMETER_RDG_BUFFER_UAV(RWBuffer, OutLightingBuffer)
RENDER_TARGET_BINDING_SLOTS()
END_SHADER_PARAMETER_STRUCT()
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
{
FForwardLightingParameters::ModifyCompilationEnvironment(Parameters.Platform, OutEnvironment);
OutEnvironment.SetDefine(TEXT("LIGHTING_PS"), 1);
}
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
// Compile debug permutation only for the uniform integrator
FPermutationDomain PermutationVector(Parameters.PermutationId);
if (PermutationVector.Get<FIntegrationType>() != int32(EHairLightingIntegrationType::Uniform) && PermutationVector.Get<FDebug>())
{
return false;
}
// If using Lumen, no static lighting
if (PermutationVector.Get<FStaticLighting>() && PermutationVector.Get<FLumen>())
{
return false;
}
// If using another integrator than SH integrator, no static lighting
if (PermutationVector.Get<FStaticLighting>() && PermutationVector.Get<FIntegrationType>() != int32(EHairLightingIntegrationType::SH))
{
return false;
}
return IsHairStrandsSupported(EHairStrandsShaderType::Strands, Parameters.Platform);
}
static FPermutationDomain RemapPermutation(FPermutationDomain PermutationVector)
{
if (PermutationVector.Get<FIntegrationType>() != int32(EHairLightingIntegrationType::Uniform))
{
PermutationVector.Set<FDebug>(false);
}
return PermutationVector;
}
};
IMPLEMENT_GLOBAL_SHADER(FHairEnvironmentLightingPS, "/Engine/Private/HairStrands/HairStrandsEnvironmentLighting.usf", "MainPS", SF_Pixel);
IMPLEMENT_GLOBAL_SHADER(FHairEnvironmentLightingVS, "/Engine/Private/HairStrands/HairStrandsEnvironmentLighting.usf", "MainVS", SF_Vertex);
static void AddHairStrandsEnvironmentLightingPassPS(
FRDGBuilder& GraphBuilder,
const FScene* Scene,
const FViewInfo& View,
const FHairStrandsVisibilityData& VisibilityData,
const FHairStrandsVoxelResources& VirtualVoxelResources,
const FRDGTextureRef SceneColorTexture,
const EHairLightingSourceType LightingType,
const FHairStrandsDebugData::FPlotData* DebugData)
{
if (!Scene)
{
return;
}
EHairLightingIntegrationType IntegrationType = EHairLightingIntegrationType::AdHoc;
if (LightingType == EHairLightingSourceType::SceneColor)
{
check(SceneColorTexture != nullptr);
IntegrationType = EHairLightingIntegrationType::SceneColor;
}
else
{
switch (GHairStrandsSkyLighting_IntegrationType)
{
case 0: IntegrationType = EHairLightingIntegrationType::AdHoc; break;
case 1: IntegrationType = EHairLightingIntegrationType::Uniform; break;
case 2: IntegrationType = EHairLightingIntegrationType::SH; break;
}
}
// The specular sky light contribution is also needed by RT Reflections as a fallback.
const bool bSkyLight = Scene->SkyLight && !Scene->SkyLight->bHasStaticLighting;
const bool bDynamicSkyLight = ShouldRenderDeferredDynamicSkyLight(Scene, *View.Family);
const bool bReflectionEnv = ShouldDoReflectionEnvironment(Scene, *View.Family);
// Only support static lighting with SH integrator at the moment
const bool bUseVolumetricLightmap = Scene && Scene->VolumetricLightmapSceneData.HasData();
const bool bLumenActive = ShouldRenderLumenDiffuseGI(Scene, View);
const bool bHasStaticLighting = IsStaticLightingAllowed() && bUseVolumetricLightmap && !bLumenActive && IntegrationType == EHairLightingIntegrationType::SH;
// Sanity check
if (bHasStaticLighting) { check(LightingType != EHairLightingSourceType::Lumen); }
// Early out if there is no static lighting, no sky lighting, nor reflection probes, nor Lumen
if (!bSkyLight && !bDynamicSkyLight && !bHasStaticLighting && !bReflectionEnv && !bLumenActive && IntegrationType != EHairLightingIntegrationType::SceneColor)
return;
FSceneTextureParameters SceneTextures = GetSceneTextureParameters(GraphBuilder, View);
check(VirtualVoxelResources.IsValid());
// Render the reflection environment with tiled deferred culling
const bool bHasBoxCaptures = (View.NumBoxReflectionCaptures > 0);
const bool bHasSphereCaptures = (View.NumSphereReflectionCaptures > 0);
FHairEnvironmentLightingPS::FParameters* ParametersPS = GraphBuilder.AllocParameters<FHairEnvironmentLightingPS::FParameters>();
ParametersPS->SceneColorTexture = SceneColorTexture;
ParametersPS->HairEnergyLUTTexture = GetHairLUT(GraphBuilder, View, HairLUTType_MeanEnergy);
ParametersPS->bDynamicSkyLight = bDynamicSkyLight ? 1 : 0;
ParametersPS->bHasStaticLighting = bHasStaticLighting ? 1 : 0;
ParametersPS->SkyDiffuseLighting = GetSkyDiffuseLightingParameters(Scene->SkyLight, 1.0f /*DynamicBentNormalAO*/);
ParametersPS->HairDistanceThreshold = FMath::Max(GHairStrandsSkyLightingDistanceThreshold, 1.f);
ParametersPS->bHairUseViewHairCount = VisibilityData.ViewHairCountTexture && GHairStrandsSkyLightingUseHairCountTexture ? 1 : 0;
ParametersPS->MultipleScatterSampleCount = FMath::Max(uint32(GHairStrandsSkyLightingSampleCount), 1u);
ParametersPS->HairDualScatteringRoughnessOverride = GetHairDualScatteringRoughnessOverride();
ParametersPS->TransmissionDensityScaleFactor = FMath::Max(0.f, GHairStrandsTransmissionDensityScaleFactor);
ParametersPS->PreIntegratedGF = GSystemTextures.PreintegratedGF->GetRHI();
ParametersPS->PreIntegratedGFSampler = TStaticSamplerState<SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
ParametersPS->SceneTextures = SceneTextures;
ParametersPS->VirtualVoxel = VirtualVoxelResources.UniformBuffer;
ParametersPS->HairStrands = HairStrands::BindHairStrandsViewUniformParameters(View);
ParametersPS->ViewUniformBuffer = View.ViewUniformBuffer;
ParametersPS->ReflectionCaptureData = View.ReflectionCaptureUniformBuffer;
ParametersPS->ReflectionsParameters = CreateReflectionUniformBuffer(GraphBuilder, View);
FBlueNoise BlueNoise = GetBlueNoiseGlobalParameters();
ParametersPS->BlueNoise = CreateUniformBufferImmediate(BlueNoise, EUniformBufferUsage::UniformBuffer_SingleDraw);
const bool bScreenTrace = IsHZBValid(View, EHZBType::FurthestHZB) && GHairStrandsSkyLighting_ScreenTraceOcclusion && IntegrationType != EHairLightingIntegrationType::SceneColor;
ParametersPS->bScreenTrace = bScreenTrace ? 1u : 0u;
if (bScreenTrace)
{
// Default values, need more more testing/tweaking
const float MaxScreenTraceFraction = 128 * 2.0f / (float)View.ViewRect.Width();
const float ScreenTraceNoFallbackThicknessScale = View.ViewMatrices.GetPerProjectionDepthThicknessScale();
ParametersPS->HZBParameters = GetHZBParameters(GraphBuilder, View, EHZBType::FurthestHZB);
ParametersPS->MaxScreenTraceFraction = MaxScreenTraceFraction;
ParametersPS->ScreenTraceNoFallbackThicknessScale = ScreenTraceNoFallbackThicknessScale;
ParametersPS->SlopeCompareToleranceScale = 0.5f;
}
else
{
ParametersPS->HZBParameters = GetDummyHZBParameters(GraphBuilder);
}
if (LightingType == EHairLightingSourceType::Lumen)
{
const FRadianceCacheState& RadianceCacheState = View.ViewState->Lumen.RadianceCacheState;
const LumenRadianceCache::FRadianceCacheInputs RadianceCacheInputs = LumenScreenProbeGatherRadianceCache::SetupRadianceCacheInputs(View);
LumenRadianceCache::GetInterpolationParameters(View, GraphBuilder, RadianceCacheState, RadianceCacheInputs, ParametersPS->RadianceCache);
}
ParametersPS->ForwardLightStruct = View.ForwardLightingResources.ForwardLightUniformBuffer;
ParametersPS->OutLightingBuffer = nullptr;
if (ShaderPrint::IsValid(View.ShaderPrintData))
{
ShaderPrint::SetParameters(GraphBuilder, View.ShaderPrintData, ParametersPS->ShaderPrintParameters);
}
if (DebugData)
{
FHairStrandsDebugData::SetParameters(GraphBuilder, *DebugData, ParametersPS->DebugData);
}
FHairEnvironmentLightingPS::FPermutationDomain PermutationVector;
PermutationVector.Set<FHairEnvironmentLightingPS::FIntegrationType>(uint32(IntegrationType));
PermutationVector.Set<FHairEnvironmentLightingPS::FLumen>(LightingType == EHairLightingSourceType::Lumen);
PermutationVector.Set<FHairEnvironmentLightingPS::FDebug>(DebugData != nullptr);
PermutationVector.Set<FHairEnvironmentLightingPS::FStaticLighting>(bHasStaticLighting);
PermutationVector = FHairEnvironmentLightingPS::RemapPermutation(PermutationVector);
FIntPoint ViewportResolution = VisibilityData.SampleLightingViewportResolution;
const FViewInfo* CapturedView = &View;
TShaderMapRef<FHairEnvironmentLightingVS> VertexShader(View.ShaderMap);
TShaderMapRef<FHairEnvironmentLightingPS> PixelShader(View.ShaderMap, PermutationVector);
check(VisibilityData.SampleLightingTexture);
ParametersPS->RenderTargets[0] = FRenderTargetBinding(VisibilityData.SampleLightingTexture, ERenderTargetLoadAction::ELoad);
GraphBuilder.AddPass(
RDG_EVENT_NAME("HairStrands::EnvLightingPS(%s)", LightingType == EHairLightingSourceType::SceneColor ? TEXT("SceneScatter") : (LightingType == EHairLightingSourceType::Lumen ? TEXT("Lumen") : TEXT("ReflectionProbe")) ),
ParametersPS,
ERDGPassFlags::Raster,
[ParametersPS, VertexShader, PixelShader, ViewportResolution, CapturedView](FRDGAsyncTask, FRHICommandList& RHICmdList)
{
FHairEnvironmentLightingVS::FParameters ParametersVS;
ParametersVS.HairStrands = ParametersPS->HairStrands;
FGraphicsPipelineStateInitializer GraphicsPSOInit;
RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit);
GraphicsPSOInit.BlendState = TStaticBlendState<CW_RGBA, BO_Add, BF_One, BF_One, BO_Max, BF_One, BF_One>::GetRHI();
GraphicsPSOInit.RasterizerState = TStaticRasterizerState<>::GetRHI();
GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState<false, CF_Always>::GetRHI();
GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GFilterVertexDeclaration.VertexDeclarationRHI;
GraphicsPSOInit.BoundShaderState.VertexShaderRHI = VertexShader.GetVertexShader();
GraphicsPSOInit.BoundShaderState.PixelShaderRHI = PixelShader.GetPixelShader();
GraphicsPSOInit.PrimitiveType = PT_TriangleList;
SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit, 0);
SetShaderParameters(RHICmdList, VertexShader, VertexShader.GetVertexShader(), ParametersVS);
SetShaderParameters(RHICmdList, PixelShader, PixelShader.GetPixelShader(), *ParametersPS);
RHICmdList.SetViewport(0, 0, 0.0f, ViewportResolution.X, ViewportResolution.Y, 1.0f);
RHICmdList.SetStreamSource(0, nullptr, 0);
RHICmdList.DrawPrimitive(0, 1, 1);
});
}
///////////////////////////////////////////////////////////////////////////////////////////////////
void RenderHairStrandsSceneColorScattering(
FRDGBuilder& GraphBuilder,
FRDGTextureRef SceneColorTexture,
const FScene* Scene,
TArrayView<const FViewInfo> Views)
{
if (Views.Num() == 0 || GHairScatterSceneLighting <= 0)
return;
for (const FViewInfo& View : Views)
{
if (!HairStrands::HasViewHairStrandsData(View))
{
continue;
}
const FHairStrandsVisibilityData& VisibilityData = View.HairStrandsViewData.VisibilityData;
const FHairStrandsVoxelResources& VoxelResources = View.HairStrandsViewData.VirtualVoxelResources;
check(VoxelResources.IsValid());
if (HasHairFlags(View.HairStrandsViewData.Flags, HAIR_FLAGS_SCATTER_SCENE_LIGHT))
{
AddHairStrandsEnvironmentLightingPassPS(GraphBuilder, Scene, View, VisibilityData, VoxelResources, SceneColorTexture, EHairLightingSourceType::SceneColor, nullptr);
}
}
}
static void InternalRenderHairStrandsEnvironmentLighting(
FRDGBuilder& GraphBuilder,
const FScene* Scene,
const FViewInfo& View,
EHairLightingSourceType LightingType)
{
if (!GetHairStrandsSkyLightingEnable() || !HairStrands::HasViewHairStrandsData(View))
return;
const FHairStrandsVisibilityData& VisibilityData = View.HairStrandsViewData.VisibilityData;
const FHairStrandsVoxelResources& VoxelResources = View.HairStrandsViewData.VirtualVoxelResources;
const bool bRenderHairLighting = VoxelResources.IsValid() && VisibilityData.CoverageTexture;
if (!bRenderHairLighting)
{
return;
}
AddHairStrandsEnvironmentLightingPassPS(GraphBuilder, Scene, View, VisibilityData, VoxelResources, nullptr, LightingType, View.HairStrandsViewData.DebugData.IsPlotDataValid() ? &View.HairStrandsViewData.DebugData.PlotData : nullptr);
}
void RenderHairStrandsLumenLighting(
FRDGBuilder& GraphBuilder,
const FScene* Scene,
const FViewInfo& View)
{
InternalRenderHairStrandsEnvironmentLighting(GraphBuilder, Scene, View, EHairLightingSourceType::Lumen);
}
void RenderHairStrandsEnvironmentLighting(
FRDGBuilder& GraphBuilder,
const FScene* Scene,
const FViewInfo& View)
{
RDG_EVENT_SCOPE_STAT(GraphBuilder, HairSkyLighting, "HairSkyLighting");
RDG_GPU_STAT_SCOPE(GraphBuilder, HairSkyLighting);
InternalRenderHairStrandsEnvironmentLighting(GraphBuilder, Scene, View, EHairLightingSourceType::ReflectionProbe);
}
void RenderHairStrandsAmbientOcclusion(
FRDGBuilder& GraphBuilder,
const FViewInfo& View,
const FRDGTextureRef& InAOTexture)
{
if (!GetHairStrandsSkyAOEnable() || !HairStrands::HasViewHairStrandsData(View) || !InAOTexture)
return;
const FHairStrandsVisibilityData& VisibilityData = View.HairStrandsViewData.VisibilityData;
const FHairStrandsVoxelResources& VoxelResources = View.HairStrandsViewData.VirtualVoxelResources;
const bool bRenderHairLighting = VoxelResources.IsValid() && VisibilityData.CoverageTexture;
check(bRenderHairLighting);
for (const FHairStrandsMacroGroupData& MacroGroupData : View.HairStrandsViewData.MacroGroupDatas)
{
AddHairStrandsEnvironmentAOPass(GraphBuilder, View, VoxelResources, MacroGroupData, InAOTexture);
}
}